blob: 52de8bbc912ed0985285bbe34b46509a076e79fb [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) {
Douglas Gregor51c6d382010-01-29 00:41:11 +0000157 if (Location)
158 *Location = clang_getNullLocation();
159
Douglas Gregor5352ac02010-01-28 00:27:43 +0000160 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
161 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
162 return CIndexer::createCXString("");
163
164 const CodeModificationHint &Hint
165 = StoredDiag->Info.getCodeModificationHint(FixIt);
Douglas Gregor51c6d382010-01-29 00:41:11 +0000166
167 if (Location && StoredDiag->Info.getLocation().isValid())
168 *Location = translateSourceLocation(
169 StoredDiag->Info.getLocation().getManager(),
170 StoredDiag->LangOpts,
171 Hint.InsertionLoc);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000172 return CIndexer::createCXString(Hint.CodeToInsert);
173}
174
175CXSourceRange clang_getDiagnosticFixItRemoval(CXDiagnostic Diag,
176 unsigned FixIt) {
177 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
178 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
179 StoredDiag->Info.getLocation().isInvalid())
180 return clang_getNullRange();
181
182 const CodeModificationHint &Hint
183 = StoredDiag->Info.getCodeModificationHint(FixIt);
184 return translateSourceRange(StoredDiag->Info.getLocation().getManager(),
185 StoredDiag->LangOpts,
186 Hint.RemoveRange);
187}
188
189CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag,
190 unsigned FixIt,
191 CXSourceRange *Range) {
Douglas Gregor51c6d382010-01-29 00:41:11 +0000192 if (Range)
193 *Range = clang_getNullRange();
194
Douglas Gregor5352ac02010-01-28 00:27:43 +0000195 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
196 if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
197 StoredDiag->Info.getLocation().isInvalid()) {
198 if (Range)
199 *Range = clang_getNullRange();
200
201 return CIndexer::createCXString("");
202 }
203
204 const CodeModificationHint &Hint
205 = StoredDiag->Info.getCodeModificationHint(FixIt);
206 if (Range)
207 *Range = translateSourceRange(StoredDiag->Info.getLocation().getManager(),
208 StoredDiag->LangOpts,
209 Hint.RemoveRange);
210 return CIndexer::createCXString(Hint.CodeToInsert);
211}
212
213} // end extern "C"
Douglas Gregord93256e2010-01-28 06:00:51 +0000214
215void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
216 Diagnostic &Diags,
217 unsigned num_unsaved_files,
218 struct CXUnsavedFile *unsaved_files) {
219 using llvm::MemoryBuffer;
220 using llvm::StringRef;
221 MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
222 if (!F)
223 return;
224
225 // Enter the unsaved files into the file manager.
226 SourceManager SourceMgr;
227 FileManager FileMgr;
228 for (unsigned I = 0; I != num_unsaved_files; ++I) {
229 const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
230 unsaved_files[I].Length,
231 0);
232 if (!File) {
233 Diags.Report(diag::err_fe_remap_missing_from_file)
234 << unsaved_files[I].Filename;
235 return;
236 }
237
238 MemoryBuffer *Buffer
239 = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
240 unsaved_files[I].Contents + unsaved_files[I].Length);
241 if (!Buffer)
242 return;
243
244 SourceMgr.overrideFileContents(File, Buffer);
245 }
246
247 // Parse the diagnostics, emitting them one by one until we've
248 // exhausted the data.
249 StringRef Buffer = F->getBuffer();
250 const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
251 while (Memory != MemoryEnd) {
252 DiagnosticBuilder DB = Diags.Deserialize(FileMgr, SourceMgr,
253 Memory, MemoryEnd);
254 if (!DB.isActive())
255 return;
256 }
257}