blob: 436ea37038a9e41e4ec944a2cebd3675fd25de03 [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
42static CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU) {
43 if (!TU->Diagnostics) {
44 ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
45 CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
46 TU->Diagnostics = Set;
47
48 for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
49 ei = AU->stored_diag_end(); it != ei; ++it) {
50 CXStoredDiagnostic *D =
51 new CXStoredDiagnostic(*it, AU->getASTContext().getLangOptions());
52 Set->appendDiagnostic(D);
53 }
54 }
55 return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
56}
57
Douglas Gregor5352ac02010-01-28 00:27:43 +000058//-----------------------------------------------------------------------------
Ted Kremenekee4db4f2010-02-17 00:41:08 +000059// C Interface Routines
Douglas Gregor5352ac02010-01-28 00:27:43 +000060//-----------------------------------------------------------------------------
61extern "C" {
Ted Kremenekee4db4f2010-02-17 00:41:08 +000062
Douglas Gregora88084b2010-02-18 18:08:43 +000063unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
Ted Kremenek15322172011-11-10 08:43:12 +000064 if (!Unit->TUData)
65 return 0;
66 return lazyCreateDiags(Unit)->getNumDiagnostics();
Douglas Gregora88084b2010-02-18 18:08:43 +000067}
68
69CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
Ted Kremenek15322172011-11-10 08:43:12 +000070 if (!Unit->TUData)
Douglas Gregora88084b2010-02-18 18:08:43 +000071 return 0;
72
Ted Kremenek15322172011-11-10 08:43:12 +000073 CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit);
74 if (Index >= Diags->getNumDiagnostics())
75 return 0;
76
77 return Diags->getDiagnostic(Index);
Douglas Gregora88084b2010-02-18 18:08:43 +000078}
79
80void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
Ted Kremenek15322172011-11-10 08:43:12 +000081 // No-op. Kept as a legacy API. CXDiagnostics are now managed
82 // by the enclosing CXDiagnosticSet.
Douglas Gregora88084b2010-02-18 18:08:43 +000083}
84
Douglas Gregor274f1902010-02-22 23:17:23 +000085CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
86 if (!Diagnostic)
87 return createCXString("");
Douglas Gregor0a812cf2010-02-18 23:07:20 +000088
89 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
90
Douglas Gregor274f1902010-02-22 23:17:23 +000091 llvm::SmallString<256> Str;
92 llvm::raw_svector_ostream Out(Str);
93
Douglas Gregor0a812cf2010-02-18 23:07:20 +000094 if (Options & CXDiagnostic_DisplaySourceLocation) {
95 // Print source location (file:line), along with optional column
96 // and source ranges.
97 CXFile File;
98 unsigned Line, Column;
Douglas Gregora9b06d42010-11-09 06:24:54 +000099 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
100 &File, &Line, &Column, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000101 if (File) {
102 CXString FName = clang_getFileName(File);
Douglas Gregor274f1902010-02-22 23:17:23 +0000103 Out << clang_getCString(FName) << ":" << Line << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000104 clang_disposeString(FName);
105 if (Options & CXDiagnostic_DisplayColumn)
Douglas Gregor274f1902010-02-22 23:17:23 +0000106 Out << Column << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000107
108 if (Options & CXDiagnostic_DisplaySourceRanges) {
109 unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
110 bool PrintedRange = false;
111 for (unsigned I = 0; I != N; ++I) {
112 CXFile StartFile, EndFile;
113 CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
114
115 unsigned StartLine, StartColumn, EndLine, EndColumn;
Douglas Gregora9b06d42010-11-09 06:24:54 +0000116 clang_getSpellingLocation(clang_getRangeStart(Range),
117 &StartFile, &StartLine, &StartColumn,
118 0);
119 clang_getSpellingLocation(clang_getRangeEnd(Range),
120 &EndFile, &EndLine, &EndColumn, 0);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000121
122 if (StartFile != EndFile || StartFile != File)
123 continue;
124
Douglas Gregor274f1902010-02-22 23:17:23 +0000125 Out << "{" << StartLine << ":" << StartColumn << "-"
126 << EndLine << ":" << EndColumn << "}";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000127 PrintedRange = true;
128 }
129 if (PrintedRange)
Douglas Gregor274f1902010-02-22 23:17:23 +0000130 Out << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000131 }
Douglas Gregor4cd912a2010-10-12 00:50:20 +0000132
133 Out << " ";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000134 }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000135 }
136
137 /* Print warning/error/etc. */
138 switch (Severity) {
David Blaikieeb2d1f12011-09-23 20:26:49 +0000139 case CXDiagnostic_Ignored: llvm_unreachable("impossible");
Douglas Gregor274f1902010-02-22 23:17:23 +0000140 case CXDiagnostic_Note: Out << "note: "; break;
141 case CXDiagnostic_Warning: Out << "warning: "; break;
142 case CXDiagnostic_Error: Out << "error: "; break;
143 case CXDiagnostic_Fatal: Out << "fatal error: "; break;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000144 }
145
146 CXString Text = clang_getDiagnosticSpelling(Diagnostic);
147 if (clang_getCString(Text))
Douglas Gregor274f1902010-02-22 23:17:23 +0000148 Out << clang_getCString(Text);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000149 else
Douglas Gregor274f1902010-02-22 23:17:23 +0000150 Out << "<no diagnostic text>";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000151 clang_disposeString(Text);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000152
153 if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
154 CXDiagnostic_DisplayCategoryName)) {
155 bool NeedBracket = true;
156 bool NeedComma = false;
157
158 if (Options & CXDiagnostic_DisplayOption) {
159 CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0);
160 if (const char *OptionText = clang_getCString(OptionName)) {
161 if (OptionText[0]) {
162 Out << " [" << OptionText;
163 NeedBracket = false;
164 NeedComma = true;
165 }
166 }
167 clang_disposeString(OptionName);
168 }
169
170 if (Options & (CXDiagnostic_DisplayCategoryId |
171 CXDiagnostic_DisplayCategoryName)) {
172 if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {
173 if (Options & CXDiagnostic_DisplayCategoryId) {
174 if (NeedBracket)
175 Out << " [";
176 if (NeedComma)
177 Out << ", ";
178 Out << CategoryID;
179 NeedBracket = false;
180 NeedComma = true;
181 }
182
183 if (Options & CXDiagnostic_DisplayCategoryName) {
184 CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
185 if (NeedBracket)
186 Out << " [";
187 if (NeedComma)
188 Out << ", ";
189 Out << clang_getCString(CategoryName);
190 NeedBracket = false;
191 NeedComma = true;
192 clang_disposeString(CategoryName);
193 }
194 }
195 }
196
197 if (!NeedBracket)
198 Out << "]";
199 }
200
Douglas Gregor274f1902010-02-22 23:17:23 +0000201 return createCXString(Out.str(), true);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000202}
203
204unsigned clang_defaultDiagnosticDisplayOptions() {
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000205 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
206 CXDiagnostic_DisplayOption;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000207}
208
Douglas Gregor5352ac02010-01-28 00:27:43 +0000209enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000210 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
211 return D->getSeverity();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000212 return CXDiagnostic_Ignored;
213}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000214
Douglas Gregor5352ac02010-01-28 00:27:43 +0000215CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000216 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
217 return D->getLocation();
218 return clang_getNullLocation();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000219}
220
221CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000222 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
223 return D->getSpelling();
224 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000225}
226
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000227CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
228 if (Disable)
229 *Disable = createCXString("");
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000230
231 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
232 return D->getDiagnosticOption(Disable);
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000233
234 return createCXString("");
235}
236
237unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000238 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
239 return D->getCategory();
240 return 0;
Douglas Gregoraa5f1352010-11-19 16:18:16 +0000241}
242
243CXString clang_getDiagnosticCategoryName(unsigned Category) {
244 return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
245}
246
Douglas Gregora3890ba2010-02-08 23:11:56 +0000247unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000248 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
249 return D->getNumRanges();
250 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000251}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000252
Douglas Gregora3890ba2010-02-08 23:11:56 +0000253CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000254 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
255 if (!D || Range >= D->getNumRanges())
Douglas Gregora3890ba2010-02-08 23:11:56 +0000256 return clang_getNullRange();
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000257 return D->getRange(Range);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000258}
259
260unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000261 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
262 return D->getNumFixIts();
263 return 0;
Douglas Gregor5352ac02010-01-28 00:27:43 +0000264}
265
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000266CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
Douglas Gregor473d7012010-02-19 18:16:06 +0000267 CXSourceRange *ReplacementRange) {
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000268 CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
269 if (!D || FixIt >= D->getNumFixIts()) {
Douglas Gregor473d7012010-02-19 18:16:06 +0000270 if (ReplacementRange)
271 *ReplacementRange = clang_getNullRange();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000272 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000273 }
Ted Kremenek1edabbc2011-10-31 21:40:19 +0000274 return D->getFixIt(FixIt, ReplacementRange);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000275}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000276
Ted Kremenek15322172011-11-10 08:43:12 +0000277void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
278 CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
279 if (D->isExternallyManaged())
280 delete D;
281}
282
283CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
284 unsigned Index) {
285 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
286 if (Index < D->getNumDiagnostics())
287 return D->getDiagnostic(Index);
288 return 0;
289}
290
291CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
292 if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
293 CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
294 return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
295 }
296 return 0;
297}
298
299unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
300 if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
301 return D->getNumDiagnostics();
302 return 0;
303}
304
Douglas Gregor5352ac02010-01-28 00:27:43 +0000305} // end extern "C"