CIndexDiagnostic.cpp revision a60ed47da13393796d8552b9fdca12abbb3eea42
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 "CXSourceLocation.h" 16#include "CXString.h" 17 18#include "clang/Frontend/ASTUnit.h" 19#include "clang/Frontend/FrontendDiagnostic.h" 20#include "llvm/ADT/SmallString.h" 21#include "llvm/ADT/Twine.h" 22#include "llvm/Support/MemoryBuffer.h" 23#include "llvm/Support/raw_ostream.h" 24 25using namespace clang; 26using namespace clang::cxloc; 27using namespace clang::cxstring; 28using namespace llvm; 29 30//----------------------------------------------------------------------------- 31// C Interface Routines 32//----------------------------------------------------------------------------- 33extern "C" { 34 35unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { 36 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData); 37 return CXXUnit? CXXUnit->stored_diag_size() : 0; 38} 39 40CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { 41 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData); 42 if (!CXXUnit || Index >= CXXUnit->stored_diag_size()) 43 return 0; 44 45 return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index], 46 CXXUnit->getASTContext().getLangOptions()); 47} 48 49void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { 50 CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic); 51 delete Stored; 52} 53 54CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { 55 if (!Diagnostic) 56 return createCXString(""); 57 58 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); 59 60 llvm::SmallString<256> Str; 61 llvm::raw_svector_ostream Out(Str); 62 63 if (Options & CXDiagnostic_DisplaySourceLocation) { 64 // Print source location (file:line), along with optional column 65 // and source ranges. 66 CXFile File; 67 unsigned Line, Column; 68 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), 69 &File, &Line, &Column, 0); 70 if (File) { 71 CXString FName = clang_getFileName(File); 72 Out << clang_getCString(FName) << ":" << Line << ":"; 73 clang_disposeString(FName); 74 if (Options & CXDiagnostic_DisplayColumn) 75 Out << Column << ":"; 76 77 if (Options & CXDiagnostic_DisplaySourceRanges) { 78 unsigned N = clang_getDiagnosticNumRanges(Diagnostic); 79 bool PrintedRange = false; 80 for (unsigned I = 0; I != N; ++I) { 81 CXFile StartFile, EndFile; 82 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); 83 84 unsigned StartLine, StartColumn, EndLine, EndColumn; 85 clang_getSpellingLocation(clang_getRangeStart(Range), 86 &StartFile, &StartLine, &StartColumn, 87 0); 88 clang_getSpellingLocation(clang_getRangeEnd(Range), 89 &EndFile, &EndLine, &EndColumn, 0); 90 91 if (StartFile != EndFile || StartFile != File) 92 continue; 93 94 Out << "{" << StartLine << ":" << StartColumn << "-" 95 << EndLine << ":" << EndColumn << "}"; 96 PrintedRange = true; 97 } 98 if (PrintedRange) 99 Out << ":"; 100 } 101 102 Out << " "; 103 } 104 } 105 106 /* Print warning/error/etc. */ 107 switch (Severity) { 108 case CXDiagnostic_Ignored: assert(0 && "impossible"); break; 109 case CXDiagnostic_Note: Out << "note: "; break; 110 case CXDiagnostic_Warning: Out << "warning: "; break; 111 case CXDiagnostic_Error: Out << "error: "; break; 112 case CXDiagnostic_Fatal: Out << "fatal error: "; break; 113 } 114 115 CXString Text = clang_getDiagnosticSpelling(Diagnostic); 116 if (clang_getCString(Text)) 117 Out << clang_getCString(Text); 118 else 119 Out << "<no diagnostic text>"; 120 clang_disposeString(Text); 121 return createCXString(Out.str(), true); 122} 123 124unsigned clang_defaultDiagnosticDisplayOptions() { 125 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn; 126} 127 128enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { 129 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 130 if (!StoredDiag) 131 return CXDiagnostic_Ignored; 132 133 switch (StoredDiag->Diag.getLevel()) { 134 case Diagnostic::Ignored: return CXDiagnostic_Ignored; 135 case Diagnostic::Note: return CXDiagnostic_Note; 136 case Diagnostic::Warning: return CXDiagnostic_Warning; 137 case Diagnostic::Error: return CXDiagnostic_Error; 138 case Diagnostic::Fatal: return CXDiagnostic_Fatal; 139 } 140 141 llvm_unreachable("Invalid diagnostic level"); 142 return CXDiagnostic_Ignored; 143} 144 145CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { 146 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 147 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 148 return clang_getNullLocation(); 149 150 return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(), 151 StoredDiag->LangOpts, 152 StoredDiag->Diag.getLocation()); 153} 154 155CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { 156 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 157 if (!StoredDiag) 158 return createCXString(""); 159 160 return createCXString(StoredDiag->Diag.getMessage(), false); 161} 162 163unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { 164 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 165 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) 166 return 0; 167 168 return StoredDiag->Diag.range_size(); 169} 170 171CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { 172 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 173 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || 174 StoredDiag->Diag.getLocation().isInvalid()) 175 return clang_getNullRange(); 176 177 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 178 StoredDiag->LangOpts, 179 StoredDiag->Diag.range_begin()[Range]); 180} 181 182unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { 183 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag); 184 if (!StoredDiag) 185 return 0; 186 187 return StoredDiag->Diag.fixit_size(); 188} 189 190CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, 191 CXSourceRange *ReplacementRange) { 192 CXStoredDiagnostic *StoredDiag 193 = static_cast<CXStoredDiagnostic *>(Diagnostic); 194 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || 195 StoredDiag->Diag.getLocation().isInvalid()) { 196 if (ReplacementRange) 197 *ReplacementRange = clang_getNullRange(); 198 199 return createCXString(""); 200 } 201 202 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; 203 if (ReplacementRange) { 204 // Create a range that covers the entire replacement (or 205 // removal) range, adjusting the end of the range to point to 206 // the end of the token. 207 *ReplacementRange 208 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), 209 StoredDiag->LangOpts, 210 Hint.RemoveRange); 211 } 212 213 return createCXString(Hint.CodeToInsert); 214} 215 216} // end extern "C" 217