CIndexDiagnostic.cpp revision 0373fcc3e5b205cc26656c70d7dff737b0e08345
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 clang::cxdiag; 30using namespace llvm; 31 32 33CXDiagnosticSetImpl::~CXDiagnosticSetImpl() { 34 for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(), 35 et = Diagnostics.end(); 36 it != et; ++it) { 37 delete *it; 38 } 39} 40 41CXDiagnosticImpl::~CXDiagnosticImpl() {} 42 43CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU, 44 bool checkIfChanged) { 45 ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData); 46 47 if (TU->Diagnostics && checkIfChanged) { 48 // In normal use, ASTUnit's diagnostics should not change unless we reparse. 49 // Currently they can only change by using the internal testing flag 50 // '-error-on-deserialized-decl' which will error during deserialization of 51 // a declaration. What will happen is: 52 // 53 // -c-index-test gets a CXTranslationUnit 54 // -checks the diagnostics, the diagnostics set is lazily created, 55 // no errors are reported 56 // -later does an operation, like annotation of tokens, that triggers 57 // -error-on-deserialized-decl, that will emit a diagnostic error, 58 // that ASTUnit will catch and add to its stored diagnostics vector. 59 // -c-index-test wants to check whether an error occurred after performing 60 // the operation but can only query the lazily created set. 61 // 62 // We check here if a new diagnostic was appended since the last time the 63 // diagnostic set was created, in which case we reset it. 64 65 CXDiagnosticSetImpl * 66 Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); 67 if (AU->stored_diag_size() != Set->getNumDiagnostics()) { 68 // Diagnostics in the ASTUnit were updated, reset the associated 69 // diagnostics. 70 delete Set; 71 TU->Diagnostics = 0; 72 } 73 } 74 75 if (!TU->Diagnostics) { 76 CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl(); 77 TU->Diagnostics = Set; 78 79 for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(), 80 ei = AU->stored_diag_end(); it != ei; ++it) { 81 CXStoredDiagnostic *D = 82 new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions()); 83 Set->appendDiagnostic(D); 84 } 85 } 86 return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); 87} 88 89//----------------------------------------------------------------------------- 90// C Interface Routines 91//----------------------------------------------------------------------------- 92extern "C" { 93 94unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 95 if (!Unit->TUData) 96 return 0; 97 return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics(); 98} 99 100CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { 101 CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit); 102 if (!D) 103 return 0; 104 105 CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D); 106 if (Index >= Diags->getNumDiagnostics()) 107 return 0; 108 109 return Diags->getDiagnostic(Index); 110} 111 112CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) { 113 if (!Unit->TUData) 114 return 0; 115 return static_cast<CXDiagnostic>(lazyCreateDiags(Unit)); 116} 117 118void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 119 // No-op. Kept as a legacy API. CXDiagnostics are now managed 120 // by the enclosing CXDiagnosticSet. 121} 122 123CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 124 if (!Diagnostic) 125 return createCXString(""); 126 127 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 128 129 llvm::SmallString<256> Str; 130 llvm::raw_svector_ostream Out(Str); 131 132 if (Options & CXDiagnostic_DisplaySourceLocation) { 133 // Print source location (file:line), along with optional column 134 // and source ranges. 135 CXFile File; 136 unsigned Line, Column; 137 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), 138 &File, &Line, &Column, 0); 139 if (File) { 140 CXString FName = clang_getFileName(File); 141 Out << clang_getCString(FName) << ":" << Line << ":"; 142 clang_disposeString(FName); 143 if (Options & CXDiagnostic_DisplayColumn) 144 Out << Column << ":"; 145 146 if (Options & CXDiagnostic_DisplaySourceRanges) { 147 unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 148 bool PrintedRange = false; 149 for (unsigned I = 0; I != N; ++I) { 150 CXFile StartFile, EndFile; 151 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 152 153 unsigned StartLine, StartColumn, EndLine, EndColumn; 154 clang_getSpellingLocation(clang_getRangeStart(Range), 155 &StartFile, &StartLine, &StartColumn, 156 0); 157 clang_getSpellingLocation(clang_getRangeEnd(Range), 158 &EndFile, &EndLine, &EndColumn, 0); 159 160 if (StartFile != EndFile || StartFile != File) 161 continue; 162 163 Out << "{" << StartLine << ":" << StartColumn << "-" 164 << EndLine << ":" << EndColumn << "}"; 165 PrintedRange = true; 166 } 167 if (PrintedRange) 168 Out << ":"; 169 } 170 171 Out << " "; 172 } 173 } 174 175 /* Print warning/error/etc. */ 176 switch (Severity) { 177 case CXDiagnostic_Ignored: llvm_unreachable("impossible"); 178 case CXDiagnostic_Note: Out << "note: "; break; 179 case CXDiagnostic_Warning: Out << "warning: "; break; 180 case CXDiagnostic_Error: Out << "error: "; break; 181 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 182 } 183 184 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 185 if (clang_getCString(Text)) 186 Out << clang_getCString(Text); 187 else 188 Out << "<no diagnostic text>"; 189 clang_disposeString(Text); 190 191 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | 192 CXDiagnostic_DisplayCategoryName)) { 193 bool NeedBracket = true; 194 bool NeedComma = false; 195 196 if (Options & CXDiagnostic_DisplayOption) { 197 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0); 198 if (const char *OptionText = clang_getCString(OptionName)) { 199 if (OptionText[0]) { 200 Out << " [" << OptionText; 201 NeedBracket = false; 202 NeedComma = true; 203 } 204 } 205 clang_disposeString(OptionName); 206 } 207 208 if (Options & (CXDiagnostic_DisplayCategoryId | 209 CXDiagnostic_DisplayCategoryName)) { 210 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { 211 if (Options & CXDiagnostic_DisplayCategoryId) { 212 if (NeedBracket) 213 Out << " ["; 214 if (NeedComma) 215 Out << ", "; 216 Out << CategoryID; 217 NeedBracket = false; 218 NeedComma = true; 219 } 220 221 if (Options & CXDiagnostic_DisplayCategoryName) { 222 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID); 223 if (NeedBracket) 224 Out << " ["; 225 if (NeedComma) 226 Out << ", "; 227 Out << clang_getCString(CategoryName); 228 NeedBracket = false; 229 NeedComma = true; 230 clang_disposeString(CategoryName); 231 } 232 } 233 } 234 235 if (!NeedBracket) 236 Out << "]"; 237 } 238 239 return createCXString(Out.str(), true); 240} 241 242unsigned clang_defaultDiagnosticDisplayOptions() { 243 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | 244 CXDiagnostic_DisplayOption; 245} 246 247enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 248 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) 249 return D->getSeverity(); 250 return CXDiagnostic_Ignored; 251} 252 253CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 254 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) 255 return D->getLocation(); 256 return clang_getNullLocation(); 257} 258 259CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 260 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 261 return D->getSpelling(); 262 return createCXString(""); 263} 264 265CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { 266 if (Disable) 267 *Disable = createCXString(""); 268 269 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 270 return D->getDiagnosticOption(Disable); 271 272 return createCXString(""); 273} 274 275unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { 276 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 277 return D->getCategory(); 278 return 0; 279} 280 281CXString clang_getDiagnosticCategoryName(unsigned Category) { 282 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); 283} 284 285unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 286 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 287 return D->getNumRanges(); 288 return 0; 289} 290 291CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 292 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); 293 if (!D || Range >= D->getNumRanges()) 294 return clang_getNullRange(); 295 return D->getRange(Range); 296} 297 298unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 299 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 300 return D->getNumFixIts(); 301 return 0; 302} 303 304CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt, 305 CXSourceRange *ReplacementRange) { 306 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); 307 if (!D || FixIt >= D->getNumFixIts()) { 308 if (ReplacementRange) 309 *ReplacementRange = clang_getNullRange(); 310 return createCXString(""); 311 } 312 return D->getFixIt(FixIt, ReplacementRange); 313} 314 315void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) { 316 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags); 317 if (D->isExternallyManaged()) 318 delete D; 319} 320 321CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, 322 unsigned Index) { 323 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) 324 if (Index < D->getNumDiagnostics()) 325 return D->getDiagnostic(Index); 326 return 0; 327} 328 329CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) { 330 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) { 331 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics(); 332 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags; 333 } 334 return 0; 335} 336 337unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) { 338 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) 339 return D->getNumDiagnostics(); 340 return 0; 341} 342 343} // end extern "C" 344