summaryrefslogtreecommitdiffstats
path: root/tools/libclang/CIndexDiagnostic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/libclang/CIndexDiagnostic.cpp')
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
new file mode 100644
index 0000000..3db37b9
--- /dev/null
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -0,0 +1,285 @@
+/*===-- 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/ASTUnit.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.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<ASTUnit *>(Unit);
+ return CXXUnit? CXXUnit->stored_diag_size() : 0;
+}
+
+CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
+ if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
+ return 0;
+
+ return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
+ CXXUnit->getASTContext().getLangOptions());
+}
+
+void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
+ CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
+ delete Stored;
+}
+
+CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
+ if (!Diagnostic)
+ return createCXString("");
+
+ CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
+
+ // Ignore diagnostics that should be ignored.
+ if (Severity == CXDiagnostic_Ignored)
+ return createCXString("");
+
+ llvm::SmallString<256> Str;
+ llvm::raw_svector_ostream Out(Str);
+
+ if (Options & CXDiagnostic_DisplaySourceLocation) {
+ // Print source location (file:line), along with optional column
+ // and source ranges.
+ CXFile File;
+ unsigned Line, Column;
+ clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
+ &File, &Line, &Column, 0);
+ if (File) {
+ CXString FName = clang_getFileName(File);
+ Out << clang_getCString(FName) << ":" << Line << ":";
+ clang_disposeString(FName);
+ if (Options & CXDiagnostic_DisplayColumn)
+ Out << Column << ":";
+
+ if (Options & CXDiagnostic_DisplaySourceRanges) {
+ unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
+ bool PrintedRange = false;
+ for (unsigned I = 0; I != N; ++I) {
+ CXFile StartFile, EndFile;
+ CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
+
+ unsigned StartLine, StartColumn, EndLine, EndColumn;
+ clang_getInstantiationLocation(clang_getRangeStart(Range),
+ &StartFile, &StartLine, &StartColumn,
+ 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(Range),
+ &EndFile, &EndLine, &EndColumn, 0);
+
+ if (StartFile != EndFile || StartFile != File)
+ continue;
+
+ Out << "{" << StartLine << ":" << StartColumn << "-"
+ << EndLine << ":" << EndColumn << "}";
+ PrintedRange = true;
+ }
+ if (PrintedRange)
+ Out << ":";
+ }
+ }
+
+ Out << " ";
+ }
+
+ /* Print warning/error/etc. */
+ switch (Severity) {
+ case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
+ case CXDiagnostic_Note: Out << "note: "; break;
+ case CXDiagnostic_Warning: Out << "warning: "; break;
+ case CXDiagnostic_Error: Out << "error: "; break;
+ case CXDiagnostic_Fatal: Out << "fatal error: "; break;
+ }
+
+ CXString Text = clang_getDiagnosticSpelling(Diagnostic);
+ if (clang_getCString(Text))
+ Out << clang_getCString(Text);
+ else
+ Out << "<no diagnostic text>";
+ clang_disposeString(Text);
+ return createCXString(Out.str(), true);
+}
+
+unsigned clang_defaultDiagnosticDisplayOptions() {
+ return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
+}
+
+enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(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<CXStoredDiagnostic *>(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<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return createCXString("");
+
+ return createCXString(StoredDiag->Diag.getMessage(), false);
+}
+
+unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(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<CXStoredDiagnostic *>(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<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return 0;
+
+ return StoredDiag->Diag.fixit_size();
+}
+
+CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
+ CXSourceRange *ReplacementRange) {
+ CXStoredDiagnostic *StoredDiag
+ = static_cast<CXStoredDiagnostic *>(Diagnostic);
+ if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
+ StoredDiag->Diag.getLocation().isInvalid()) {
+ if (ReplacementRange)
+ *ReplacementRange = clang_getNullRange();
+
+ return createCXString("");
+ }
+
+ const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
+ if (ReplacementRange) {
+ if (Hint.RemoveRange.isInvalid()) {
+ // Create an empty range that refers to a single source
+ // location (which is the insertion point).
+ CXSourceRange Range = {
+ { (void *)&StoredDiag->Diag.getLocation().getManager(),
+ (void *)&StoredDiag->LangOpts },
+ Hint.InsertionLoc.getRawEncoding(),
+ Hint.InsertionLoc.getRawEncoding()
+ };
+
+ *ReplacementRange = Range;
+ } else {
+ // Create a range that covers the entire replacement (or
+ // removal) range, adjusting the end of the range to point to
+ // the end of the token.
+ *ReplacementRange
+ = 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<StoredDiagnostic> &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()));
+ delete F;
+ return;
+ }
+
+ MemoryBuffer *Buffer
+ = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
+ unsaved_files[I].Contents + unsaved_files[I].Length);
+ if (!Buffer) {
+ delete F;
+ return;
+ }
+
+ SourceMgr.overrideFileContents(File, Buffer);
+ SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+ }
+
+ // 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)
+ break;
+
+ Diags.push_back(Stored);
+ }
+ delete F;
+}
OpenPOWER on IntegriCloud