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