/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\ |* *| |* The LLVM Compiler Infrastructure *| |* *| |* This file is distributed under the University of Illinois Open Source *| |* License. See LICENSE.TXT for details. *| |* *| |*===----------------------------------------------------------------------===*| |* *| |* Implements the diagnostic functions of the Clang C interface. *| |* *| \*===----------------------------------------------------------------------===*/ #include "CIndexDiagnostic.h" #include "CIndexer.h" #include "CXSourceLocation.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/MemoryBuffer.h" using namespace clang; using namespace clang::cxloc; using namespace clang::cxstring; using namespace llvm; //----------------------------------------------------------------------------- // C Interface Routines //----------------------------------------------------------------------------- extern "C" { unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { ASTUnit *CXXUnit = static_cast(Unit); return CXXUnit? CXXUnit->diag_size() : 0; } CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { ASTUnit *CXXUnit = static_cast(Unit); if (!CXXUnit || Index >= CXXUnit->diag_size()) return 0; return new CXStoredDiagnostic(CXXUnit->diag_begin()[Index], CXXUnit->getASTContext().getLangOptions()); } void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { CXStoredDiagnostic *Stored = static_cast(Diagnostic); delete Stored; } enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag) return CXDiagnostic_Ignored; switch (StoredDiag->Diag.getLevel()) { case Diagnostic::Ignored: return CXDiagnostic_Ignored; case Diagnostic::Note: return CXDiagnostic_Note; case Diagnostic::Warning: return CXDiagnostic_Warning; case Diagnostic::Error: return CXDiagnostic_Error; case Diagnostic::Fatal: return CXDiagnostic_Fatal; } llvm_unreachable("Invalid diagnostic level"); return CXDiagnostic_Ignored; } CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) return clang_getNullLocation(); return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(), StoredDiag->LangOpts, StoredDiag->Diag.getLocation()); } CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag) return createCXString(""); return createCXString(StoredDiag->Diag.getMessage(), false); } unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) return 0; return StoredDiag->Diag.range_size(); } CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || StoredDiag->Diag.getLocation().isInvalid()) return clang_getNullRange(); return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), StoredDiag->LangOpts, StoredDiag->Diag.range_begin()[Range]); } unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag) return 0; return StoredDiag->Diag.fixit_size(); } enum CXFixItKind clang_getDiagnosticFixItKind(CXDiagnostic Diag, unsigned FixIt) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size()) return CXFixIt_Insertion; const CodeModificationHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; if (Hint.RemoveRange.isInvalid()) return CXFixIt_Insertion; if (Hint.InsertionLoc.isInvalid()) return CXFixIt_Removal; return CXFixIt_Replacement; } CXString clang_getDiagnosticFixItInsertion(CXDiagnostic Diag, unsigned FixIt, CXSourceLocation *Location) { if (Location) *Location = clang_getNullLocation(); CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size()) return createCXString(""); const CodeModificationHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; if (Location && StoredDiag->Diag.getLocation().isValid()) *Location = translateSourceLocation( StoredDiag->Diag.getLocation().getManager(), StoredDiag->LangOpts, Hint.InsertionLoc); return createCXString(Hint.CodeToInsert); } CXSourceRange clang_getDiagnosticFixItRemoval(CXDiagnostic Diag, unsigned FixIt) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || StoredDiag->Diag.getLocation().isInvalid()) return clang_getNullRange(); const CodeModificationHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), StoredDiag->LangOpts, Hint.RemoveRange); } CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag, unsigned FixIt, CXSourceRange *Range) { if (Range) *Range = clang_getNullRange(); CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || StoredDiag->Diag.getLocation().isInvalid()) { if (Range) *Range = clang_getNullRange(); return createCXString(""); } const CodeModificationHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; if (Range) *Range = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), StoredDiag->LangOpts, Hint.RemoveRange); return createCXString(Hint.CodeToInsert); } } // end extern "C" void clang::LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files, FileManager &FileMgr, SourceManager &SourceMgr, SmallVectorImpl &Diags) { using llvm::MemoryBuffer; using llvm::StringRef; MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str()); if (!F) return; // Enter the unsaved files into the file manager. for (unsigned I = 0; I != num_unsaved_files; ++I) { const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename, unsaved_files[I].Length, 0); if (!File) { // FIXME: Hard to localize when we have no diagnostics engine! Diags.push_back(StoredDiagnostic(Diagnostic::Fatal, (Twine("could not remap from missing file ") + unsaved_files[I].Filename).str())); return; } MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, unsaved_files[I].Contents + unsaved_files[I].Length); if (!Buffer) return; SourceMgr.overrideFileContents(File, Buffer); } // Parse the diagnostics, emitting them one by one until we've // exhausted the data. StringRef Buffer = F->getBuffer(); const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size(); while (Memory != MemoryEnd) { StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr, Memory, MemoryEnd); if (!Stored) return; Diags.push_back(Stored); } }