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 "CXTranslationUnit.h" 16 #include "CXSourceLocation.h" 17 #include "CXString.h" 18 19 #include "clang/Frontend/ASTUnit.h" 20 #include "clang/Frontend/FrontendDiagnostic.h" 21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/ADT/Twine.h" 23 #include "llvm/Support/MemoryBuffer.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 using namespace clang; 27 using namespace clang::cxloc; 28 using namespace clang::cxstring; 29 using namespace llvm; 30 31 //----------------------------------------------------------------------------- 32 // C Interface Routines 33 //----------------------------------------------------------------------------- 34 extern "C" { 35 36 unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 37 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData); 38 return CXXUnit? CXXUnit->stored_diag_size() : 0; 39 } 40 41 CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { 42 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData); 43 if (!CXXUnit || Index >= CXXUnit->stored_diag_size()) 44 return 0; 45 46 return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index], 47 CXXUnit->getASTContext().getLangOptions()); 48 } 49 50 void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 51 CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic); 52 delete Stored; 53 } 54 55 CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 56 if (!Diagnostic) 57 return createCXString(""); 58 59 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 60 61 llvm::SmallString<256> Str; 62 llvm::raw_svector_ostream Out(Str); 63 64 if (Options & CXDiagnostic_DisplaySourceLocation) { 65 // Print source location (file:line), along with optional column 66 // and source ranges. 67 CXFile File; 68 unsigned Line, Column; 69 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), 70 &File, &Line, &Column, 0); 71 if (File) { 72 CXString FName = clang_getFileName(File); 73 Out << clang_getCString(FName) << ":" << Line << ":"; 74 clang_disposeString(FName); 75 if (Options & CXDiagnostic_DisplayColumn) 76 Out << Column << ":"; 77 78 if (Options & CXDiagnostic_DisplaySourceRanges) { 79 unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 80 bool PrintedRange = false; 81 for (unsigned I = 0; I != N; ++I) { 82 CXFile StartFile, EndFile; 83 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 84 85 unsigned StartLine, StartColumn, EndLine, EndColumn; 86 clang_getSpellingLocation(clang_getRangeStart(Range), 87 &StartFile, &StartLine, &StartColumn, 88 0); 89 clang_getSpellingLocation(clang_getRangeEnd(Range), 90 &EndFile, &EndLine, &EndColumn, 0); 91 92 if (StartFile != EndFile || StartFile != File) 93 continue; 94 95 Out << "{" << StartLine << ":" << StartColumn << "-" 96 << EndLine << ":" << EndColumn << "}"; 97 PrintedRange = true; 98 } 99 if (PrintedRange) 100 Out << ":"; 101 } 102 103 Out << " "; 104 } 105 } 106 107 /* Print warning/error/etc. */ 108 switch (Severity) { 109 case CXDiagnostic_Ignored: assert(0 && "impossible"); break; 110 case CXDiagnostic_Note: Out << "note: "; break; 111 case CXDiagnostic_Warning: Out << "warning: "; break; 112 case CXDiagnostic_Error: Out << "error: "; break; 113 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 114 } 115 116 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 117 if (clang_getCString(Text)) 118 Out << clang_getCString(Text); 119 else 120 Out << "<no diagnostic text>"; 121 clang_disposeString(Text); 122 123 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | 124 CXDiagnostic_DisplayCategoryName)) { 125 bool NeedBracket = true; 126 bool NeedComma = false; 127 128 if (Options & CXDiagnostic_DisplayOption) { 129 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0); 130 if (const char *OptionText = clang_getCString(OptionName)) { 131 if (OptionText[0]) { 132 Out << " [" << OptionText; 133 NeedBracket = false; 134 NeedComma = true; 135 } 136 } 137 clang_disposeString(OptionName); 138 } 139 140 if (Options & (CXDiagnostic_DisplayCategoryId | 141 CXDiagnostic_DisplayCategoryName)) { 142 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { 143 if (Options & CXDiagnostic_DisplayCategoryId) { 144 if (NeedBracket) 145 Out << " ["; 146 if (NeedComma) 147 Out << ", "; 148 Out << CategoryID; 149 NeedBracket = false; 150 NeedComma = true; 151 } 152 153 if (Options & CXDiagnostic_DisplayCategoryName) { 154 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID); 155 if (NeedBracket) 156 Out << " ["; 157 if (NeedComma) 158 Out << ", "; 159 Out << clang_getCString(CategoryName); 160 NeedBracket = false; 161 NeedComma = true; 162 clang_disposeString(CategoryName); 163 } 164 } 165 } 166 167 if (!NeedBracket) 168 Out << "]"; 169 } 170 171 return createCXString(Out.str(), true); 172 } 173 174 unsigned clang_defaultDiagnosticDisplayOptions() { 175 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | 176 CXDiagnostic_DisplayOption; 177 } 178 179 enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 180 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 181 if (!StoredDiag) 182 return CXDiagnostic_Ignored; 183 184 switch (StoredDiag->Diag.getLevel()) { 185 case Diagnostic::Ignored: return CXDiagnostic_Ignored; 186 case Diagnostic::Note: return CXDiagnostic_Note; 187 case Diagnostic::Warning: return CXDiagnostic_Warning; 188 case Diagnostic::Error: return CXDiagnostic_Error; 189 case Diagnostic::Fatal: return CXDiagnostic_Fatal; 190 } 191 192 llvm_unreachable("Invalid diagnostic level"); 193 return CXDiagnostic_Ignored; 194 } 195 196 CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 197 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 198 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 199 return clang_getNullLocation(); 200 201 return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(), 202 StoredDiag->LangOpts, 203 StoredDiag->Diag.getLocation()); 204 } 205 206 CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 207 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 208 if (!StoredDiag) 209 return createCXString(""); 210 211 return createCXString(StoredDiag->Diag.getMessage(), false); 212 } 213 214 CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { 215 if (Disable) 216 *Disable = createCXString(""); 217 218 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 219 if (!StoredDiag) 220 return createCXString(""); 221 222 unsigned ID = StoredDiag->Diag.getID(); 223 llvm::StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID); 224 if (!Option.empty()) { 225 if (Disable) 226 *Disable = createCXString((llvm::Twine("-Wno-") + Option).str()); 227 return createCXString((llvm::Twine("-W") + Option).str()); 228 } 229 230 if (ID == diag::fatal_too_many_errors) { 231 if (Disable) 232 *Disable = createCXString("-ferror-limit=0"); 233 return createCXString("-ferror-limit="); 234 } 235 236 bool EnabledByDefault; 237 if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) && 238 !EnabledByDefault) 239 return createCXString("-pedantic"); 240 241 return createCXString(""); 242 } 243 244 unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { 245 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 246 if (!StoredDiag) 247 return 0; 248 249 return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID()); 250 } 251 252 CXString clang_getDiagnosticCategoryName(unsigned Category) { 253 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); 254 } 255 256 unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 257 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 258 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 259 return 0; 260 261 return StoredDiag->Diag.range_size(); 262 } 263 264 CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 265 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 266 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || 267 StoredDiag->Diag.getLocation().isInvalid()) 268 return clang_getNullRange(); 269 270 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 271 StoredDiag->LangOpts, 272 StoredDiag->Diag.range_begin()[Range]); 273 } 274 275 unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 276 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 277 if (!StoredDiag) 278 return 0; 279 280 return StoredDiag->Diag.fixit_size(); 281 } 282 283 CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, 284 CXSourceRange *ReplacementRange) { 285 CXStoredDiagnostic *StoredDiag 286 = static_cast<CXStoredDiagnostic *>(Diagnostic); 287 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || 288 StoredDiag->Diag.getLocation().isInvalid()) { 289 if (ReplacementRange) 290 *ReplacementRange = clang_getNullRange(); 291 292 return createCXString(""); 293 } 294 295 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; 296 if (ReplacementRange) { 297 // Create a range that covers the entire replacement (or 298 // removal) range, adjusting the end of the range to point to 299 // the end of the token. 300 *ReplacementRange 301 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 302 StoredDiag->LangOpts, 303 Hint.RemoveRange); 304 } 305 306 return createCXString(Hint.CodeToInsert); 307 } 308 309 } // end extern "C" 310