CIndexDiagnostic.cpp revision d3ab63e0f66429abf2a3e4cde889e420e41e8790
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 "CXSourceLocation.h"
16
17#include "clang/Frontend/ASTUnit.h"
18#include "clang/Frontend/FrontendDiagnostic.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/Support/MemoryBuffer.h"
22#include "llvm/Support/raw_ostream.h"
23
24using namespace clang;
25using namespace clang::cxloc;
26using namespace clang::cxstring;
27using namespace llvm;
28
29//-----------------------------------------------------------------------------
30// C Interface Routines
31//-----------------------------------------------------------------------------
32extern "C" {
33
34unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
35  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
36  return CXXUnit? CXXUnit->stored_diag_size() : 0;
37}
38
39CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
40  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
41  if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
42    return 0;
43
44  return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
45                                CXXUnit->getASTContext().getLangOptions());
46}
47
48void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
49  CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
50  delete Stored;
51}
52
53CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
54  if (!Diagnostic)
55    return createCXString("");
56
57  CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
58
59  // Ignore diagnostics that should be ignored.
60  if (Severity == CXDiagnostic_Ignored)
61    return createCXString("");
62
63  llvm::SmallString<256> Str;
64  llvm::raw_svector_ostream Out(Str);
65
66  if (Options & CXDiagnostic_DisplaySourceLocation) {
67    // Print source location (file:line), along with optional column
68    // and source ranges.
69    CXFile File;
70    unsigned Line, Column;
71    clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
72                                   &File, &Line, &Column, 0);
73    if (File) {
74      CXString FName = clang_getFileName(File);
75      Out << clang_getCString(FName) << ":" << Line << ":";
76      clang_disposeString(FName);
77      if (Options & CXDiagnostic_DisplayColumn)
78        Out << Column << ":";
79
80      if (Options & CXDiagnostic_DisplaySourceRanges) {
81        unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
82        bool PrintedRange = false;
83        for (unsigned I = 0; I != N; ++I) {
84          CXFile StartFile, EndFile;
85          CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
86
87          unsigned StartLine, StartColumn, EndLine, EndColumn;
88          clang_getInstantiationLocation(clang_getRangeStart(Range),
89                                         &StartFile, &StartLine, &StartColumn,
90                                         0);
91          clang_getInstantiationLocation(clang_getRangeEnd(Range),
92                                         &EndFile, &EndLine, &EndColumn, 0);
93
94          if (StartFile != EndFile || StartFile != File)
95            continue;
96
97          Out << "{" << StartLine << ":" << StartColumn << "-"
98              << EndLine << ":" << EndColumn << "}";
99          PrintedRange = true;
100        }
101        if (PrintedRange)
102          Out << ":";
103      }
104    }
105
106    Out << " ";
107  }
108
109  /* Print warning/error/etc. */
110  switch (Severity) {
111  case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
112  case CXDiagnostic_Note: Out << "note: "; break;
113  case CXDiagnostic_Warning: Out << "warning: "; break;
114  case CXDiagnostic_Error: Out << "error: "; break;
115  case CXDiagnostic_Fatal: Out << "fatal error: "; break;
116  }
117
118  CXString Text = clang_getDiagnosticSpelling(Diagnostic);
119  if (clang_getCString(Text))
120    Out << clang_getCString(Text);
121  else
122    Out << "<no diagnostic text>";
123  clang_disposeString(Text);
124  return createCXString(Out.str(), true);
125}
126
127unsigned clang_defaultDiagnosticDisplayOptions() {
128  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
129}
130
131enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
132  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
133  if (!StoredDiag)
134    return CXDiagnostic_Ignored;
135
136  switch (StoredDiag->Diag.getLevel()) {
137  case Diagnostic::Ignored: return CXDiagnostic_Ignored;
138  case Diagnostic::Note:    return CXDiagnostic_Note;
139  case Diagnostic::Warning: return CXDiagnostic_Warning;
140  case Diagnostic::Error:   return CXDiagnostic_Error;
141  case Diagnostic::Fatal:   return CXDiagnostic_Fatal;
142  }
143
144  llvm_unreachable("Invalid diagnostic level");
145  return CXDiagnostic_Ignored;
146}
147
148CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
149  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
150  if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
151    return clang_getNullLocation();
152
153  return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
154                                 StoredDiag->LangOpts,
155                                 StoredDiag->Diag.getLocation());
156}
157
158CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
159  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
160  if (!StoredDiag)
161    return createCXString("");
162
163  return createCXString(StoredDiag->Diag.getMessage(), false);
164}
165
166unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
167  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
168  if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
169    return 0;
170
171  return StoredDiag->Diag.range_size();
172}
173
174CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
175  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
176  if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
177      StoredDiag->Diag.getLocation().isInvalid())
178    return clang_getNullRange();
179
180  return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
181                              StoredDiag->LangOpts,
182                              StoredDiag->Diag.range_begin()[Range]);
183}
184
185unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
186  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
187  if (!StoredDiag)
188    return 0;
189
190  return StoredDiag->Diag.fixit_size();
191}
192
193CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
194                                  CXSourceRange *ReplacementRange) {
195  CXStoredDiagnostic *StoredDiag
196    = static_cast<CXStoredDiagnostic *>(Diagnostic);
197  if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
198      StoredDiag->Diag.getLocation().isInvalid()) {
199    if (ReplacementRange)
200      *ReplacementRange = clang_getNullRange();
201
202    return createCXString("");
203  }
204
205  const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
206  if (ReplacementRange) {
207    // Create a range that covers the entire replacement (or
208    // removal) range, adjusting the end of the range to point to
209    // the end of the token.
210    *ReplacementRange
211        = translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
212                                StoredDiag->LangOpts,
213                                Hint.RemoveRange);
214  }
215
216  return createCXString(Hint.CodeToInsert);
217}
218
219} // end extern "C"
220