blob: de0e8d4c8f5332e399513f41f4f44c9faf697c55 [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;
Douglas Gregora88084b2010-02-18 18:08:43 +000029using namespace llvm;
Douglas Gregor5352ac02010-01-28 00:27:43 +000030
Ted Kremenek15322172011-11-10 08:43:12 +000031
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
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000042static CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU,
43 bool checkIfChanged = false) {
44 ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
45
46 if (TU->Diagnostics && checkIfChanged) {
Argyrios Kyrtzidisc88e58c2011-11-16 08:59:00 +000047 // In normal use, ASTUnit's diagnostics should not change unless we reparse.
48 // Currently they can only change by using the internal testing flag
49 // '-error-on-deserialized-decl' which will error during deserialization of
50 // a declaration. What will happen is:
51 //
52 // -c-index-test gets a CXTranslationUnit
53 // -checks the diagnostics, the diagnostics set is lazily created,
54 // no errors are reported
55 // -later does an operation, like annotation of tokens, that triggers
56 // -error-on-deserialized-decl, that will emit a diagnostic error,
57 // that ASTUnit will catch and add to its stored diagnostics vector.
58 // -c-index-test wants to check whether an error occurred after performing
59 // the operation but can only query the lazily created set.
60 //
61 // We check here if a new diagnostic was appended since the last time the
62 // diagnostic set was created, in which case we reset it.
63
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000064 CXDiagnosticSetImpl *
65 Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
66 if (AU->stored_diag_size() != Set->getNumDiagnostics()) {
67 // Diagnostics in the ASTUnit were updated, reset the associated
68 // diagnostics.
69 delete Set;
70 TU->Diagnostics = 0;
71 }
72 }
73
Ted Kremenek15322172011-11-10 08:43:12 +000074 if (!TU->Diagnostics) {
Ted Kremenek15322172011-11-10 08:43:12 +000075 CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
76 TU->Diagnostics = Set;
77
78 for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
79 ei = AU->stored_diag_end(); it != ei; ++it) {
80 CXStoredDiagnostic *D =
81 new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions());
82 Set->appendDiagnostic(D);
83 }
84 }
85 return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
86}
87
Douglas Gregor5352ac02010-01-28 00:27:43 +000088//-----------------------------------------------------------------------------
Ted Kremenekee4db4f2010-02-17 00:41:08 +000089// C Interface Routines
Douglas Gregor5352ac02010-01-28 00:27:43 +000090//-----------------------------------------------------------------------------
91extern "C" {
Ted Kremenekee4db4f2010-02-17 00:41:08 +000092
Douglas Gregora88084b2010-02-18 18:08:43 +000093unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
Ted Kremenek15322172011-11-10 08:43:12 +000094 if (!Unit->TUData)
95 return 0;
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000096 return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
Douglas Gregora88084b2010-02-18 18:08:43 +000097}
98
99CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
Ted Kremenek15322172011-11-10 08:43:12 +0000100 if (!Unit->TUData)
Douglas Gregora88084b2010-02-18 18:08:43 +0000101 return 0;
102
Ted Kremenek15322172011-11-10 08:43:12 +0000103 CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit);
104 if (Index >= Diags->getNumDiagnostics())
105 return 0;
106
107 return Diags->getDiagnostic(Index);
Douglas Gregora88084b2010-02-18 18:08:43 +0000108}
109
110void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
Ted Kremenek15322172011-11-10 08:43:12 +0000111 // No-op. Kept as a legacy API. CXDiagnostics are now managed
112 // by the enclosing CXDiagnosticSet.
Douglas Gregora88084b2010-02-18 18:08:43 +0000113}
114
Douglas Gregor274f1902010-02-22 23:17:23 +0000115CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
116 if (!Diagnostic)
117 return createCXString("");
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000118
119 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
120
Douglas Gregor274f1902010-02-22 23:17:23 +0000121 llvm::SmallString<256> Str;
122 llvm::raw_svector_ostream Out(Str);
123
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000124 if (Options & CXDiagnostic_DisplaySourceLocation) {
125 // Print source location (file:line), along with optional column
126 // and source ranges.
127 CXFile File;
128 unsigned Line, Column;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000129 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
130 &File, &Line, &Column, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000131 if (File) {
132 CXString FName = clang_getFileName(File);
Douglas Gregor274f1902010-02-22 23:17:23 +0000133 Out << clang_getCString(FName) << ":" << Line << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000134 clang_disposeString(FName);
135 if (Options & CXDiagnostic_DisplayColumn)
Douglas Gregor274f1902010-02-22 23:17:23 +0000136 Out << Column << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000137
138 if (Options & CXDiagnostic_DisplaySourceRanges) {
139 unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
140 bool PrintedRange = false;
141 for (unsigned I = 0; I != N; ++I) {
142 CXFile StartFile, EndFile;
143 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
144
145 unsigned StartLine, StartColumn, EndLine, EndColumn;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000146 clang_getSpellingLocation(clang_getRangeStart(Range),
147 &StartFile, &StartLine, &StartColumn,
148 0);
149 clang_getSpellingLocation(clang_getRangeEnd(Range),
150 &EndFile, &EndLine, &EndColumn, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000151
152 if (StartFile != EndFile || StartFile != File)
153 continue;
154
Douglas Gregor274f1902010-02-22 23:17:23 +0000155 Out << "{" << StartLine << ":" << StartColumn << "-"
156 << EndLine << ":" << EndColumn << "}";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000157 PrintedRange = true;
158 }
159 if (PrintedRange)
Douglas Gregor274f1902010-02-22 23:17:23 +0000160 Out << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000161 }
Douglas Gregor4cd912a2010-10-12 00:50:20 +0000162
163 Out << " ";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000164 }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000165 }
166
167 /* Print warning/error/etc. */
168 switch (Severity) {
David Blaikieeb2d1f12011-09-23 20:26:49 +0000169 case CXDiagnostic_Ignored: llvm_unreachable("impossible");
Douglas Gregor274f1902010-02-22 23:17:23 +0000170 case CXDiagnostic_Note: Out << "note: "; break;
171 case CXDiagnostic_Warning: Out << "warning: "; break;
172 case CXDiagnostic_Error: Out << "error: "; break;
173 case CXDiagnostic_Fatal: Out << "fatal error: "; break;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000174 }
175
176 CXString Text = clang_getDiagnosticSpelling(Diagnostic);
177 if (clang_getCString(Text))
Douglas Gregor274f1902010-02-22 23:17:23 +0000178 Out << clang_getCString(Text);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000179 else
Douglas Gregor274f1902010-02-22 23:17:23 +0000180 Out << "<no diagnostic text>";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000181 clang_disposeString(Text);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000182
183 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
184 CXDiagnostic_DisplayCategoryName)) {
185 bool NeedBracket = true;
186 bool NeedComma = false;
187
188 if (Options & CXDiagnostic_DisplayOption) {
189 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0);
190 if (const char *OptionText = clang_getCString(OptionName)) {
191 if (OptionText[0]) {
192 Out << " [" << OptionText;
193 NeedBracket = false;
194 NeedComma = true;
195 }
196 }
197 clang_disposeString(OptionName);
198 }
199
200 if (Options & (CXDiagnostic_DisplayCategoryId |
201 CXDiagnostic_DisplayCategoryName)) {
202 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {
203 if (Options & CXDiagnostic_DisplayCategoryId) {
204 if (NeedBracket)
205 Out << " [";
206 if (NeedComma)
207 Out << ", ";
208 Out << CategoryID;
209 NeedBracket = false;
210 NeedComma = true;
211 }
212
213 if (Options & CXDiagnostic_DisplayCategoryName) {
214 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
215 if (NeedBracket)
216 Out << " [";
217 if (NeedComma)
218 Out << ", ";
219 Out << clang_getCString(CategoryName);
220 NeedBracket = false;
221 NeedComma = true;
222 clang_disposeString(CategoryName);
223 }
224 }
225 }
226
227 if (!NeedBracket)
228 Out << "]";
229 }
230
Douglas Gregor274f1902010-02-22 23:17:23 +0000231 return createCXString(Out.str(), true);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000232}
233
234unsigned clang_defaultDiagnosticDisplayOptions() {
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000235 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
236 CXDiagnostic_DisplayOption;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000237}
238
Douglas Gregor5352ac02010-01-28 00:27:43 +0000239enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000240 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
241 return D->getSeverity();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000242 return CXDiagnostic_Ignored;
243}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000244
Douglas Gregor5352ac02010-01-28 00:27:43 +0000245CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000246 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
247 return D->getLocation();
248 return clang_getNullLocation();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000249}
250
251CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000252 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
253 return D->getSpelling();
254 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000255}
256
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000257CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
258 if (Disable)
259 *Disable = createCXString("");
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000260
261 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
262 return D->getDiagnosticOption(Disable);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000263
264 return createCXString("");
265}
266
267unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000268 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
269 return D->getCategory();
270 return 0;
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000271}
272
273CXString clang_getDiagnosticCategoryName(unsigned Category) {
274 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
275}
276
Douglas Gregora3890ba2010-02-08 23:11:56 +0000277unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000278 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
279 return D->getNumRanges();
280 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000281}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000282
Douglas Gregora3890ba2010-02-08 23:11:56 +0000283CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000284 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
285 if (!D || Range >= D->getNumRanges())
Douglas Gregora3890ba2010-02-08 23:11:56 +0000286 return clang_getNullRange();
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000287 return D->getRange(Range);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000288}
289
290unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000291 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
292 return D->getNumFixIts();
293 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000294}
295
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000296CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
Douglas Gregor473d7012010-02-19 18:16:06 +0000297 CXSourceRange *ReplacementRange) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000298 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
299 if (!D || FixIt >= D->getNumFixIts()) {
Douglas Gregor473d7012010-02-19 18:16:06 +0000300 if (ReplacementRange)
301 *ReplacementRange = clang_getNullRange();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000302 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000303 }
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000304 return D->getFixIt(FixIt, ReplacementRange);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000305}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000306
Ted Kremenek15322172011-11-10 08:43:12 +0000307void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
308 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
309 if (D->isExternallyManaged())
310 delete D;
311}
312
313CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
314 unsigned Index) {
315 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
316 if (Index < D->getNumDiagnostics())
317 return D->getDiagnostic(Index);
318 return 0;
319}
320
321CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
322 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
323 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
324 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
325 }
326 return 0;
327}
328
329unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
330 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
331 return D->getNumDiagnostics();
332 return 0;
333}
334
Douglas Gregor5352ac02010-01-28 00:27:43 +0000335} // end extern "C"