CIndexDiagnostic.cpp revision a9b06d4c246d6c301e3dd1844f5dba669ed9c631
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  llvm::SmallString<256> Str;
60  llvm::raw_svector_ostream Out(Str);
61
62  if (Options & CXDiagnostic_DisplaySourceLocation) {
63    // Print source location (file:line), along with optional column
64    // and source ranges.
65    CXFile File;
66    unsigned Line, Column;
67    clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
68                              &File, &Line, &Column, 0);
69    if (File) {
70      CXString FName = clang_getFileName(File);
71      Out << clang_getCString(FName) << ":" << Line << ":";
72      clang_disposeString(FName);
73      if (Options & CXDiagnostic_DisplayColumn)
74        Out << Column << ":";
75
76      if (Options & CXDiagnostic_DisplaySourceRanges) {
77        unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
78        bool PrintedRange = false;
79        for (unsigned I = 0; I != N; ++I) {
80          CXFile StartFile, EndFile;
81          CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
82
83          unsigned StartLine, StartColumn, EndLine, EndColumn;
84          clang_getSpellingLocation(clang_getRangeStart(Range),
85                                    &StartFile, &StartLine, &StartColumn,
86                                    0);
87          clang_getSpellingLocation(clang_getRangeEnd(Range),
88                                    &EndFile, &EndLine, &EndColumn, 0);
89
90          if (StartFile != EndFile || StartFile != File)
91            continue;
92
93          Out << "{" << StartLine << ":" << StartColumn << "-"
94              << EndLine << ":" << EndColumn << "}";
95          PrintedRange = true;
96        }
97        if (PrintedRange)
98          Out << ":";
99      }
100
101      Out << " ";
102    }
103  }
104
105  /* Print warning/error/etc. */
106  switch (Severity) {
107  case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
108  case CXDiagnostic_Note: Out << "note: "; break;
109  case CXDiagnostic_Warning: Out << "warning: "; break;
110  case CXDiagnostic_Error: Out << "error: "; break;
111  case CXDiagnostic_Fatal: Out << "fatal error: "; break;
112  }
113
114  CXString Text = clang_getDiagnosticSpelling(Diagnostic);
115  if (clang_getCString(Text))
116    Out << clang_getCString(Text);
117  else
118    Out << "<no diagnostic text>";
119  clang_disposeString(Text);
120  return createCXString(Out.str(), true);
121}
122
123unsigned clang_defaultDiagnosticDisplayOptions() {
124  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
125}
126
127enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
128  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
129  if (!StoredDiag)
130    return CXDiagnostic_Ignored;
131
132  switch (StoredDiag->Diag.getLevel()) {
133  case Diagnostic::Ignored: return CXDiagnostic_Ignored;
134  case Diagnostic::Note:    return CXDiagnostic_Note;
135  case Diagnostic::Warning: return CXDiagnostic_Warning;
136  case Diagnostic::Error:   return CXDiagnostic_Error;
137  case Diagnostic::Fatal:   return CXDiagnostic_Fatal;
138  }
139
140  llvm_unreachable("Invalid diagnostic level");
141  return CXDiagnostic_Ignored;
142}
143
144CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
145  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
146  if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
147    return clang_getNullLocation();
148
149  return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
150                                 StoredDiag->LangOpts,
151                                 StoredDiag->Diag.getLocation());
152}
153
154CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
155  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
156  if (!StoredDiag)
157    return createCXString("");
158
159  return createCXString(StoredDiag->Diag.getMessage(), false);
160}
161
162unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
163  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
164  if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
165    return 0;
166
167  return StoredDiag->Diag.range_size();
168}
169
170CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
171  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
172  if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
173      StoredDiag->Diag.getLocation().isInvalid())
174    return clang_getNullRange();
175
176  return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
177                              StoredDiag->LangOpts,
178                              StoredDiag->Diag.range_begin()[Range]);
179}
180
181unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
182  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
183  if (!StoredDiag)
184    return 0;
185
186  return StoredDiag->Diag.fixit_size();
187}
188
189CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
190                                  CXSourceRange *ReplacementRange) {
191  CXStoredDiagnostic *StoredDiag
192    = static_cast<CXStoredDiagnostic *>(Diagnostic);
193  if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
194      StoredDiag->Diag.getLocation().isInvalid()) {
195    if (ReplacementRange)
196      *ReplacementRange = clang_getNullRange();
197
198    return createCXString("");
199  }
200
201  const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
202  if (ReplacementRange) {
203    // Create a range that covers the entire replacement (or
204    // removal) range, adjusting the end of the range to point to
205    // the end of the token.
206    *ReplacementRange
207        = translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
208                                StoredDiag->LangOpts,
209                                Hint.RemoveRange);
210  }
211
212  return createCXString(Hint.CodeToInsert);
213}
214
215} // end extern "C"
216