blob: 3db37b97da145fc21146c0c94a4ee8acd3b8e182 [file] [log] [blame]
Douglas Gregora88084b2010-02-18 18:08:43 +00001/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\
Douglas Gregor5352ac02010-01-28 00:27:43 +00002|* *|
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
Benjamin Kramerb846deb2010-04-12 19:45:50 +000017#include "clang/Frontend/ASTUnit.h"
Douglas Gregord93256e2010-01-28 06:00:51 +000018#include "clang/Frontend/FrontendDiagnostic.h"
Douglas Gregor274f1902010-02-22 23:17:23 +000019#include "llvm/ADT/SmallString.h"
Douglas Gregora88084b2010-02-18 18:08:43 +000020#include "llvm/ADT/Twine.h"
Douglas Gregord93256e2010-01-28 06:00:51 +000021#include "llvm/Support/MemoryBuffer.h"
Douglas Gregor274f1902010-02-22 23:17:23 +000022#include "llvm/Support/raw_ostream.h"
Douglas Gregord93256e2010-01-28 06:00:51 +000023
Douglas Gregor5352ac02010-01-28 00:27:43 +000024using namespace clang;
25using namespace clang::cxloc;
Ted Kremenekee4db4f2010-02-17 00:41:08 +000026using namespace clang::cxstring;
Douglas Gregora88084b2010-02-18 18:08:43 +000027using namespace llvm;
Douglas Gregor5352ac02010-01-28 00:27:43 +000028
29//-----------------------------------------------------------------------------
Ted Kremenekee4db4f2010-02-17 00:41:08 +000030// C Interface Routines
Douglas Gregor5352ac02010-01-28 00:27:43 +000031//-----------------------------------------------------------------------------
32extern "C" {
Ted Kremenekee4db4f2010-02-17 00:41:08 +000033
Douglas Gregora88084b2010-02-18 18:08:43 +000034unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
35 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
Douglas Gregor405634b2010-04-05 18:10:21 +000036 return CXXUnit? CXXUnit->stored_diag_size() : 0;
Douglas Gregora88084b2010-02-18 18:08:43 +000037}
38
39CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
40 ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
Douglas Gregor405634b2010-04-05 18:10:21 +000041 if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
Douglas Gregora88084b2010-02-18 18:08:43 +000042 return 0;
43
Douglas Gregor405634b2010-04-05 18:10:21 +000044 return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
Douglas Gregora88084b2010-02-18 18:08:43 +000045 CXXUnit->getASTContext().getLangOptions());
46}
47
48void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
49 CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
50 delete Stored;
51}
52
Douglas Gregor274f1902010-02-22 23:17:23 +000053CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
54 if (!Diagnostic)
55 return createCXString("");
Douglas Gregor0a812cf2010-02-18 23:07:20 +000056
57 CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
58
59 // Ignore diagnostics that should be ignored.
60 if (Severity == CXDiagnostic_Ignored)
Douglas Gregor274f1902010-02-22 23:17:23 +000061 return createCXString("");
Douglas Gregor0a812cf2010-02-18 23:07:20 +000062
Douglas Gregor274f1902010-02-22 23:17:23 +000063 llvm::SmallString<256> Str;
64 llvm::raw_svector_ostream Out(Str);
65
Douglas Gregor0a812cf2010-02-18 23:07:20 +000066 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);
Douglas Gregor274f1902010-02-22 23:17:23 +000075 Out << clang_getCString(FName) << ":" << Line << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +000076 clang_disposeString(FName);
77 if (Options & CXDiagnostic_DisplayColumn)
Douglas Gregor274f1902010-02-22 23:17:23 +000078 Out << Column << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +000079
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
Douglas Gregor274f1902010-02-22 23:17:23 +000097 Out << "{" << StartLine << ":" << StartColumn << "-"
98 << EndLine << ":" << EndColumn << "}";
Douglas Gregor0a812cf2010-02-18 23:07:20 +000099 PrintedRange = true;
100 }
101 if (PrintedRange)
Douglas Gregor274f1902010-02-22 23:17:23 +0000102 Out << ":";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000103 }
104 }
105
Douglas Gregor274f1902010-02-22 23:17:23 +0000106 Out << " ";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000107 }
108
109 /* Print warning/error/etc. */
110 switch (Severity) {
111 case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
Douglas Gregor274f1902010-02-22 23:17:23 +0000112 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;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000116 }
117
118 CXString Text = clang_getDiagnosticSpelling(Diagnostic);
119 if (clang_getCString(Text))
Douglas Gregor274f1902010-02-22 23:17:23 +0000120 Out << clang_getCString(Text);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000121 else
Douglas Gregor274f1902010-02-22 23:17:23 +0000122 Out << "<no diagnostic text>";
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000123 clang_disposeString(Text);
Douglas Gregor274f1902010-02-22 23:17:23 +0000124 return createCXString(Out.str(), true);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000125}
126
127unsigned clang_defaultDiagnosticDisplayOptions() {
128 return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
129}
130
Douglas Gregor5352ac02010-01-28 00:27:43 +0000131enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
132 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
133 if (!StoredDiag)
134 return CXDiagnostic_Ignored;
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000135
Douglas Gregora88084b2010-02-18 18:08:43 +0000136 switch (StoredDiag->Diag.getLevel()) {
Douglas Gregor5352ac02010-01-28 00:27:43 +0000137 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 }
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000143
Douglas Gregor5352ac02010-01-28 00:27:43 +0000144 llvm_unreachable("Invalid diagnostic level");
145 return CXDiagnostic_Ignored;
146}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000147
Douglas Gregor5352ac02010-01-28 00:27:43 +0000148CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
149 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
Douglas Gregora88084b2010-02-18 18:08:43 +0000150 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
Douglas Gregor5352ac02010-01-28 00:27:43 +0000151 return clang_getNullLocation();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000152
Douglas Gregora88084b2010-02-18 18:08:43 +0000153 return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
154 StoredDiag->LangOpts,
155 StoredDiag->Diag.getLocation());
Douglas Gregor5352ac02010-01-28 00:27:43 +0000156}
157
158CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
159 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
160 if (!StoredDiag)
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000161 return createCXString("");
162
Douglas Gregora88084b2010-02-18 18:08:43 +0000163 return createCXString(StoredDiag->Diag.getMessage(), false);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000164}
165
Douglas Gregora3890ba2010-02-08 23:11:56 +0000166unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
Douglas Gregor5352ac02010-01-28 00:27:43 +0000167 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
Douglas Gregora88084b2010-02-18 18:08:43 +0000168 if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
Douglas Gregora3890ba2010-02-08 23:11:56 +0000169 return 0;
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000170
Douglas Gregora88084b2010-02-18 18:08:43 +0000171 return StoredDiag->Diag.range_size();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000172}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000173
Douglas Gregora3890ba2010-02-08 23:11:56 +0000174CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
175 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
Douglas Gregora88084b2010-02-18 18:08:43 +0000176 if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
177 StoredDiag->Diag.getLocation().isInvalid())
Douglas Gregora3890ba2010-02-08 23:11:56 +0000178 return clang_getNullRange();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000179
Douglas Gregora88084b2010-02-18 18:08:43 +0000180 return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
181 StoredDiag->LangOpts,
182 StoredDiag->Diag.range_begin()[Range]);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000183}
184
185unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
186 CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
187 if (!StoredDiag)
188 return 0;
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000189
Douglas Gregora88084b2010-02-18 18:08:43 +0000190 return StoredDiag->Diag.fixit_size();
Douglas Gregor5352ac02010-01-28 00:27:43 +0000191}
192
Douglas Gregor473d7012010-02-19 18:16:06 +0000193CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
194 CXSourceRange *ReplacementRange) {
195 CXStoredDiagnostic *StoredDiag
196 = static_cast<CXStoredDiagnostic *>(Diagnostic);
Douglas Gregora88084b2010-02-18 18:08:43 +0000197 if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
198 StoredDiag->Diag.getLocation().isInvalid()) {
Douglas Gregor473d7012010-02-19 18:16:06 +0000199 if (ReplacementRange)
200 *ReplacementRange = clang_getNullRange();
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000201
202 return createCXString("");
Douglas Gregor5352ac02010-01-28 00:27:43 +0000203 }
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000204
Douglas Gregor849b2432010-03-31 17:46:05 +0000205 const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
Douglas Gregor473d7012010-02-19 18:16:06 +0000206 if (ReplacementRange) {
207 if (Hint.RemoveRange.isInvalid()) {
208 // Create an empty range that refers to a single source
209 // location (which is the insertion point).
210 CXSourceRange Range = {
211 { (void *)&StoredDiag->Diag.getLocation().getManager(),
212 (void *)&StoredDiag->LangOpts },
213 Hint.InsertionLoc.getRawEncoding(),
214 Hint.InsertionLoc.getRawEncoding()
215 };
216
217 *ReplacementRange = Range;
218 } else {
219 // Create a range that covers the entire replacement (or
220 // removal) range, adjusting the end of the range to point to
221 // the end of the token.
222 *ReplacementRange
223 = translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
224 StoredDiag->LangOpts,
225 Hint.RemoveRange);
226 }
227 }
228
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000229 return createCXString(Hint.CodeToInsert);
Douglas Gregor5352ac02010-01-28 00:27:43 +0000230}
Ted Kremenekee4db4f2010-02-17 00:41:08 +0000231
Douglas Gregor5352ac02010-01-28 00:27:43 +0000232} // end extern "C"
Douglas Gregord93256e2010-01-28 06:00:51 +0000233
Douglas Gregora88084b2010-02-18 18:08:43 +0000234void clang::LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
235 unsigned num_unsaved_files,
236 struct CXUnsavedFile *unsaved_files,
237 FileManager &FileMgr,
238 SourceManager &SourceMgr,
239 SmallVectorImpl<StoredDiagnostic> &Diags) {
Douglas Gregord93256e2010-01-28 06:00:51 +0000240 using llvm::MemoryBuffer;
241 using llvm::StringRef;
242 MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
243 if (!F)
244 return;
245
246 // Enter the unsaved files into the file manager.
Douglas Gregord93256e2010-01-28 06:00:51 +0000247 for (unsigned I = 0; I != num_unsaved_files; ++I) {
248 const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
249 unsaved_files[I].Length,
250 0);
251 if (!File) {
Douglas Gregora88084b2010-02-18 18:08:43 +0000252 // FIXME: Hard to localize when we have no diagnostics engine!
253 Diags.push_back(StoredDiagnostic(Diagnostic::Fatal,
254 (Twine("could not remap from missing file ") +
255 unsaved_files[I].Filename).str()));
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000256 delete F;
Douglas Gregord93256e2010-01-28 06:00:51 +0000257 return;
258 }
259
260 MemoryBuffer *Buffer
261 = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
262 unsaved_files[I].Contents + unsaved_files[I].Length);
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000263 if (!Buffer) {
264 delete F;
Douglas Gregord93256e2010-01-28 06:00:51 +0000265 return;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000266 }
267
Douglas Gregord93256e2010-01-28 06:00:51 +0000268 SourceMgr.overrideFileContents(File, Buffer);
Douglas Gregorf7353c02010-03-24 21:04:06 +0000269 SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
Douglas Gregord93256e2010-01-28 06:00:51 +0000270 }
271
272 // Parse the diagnostics, emitting them one by one until we've
273 // exhausted the data.
274 StringRef Buffer = F->getBuffer();
275 const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
276 while (Memory != MemoryEnd) {
Douglas Gregora88084b2010-02-18 18:08:43 +0000277 StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr,
278 Memory, MemoryEnd);
279 if (!Stored)
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000280 break;
Daniel Dunbar35b84402010-01-30 23:31:40 +0000281
Douglas Gregora88084b2010-02-18 18:08:43 +0000282 Diags.push_back(Stored);
283 }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000284 delete F;
Douglas Gregord93256e2010-01-28 06:00:51 +0000285}