blob: ceb640532be58a01da64275b9b1329d1765e2027 [file] [log] [blame]
Douglas Gregora88084b2010-02-18 18:08:43 +00001/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\
Douglas Gregor5352ac02010-01-28 00:27:43 +00002|* *|
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"
Ted Kremenek0a90d322010-11-17 23:24:11 +000015#include "CXTranslationUnit.h"
Douglas Gregor5352ac02010-01-28 00:27:43 +000016#include "CXSourceLocation.h"
Ted Kremeneked122732010-11-16 01:56:27 +000017#include "CXString.h"
Douglas Gregor5352ac02010-01-28 00:27:43 +000018
Benjamin Kramerb846deb2010-04-12 19:45:50 +000019#include "clang/Frontend/ASTUnit.h"
Douglas Gregord93256e2010-01-28 06:00:51 +000020#include "clang/Frontend/FrontendDiagnostic.h"
Douglas Gregor274f1902010-02-22 23:17:23 +000021#include "llvm/ADT/SmallString.h"
Douglas Gregora88084b2010-02-18 18:08:43 +000022#include "llvm/ADT/Twine.h"
Douglas Gregord93256e2010-01-28 06:00:51 +000023#include "llvm/Support/MemoryBuffer.h"
Douglas Gregor274f1902010-02-22 23:17:23 +000024#include "llvm/Support/raw_ostream.h"
Douglas Gregord93256e2010-01-28 06:00:51 +000025
Douglas Gregor5352ac02010-01-28 00:27:43 +000026using namespace clang;
27using namespace clang::cxloc;
Ted Kremenekee4db4f2010-02-17 00:41:08 +000028using namespace clang::cxstring;
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +000029using namespace clang::cxdiag;
Douglas Gregora88084b2010-02-18 18:08:43 +000030using namespace llvm;
Douglas Gregor5352ac02010-01-28 00:27:43 +000031
Ted Kremenek15322172011-11-10 08:43:12 +000032
33CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {
34 for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(),
35 et = Diagnostics.end();
36 it != et; ++it) {
37 delete *it;
38 }
39}
40
41CXDiagnosticImpl::~CXDiagnosticImpl() {}
42
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +000043CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
44 bool checkIfChanged) {
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000045 ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
46
47 if (TU->Diagnostics && checkIfChanged) {
Argyrios Kyrtzidisc88e58c2011-11-16 08:59:00 +000048 // In normal use, ASTUnit's diagnostics should not change unless we reparse.
49 // Currently they can only change by using the internal testing flag
50 // '-error-on-deserialized-decl' which will error during deserialization of
51 // a declaration. What will happen is:
52 //
53 // -c-index-test gets a CXTranslationUnit
54 // -checks the diagnostics, the diagnostics set is lazily created,
55 // no errors are reported
56 // -later does an operation, like annotation of tokens, that triggers
57 // -error-on-deserialized-decl, that will emit a diagnostic error,
58 // that ASTUnit will catch and add to its stored diagnostics vector.
59 // -c-index-test wants to check whether an error occurred after performing
60 // the operation but can only query the lazily created set.
61 //
62 // We check here if a new diagnostic was appended since the last time the
63 // diagnostic set was created, in which case we reset it.
64
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000065 CXDiagnosticSetImpl *
66 Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
67 if (AU->stored_diag_size() != Set->getNumDiagnostics()) {
68 // Diagnostics in the ASTUnit were updated, reset the associated
69 // diagnostics.
70 delete Set;
71 TU->Diagnostics = 0;
72 }
73 }
74
Ted Kremenek15322172011-11-10 08:43:12 +000075 if (!TU->Diagnostics) {
Ted Kremenek15322172011-11-10 08:43:12 +000076 CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
77 TU->Diagnostics = Set;
78
79 for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
80 ei = AU->stored_diag_end(); it != ei; ++it) {
81 CXStoredDiagnostic *D =
82 new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions());
83 Set->appendDiagnostic(D);
84 }
85 }
86 return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
87}
88
Douglas Gregor5352ac02010-01-28 00:27:43 +000089//-----------------------------------------------------------------------------
Ted Kremenekee4db4f2010-02-17 00:41:08 +000090// C Interface Routines
Douglas Gregor5352ac02010-01-28 00:27:43 +000091//-----------------------------------------------------------------------------
92extern "C" {
Ted Kremenekee4db4f2010-02-17 00:41:08 +000093
Douglas Gregora88084b2010-02-18 18:08:43 +000094unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
Ted Kremenek15322172011-11-10 08:43:12 +000095 if (!Unit->TUData)
96 return 0;
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000097 return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
Douglas Gregora88084b2010-02-18 18:08:43 +000098}
99
100CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
Ted Kremenek0373fcc2011-12-09 22:28:32 +0000101 CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit);
102 if (!D)
Douglas Gregora88084b2010-02-18 18:08:43 +0000103 return 0;
104
Ted Kremenek0373fcc2011-12-09 22:28:32 +0000105 CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D);
Ted Kremenek15322172011-11-10 08:43:12 +0000106 if (Index >= Diags->getNumDiagnostics())
107 return 0;
108
109 return Diags->getDiagnostic(Index);
Douglas Gregora88084b2010-02-18 18:08:43 +0000110}
Ted Kremenek0373fcc2011-12-09 22:28:32 +0000111
112CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {
113 if (!Unit->TUData)
114 return 0;
115 return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));
116}
Douglas Gregora88084b2010-02-18 18:08:43 +0000117
118void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
Ted Kremenek15322172011-11-10 08:43:12 +0000119 // No-op. Kept as a legacy API. CXDiagnostics are now managed
120 // by the enclosing CXDiagnosticSet.
Douglas Gregora88084b2010-02-18 18:08:43 +0000121}
122
Douglas Gregor274f1902010-02-22 23:17:23 +0000123CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
124 if (!Diagnostic)
125 return createCXString("");
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000126
127 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
128
Douglas Gregor274f1902010-02-22 23:17:23 +0000129 llvm::SmallString<256> Str;
130 llvm::raw_svector_ostream Out(Str);
131
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000132 if (Options & CXDiagnostic_DisplaySourceLocation) {
133 // Print source location (file:line), along with optional column
134 // and source ranges.
135 CXFile File;
136 unsigned Line, Column;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000137 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
138 &File, &Line, &Column, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000139 if (File) {
140 CXString FName = clang_getFileName(File);
Douglas Gregor274f1902010-02-22 23:17:23 +0000141 Out << clang_getCString(FName) << ":" << Line << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000142 clang_disposeString(FName);
143 if (Options & CXDiagnostic_DisplayColumn)
Douglas Gregor274f1902010-02-22 23:17:23 +0000144 Out << Column << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000145
146 if (Options & CXDiagnostic_DisplaySourceRanges) {
147 unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
148 bool PrintedRange = false;
149 for (unsigned I = 0; I != N; ++I) {
150 CXFile StartFile, EndFile;
151 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
152
153 unsigned StartLine, StartColumn, EndLine, EndColumn;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000154 clang_getSpellingLocation(clang_getRangeStart(Range),
155 &StartFile, &StartLine, &StartColumn,
156 0);
157 clang_getSpellingLocation(clang_getRangeEnd(Range),
158 &EndFile, &EndLine, &EndColumn, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000159
160 if (StartFile != EndFile || StartFile != File)
161 continue;
162
Douglas Gregor274f1902010-02-22 23:17:23 +0000163 Out << "{" << StartLine << ":" << StartColumn << "-"
164 << EndLine << ":" << EndColumn << "}";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000165 PrintedRange = true;
166 }
167 if (PrintedRange)
Douglas Gregor274f1902010-02-22 23:17:23 +0000168 Out << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000169 }
Douglas Gregor4cd912a2010-10-12 00:50:20 +0000170
171 Out << " ";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000172 }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000173 }
174
175 /* Print warning/error/etc. */
176 switch (Severity) {
David Blaikieeb2d1f12011-09-23 20:26:49 +0000177 case CXDiagnostic_Ignored: llvm_unreachable("impossible");
Douglas Gregor274f1902010-02-22 23:17:23 +0000178 case CXDiagnostic_Note: Out << "note: "; break;
179 case CXDiagnostic_Warning: Out << "warning: "; break;
180 case CXDiagnostic_Error: Out << "error: "; break;
181 case CXDiagnostic_Fatal: Out << "fatal error: "; break;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000182 }
183
184 CXString Text = clang_getDiagnosticSpelling(Diagnostic);
185 if (clang_getCString(Text))
Douglas Gregor274f1902010-02-22 23:17:23 +0000186 Out << clang_getCString(Text);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000187 else
Douglas Gregor274f1902010-02-22 23:17:23 +0000188 Out << "<no diagnostic text>";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000189 clang_disposeString(Text);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000190
191 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
192 CXDiagnostic_DisplayCategoryName)) {
193 bool NeedBracket = true;
194 bool NeedComma = false;
195
196 if (Options & CXDiagnostic_DisplayOption) {
197 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0);
198 if (const char *OptionText = clang_getCString(OptionName)) {
199 if (OptionText[0]) {
200 Out << " [" << OptionText;
201 NeedBracket = false;
202 NeedComma = true;
203 }
204 }
205 clang_disposeString(OptionName);
206 }
207
208 if (Options & (CXDiagnostic_DisplayCategoryId |
209 CXDiagnostic_DisplayCategoryName)) {
210 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {
211 if (Options & CXDiagnostic_DisplayCategoryId) {
212 if (NeedBracket)
213 Out << " [";
214 if (NeedComma)
215 Out << ", ";
216 Out << CategoryID;
217 NeedBracket = false;
218 NeedComma = true;
219 }
220
221 if (Options & CXDiagnostic_DisplayCategoryName) {
222 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
223 if (NeedBracket)
224 Out << " [";
225 if (NeedComma)
226 Out << ", ";
227 Out << clang_getCString(CategoryName);
228 NeedBracket = false;
229 NeedComma = true;
230 clang_disposeString(CategoryName);
231 }
232 }
233 }
234
235 if (!NeedBracket)
236 Out << "]";
237 }
238
Douglas Gregor274f1902010-02-22 23:17:23 +0000239 return createCXString(Out.str(), true);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000240}
241
242unsigned clang_defaultDiagnosticDisplayOptions() {
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000243 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
244 CXDiagnostic_DisplayOption;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000245}
246
Douglas Gregor5352ac02010-01-28 00:27:43 +0000247enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000248 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
249 return D->getSeverity();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000250 return CXDiagnostic_Ignored;
251}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000252
Douglas Gregor5352ac02010-01-28 00:27:43 +0000253CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000254 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
255 return D->getLocation();
256 return clang_getNullLocation();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000257}
258
259CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000260 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
261 return D->getSpelling();
262 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000263}
264
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000265CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
266 if (Disable)
267 *Disable = createCXString("");
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000268
269 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
270 return D->getDiagnosticOption(Disable);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000271
272 return createCXString("");
273}
274
275unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000276 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
277 return D->getCategory();
278 return 0;
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000279}
280
281CXString clang_getDiagnosticCategoryName(unsigned Category) {
282 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
283}
284
Douglas Gregora3890ba2010-02-08 23:11:56 +0000285unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000286 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
287 return D->getNumRanges();
288 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000289}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000290
Douglas Gregora3890ba2010-02-08 23:11:56 +0000291CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000292 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
293 if (!D || Range >= D->getNumRanges())
Douglas Gregora3890ba2010-02-08 23:11:56 +0000294 return clang_getNullRange();
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000295 return D->getRange(Range);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000296}
297
298unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000299 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
300 return D->getNumFixIts();
301 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000302}
303
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000304CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
Douglas Gregor473d7012010-02-19 18:16:06 +0000305 CXSourceRange *ReplacementRange) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000306 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
307 if (!D || FixIt >= D->getNumFixIts()) {
Douglas Gregor473d7012010-02-19 18:16:06 +0000308 if (ReplacementRange)
309 *ReplacementRange = clang_getNullRange();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000310 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000311 }
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000312 return D->getFixIt(FixIt, ReplacementRange);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000313}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000314
Ted Kremenek15322172011-11-10 08:43:12 +0000315void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
316 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
317 if (D->isExternallyManaged())
318 delete D;
319}
320
321CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
322 unsigned Index) {
323 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
324 if (Index < D->getNumDiagnostics())
325 return D->getDiagnostic(Index);
326 return 0;
327}
328
329CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
330 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
331 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
332 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
333 }
334 return 0;
335}
336
337unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
338 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
339 return D->getNumDiagnostics();
340 return 0;
341}
342
Douglas Gregor5352ac02010-01-28 00:27:43 +0000343} // end extern "C"