CIndexDiagnostic.cpp revision f51f20fa34654da75d15a9e2a1a0cd2fc0d8603d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*                                                                            *|
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*                     The LLVM Compiler Infrastructure                       *|
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*                                                                            *|
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* This file is distributed under the University of Illinois Open Source      *|
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* License. See LICENSE.TXT for details.                                      *|
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*                                                                            *|
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*===----------------------------------------------------------------------===*|
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*                                                                            *|
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|* Implements the diagnostic functions of the Clang C interface.              *|
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)|*                                                                            *|
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)\*===----------------------------------------------------------------------===*/
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CIndexDiagnostic.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CIndexer.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CXSourceLocation.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/ASTUnit.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/FrontendDiagnostic.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/SmallString.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/Twine.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/MemoryBuffer.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang::cxloc;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang::cxstring;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace llvm;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//-----------------------------------------------------------------------------
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// C Interface Routines
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//-----------------------------------------------------------------------------
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CXXUnit? CXXUnit->stored_diag_size() : 0;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                CXXUnit->getASTContext().getLangOptions());
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete Stored;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Diagnostic)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return createCXString("");
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ignore diagnostics that should be ignored.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Severity == CXDiagnostic_Ignored)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return createCXString("");
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  llvm::SmallString<256> Str;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  llvm::raw_svector_ostream Out(Str);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Options & CXDiagnostic_DisplaySourceLocation) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Print source location (file:line), along with optional column
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and source ranges.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CXFile File;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned Line, Column;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   &File, &Line, &Column, 0);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (File) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CXString FName = clang_getFileName(File);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Out << clang_getCString(FName) << ":" << Line << ":";
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      clang_disposeString(FName);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (Options & CXDiagnostic_DisplayColumn)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Out << Column << ":";
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (Options & CXDiagnostic_DisplaySourceRanges) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool PrintedRange = false;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (unsigned I = 0; I != N; ++I) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CXFile StartFile, EndFile;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unsigned StartLine, StartColumn, EndLine, EndColumn;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          clang_getInstantiationLocation(clang_getRangeStart(Range),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &StartFile, &StartLine, &StartColumn,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         0);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          clang_getInstantiationLocation(clang_getRangeEnd(Range),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &EndFile, &EndLine, &EndColumn, 0);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (StartFile != EndFile || StartFile != File)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Out << "{" << StartLine << ":" << StartColumn << "-"
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << EndLine << ":" << EndColumn << "}";
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PrintedRange = true;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (PrintedRange)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Out << ":";
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Out << " ";
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Print warning/error/etc. */
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (Severity) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  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;
116  }
117
118  CXString Text = clang_getDiagnosticSpelling(Diagnostic);
119  if (clang_getCString(Text))
120    Out << clang_getCString(Text);
121  else
122    Out << "<no diagnostic text>";
123  clang_disposeString(Text);
124  return createCXString(Out.str(), true);
125}
126
127unsigned clang_defaultDiagnosticDisplayOptions() {
128  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
129}
130
131enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
132  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
133  if (!StoredDiag)
134    return CXDiagnostic_Ignored;
135
136  switch (StoredDiag->Diag.getLevel()) {
137  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  }
143
144  llvm_unreachable("Invalid diagnostic level");
145  return CXDiagnostic_Ignored;
146}
147
148CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
149  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
150  if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
151    return clang_getNullLocation();
152
153  return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
154                                 StoredDiag->LangOpts,
155                                 StoredDiag->Diag.getLocation());
156}
157
158CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
159  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
160  if (!StoredDiag)
161    return createCXString("");
162
163  return createCXString(StoredDiag->Diag.getMessage(), false);
164}
165
166unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
167  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
168  if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
169    return 0;
170
171  return StoredDiag->Diag.range_size();
172}
173
174CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
175  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
176  if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
177      StoredDiag->Diag.getLocation().isInvalid())
178    return clang_getNullRange();
179
180  return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
181                              StoredDiag->LangOpts,
182                              StoredDiag->Diag.range_begin()[Range]);
183}
184
185unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
186  CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
187  if (!StoredDiag)
188    return 0;
189
190  return StoredDiag->Diag.fixit_size();
191}
192
193CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
194                                  CXSourceRange *ReplacementRange) {
195  CXStoredDiagnostic *StoredDiag
196    = static_cast<CXStoredDiagnostic *>(Diagnostic);
197  if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
198      StoredDiag->Diag.getLocation().isInvalid()) {
199    if (ReplacementRange)
200      *ReplacementRange = clang_getNullRange();
201
202    return createCXString("");
203  }
204
205  const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
206  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
229  return createCXString(Hint.CodeToInsert);
230}
231
232} // end extern "C"
233
234void 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) {
240  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.
247  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) {
252      // 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()));
256      delete F;
257      return;
258    }
259
260    MemoryBuffer *Buffer
261      = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
262                           unsaved_files[I].Contents + unsaved_files[I].Length);
263    if (!Buffer) {
264      delete F;
265      return;
266    }
267
268    SourceMgr.overrideFileContents(File, Buffer);
269    SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
270  }
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) {
277    StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr,
278                                                            Memory, MemoryEnd);
279    if (!Stored)
280      break;
281
282    Diags.push_back(Stored);
283  }
284  delete F;
285}
286