blob: eb039dff6e33cfb91a334065f8c31df0d0373cb2 [file] [log] [blame]
Douglas Gregor5352ac02010-01-28 00:27:43 +00001/*===-- 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
Douglas Gregord93256e2010-01-28 06:00:51 +000017#include "clang/Frontend/FrontendDiagnostic.h"
18#include "llvm/Support/MemoryBuffer.h"
19
Douglas Gregor5352ac02010-01-28 00:27:43 +000020using namespace clang;
21using namespace clang::cxloc;
22
23//-----------------------------------------------------------------------------
24// Opaque data structures
25//-----------------------------------------------------------------------------
26namespace {
27 /// \brief The storage behind a CXDiagnostic
28 struct CXStoredDiagnostic {
29 /// \brief The translation unit this diagnostic came from.
30 const LangOptions &LangOpts;
31
32 /// \brief The severity level of this diagnostic.
33 Diagnostic::Level Level;
34
35 /// \brief A reference to the diagnostic information.
36 const DiagnosticInfo &Info;
37 };
38}
39
40//-----------------------------------------------------------------------------
41// CIndex Diagnostic Client
42//-----------------------------------------------------------------------------
43CIndexDiagnosticClient::~CIndexDiagnosticClient() { }
44
45void CIndexDiagnosticClient::BeginSourceFile(const LangOptions &LangOpts,
46 const Preprocessor *PP) {
47 this->LangOpts = LangOpts;
48}
49
50void CIndexDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
51 const DiagnosticInfo &Info) {
52 if (!Callback)
53 return;
54
55 CXStoredDiagnostic Stored = { this->LangOpts, DiagLevel, Info };
56 Callback(&Stored, ClientData);
57}
58
59//-----------------------------------------------------------------------------
60// C Interface Routines
61//-----------------------------------------------------------------------------
62extern "C" {
63
64enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
65 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
66 if (!StoredDiag)
67 return CXDiagnostic_Ignored;
68
69 switch (StoredDiag->Level) {
70 case Diagnostic::Ignored: return CXDiagnostic_Ignored;
71 case Diagnostic::Note: return CXDiagnostic_Note;
72 case Diagnostic::Warning: return CXDiagnostic_Warning;
73 case Diagnostic::Error: return CXDiagnostic_Error;
74 case Diagnostic::Fatal: return CXDiagnostic_Fatal;
75 }
76
77 llvm_unreachable("Invalid diagnostic level");
78 return CXDiagnostic_Ignored;
79}
80
81CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
82 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
83 if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid())
84 return clang_getNullLocation();
85
86 return translateSourceLocation(StoredDiag->Info.getLocation().getManager(),
87 StoredDiag->LangOpts,
88 StoredDiag->Info.getLocation());
89}
90
91CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
92 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
93 if (!StoredDiag)
94 return CIndexer::createCXString("");
95
96 llvm::SmallString<64> Spelling;
97 StoredDiag->Info.FormatDiagnostic(Spelling);
98 return CIndexer::createCXString(Spelling.str(), true);
99}
100
101void clang_getDiagnosticRanges(CXDiagnostic Diag,
102 CXSourceRange **Ranges,
103 unsigned *NumRanges) {
104 if (Ranges)
105 *Ranges = 0;
106 if (NumRanges)
107 *NumRanges = 0;
108
109 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
110 if (!StoredDiag || !Ranges || !NumRanges ||
111 !StoredDiag->Info.getNumRanges() ||
112 StoredDiag->Info.getLocation().isInvalid())
113 return;
114
115 unsigned N = StoredDiag->Info.getNumRanges();
116 *Ranges = (CXSourceRange *)malloc(sizeof(CXSourceRange) * N);
117 *NumRanges = N;
118 for (unsigned I = 0; I != N; ++I)
119 (*Ranges)[I] = translateSourceRange(
120 StoredDiag->Info.getLocation().getManager(),
121 StoredDiag->LangOpts,
122 StoredDiag->Info.getRange(I));
123}
124
125void clang_disposeDiagnosticRanges(CXSourceRange *Ranges,
126 unsigned NumRanges) {
127 free(Ranges);
128}
129
130unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
131 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
132 if (!StoredDiag)
133 return 0;
134
135 return StoredDiag->Info.getNumCodeModificationHints();
136}
137
138enum CXFixItKind clang_getDiagnosticFixItKind(CXDiagnostic Diag,
139 unsigned FixIt) {
140 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
141 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
142 return CXFixIt_Insertion;
143
144 const CodeModificationHint &Hint
145 = StoredDiag->Info.getCodeModificationHint(FixIt);
146 if (Hint.RemoveRange.isInvalid())
147 return CXFixIt_Insertion;
148 if (Hint.InsertionLoc.isInvalid())
149 return CXFixIt_Removal;
150
151 return CXFixIt_Replacement;
152}
153
154CXString clang_getDiagnosticFixItInsertion(CXDiagnostic Diag,
155 unsigned FixIt,
156 CXSourceLocation *Location) {
157 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
158 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
159 return CIndexer::createCXString("");
160
161 const CodeModificationHint &Hint
162 = StoredDiag->Info.getCodeModificationHint(FixIt);
163 return CIndexer::createCXString(Hint.CodeToInsert);
164}
165
166CXSourceRange clang_getDiagnosticFixItRemoval(CXDiagnostic Diag,
167 unsigned FixIt) {
168 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
169 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
170 StoredDiag->Info.getLocation().isInvalid())
171 return clang_getNullRange();
172
173 const CodeModificationHint &Hint
174 = StoredDiag->Info.getCodeModificationHint(FixIt);
175 return translateSourceRange(StoredDiag->Info.getLocation().getManager(),
176 StoredDiag->LangOpts,
177 Hint.RemoveRange);
178}
179
180CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag,
181 unsigned FixIt,
182 CXSourceRange *Range) {
183 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
184 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
185 StoredDiag->Info.getLocation().isInvalid()) {
186 if (Range)
187 *Range = clang_getNullRange();
188
189 return CIndexer::createCXString("");
190 }
191
192 const CodeModificationHint &Hint
193 = StoredDiag->Info.getCodeModificationHint(FixIt);
194 if (Range)
195 *Range = translateSourceRange(StoredDiag->Info.getLocation().getManager(),
196 StoredDiag->LangOpts,
197 Hint.RemoveRange);
198 return CIndexer::createCXString(Hint.CodeToInsert);
199}
200
201} // end extern "C"
Douglas Gregord93256e2010-01-28 06:00:51 +0000202
203void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
204 Diagnostic &Diags,
205 unsigned num_unsaved_files,
206 struct CXUnsavedFile *unsaved_files) {
207 using llvm::MemoryBuffer;
208 using llvm::StringRef;
209 MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
210 if (!F)
211 return;
212
213 // Enter the unsaved files into the file manager.
214 SourceManager SourceMgr;
215 FileManager FileMgr;
216 for (unsigned I = 0; I != num_unsaved_files; ++I) {
217 const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
218 unsaved_files[I].Length,
219 0);
220 if (!File) {
221 Diags.Report(diag::err_fe_remap_missing_from_file)
222 << unsaved_files[I].Filename;
223 return;
224 }
225
226 MemoryBuffer *Buffer
227 = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
228 unsaved_files[I].Contents + unsaved_files[I].Length);
229 if (!Buffer)
230 return;
231
232 SourceMgr.overrideFileContents(File, Buffer);
233 }
234
235 // Parse the diagnostics, emitting them one by one until we've
236 // exhausted the data.
237 StringRef Buffer = F->getBuffer();
238 const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
239 while (Memory != MemoryEnd) {
240 DiagnosticBuilder DB = Diags.Deserialize(FileMgr, SourceMgr,
241 Memory, MemoryEnd);
242 if (!DB.isActive())
243 return;
244 }
245}