CIndexDiagnostic.cpp revision 996e6e564af7483e2d5e0b70df5fdb9f79ec4b5a
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 if (!Unit->TUData) 102 return 0; 103 104 CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit); 105 if (Index >= Diags->getNumDiagnostics()) 106 return 0; 107 108 return Diags->getDiagnostic(Index); 109} 110 111void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 112 // No-op. Kept as a legacy API. CXDiagnostics are now managed 113 // by the enclosing CXDiagnosticSet. 114} 115 116CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 117 if (!Diagnostic) 118 return createCXString(""); 119 120 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 121 122 llvm::SmallString<256> Str; 123 llvm::raw_svector_ostream Out(Str); 124 125 if (Options & CXDiagnostic_DisplaySourceLocation) { 126 // Print source location (file:line), along with optional column 127 // and source ranges. 128 CXFile File; 129 unsigned Line, Column; 130 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), 131 &File, &Line, &Column, 0); 132 if (File) { 133 CXString FName = clang_getFileName(File); 134 Out << clang_getCString(FName) << ":" << Line << ":"; 135 clang_disposeString(FName); 136 if (Options & CXDiagnostic_DisplayColumn) 137 Out << Column << ":"; 138 139 if (Options & CXDiagnostic_DisplaySourceRanges) { 140 unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 141 bool PrintedRange = false; 142 for (unsigned I = 0; I != N; ++I) { 143 CXFile StartFile, EndFile; 144 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 145 146 unsigned StartLine, StartColumn, EndLine, EndColumn; 147 clang_getSpellingLocation(clang_getRangeStart(Range), 148 &StartFile, &StartLine, &StartColumn, 149 0); 150 clang_getSpellingLocation(clang_getRangeEnd(Range), 151 &EndFile, &EndLine, &EndColumn, 0); 152 153 if (StartFile != EndFile || StartFile != File) 154 continue; 155 156 Out << "{" << StartLine << ":" << StartColumn << "-" 157 << EndLine << ":" << EndColumn << "}"; 158 PrintedRange = true; 159 } 160 if (PrintedRange) 161 Out << ":"; 162 } 163 164 Out << " "; 165 } 166 } 167 168 /* Print warning/error/etc. */ 169 switch (Severity) { 170 case CXDiagnostic_Ignored: llvm_unreachable("impossible"); 171 case CXDiagnostic_Note: Out << "note: "; break; 172 case CXDiagnostic_Warning: Out << "warning: "; break; 173 case CXDiagnostic_Error: Out << "error: "; break; 174 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 175 } 176 177 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 178 if (clang_getCString(Text)) 179 Out << clang_getCString(Text); 180 else 181 Out << "<no diagnostic text>"; 182 clang_disposeString(Text); 183 184 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | 185 CXDiagnostic_DisplayCategoryName)) { 186 bool NeedBracket = true; 187 bool NeedComma = false; 188 189 if (Options & CXDiagnostic_DisplayOption) { 190 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0); 191 if (const char *OptionText = clang_getCString(OptionName)) { 192 if (OptionText[0]) { 193 Out << " [" << OptionText; 194 NeedBracket = false; 195 NeedComma = true; 196 } 197 } 198 clang_disposeString(OptionName); 199 } 200 201 if (Options & (CXDiagnostic_DisplayCategoryId | 202 CXDiagnostic_DisplayCategoryName)) { 203 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { 204 if (Options & CXDiagnostic_DisplayCategoryId) { 205 if (NeedBracket) 206 Out << " ["; 207 if (NeedComma) 208 Out << ", "; 209 Out << CategoryID; 210 NeedBracket = false; 211 NeedComma = true; 212 } 213 214 if (Options & CXDiagnostic_DisplayCategoryName) { 215 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID); 216 if (NeedBracket) 217 Out << " ["; 218 if (NeedComma) 219 Out << ", "; 220 Out << clang_getCString(CategoryName); 221 NeedBracket = false; 222 NeedComma = true; 223 clang_disposeString(CategoryName); 224 } 225 } 226 } 227 228 if (!NeedBracket) 229 Out << "]"; 230 } 231 232 return createCXString(Out.str(), true); 233} 234 235unsigned clang_defaultDiagnosticDisplayOptions() { 236 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | 237 CXDiagnostic_DisplayOption; 238} 239 240enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 241 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) 242 return D->getSeverity(); 243 return CXDiagnostic_Ignored; 244} 245 246CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 247 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) 248 return D->getLocation(); 249 return clang_getNullLocation(); 250} 251 252CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 253 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 254 return D->getSpelling(); 255 return createCXString(""); 256} 257 258CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { 259 if (Disable) 260 *Disable = createCXString(""); 261 262 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 263 return D->getDiagnosticOption(Disable); 264 265 return createCXString(""); 266} 267 268unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { 269 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 270 return D->getCategory(); 271 return 0; 272} 273 274CXString clang_getDiagnosticCategoryName(unsigned Category) { 275 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); 276} 277 278unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 279 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 280 return D->getNumRanges(); 281 return 0; 282} 283 284CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 285 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); 286 if (!D || Range >= D->getNumRanges()) 287 return clang_getNullRange(); 288 return D->getRange(Range); 289} 290 291unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 292 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 293 return D->getNumFixIts(); 294 return 0; 295} 296 297CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt, 298 CXSourceRange *ReplacementRange) { 299 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); 300 if (!D || FixIt >= D->getNumFixIts()) { 301 if (ReplacementRange) 302 *ReplacementRange = clang_getNullRange(); 303 return createCXString(""); 304 } 305 return D->getFixIt(FixIt, ReplacementRange); 306} 307 308void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) { 309 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags); 310 if (D->isExternallyManaged()) 311 delete D; 312} 313 314CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, 315 unsigned Index) { 316 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) 317 if (Index < D->getNumDiagnostics()) 318 return D->getDiagnostic(Index); 319 return 0; 320} 321 322CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) { 323 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) { 324 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics(); 325 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags; 326 } 327 return 0; 328} 329 330unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) { 331 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) 332 return D->getNumDiagnostics(); 333 return 0; 334} 335 336} // end extern "C" 337