CIndexDiagnostic.cpp revision 153221717e39ce41323d5bc6b8b8bf130923c1bd
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
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
58//-----------------------------------------------------------------------------
59// C Interface Routines
60//-----------------------------------------------------------------------------
61extern "C" {
62
63unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
64  if (!Unit->TUData)
65    return 0;
66  return lazyCreateDiags(Unit)->getNumDiagnostics();
67}
68
69CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
70  if (!Unit->TUData)
71    return 0;
72
73  CXDiagnosticSetImpl *Diags = lazyCreateDiags(Unit);
74  if (Index >= Diags->getNumDiagnostics())
75    return 0;
76
77  return Diags->getDiagnostic(Index);
78}
79
80void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
81  // No-op.  Kept as a legacy API.  CXDiagnostics are now managed
82  // by the enclosing CXDiagnosticSet.
83}
84
85CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
86  if (!Diagnostic)
87    return createCXString("");
88
89  CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
90
91  llvm::SmallString<256> Str;
92  llvm::raw_svector_ostream Out(Str);
93
94  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;
99    clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
100                              &File, &Line, &Column, 0);
101    if (File) {
102      CXString FName = clang_getFileName(File);
103      Out << clang_getCString(FName) << ":" << Line << ":";
104      clang_disposeString(FName);
105      if (Options & CXDiagnostic_DisplayColumn)
106        Out << Column << ":";
107
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;
116          clang_getSpellingLocation(clang_getRangeStart(Range),
117                                    &StartFile, &StartLine, &StartColumn,
118                                    0);
119          clang_getSpellingLocation(clang_getRangeEnd(Range),
120                                    &EndFile, &EndLine, &EndColumn, 0);
121
122          if (StartFile != EndFile || StartFile != File)
123            continue;
124
125          Out << "{" << StartLine << ":" << StartColumn << "-"
126              << EndLine << ":" << EndColumn << "}";
127          PrintedRange = true;
128        }
129        if (PrintedRange)
130          Out << ":";
131      }
132
133      Out << " ";
134    }
135  }
136
137  /* Print warning/error/etc. */
138  switch (Severity) {
139  case CXDiagnostic_Ignored: llvm_unreachable("impossible");
140  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;
144  }
145
146  CXString Text = clang_getDiagnosticSpelling(Diagnostic);
147  if (clang_getCString(Text))
148    Out << clang_getCString(Text);
149  else
150    Out << "<no diagnostic text>";
151  clang_disposeString(Text);
152
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
201  return createCXString(Out.str(), true);
202}
203
204unsigned clang_defaultDiagnosticDisplayOptions() {
205  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
206         CXDiagnostic_DisplayOption;
207}
208
209enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
210  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
211    return D->getSeverity();
212  return CXDiagnostic_Ignored;
213}
214
215CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
216  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
217    return D->getLocation();
218  return clang_getNullLocation();
219}
220
221CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
222  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
223    return D->getSpelling();
224  return createCXString("");
225}
226
227CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
228  if (Disable)
229    *Disable = createCXString("");
230
231  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
232    return D->getDiagnosticOption(Disable);
233
234  return createCXString("");
235}
236
237unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
238  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
239    return D->getCategory();
240  return 0;
241}
242
243CXString clang_getDiagnosticCategoryName(unsigned Category) {
244  return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
245}
246
247unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
248  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
249    return D->getNumRanges();
250  return 0;
251}
252
253CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
254  CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
255  if (!D || Range >= D->getNumRanges())
256    return clang_getNullRange();
257  return D->getRange(Range);
258}
259
260unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
261  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
262    return D->getNumFixIts();
263  return 0;
264}
265
266CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
267                                  CXSourceRange *ReplacementRange) {
268  CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
269  if (!D || FixIt >= D->getNumFixIts()) {
270    if (ReplacementRange)
271      *ReplacementRange = clang_getNullRange();
272    return createCXString("");
273  }
274  return D->getFixIt(FixIt, ReplacementRange);
275}
276
277void 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
305} // end extern "C"
306