CIndexDiagnostic.cpp revision a9b06d4c246d6c301e3dd1844f5dba669ed9c631
1/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\ 2|* *| 3|* The LLVM Compiler Infrastructure *| 4|* *| 5|* This file is distributed under the University of Illinois Open Source *| 6|* License. See LICENSE.TXT for details. *| 7|* *| 8|*===----------------------------------------------------------------------===*| 9|* *| 10|* Implements the diagnostic functions of the Clang C interface. *| 11|* *| 12\*===----------------------------------------------------------------------===*/ 13#include "CIndexDiagnostic.h" 14#include "CIndexer.h" 15#include "CXSourceLocation.h" 16 17#include "clang/Frontend/ASTUnit.h" 18#include "clang/Frontend/FrontendDiagnostic.h" 19#include "llvm/ADT/SmallString.h" 20#include "llvm/ADT/Twine.h" 21#include "llvm/Support/MemoryBuffer.h" 22#include "llvm/Support/raw_ostream.h" 23 24using namespace clang; 25using namespace clang::cxloc; 26using namespace clang::cxstring; 27using namespace llvm; 28 29//----------------------------------------------------------------------------- 30// C Interface Routines 31//----------------------------------------------------------------------------- 32extern "C" { 33 34unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 35 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit); 36 return CXXUnit? CXXUnit->stored_diag_size() : 0; 37} 38 39CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { 40 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit); 41 if (!CXXUnit || Index >= CXXUnit->stored_diag_size()) 42 return 0; 43 44 return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index], 45 CXXUnit->getASTContext().getLangOptions()); 46} 47 48void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 49 CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic); 50 delete Stored; 51} 52 53CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 54 if (!Diagnostic) 55 return createCXString(""); 56 57 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 58 59 llvm::SmallString<256> Str; 60 llvm::raw_svector_ostream Out(Str); 61 62 if (Options & CXDiagnostic_DisplaySourceLocation) { 63 // Print source location (file:line), along with optional column 64 // and source ranges. 65 CXFile File; 66 unsigned Line, Column; 67 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), 68 &File, &Line, &Column, 0); 69 if (File) { 70 CXString FName = clang_getFileName(File); 71 Out << clang_getCString(FName) << ":" << Line << ":"; 72 clang_disposeString(FName); 73 if (Options & CXDiagnostic_DisplayColumn) 74 Out << Column << ":"; 75 76 if (Options & CXDiagnostic_DisplaySourceRanges) { 77 unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 78 bool PrintedRange = false; 79 for (unsigned I = 0; I != N; ++I) { 80 CXFile StartFile, EndFile; 81 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 82 83 unsigned StartLine, StartColumn, EndLine, EndColumn; 84 clang_getSpellingLocation(clang_getRangeStart(Range), 85 &StartFile, &StartLine, &StartColumn, 86 0); 87 clang_getSpellingLocation(clang_getRangeEnd(Range), 88 &EndFile, &EndLine, &EndColumn, 0); 89 90 if (StartFile != EndFile || StartFile != File) 91 continue; 92 93 Out << "{" << StartLine << ":" << StartColumn << "-" 94 << EndLine << ":" << EndColumn << "}"; 95 PrintedRange = true; 96 } 97 if (PrintedRange) 98 Out << ":"; 99 } 100 101 Out << " "; 102 } 103 } 104 105 /* Print warning/error/etc. */ 106 switch (Severity) { 107 case CXDiagnostic_Ignored: assert(0 && "impossible"); break; 108 case CXDiagnostic_Note: Out << "note: "; break; 109 case CXDiagnostic_Warning: Out << "warning: "; break; 110 case CXDiagnostic_Error: Out << "error: "; break; 111 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 112 } 113 114 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 115 if (clang_getCString(Text)) 116 Out << clang_getCString(Text); 117 else 118 Out << "<no diagnostic text>"; 119 clang_disposeString(Text); 120 return createCXString(Out.str(), true); 121} 122 123unsigned clang_defaultDiagnosticDisplayOptions() { 124 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn; 125} 126 127enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 128 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 129 if (!StoredDiag) 130 return CXDiagnostic_Ignored; 131 132 switch (StoredDiag->Diag.getLevel()) { 133 case Diagnostic::Ignored: return CXDiagnostic_Ignored; 134 case Diagnostic::Note: return CXDiagnostic_Note; 135 case Diagnostic::Warning: return CXDiagnostic_Warning; 136 case Diagnostic::Error: return CXDiagnostic_Error; 137 case Diagnostic::Fatal: return CXDiagnostic_Fatal; 138 } 139 140 llvm_unreachable("Invalid diagnostic level"); 141 return CXDiagnostic_Ignored; 142} 143 144CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 145 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 146 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 147 return clang_getNullLocation(); 148 149 return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(), 150 StoredDiag->LangOpts, 151 StoredDiag->Diag.getLocation()); 152} 153 154CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 155 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 156 if (!StoredDiag) 157 return createCXString(""); 158 159 return createCXString(StoredDiag->Diag.getMessage(), false); 160} 161 162unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 163 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 164 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 165 return 0; 166 167 return StoredDiag->Diag.range_size(); 168} 169 170CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 171 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 172 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || 173 StoredDiag->Diag.getLocation().isInvalid()) 174 return clang_getNullRange(); 175 176 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 177 StoredDiag->LangOpts, 178 StoredDiag->Diag.range_begin()[Range]); 179} 180 181unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 182 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 183 if (!StoredDiag) 184 return 0; 185 186 return StoredDiag->Diag.fixit_size(); 187} 188 189CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, 190 CXSourceRange *ReplacementRange) { 191 CXStoredDiagnostic *StoredDiag 192 = static_cast<CXStoredDiagnostic *>(Diagnostic); 193 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || 194 StoredDiag->Diag.getLocation().isInvalid()) { 195 if (ReplacementRange) 196 *ReplacementRange = clang_getNullRange(); 197 198 return createCXString(""); 199 } 200 201 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; 202 if (ReplacementRange) { 203 // Create a range that covers the entire replacement (or 204 // removal) range, adjusting the end of the range to point to 205 // the end of the token. 206 *ReplacementRange 207 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 208 StoredDiag->LangOpts, 209 Hint.RemoveRange); 210 } 211 212 return createCXString(Hint.CodeToInsert); 213} 214 215} // end extern "C" 216