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
26 using namespace clang;
27 using namespace clang::cxloc;
28 using namespace clang::cxstring;
29 using namespace llvm;
30
31 //-----------------------------------------------------------------------------
32 // C Interface Routines
33 //-----------------------------------------------------------------------------
34 extern "C" {
35
clang_getNumDiagnostics(CXTranslationUnit Unit)36 unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
37 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
38 return CXXUnit? CXXUnit->stored_diag_size() : 0;
39 }
40
clang_getDiagnostic(CXTranslationUnit Unit,unsigned Index)41 CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
42 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
43 if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
44 return 0;
45
46 return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
47 CXXUnit->getASTContext().getLangOptions());
48 }
49
clang_disposeDiagnostic(CXDiagnostic Diagnostic)50 void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
51 CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
52 delete Stored;
53 }
54
clang_formatDiagnostic(CXDiagnostic Diagnostic,unsigned Options)55 CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
56 if (!Diagnostic)
57 return createCXString("");
58
59 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
60
61 llvm::SmallString<256> Str;
62 llvm::raw_svector_ostream Out(Str);
63
64 if (Options & CXDiagnostic_DisplaySourceLocation) {
65 // Print source location (file:line), along with optional column
66 // and source ranges.
67 CXFile File;
68 unsigned Line, Column;
69 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
70 &File, &Line, &Column, 0);
71 if (File) {
72 CXString FName = clang_getFileName(File);
73 Out << clang_getCString(FName) << ":" << Line << ":";
74 clang_disposeString(FName);
75 if (Options & CXDiagnostic_DisplayColumn)
76 Out << Column << ":";
77
78 if (Options & CXDiagnostic_DisplaySourceRanges) {
79 unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
80 bool PrintedRange = false;
81 for (unsigned I = 0; I != N; ++I) {
82 CXFile StartFile, EndFile;
83 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
84
85 unsigned StartLine, StartColumn, EndLine, EndColumn;
86 clang_getSpellingLocation(clang_getRangeStart(Range),
87 &StartFile, &StartLine, &StartColumn,
88 0);
89 clang_getSpellingLocation(clang_getRangeEnd(Range),
90 &EndFile, &EndLine, &EndColumn, 0);
91
92 if (StartFile != EndFile || StartFile != File)
93 continue;
94
95 Out << "{" << StartLine << ":" << StartColumn << "-"
96 << EndLine << ":" << EndColumn << "}";
97 PrintedRange = true;
98 }
99 if (PrintedRange)
100 Out << ":";
101 }
102
103 Out << " ";
104 }
105 }
106
107 /* Print warning/error/etc. */
108 switch (Severity) {
109 case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
110 case CXDiagnostic_Note: Out << "note: "; break;
111 case CXDiagnostic_Warning: Out << "warning: "; break;
112 case CXDiagnostic_Error: Out << "error: "; break;
113 case CXDiagnostic_Fatal: Out << "fatal error: "; break;
114 }
115
116 CXString Text = clang_getDiagnosticSpelling(Diagnostic);
117 if (clang_getCString(Text))
118 Out << clang_getCString(Text);
119 else
120 Out << "<no diagnostic text>";
121 clang_disposeString(Text);
122
123 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
124 CXDiagnostic_DisplayCategoryName)) {
125 bool NeedBracket = true;
126 bool NeedComma = false;
127
128 if (Options & CXDiagnostic_DisplayOption) {
129 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0);
130 if (const char *OptionText = clang_getCString(OptionName)) {
131 if (OptionText[0]) {
132 Out << " [" << OptionText;
133 NeedBracket = false;
134 NeedComma = true;
135 }
136 }
137 clang_disposeString(OptionName);
138 }
139
140 if (Options & (CXDiagnostic_DisplayCategoryId |
141 CXDiagnostic_DisplayCategoryName)) {
142 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {
143 if (Options & CXDiagnostic_DisplayCategoryId) {
144 if (NeedBracket)
145 Out << " [";
146 if (NeedComma)
147 Out << ", ";
148 Out << CategoryID;
149 NeedBracket = false;
150 NeedComma = true;
151 }
152
153 if (Options & CXDiagnostic_DisplayCategoryName) {
154 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
155 if (NeedBracket)
156 Out << " [";
157 if (NeedComma)
158 Out << ", ";
159 Out << clang_getCString(CategoryName);
160 NeedBracket = false;
161 NeedComma = true;
162 clang_disposeString(CategoryName);
163 }
164 }
165 }
166
167 if (!NeedBracket)
168 Out << "]";
169 }
170
171 return createCXString(Out.str(), true);
172 }
173
clang_defaultDiagnosticDisplayOptions()174 unsigned clang_defaultDiagnosticDisplayOptions() {
175 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
176 CXDiagnostic_DisplayOption;
177 }
178
clang_getDiagnosticSeverity(CXDiagnostic Diag)179 enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
180 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
181 if (!StoredDiag)
182 return CXDiagnostic_Ignored;
183
184 switch (StoredDiag->Diag.getLevel()) {
185 case Diagnostic::Ignored: return CXDiagnostic_Ignored;
186 case Diagnostic::Note: return CXDiagnostic_Note;
187 case Diagnostic::Warning: return CXDiagnostic_Warning;
188 case Diagnostic::Error: return CXDiagnostic_Error;
189 case Diagnostic::Fatal: return CXDiagnostic_Fatal;
190 }
191
192 llvm_unreachable("Invalid diagnostic level");
193 return CXDiagnostic_Ignored;
194 }
195
clang_getDiagnosticLocation(CXDiagnostic Diag)196 CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
197 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
198 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
199 return clang_getNullLocation();
200
201 return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
202 StoredDiag->LangOpts,
203 StoredDiag->Diag.getLocation());
204 }
205
clang_getDiagnosticSpelling(CXDiagnostic Diag)206 CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
207 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
208 if (!StoredDiag)
209 return createCXString("");
210
211 return createCXString(StoredDiag->Diag.getMessage(), false);
212 }
213
clang_getDiagnosticOption(CXDiagnostic Diag,CXString * Disable)214 CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
215 if (Disable)
216 *Disable = createCXString("");
217
218 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
219 if (!StoredDiag)
220 return createCXString("");
221
222 unsigned ID = StoredDiag->Diag.getID();
223 llvm::StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
224 if (!Option.empty()) {
225 if (Disable)
226 *Disable = createCXString((llvm::Twine("-Wno-") + Option).str());
227 return createCXString((llvm::Twine("-W") + Option).str());
228 }
229
230 if (ID == diag::fatal_too_many_errors) {
231 if (Disable)
232 *Disable = createCXString("-ferror-limit=0");
233 return createCXString("-ferror-limit=");
234 }
235
236 bool EnabledByDefault;
237 if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
238 !EnabledByDefault)
239 return createCXString("-pedantic");
240
241 return createCXString("");
242 }
243
clang_getDiagnosticCategory(CXDiagnostic Diag)244 unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
245 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
246 if (!StoredDiag)
247 return 0;
248
249 return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID());
250 }
251
clang_getDiagnosticCategoryName(unsigned Category)252 CXString clang_getDiagnosticCategoryName(unsigned Category) {
253 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
254 }
255
clang_getDiagnosticNumRanges(CXDiagnostic Diag)256 unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
257 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
258 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
259 return 0;
260
261 return StoredDiag->Diag.range_size();
262 }
263
clang_getDiagnosticRange(CXDiagnostic Diag,unsigned Range)264 CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
265 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
266 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
267 StoredDiag->Diag.getLocation().isInvalid())
268 return clang_getNullRange();
269
270 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
271 StoredDiag->LangOpts,
272 StoredDiag->Diag.range_begin()[Range]);
273 }
274
clang_getDiagnosticNumFixIts(CXDiagnostic Diag)275 unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
276 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
277 if (!StoredDiag)
278 return 0;
279
280 return StoredDiag->Diag.fixit_size();
281 }
282
clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,unsigned FixIt,CXSourceRange * ReplacementRange)283 CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
284 CXSourceRange *ReplacementRange) {
285 CXStoredDiagnostic *StoredDiag
286 = static_cast<CXStoredDiagnostic *>(Diagnostic);
287 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
288 StoredDiag->Diag.getLocation().isInvalid()) {
289 if (ReplacementRange)
290 *ReplacementRange = clang_getNullRange();
291
292 return createCXString("");
293 }
294
295 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
296 if (ReplacementRange) {
297 // Create a range that covers the entire replacement (or
298 // removal) range, adjusting the end of the range to point to
299 // the end of the token.
300 *ReplacementRange
301 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
302 StoredDiag->LangOpts,
303 Hint.RemoveRange);
304 }
305
306 return createCXString(Hint.CodeToInsert);
307 }
308
309 } // end extern "C"
310