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