CIndexDiagnostic.cpp revision 477aab6782795e7472055a54108d2df270ce1a89
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
26using namespace clang;
27using namespace clang::cxloc;
28using namespace clang::cxstring;
29using namespace llvm;
30
31//-----------------------------------------------------------------------------
32// C Interface Routines
33//-----------------------------------------------------------------------------
34extern "C" {
35
36unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
37  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
38  return CXXUnit? CXXUnit->stored_diag_size() : 0;
39}
40
41CXDiagnostic 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
50void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
51  CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
52  delete Stored;
53}
54
55CXString 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
174unsigned clang_defaultDiagnosticDisplayOptions() {
175  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
176         CXDiagnostic_DisplayOption;
177}
178
179enum 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
196CXSourceLocation 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
206CXString 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
214CXString 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
244unsigned 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
252CXString clang_getDiagnosticCategoryName(unsigned Category) {
253  return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
254}
255
256unsigned 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
264CXSourceRange 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
275unsigned 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
283CXString 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