CIndexDiagnostic.cpp revision aa5f135f8db82b5e5fb1640fd51f8078e0b2d82d
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 26using namespace clang; 27using namespace clang::cxloc; 28using namespace clang::cxstring; 29using namespace llvm; 30 31//----------------------------------------------------------------------------- 32// C Interface Routines 33//----------------------------------------------------------------------------- 34extern "C" { 35 36unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 37 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData); 38 return CXXUnit? CXXUnit->stored_diag_size() : 0; 39} 40 41CXDiagnostic 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 50void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 51 CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic); 52 delete Stored; 53} 54 55CXString 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 174unsigned clang_defaultDiagnosticDisplayOptions() { 175 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | 176 CXDiagnostic_DisplayOption; 177} 178 179enum 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 196CXSourceLocation 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 206CXString 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 214CXString 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 if (const char *Option = DiagnosticIDs::getWarningOptionForDiag(ID)) { 224 if (Disable) 225 *Disable = createCXString((llvm::Twine("-Wno-") + Option).str()); 226 return createCXString((llvm::Twine("-W") + Option).str()); 227 } 228 229 if (ID == diag::fatal_too_many_errors) { 230 if (Disable) 231 *Disable = createCXString("-ferror-limit=0"); 232 return createCXString("-ferror-limit="); 233 } 234 235 bool EnabledByDefault; 236 if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) && 237 !EnabledByDefault) 238 return createCXString("-pedantic"); 239 240 return createCXString(""); 241} 242 243unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { 244 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 245 if (!StoredDiag) 246 return 0; 247 248 return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID()); 249} 250 251CXString clang_getDiagnosticCategoryName(unsigned Category) { 252 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); 253} 254 255unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 256 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 257 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 258 return 0; 259 260 return StoredDiag->Diag.range_size(); 261} 262 263CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 264 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 265 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || 266 StoredDiag->Diag.getLocation().isInvalid()) 267 return clang_getNullRange(); 268 269 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 270 StoredDiag->LangOpts, 271 StoredDiag->Diag.range_begin()[Range]); 272} 273 274unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 275 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 276 if (!StoredDiag) 277 return 0; 278 279 return StoredDiag->Diag.fixit_size(); 280} 281 282CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, 283 CXSourceRange *ReplacementRange) { 284 CXStoredDiagnostic *StoredDiag 285 = static_cast<CXStoredDiagnostic *>(Diagnostic); 286 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || 287 StoredDiag->Diag.getLocation().isInvalid()) { 288 if (ReplacementRange) 289 *ReplacementRange = clang_getNullRange(); 290 291 return createCXString(""); 292 } 293 294 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; 295 if (ReplacementRange) { 296 // Create a range that covers the entire replacement (or 297 // removal) range, adjusting the end of the range to point to 298 // the end of the token. 299 *ReplacementRange 300 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 301 StoredDiag->LangOpts, 302 Hint.RemoveRange); 303 } 304 305 return createCXString(Hint.CodeToInsert); 306} 307 308} // end extern "C" 309