• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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