blob: 50641fad1cd4e068675c2850c650da11341da005 [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) {
47 CXDiagnosticSetImpl *
48 Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
49 if (AU->stored_diag_size() != Set->getNumDiagnostics()) {
50 // Diagnostics in the ASTUnit were updated, reset the associated
51 // diagnostics.
52 delete Set;
53 TU->Diagnostics = 0;
54 }
55 }
56
Ted Kremenek15322172011-11-10 08:43:12 +000057 if (!TU->Diagnostics) {
Ted Kremenek15322172011-11-10 08:43:12 +000058 CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
59 TU->Diagnostics = Set;
60
61 for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
62 ei = AU->stored_diag_end(); it != ei; ++it) {
63 CXStoredDiagnostic *D =
64 new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions());
65 Set->appendDiagnostic(D);
66 }
67 }
68 return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
69}
70
Douglas Gregor5352ac02010-01-28 00:27:43 +000071//-----------------------------------------------------------------------------
Ted Kremenekee4db4f2010-02-17 00:41:08 +000072// C Interface Routines
Douglas Gregor5352ac02010-01-28 00:27:43 +000073//-----------------------------------------------------------------------------
74extern "C" {
Ted Kremenekee4db4f2010-02-17 00:41:08 +000075
Douglas Gregora88084b2010-02-18 18:08:43 +000076unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
Ted Kremenek15322172011-11-10 08:43:12 +000077 if (!Unit->TUData)
78 return 0;
Argyrios Kyrtzidis220b45c2011-11-16 02:34:55 +000079 return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
Douglas Gregora88084b2010-02-18 18:08:43 +000080}
81
82CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
Ted Kremenek15322172011-11-10 08:43:12 +000083 if (!Unit->TUData)
Douglas Gregora88084b2010-02-18 18:08:43 +000084 return 0;
85
Ted Kremenek15322172011-11-10 08:43:12 +000086 CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit);
87 if (Index >= Diags->getNumDiagnostics())
88 return 0;
89
90 return Diags->getDiagnostic(Index);
Douglas Gregora88084b2010-02-18 18:08:43 +000091}
92
93void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
Ted Kremenek15322172011-11-10 08:43:12 +000094 // No-op. Kept as a legacy API. CXDiagnostics are now managed
95 // by the enclosing CXDiagnosticSet.
Douglas Gregora88084b2010-02-18 18:08:43 +000096}
97
Douglas Gregor274f1902010-02-22 23:17:23 +000098CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
99 if (!Diagnostic)
100 return createCXString("");
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000101
102 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
103
Douglas Gregor274f1902010-02-22 23:17:23 +0000104 llvm::SmallString<256> Str;
105 llvm::raw_svector_ostream Out(Str);
106
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000107 if (Options & CXDiagnostic_DisplaySourceLocation) {
108 // Print source location (file:line), along with optional column
109 // and source ranges.
110 CXFile File;
111 unsigned Line, Column;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000112 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
113 &File, &Line, &Column, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000114 if (File) {
115 CXString FName = clang_getFileName(File);
Douglas Gregor274f1902010-02-22 23:17:23 +0000116 Out << clang_getCString(FName) << ":" << Line << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000117 clang_disposeString(FName);
118 if (Options & CXDiagnostic_DisplayColumn)
Douglas Gregor274f1902010-02-22 23:17:23 +0000119 Out << Column << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000120
121 if (Options & CXDiagnostic_DisplaySourceRanges) {
122 unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
123 bool PrintedRange = false;
124 for (unsigned I = 0; I != N; ++I) {
125 CXFile StartFile, EndFile;
126 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
127
128 unsigned StartLine, StartColumn, EndLine, EndColumn;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000129 clang_getSpellingLocation(clang_getRangeStart(Range),
130 &StartFile, &StartLine, &StartColumn,
131 0);
132 clang_getSpellingLocation(clang_getRangeEnd(Range),
133 &EndFile, &EndLine, &EndColumn, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000134
135 if (StartFile != EndFile || StartFile != File)
136 continue;
137
Douglas Gregor274f1902010-02-22 23:17:23 +0000138 Out << "{" << StartLine << ":" << StartColumn << "-"
139 << EndLine << ":" << EndColumn << "}";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000140 PrintedRange = true;
141 }
142 if (PrintedRange)
Douglas Gregor274f1902010-02-22 23:17:23 +0000143 Out << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000144 }
Douglas Gregor4cd912a2010-10-12 00:50:20 +0000145
146 Out << " ";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000147 }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000148 }
149
150 /* Print warning/error/etc. */
151 switch (Severity) {
David Blaikieeb2d1f12011-09-23 20:26:49 +0000152 case CXDiagnostic_Ignored: llvm_unreachable("impossible");
Douglas Gregor274f1902010-02-22 23:17:23 +0000153 case CXDiagnostic_Note: Out << "note: "; break;
154 case CXDiagnostic_Warning: Out << "warning: "; break;
155 case CXDiagnostic_Error: Out << "error: "; break;
156 case CXDiagnostic_Fatal: Out << "fatal error: "; break;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000157 }
158
159 CXString Text = clang_getDiagnosticSpelling(Diagnostic);
160 if (clang_getCString(Text))
Douglas Gregor274f1902010-02-22 23:17:23 +0000161 Out << clang_getCString(Text);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000162 else
Douglas Gregor274f1902010-02-22 23:17:23 +0000163 Out << "<no diagnostic text>";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000164 clang_disposeString(Text);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000165
166 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
167 CXDiagnostic_DisplayCategoryName)) {
168 bool NeedBracket = true;
169 bool NeedComma = false;
170
171 if (Options & CXDiagnostic_DisplayOption) {
172 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0);
173 if (const char *OptionText = clang_getCString(OptionName)) {
174 if (OptionText[0]) {
175 Out << " [" << OptionText;
176 NeedBracket = false;
177 NeedComma = true;
178 }
179 }
180 clang_disposeString(OptionName);
181 }
182
183 if (Options & (CXDiagnostic_DisplayCategoryId |
184 CXDiagnostic_DisplayCategoryName)) {
185 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {
186 if (Options & CXDiagnostic_DisplayCategoryId) {
187 if (NeedBracket)
188 Out << " [";
189 if (NeedComma)
190 Out << ", ";
191 Out << CategoryID;
192 NeedBracket = false;
193 NeedComma = true;
194 }
195
196 if (Options & CXDiagnostic_DisplayCategoryName) {
197 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
198 if (NeedBracket)
199 Out << " [";
200 if (NeedComma)
201 Out << ", ";
202 Out << clang_getCString(CategoryName);
203 NeedBracket = false;
204 NeedComma = true;
205 clang_disposeString(CategoryName);
206 }
207 }
208 }
209
210 if (!NeedBracket)
211 Out << "]";
212 }
213
Douglas Gregor274f1902010-02-22 23:17:23 +0000214 return createCXString(Out.str(), true);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000215}
216
217unsigned clang_defaultDiagnosticDisplayOptions() {
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000218 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
219 CXDiagnostic_DisplayOption;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000220}
221
Douglas Gregor5352ac02010-01-28 00:27:43 +0000222enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000223 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
224 return D->getSeverity();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000225 return CXDiagnostic_Ignored;
226}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000227
Douglas Gregor5352ac02010-01-28 00:27:43 +0000228CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000229 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
230 return D->getLocation();
231 return clang_getNullLocation();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000232}
233
234CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000235 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
236 return D->getSpelling();
237 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000238}
239
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000240CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
241 if (Disable)
242 *Disable = createCXString("");
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000243
244 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
245 return D->getDiagnosticOption(Disable);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000246
247 return createCXString("");
248}
249
250unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000251 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
252 return D->getCategory();
253 return 0;
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000254}
255
256CXString clang_getDiagnosticCategoryName(unsigned Category) {
257 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
258}
259
Douglas Gregora3890ba2010-02-08 23:11:56 +0000260unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000261 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
262 return D->getNumRanges();
263 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000264}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000265
Douglas Gregora3890ba2010-02-08 23:11:56 +0000266CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000267 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
268 if (!D || Range >= D->getNumRanges())
Douglas Gregora3890ba2010-02-08 23:11:56 +0000269 return clang_getNullRange();
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000270 return D->getRange(Range);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000271}
272
273unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000274 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
275 return D->getNumFixIts();
276 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000277}
278
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000279CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
Douglas Gregor473d7012010-02-19 18:16:06 +0000280 CXSourceRange *ReplacementRange) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000281 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
282 if (!D || FixIt >= D->getNumFixIts()) {
Douglas Gregor473d7012010-02-19 18:16:06 +0000283 if (ReplacementRange)
284 *ReplacementRange = clang_getNullRange();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000285 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000286 }
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000287 return D->getFixIt(FixIt, ReplacementRange);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000288}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000289
Ted Kremenek15322172011-11-10 08:43:12 +0000290void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
291 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
292 if (D->isExternallyManaged())
293 delete D;
294}
295
296CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
297 unsigned Index) {
298 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
299 if (Index < D->getNumDiagnostics())
300 return D->getDiagnostic(Index);
301 return 0;
302}
303
304CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
305 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
306 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
307 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
308 }
309 return 0;
310}
311
312unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
313 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
314 return D->getNumDiagnostics();
315 return 0;
316}
317
Douglas Gregor5352ac02010-01-28 00:27:43 +0000318} // end extern "C"