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