int displayDiagnostics);
CINDEX_LINKAGE void clang_disposeIndex(CXIndex index);
-/**
- * \brief Get the original translation unit source file name.
- */
-CINDEX_LINKAGE CXString
-clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
-
/**
* \brief Request that AST's be generated externally for API calls which parse
* source code on the fly, e.g. \see createTranslationUnitFromSourceFile.
*/
CINDEX_LINKAGE void clang_setUseExternalASTGeneration(CXIndex index,
int value);
-
-/**
- * \brief Create a translation unit from an AST file (-emit-ast).
- */
-CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(
- CXIndex, const char *ast_filename
-);
-
-/**
- * \brief Destroy the specified CXTranslationUnit object.
- */
-CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
-
-/**
- * \brief Return the CXTranslationUnit for a given source file and the provided
- * command line arguments one would pass to the compiler.
- *
- * Note: The 'source_filename' argument is optional. If the caller provides a
- * NULL pointer, the name of the source file is expected to reside in the
- * specified command line arguments.
- *
- * Note: When encountered in 'clang_command_line_args', the following options
- * are ignored:
- *
- * '-c'
- * '-emit-ast'
- * '-fsyntax-only'
- * '-o <output file>' (both '-o' and '<output file>' are ignored)
- *
- *
- * \param source_filename - The name of the source file to load, or NULL if the
- * source file is included in clang_command_line_args.
- *
- * \param num_unsaved_files the number of unsaved file entries in \p
- * unsaved_files.
- *
- * \param unsaved_files the files that have not yet been saved to disk
- * but may be required for code completion, including the contents of
- * those files.
- */
-CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
- CXIndex CIdx,
- const char *source_filename,
- int num_clang_command_line_args,
- const char **clang_command_line_args,
- unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files);
-
/**
* \defgroup CINDEX_FILES File manipulation routines
*
* particular file, line, and column.
*/
typedef struct {
- void *ptr_data;
+ void *ptr_data[2];
unsigned int_data;
} CXSourceLocation;
* starting and end locations from a source range, respectively.
*/
typedef struct {
- void *ptr_data;
+ void *ptr_data[2];
unsigned begin_int_data;
unsigned end_int_data;
} CXSourceRange;
unsigned line,
unsigned column);
+/**
+ * \brief Retrieve a NULL (invalid) source range.
+ */
+CINDEX_LINKAGE CXSourceRange clang_getNullRange();
+
/**
* \brief Retrieve a source range given the beginning and ending source
* locations.
* @}
*/
+/**
+ * \defgroup CINDEX_DIAG Diagnostic reporting
+ *
+ * @{
+ */
+
+/**
+ * \brief Describes the severity of a particular diagnostic.
+ */
+enum CXDiagnosticSeverity {
+ /**
+ * \brief A diagnostic that has been suppressed, e.g., by a command-line
+ * option.
+ */
+ CXDiagnostic_Ignored = 0,
+
+ /**
+ * \brief This diagnostic is a note that should be attached to the
+ * previous (non-note) diagnostic.
+ */
+ CXDiagnostic_Note = 1,
+
+ /**
+ * \brief This diagnostic indicates suspicious code that may not be
+ * wrong.
+ */
+ CXDiagnostic_Warning = 2,
+
+ /**
+ * \brief This diagnostic indicates that the code is ill-formed.
+ */
+ CXDiagnostic_Error = 3,
+
+ /**
+ * \brief This diagnostic indicates that the code is ill-formed such
+ * that future parser recovery is unlikely to produce useful
+ * results.
+ */
+ CXDiagnostic_Fatal = 4
+};
+
+/**
+ * \brief Describes the kind of fix-it hint expressed within a
+ * diagnostic.
+ */
+enum CXFixItKind {
+ /**
+ * \brief A fix-it hint that inserts code at a particular position.
+ */
+ CXFixIt_Insertion = 0,
+
+ /**
+ * \brief A fix-it hint that removes code within a range.
+ */
+ CXFixIt_Removal = 1,
+
+ /**
+ * \brief A fix-it hint that replaces the code within a range with another
+ * string.
+ */
+ CXFixIt_Replacement = 2
+};
+
+/**
+ * \brief A single diagnostic, containing the diagnostic's severity,
+ * location, text, source ranges, and fix-it hints.
+ */
+typedef void *CXDiagnostic;
+
+/**
+ * \brief Callback function invoked for each diagnostic emitted during
+ * translation.
+ *
+ * \param Diagnostic the diagnostic emitted during translation. This
+ * diagnostic pointer is only valid during the execution of the
+ * callback.
+ *
+ * \param ClientData the callback client data.
+ */
+typedef void (*CXDiagnosticCallback)(CXDiagnostic Diagnostic,
+ CXClientData ClientData);
+
+/**
+ * \brief Determine the severity of the given diagnostic.
+ */
+CINDEX_LINKAGE enum CXDiagnosticSeverity
+clang_getDiagnosticSeverity(CXDiagnostic);
+
+/**
+ * \brief Retrieve the source location of the given diagnostic.
+ *
+ * This location is where Clang would print the caret ('^') when
+ * displaying the diagnostic on the command line.
+ */
+CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic);
+
+/**
+ * \brief Retrieve the text of the given diagnostic.
+ */
+CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic);
+
+/**
+ * \brief Retrieve the source ranges associated with the diagnostic.
+ *
+ * These source ranges highlight important elements in the source
+ * code. On the command line, Clang displays source ranges by
+ * underlining them with '~' characters.
+ *
+ * \param Diagnostic the diagnostic whose ranges are being extracted.
+ *
+ * \param Ranges [out] will be set to a newly-allocated array
+ * containing the source ranges of this diagnostic. These ranges must
+ * be freed with \c clang_disposeDiagnosticRanges().
+ *
+ * \param NumRanges [out] will be set to the number of source ranges
+ * in the \p Ranges array.
+ */
+CINDEX_LINKAGE void clang_getDiagnosticRanges(CXDiagnostic Diagnostic,
+ CXSourceRange **Ranges,
+ unsigned *NumRanges);
+
+/**
+ * \brief Free the source ranges returned by \c clang_getDiagnosticRanges().
+ */
+CINDEX_LINKAGE void clang_disposeDiagnosticRanges(CXSourceRange *Ranges,
+ unsigned NumRanges);
+
+/**
+ * \brief Determine the number of fix-it hints associated with the
+ * given diagnostic.
+ */
+CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic);
+
+/**
+ * \brief Retrieve the kind of the given fix-it.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the fix-it to query.
+ */
+CINDEX_LINKAGE enum CXFixItKind
+clang_getDiagnosticFixItKind(CXDiagnostic Diagnostic, unsigned FixIt);
+
+/**
+ * \brief Retrieve the insertion information for an insertion fix-it.
+ *
+ * For a fix-it that describes an insertion into a text buffer,
+ * retrieve the source location where the text should be inserted and
+ * the text to be inserted.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the insertion fix-it.
+ *
+ * \param Location will be set to the location where text should be
+ * inserted.
+ *
+ * \returns the text string to insert at the given location.
+ */
+CINDEX_LINKAGE CXString
+clang_getDiagnosticFixItInsertion(CXDiagnostic Diagnostic, unsigned FixIt,
+ CXSourceLocation *Location);
+
+/**
+ * \brief Retrieve the removal information for a removal fix-it.
+ *
+ * For a fix-it that describes a removal from a text buffer, retrieve
+ * the source range that should be removed.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the removal fix-it.
+ *
+ * \returns a source range describing the text that should be removed
+ * from the buffer.
+ */
+CINDEX_LINKAGE CXSourceRange
+clang_getDiagnosticFixItRemoval(CXDiagnostic Diagnostic, unsigned FixIt);
+
+/**
+ * \brief Retrieve the replacement information for an replacement fix-it.
+ *
+ * For a fix-it that describes replacement of text in the text buffer
+ * with alternative text.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the replacement fix-it.
+ *
+ * \param Range will be set to the source range whose text should be
+ * replaced with the returned text.
+ *
+ * \returns the text string to use as replacement text.
+ */
+CINDEX_LINKAGE CXString
+clang_getDiagnosticFixItReplacement(CXDiagnostic Diagnostic, unsigned FixIt,
+ CXSourceRange *Range);
+
+/**
+ * @}
+ */
+
+/**
+ * \defgroup CINDEX_TRANSLATION_UNIT Translation unit manipulation
+ *
+ * The routines in this group provide the ability to create and destroy
+ * translation units from files, either by parsing the contents of the files or
+ * by reading in a serialized representation of a translation unit.
+ *
+ * @{
+ */
+
+/**
+ * \brief Get the original translation unit source file name.
+ */
+CINDEX_LINKAGE CXString
+clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
+
+/**
+ * \brief Return the CXTranslationUnit for a given source file and the provided
+ * command line arguments one would pass to the compiler.
+ *
+ * Note: The 'source_filename' argument is optional. If the caller provides a
+ * NULL pointer, the name of the source file is expected to reside in the
+ * specified command line arguments.
+ *
+ * Note: When encountered in 'clang_command_line_args', the following options
+ * are ignored:
+ *
+ * '-c'
+ * '-emit-ast'
+ * '-fsyntax-only'
+ * '-o <output file>' (both '-o' and '<output file>' are ignored)
+ *
+ *
+ * \param source_filename - The name of the source file to load, or NULL if the
+ * source file is included in clang_command_line_args.
+ *
+ * \param num_unsaved_files the number of unsaved file entries in \p
+ * unsaved_files.
+ *
+ * \param unsaved_files the files that have not yet been saved to disk
+ * but may be required for code completion, including the contents of
+ * those files.
+ *
+ * \param diag_callback callback function that will receive any diagnostics
+ * emitted while processing this source file. If NULL, diagnostics will be
+ * suppressed.
+ *
+ * \param diag_client_data client data that will be passed to the diagnostic
+ * callback function.
+ */
+CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
+ CXIndex CIdx,
+ const char *source_filename,
+ int num_clang_command_line_args,
+ const char **clang_command_line_args,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data);
+
+/**
+ * \brief Create a translation unit from an AST file (-emit-ast).
+ */
+CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex,
+ const char *ast_filename,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data);
+
+/**
+ * \brief Destroy the specified CXTranslationUnit object.
+ */
+CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
+
+/**
+ * @}
+ */
+
/**
* \brief Describes the kind of entity that a cursor refers to.
*/
#include "CIndexer.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
+#include "CIndexDiagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/AST/DeclVisitor.h"
CXXIdx->setUseExternalASTGeneration(value);
}
-// FIXME: need to pass back error info.
CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
- const char *ast_filename) {
+ const char *ast_filename,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
assert(CIdx && "Passed null CXIndex");
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
- return ASTUnit::LoadFromPCHFile(ast_filename, CXXIdx->getDiags(),
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::OwningPtr<Diagnostic> Diags;
+ Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+ CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
+ Diags->setClient(&DiagClient);
+
+ return ASTUnit::LoadFromPCHFile(ast_filename, *Diags,
CXXIdx->getOnlyLocalDecls(),
/* UseBumpAllocator = */ true);
}
int num_command_line_args,
const char **command_line_args,
unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files) {
+ struct CXUnsavedFile *unsaved_files,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
assert(CIdx && "Passed null CXIndex");
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::OwningPtr<Diagnostic> Diags;
+ Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+ CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
+ Diags->setClient(&DiagClient);
+
llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
for (unsigned I = 0; I != num_unsaved_files; ++I) {
const llvm::MemoryBuffer *Buffer
Args.insert(Args.end(), command_line_args,
command_line_args + num_command_line_args);
- unsigned NumErrors = CXXIdx->getDiags().getNumErrors();
+ unsigned NumErrors = Diags->getNumErrors();
#ifdef USE_CRASHTRACER
ArgsCrashTracerInfo ACTI(Args);
llvm::OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
- CXXIdx->getDiags(),
+ *Diags,
CXXIdx->getClangResourcesPath(),
CXXIdx->getOnlyLocalDecls(),
/* UseBumpAllocator = */ true,
// FIXME: Until we have broader testing, just drop the entire AST if we
// encountered an error.
- if (NumErrors != CXXIdx->getDiags().getNumErrors())
+ if (NumErrors != Diags->getNumErrors())
return 0;
return Unit.take();
llvm::errs() << '\n';
}
- ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, CXXIdx->getDiags(),
+ ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, *Diags,
CXXIdx->getOnlyLocalDecls(),
/* UseBumpAllocator = */ true,
RemappedFiles.data(),
extern "C" {
CXSourceLocation clang_getNullLocation() {
- CXSourceLocation Result = { 0, 0 };
+ CXSourceLocation Result = { { 0, 0 }, 0 };
return Result;
}
return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc, false);
}
+CXSourceRange clang_getNullRange() {
+ CXSourceRange Result = { { 0, 0 }, 0, 0 };
+ return Result;
+}
+
CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
- if (begin.ptr_data != end.ptr_data) {
- CXSourceRange Result = { 0, 0, 0 };
- return Result;
- }
+ if (begin.ptr_data[0] != end.ptr_data[0] ||
+ begin.ptr_data[1] != end.ptr_data[1])
+ return clang_getNullRange();
- CXSourceRange Result = { begin.ptr_data, begin.int_data, end.int_data };
+ CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
+ begin.int_data, end.int_data };
return Result;
}
unsigned *column,
unsigned *offset) {
cxloc::CXSourceLocationPtr Ptr
- = cxloc::CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data);
+ = cxloc::CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data[0]);
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
if (!Ptr.getPointer() || Loc.isInvalid()) {
// FIXME: This is largely copy-paste from
///TextDiagnosticPrinter::HighlightRange. When it is clear that this is
// what we want the two routines should be refactored.
- ASTContext &Context = *Ptr.getPointer();
- SourceManager &SM = Context.getSourceManager();
+ const SourceManager &SM = *Ptr.getPointer();
SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
if (Ptr.getInt()) {
// (CXXUnit), so that the preprocessor will be available here. At
// that point, we can use Preprocessor::getLocForEndOfToken().
unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM,
- Context.getLangOptions());
+ *static_cast<LangOptions *>(location.ptr_data[1]));
if (Length > 0)
InstLoc = InstLoc.getFileLocWithOffset(Length - 1);
}
}
CXSourceLocation clang_getRangeStart(CXSourceRange range) {
- CXSourceLocation Result = { range.ptr_data, range.begin_int_data };
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.begin_int_data };
return Result;
}
CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
- llvm::PointerIntPair<ASTContext *, 1, bool> Ptr;
- Ptr.setPointer(static_cast<ASTContext *>(range.ptr_data));
+ cxloc::CXSourceLocationPtr Ptr;
+ Ptr.setPointer(static_cast<SourceManager *>(range.ptr_data[0]));
Ptr.setInt(true);
- CXSourceLocation Result = { Ptr.getOpaqueValue(), range.end_int_data };
+ CXSourceLocation Result = { { Ptr.getOpaqueValue(), range.ptr_data[1] },
+ range.end_int_data };
return Result;
}
return cxloc::translateSourceLocation(getCursorContext(C),
getLocationFromExpr(getCursorExpr(C)));
- if (!getCursorDecl(C)) {
- CXSourceLocation empty = { 0, 0 };
- return empty;
- }
+ if (!getCursorDecl(C))
+ return clang_getNullLocation();
Decl *D = getCursorDecl(C);
SourceLocation Loc = D->getLocation();
return cxloc::translateSourceRange(getCursorContext(C),
getCursorStmt(C)->getSourceRange());
- if (!getCursorDecl(C)) {
- CXSourceRange empty = { 0, 0, 0 };
- return empty;
- }
+ if (!getCursorDecl(C))
+ return clang_getNullRange();
Decl *D = getCursorDecl(C);
return cxloc::translateSourceRange(D->getASTContext(), D->getSourceRange());
CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) {
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
- if (!CXXUnit) {
- CXSourceRange Result = { 0, 0, 0 };
- return Result;
- }
+ if (!CXXUnit)
+ return clang_getNullRange();
return cxloc::translateSourceRange(CXXUnit->getASTContext(),
SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
_clang_createTranslationUnit
_clang_createTranslationUnitFromSourceFile
_clang_disposeCodeCompleteResults
+_clang_disposeDiagnosticRanges
_clang_disposeIndex
_clang_disposeString
_clang_disposeTokens
_clang_getCursorSpelling
_clang_getCursorUSR
_clang_getDefinitionSpellingAndExtent
+_clang_getDiagnosticFixItInsertion
+_clang_getDiagnosticFixItKind
+_clang_getDiagnosticFixItRemoval
+_clang_getDiagnosticFixItReplacement
+_clang_getDiagnosticLocation
+_clang_getDiagnosticNumFixIts
+_clang_getDiagnosticRanges
+_clang_getDiagnosticSeverity
+_clang_getDiagnosticSpelling
_clang_getFile
_clang_getFileName
_clang_getFileTime
_clang_getLocation
_clang_getNullCursor
_clang_getNullLocation
+_clang_getNullRange
_clang_getNumCompletionChunks
_clang_getRange
_clang_getRangeEnd
--- /dev/null
+/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface -----------*- C -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements the diagnostic functions of the Clang C interface. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+#include "CXSourceLocation.h"
+
+using namespace clang;
+using namespace clang::cxloc;
+
+//-----------------------------------------------------------------------------
+// Opaque data structures
+//-----------------------------------------------------------------------------
+namespace {
+ /// \brief The storage behind a CXDiagnostic
+ struct CXStoredDiagnostic {
+ /// \brief The translation unit this diagnostic came from.
+ const LangOptions &LangOpts;
+
+ /// \brief The severity level of this diagnostic.
+ Diagnostic::Level Level;
+
+ /// \brief A reference to the diagnostic information.
+ const DiagnosticInfo &Info;
+ };
+}
+
+//-----------------------------------------------------------------------------
+// CIndex Diagnostic Client
+//-----------------------------------------------------------------------------
+CIndexDiagnosticClient::~CIndexDiagnosticClient() { }
+
+void CIndexDiagnosticClient::BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP) {
+ this->LangOpts = LangOpts;
+}
+
+void CIndexDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ if (!Callback)
+ return;
+
+ CXStoredDiagnostic Stored = { this->LangOpts, DiagLevel, Info };
+ Callback(&Stored, ClientData);
+}
+
+//-----------------------------------------------------------------------------
+// C Interface Routines
+//-----------------------------------------------------------------------------
+extern "C" {
+
+enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return CXDiagnostic_Ignored;
+
+ switch (StoredDiag->Level) {
+ case Diagnostic::Ignored: return CXDiagnostic_Ignored;
+ case Diagnostic::Note: return CXDiagnostic_Note;
+ case Diagnostic::Warning: return CXDiagnostic_Warning;
+ case Diagnostic::Error: return CXDiagnostic_Error;
+ case Diagnostic::Fatal: return CXDiagnostic_Fatal;
+ }
+
+ llvm_unreachable("Invalid diagnostic level");
+ return CXDiagnostic_Ignored;
+}
+
+CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid())
+ return clang_getNullLocation();
+
+ return translateSourceLocation(StoredDiag->Info.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ StoredDiag->Info.getLocation());
+}
+
+CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return CIndexer::createCXString("");
+
+ llvm::SmallString<64> Spelling;
+ StoredDiag->Info.FormatDiagnostic(Spelling);
+ return CIndexer::createCXString(Spelling.str(), true);
+}
+
+void clang_getDiagnosticRanges(CXDiagnostic Diag,
+ CXSourceRange **Ranges,
+ unsigned *NumRanges) {
+ if (Ranges)
+ *Ranges = 0;
+ if (NumRanges)
+ *NumRanges = 0;
+
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || !Ranges || !NumRanges ||
+ !StoredDiag->Info.getNumRanges() ||
+ StoredDiag->Info.getLocation().isInvalid())
+ return;
+
+ unsigned N = StoredDiag->Info.getNumRanges();
+ *Ranges = (CXSourceRange *)malloc(sizeof(CXSourceRange) * N);
+ *NumRanges = N;
+ for (unsigned I = 0; I != N; ++I)
+ (*Ranges)[I] = translateSourceRange(
+ StoredDiag->Info.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ StoredDiag->Info.getRange(I));
+}
+
+void clang_disposeDiagnosticRanges(CXSourceRange *Ranges,
+ unsigned NumRanges) {
+ free(Ranges);
+}
+
+unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return 0;
+
+ return StoredDiag->Info.getNumCodeModificationHints();
+}
+
+enum CXFixItKind clang_getDiagnosticFixItKind(CXDiagnostic Diag,
+ unsigned FixIt) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
+ return CXFixIt_Insertion;
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ if (Hint.RemoveRange.isInvalid())
+ return CXFixIt_Insertion;
+ if (Hint.InsertionLoc.isInvalid())
+ return CXFixIt_Removal;
+
+ return CXFixIt_Replacement;
+}
+
+CXString clang_getDiagnosticFixItInsertion(CXDiagnostic Diag,
+ unsigned FixIt,
+ CXSourceLocation *Location) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
+ return CIndexer::createCXString("");
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ return CIndexer::createCXString(Hint.CodeToInsert);
+}
+
+CXSourceRange clang_getDiagnosticFixItRemoval(CXDiagnostic Diag,
+ unsigned FixIt) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
+ StoredDiag->Info.getLocation().isInvalid())
+ return clang_getNullRange();
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ return translateSourceRange(StoredDiag->Info.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ Hint.RemoveRange);
+}
+
+CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag,
+ unsigned FixIt,
+ CXSourceRange *Range) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
+ StoredDiag->Info.getLocation().isInvalid()) {
+ if (Range)
+ *Range = clang_getNullRange();
+
+ return CIndexer::createCXString("");
+ }
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ if (Range)
+ *Range = translateSourceRange(StoredDiag->Info.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ Hint.RemoveRange);
+ return CIndexer::createCXString(Hint.CodeToInsert);
+}
+
+} // end extern "C"
--- /dev/null
+/*===-- CIndexDiagnostic.h - Diagnostics C Interface --------------*- C -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements the diagnostic functions of the Clang C interface. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+#ifndef LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+#define LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+
+#include "clang-c/Index.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+
+namespace clang {
+
+class Preprocessor;
+
+/**
+ * \brief Diagnostic client that translates Clang diagnostics into diagnostics
+ * for the C interface to Clang.
+ */
+class CIndexDiagnosticClient : public DiagnosticClient {
+ CXDiagnosticCallback Callback;
+ CXClientData ClientData;
+ LangOptions LangOpts;
+
+public:
+ CIndexDiagnosticClient(CXDiagnosticCallback Callback,
+ CXClientData ClientData)
+ : Callback(Callback), ClientData(ClientData), LangOpts() { }
+
+ virtual ~CIndexDiagnosticClient();
+
+ virtual void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP);
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
using namespace clang;
-/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
-/// warnings and errors.
-class IgnoreDiagnosticsClient : public DiagnosticClient {
-public:
- virtual ~IgnoreDiagnosticsClient() {}
- virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
-};
-
class CIndexer {
- DiagnosticOptions DiagOpts;
- IgnoreDiagnosticsClient IgnoreDiagClient;
- llvm::OwningPtr<Diagnostic> TextDiags;
- Diagnostic IgnoreDiags;
bool UseExternalASTGeneration;
bool OnlyLocalDecls;
bool DisplayDiagnostics;
llvm::sys::Path ClangPath;
public:
- CIndexer() : IgnoreDiags(&IgnoreDiagClient), UseExternalASTGeneration(false),
- OnlyLocalDecls(false), DisplayDiagnostics(false)
- {
- TextDiags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
- }
+ CIndexer()
+ : UseExternalASTGeneration(false), OnlyLocalDecls(false),
+ DisplayDiagnostics(false) { }
/// \brief Whether we only want to see "local" declarations (that did not
/// come from a previous precompiled header). If false, we want to see all
UseExternalASTGeneration = Value;
}
- Diagnostic &getDiags() {
- return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
- }
-
/// \brief Get the path of the clang binary.
const llvm::sys::Path& getClangPath();
add_clang_library(CIndex
CIndex.cpp
CIndexCodeCompletion.cpp
+ CIndexDiagnostic.cpp
CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
#include "clang-c/Index.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/AST/ASTContext.h"
namespace clang {
namespace cxloc {
-typedef llvm::PointerIntPair<ASTContext *, 1, bool> CXSourceLocationPtr;
+typedef llvm::PointerIntPair<const SourceManager *, 1, bool>
+ CXSourceLocationPtr;
+/// \brief Translate a Clang source location into a CIndex source location.
+static inline CXSourceLocation
+translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
+ SourceLocation Loc, bool AtEnd = false) {
+ CXSourceLocationPtr Ptr(&SM, AtEnd);
+ CXSourceLocation Result = { { Ptr.getOpaqueValue(), (void *)&LangOpts, },
+ Loc.getRawEncoding() };
+ return Result;
+}
+
/// \brief Translate a Clang source location into a CIndex source location.
static inline CXSourceLocation translateSourceLocation(ASTContext &Context,
SourceLocation Loc,
bool AtEnd = false) {
- CXSourceLocationPtr Ptr(&Context, AtEnd);
- CXSourceLocation Result = { Ptr.getOpaqueValue(), Loc.getRawEncoding() };
- return Result;
+ return translateSourceLocation(Context.getSourceManager(),
+ Context.getLangOptions(),
+ Loc, AtEnd);
}
/// \brief Translate a Clang source range into a CIndex source range.
-static inline CXSourceRange translateSourceRange(ASTContext &Context,
+static inline CXSourceRange translateSourceRange(const SourceManager &SM,
+ const LangOptions &LangOpts,
SourceRange R) {
- CXSourceRange Result = { &Context,
+ CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
R.getBegin().getRawEncoding(),
R.getEnd().getRawEncoding() };
return Result;
}
+
+/// \brief Translate a Clang source range into a CIndex source range.
+static inline CXSourceRange translateSourceRange(ASTContext &Context,
+ SourceRange R) {
+ return translateSourceRange(Context.getSourceManager(),
+ Context.getLangOptions(),
+ R);
+}
static inline SourceLocation translateSourceLocation(CXSourceLocation L) {
return SourceLocation::getFromRawEncoding(L.int_data);
extern char *basename(const char *);
#endif
+static void PrintDiagnosticCallback(CXDiagnostic Diagnostic,
+ CXClientData ClientData);
+
static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
CXTranslationUnit *TU) {
- *TU = clang_createTranslationUnit(Idx, file);
+ *TU = clang_createTranslationUnit(Idx, file, PrintDiagnosticCallback, 0);
if (!TU) {
fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
return 0;
typedef void (*PostVisitTU)(CXTranslationUnit);
+static void PrintDiagnosticCallback(CXDiagnostic Diagnostic,
+ CXClientData ClientData) {
+ FILE *out = (FILE *)ClientData;
+ CXFile file;
+ unsigned line, column;
+ CXString text;
+ enum CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(Diagnostic);
+
+ /* Ignore diagnostics that should be ignored. */
+ if (severity == CXDiagnostic_Ignored)
+ return;
+
+ /* Print file:line:column. */
+ clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
+ &file, &line, &column, 0);
+ if (file)
+ fprintf(out, "%s:%d:%d: ", clang_getFileName(file), line, column);
+
+ /* Print warning/error/etc. */
+ switch (severity) {
+ case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
+ case CXDiagnostic_Note: fprintf(out, "note: "); break;
+ case CXDiagnostic_Warning: fprintf(out, "warning: "); break;
+ case CXDiagnostic_Error: fprintf(out, "error: "); break;
+ case CXDiagnostic_Fatal: fprintf(out, "fatal error: "); break;
+ }
+
+ text = clang_getDiagnosticSpelling(Diagnostic);
+ if (clang_getCString(text))
+ fprintf(out, "%s\n", clang_getCString(text));
+ else
+ fprintf(out, "<no diagnostic text>\n");
+ clang_disposeString(text);
+}
+
/******************************************************************************/
/* Logic for testing traversal. */
/******************************************************************************/
argc - num_unsaved_files,
argv + num_unsaved_files,
num_unsaved_files,
- unsaved_files);
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
if (!TU) {
fprintf(stderr, "Unable to load translation unit!\n");
return 1;
argc - num_unsaved_files - 2 - NumLocations,
argv + num_unsaved_files + 1 + NumLocations,
num_unsaved_files,
- unsaved_files);
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
if (!TU) {
fprintf(stderr, "unable to parse input\n");
return -1;
argc - num_unsaved_files - 3,
argv + num_unsaved_files + 2,
num_unsaved_files,
- unsaved_files);
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
if (!TU) {
fprintf(stderr, "unable to parse input\n");
clang_disposeIndex(CIdx);