CIndexDiagnostic.cpp revision f51f20fa34654da75d15a9e2a1a0cd2fc0d8603d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\ 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* *| 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* The LLVM Compiler Infrastructure *| 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* *| 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* This file is distributed under the University of Illinois Open Source *| 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* License. See LICENSE.TXT for details. *| 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* *| 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*===----------------------------------------------------------------------===*| 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* *| 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* Implements the diagnostic functions of the Clang C interface. *| 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* *| 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)\*===----------------------------------------------------------------------===*/ 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CIndexDiagnostic.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CIndexer.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CXSourceLocation.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/ASTUnit.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/FrontendDiagnostic.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/SmallString.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/Twine.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/MemoryBuffer.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang::cxloc; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang::cxstring; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace llvm; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//----------------------------------------------------------------------------- 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// C Interface Routines 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//----------------------------------------------------------------------------- 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CXXUnit? CXXUnit->stored_diag_size() : 0; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CXXUnit || Index >= CXXUnit->stored_diag_size()) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index], 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXUnit->getASTContext().getLangOptions()); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete Stored; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Diagnostic) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return createCXString(""); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore diagnostics that should be ignored. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Severity == CXDiagnostic_Ignored) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return createCXString(""); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::SmallString<256> Str; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::raw_svector_ostream Out(Str); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Options & CXDiagnostic_DisplaySourceLocation) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Print source location (file:line), along with optional column 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and source ranges. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXFile File; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned Line, Column; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &File, &Line, &Column, 0); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (File) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXString FName = clang_getFileName(File); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Out << clang_getCString(FName) << ":" << Line << ":"; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clang_disposeString(FName); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Options & CXDiagnostic_DisplayColumn) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Out << Column << ":"; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Options & CXDiagnostic_DisplaySourceRanges) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool PrintedRange = false; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (unsigned I = 0; I != N; ++I) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXFile StartFile, EndFile; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned StartLine, StartColumn, EndLine, EndColumn; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clang_getInstantiationLocation(clang_getRangeStart(Range), 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &StartFile, &StartLine, &StartColumn, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clang_getInstantiationLocation(clang_getRangeEnd(Range), 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &EndFile, &EndLine, &EndColumn, 0); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (StartFile != EndFile || StartFile != File) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Out << "{" << StartLine << ":" << StartColumn << "-" 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << EndLine << ":" << EndColumn << "}"; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrintedRange = true; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (PrintedRange) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Out << ":"; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Out << " "; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Print warning/error/etc. */ 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (Severity) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CXDiagnostic_Ignored: assert(0 && "impossible"); break; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CXDiagnostic_Note: Out << "note: "; break; 113 case CXDiagnostic_Warning: Out << "warning: "; break; 114 case CXDiagnostic_Error: Out << "error: "; break; 115 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 116 } 117 118 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 119 if (clang_getCString(Text)) 120 Out << clang_getCString(Text); 121 else 122 Out << "<no diagnostic text>"; 123 clang_disposeString(Text); 124 return createCXString(Out.str(), true); 125} 126 127unsigned clang_defaultDiagnosticDisplayOptions() { 128 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn; 129} 130 131enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 132 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 133 if (!StoredDiag) 134 return CXDiagnostic_Ignored; 135 136 switch (StoredDiag->Diag.getLevel()) { 137 case Diagnostic::Ignored: return CXDiagnostic_Ignored; 138 case Diagnostic::Note: return CXDiagnostic_Note; 139 case Diagnostic::Warning: return CXDiagnostic_Warning; 140 case Diagnostic::Error: return CXDiagnostic_Error; 141 case Diagnostic::Fatal: return CXDiagnostic_Fatal; 142 } 143 144 llvm_unreachable("Invalid diagnostic level"); 145 return CXDiagnostic_Ignored; 146} 147 148CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 149 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 150 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 151 return clang_getNullLocation(); 152 153 return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(), 154 StoredDiag->LangOpts, 155 StoredDiag->Diag.getLocation()); 156} 157 158CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 159 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 160 if (!StoredDiag) 161 return createCXString(""); 162 163 return createCXString(StoredDiag->Diag.getMessage(), false); 164} 165 166unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 167 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 168 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 169 return 0; 170 171 return StoredDiag->Diag.range_size(); 172} 173 174CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 175 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 176 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || 177 StoredDiag->Diag.getLocation().isInvalid()) 178 return clang_getNullRange(); 179 180 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 181 StoredDiag->LangOpts, 182 StoredDiag->Diag.range_begin()[Range]); 183} 184 185unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 186 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 187 if (!StoredDiag) 188 return 0; 189 190 return StoredDiag->Diag.fixit_size(); 191} 192 193CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, 194 CXSourceRange *ReplacementRange) { 195 CXStoredDiagnostic *StoredDiag 196 = static_cast<CXStoredDiagnostic *>(Diagnostic); 197 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || 198 StoredDiag->Diag.getLocation().isInvalid()) { 199 if (ReplacementRange) 200 *ReplacementRange = clang_getNullRange(); 201 202 return createCXString(""); 203 } 204 205 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; 206 if (ReplacementRange) { 207 if (Hint.RemoveRange.isInvalid()) { 208 // Create an empty range that refers to a single source 209 // location (which is the insertion point). 210 CXSourceRange Range = { 211 { (void *)&StoredDiag->Diag.getLocation().getManager(), 212 (void *)&StoredDiag->LangOpts }, 213 Hint.InsertionLoc.getRawEncoding(), 214 Hint.InsertionLoc.getRawEncoding() 215 }; 216 217 *ReplacementRange = Range; 218 } else { 219 // Create a range that covers the entire replacement (or 220 // removal) range, adjusting the end of the range to point to 221 // the end of the token. 222 *ReplacementRange 223 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 224 StoredDiag->LangOpts, 225 Hint.RemoveRange); 226 } 227 } 228 229 return createCXString(Hint.CodeToInsert); 230} 231 232} // end extern "C" 233 234void clang::LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath, 235 unsigned num_unsaved_files, 236 struct CXUnsavedFile *unsaved_files, 237 FileManager &FileMgr, 238 SourceManager &SourceMgr, 239 SmallVectorImpl<StoredDiagnostic> &Diags) { 240 using llvm::MemoryBuffer; 241 using llvm::StringRef; 242 MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str()); 243 if (!F) 244 return; 245 246 // Enter the unsaved files into the file manager. 247 for (unsigned I = 0; I != num_unsaved_files; ++I) { 248 const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename, 249 unsaved_files[I].Length, 250 0); 251 if (!File) { 252 // FIXME: Hard to localize when we have no diagnostics engine! 253 Diags.push_back(StoredDiagnostic(Diagnostic::Fatal, 254 (Twine("could not remap from missing file ") + 255 unsaved_files[I].Filename).str())); 256 delete F; 257 return; 258 } 259 260 MemoryBuffer *Buffer 261 = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, 262 unsaved_files[I].Contents + unsaved_files[I].Length); 263 if (!Buffer) { 264 delete F; 265 return; 266 } 267 268 SourceMgr.overrideFileContents(File, Buffer); 269 SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User); 270 } 271 272 // Parse the diagnostics, emitting them one by one until we've 273 // exhausted the data. 274 StringRef Buffer = F->getBuffer(); 275 const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size(); 276 while (Memory != MemoryEnd) { 277 StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr, 278 Memory, MemoryEnd); 279 if (!Stored) 280 break; 281 282 Diags.push_back(Stored); 283 } 284 delete F; 285} 286