CIndexDiagnostic.cpp revision 153221717e39ce41323d5bc6b8b8bf130923c1bd
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 if (!TU->Diagnostics) { 44 ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData); 45 CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl(); 46 TU->Diagnostics = Set; 47 48 for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(), 49 ei = AU->stored_diag_end(); it != ei; ++it) { 50 CXStoredDiagnostic *D = 51 new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions()); 52 Set->appendDiagnostic(D); 53 } 54 } 55 return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); 56} 57 58//----------------------------------------------------------------------------- 59// C Interface Routines 60//----------------------------------------------------------------------------- 61extern "C" { 62 63unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 64 if (!Unit->TUData) 65 return 0; 66 return lazyCreateDiags(Unit)->getNumDiagnostics(); 67} 68 69CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { 70 if (!Unit->TUData) 71 return 0; 72 73 CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit); 74 if (Index >= Diags->getNumDiagnostics()) 75 return 0; 76 77 return Diags->getDiagnostic(Index); 78} 79 80void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 81 // No-op. Kept as a legacy API. CXDiagnostics are now managed 82 // by the enclosing CXDiagnosticSet. 83} 84 85CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 86 if (!Diagnostic) 87 return createCXString(""); 88 89 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 90 91 llvm::SmallString<256> Str; 92 llvm::raw_svector_ostream Out(Str); 93 94 if (Options & CXDiagnostic_DisplaySourceLocation) { 95 // Print source location (file:line), along with optional column 96 // and source ranges. 97 CXFile File; 98 unsigned Line, Column; 99 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), 100 &File, &Line, &Column, 0); 101 if (File) { 102 CXString FName = clang_getFileName(File); 103 Out << clang_getCString(FName) << ":" << Line << ":"; 104 clang_disposeString(FName); 105 if (Options & CXDiagnostic_DisplayColumn) 106 Out << Column << ":"; 107 108 if (Options & CXDiagnostic_DisplaySourceRanges) { 109 unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 110 bool PrintedRange = false; 111 for (unsigned I = 0; I != N; ++I) { 112 CXFile StartFile, EndFile; 113 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 114 115 unsigned StartLine, StartColumn, EndLine, EndColumn; 116 clang_getSpellingLocation(clang_getRangeStart(Range), 117 &StartFile, &StartLine, &StartColumn, 118 0); 119 clang_getSpellingLocation(clang_getRangeEnd(Range), 120 &EndFile, &EndLine, &EndColumn, 0); 121 122 if (StartFile != EndFile || StartFile != File) 123 continue; 124 125 Out << "{" << StartLine << ":" << StartColumn << "-" 126 << EndLine << ":" << EndColumn << "}"; 127 PrintedRange = true; 128 } 129 if (PrintedRange) 130 Out << ":"; 131 } 132 133 Out << " "; 134 } 135 } 136 137 /* Print warning/error/etc. */ 138 switch (Severity) { 139 case CXDiagnostic_Ignored: llvm_unreachable("impossible"); 140 case CXDiagnostic_Note: Out << "note: "; break; 141 case CXDiagnostic_Warning: Out << "warning: "; break; 142 case CXDiagnostic_Error: Out << "error: "; break; 143 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 144 } 145 146 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 147 if (clang_getCString(Text)) 148 Out << clang_getCString(Text); 149 else 150 Out << "<no diagnostic text>"; 151 clang_disposeString(Text); 152 153 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | 154 CXDiagnostic_DisplayCategoryName)) { 155 bool NeedBracket = true; 156 bool NeedComma = false; 157 158 if (Options & CXDiagnostic_DisplayOption) { 159 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0); 160 if (const char *OptionText = clang_getCString(OptionName)) { 161 if (OptionText[0]) { 162 Out << " [" << OptionText; 163 NeedBracket = false; 164 NeedComma = true; 165 } 166 } 167 clang_disposeString(OptionName); 168 } 169 170 if (Options & (CXDiagnostic_DisplayCategoryId | 171 CXDiagnostic_DisplayCategoryName)) { 172 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { 173 if (Options & CXDiagnostic_DisplayCategoryId) { 174 if (NeedBracket) 175 Out << " ["; 176 if (NeedComma) 177 Out << ", "; 178 Out << CategoryID; 179 NeedBracket = false; 180 NeedComma = true; 181 } 182 183 if (Options & CXDiagnostic_DisplayCategoryName) { 184 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID); 185 if (NeedBracket) 186 Out << " ["; 187 if (NeedComma) 188 Out << ", "; 189 Out << clang_getCString(CategoryName); 190 NeedBracket = false; 191 NeedComma = true; 192 clang_disposeString(CategoryName); 193 } 194 } 195 } 196 197 if (!NeedBracket) 198 Out << "]"; 199 } 200 201 return createCXString(Out.str(), true); 202} 203 204unsigned clang_defaultDiagnosticDisplayOptions() { 205 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | 206 CXDiagnostic_DisplayOption; 207} 208 209enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 210 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) 211 return D->getSeverity(); 212 return CXDiagnostic_Ignored; 213} 214 215CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 216 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) 217 return D->getLocation(); 218 return clang_getNullLocation(); 219} 220 221CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 222 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 223 return D->getSpelling(); 224 return createCXString(""); 225} 226 227CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { 228 if (Disable) 229 *Disable = createCXString(""); 230 231 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 232 return D->getDiagnosticOption(Disable); 233 234 return createCXString(""); 235} 236 237unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { 238 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 239 return D->getCategory(); 240 return 0; 241} 242 243CXString clang_getDiagnosticCategoryName(unsigned Category) { 244 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); 245} 246 247unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 248 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 249 return D->getNumRanges(); 250 return 0; 251} 252 253CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 254 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); 255 if (!D || Range >= D->getNumRanges()) 256 return clang_getNullRange(); 257 return D->getRange(Range); 258} 259 260unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 261 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) 262 return D->getNumFixIts(); 263 return 0; 264} 265 266CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt, 267 CXSourceRange *ReplacementRange) { 268 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); 269 if (!D || FixIt >= D->getNumFixIts()) { 270 if (ReplacementRange) 271 *ReplacementRange = clang_getNullRange(); 272 return createCXString(""); 273 } 274 return D->getFixIt(FixIt, ReplacementRange); 275} 276 277void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) { 278 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags); 279 if (D->isExternallyManaged()) 280 delete D; 281} 282 283CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, 284 unsigned Index) { 285 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) 286 if (Index < D->getNumDiagnostics()) 287 return D->getDiagnostic(Index); 288 return 0; 289} 290 291CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) { 292 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) { 293 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics(); 294 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags; 295 } 296 return 0; 297} 298 299unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) { 300 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) 301 return D->getNumDiagnostics(); 302 return 0; 303} 304 305} // end extern "C" 306