summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CIndex/CIndex.cpp704
-rw-r--r--tools/CIndex/CIndex.exports19
-rw-r--r--tools/CIndex/CIndexCodeCompletion.cpp49
-rw-r--r--tools/CIndex/CIndexDiagnostic.cpp260
-rw-r--r--tools/CIndex/CIndexDiagnostic.h66
-rw-r--r--tools/CIndex/CIndexInclusionStack.cpp65
-rw-r--r--tools/CIndex/CIndexUSRs.cpp2
-rw-r--r--tools/CIndex/CIndexer.cpp34
-rw-r--r--tools/CIndex/CIndexer.h31
-rw-r--r--tools/CIndex/CMakeLists.txt2
-rw-r--r--tools/CIndex/CXCursor.cpp11
-rw-r--r--tools/CIndex/CXCursor.h2
-rw-r--r--tools/CIndex/CXSourceLocation.h76
-rw-r--r--tools/CIndex/Makefile1
-rw-r--r--tools/c-index-test/Makefile1
-rw-r--r--tools/c-index-test/c-index-test.c548
-rw-r--r--tools/driver/CMakeLists.txt5
-rw-r--r--tools/driver/Makefile7
-rw-r--r--tools/driver/cc1_main.cpp22
-rwxr-xr-xtools/scan-build/ccc-analyzer7
-rwxr-xr-xtools/scan-build/scan-build57
-rwxr-xr-xtools/scan-build/set-xcode-analyzer77
22 files changed, 1623 insertions, 423 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 84f908d57183..f9995eb743df 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -14,11 +14,15 @@
#include "CIndexer.h"
#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CIndexDiagnostic.h"
#include "clang/Basic/Version.h"
+
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -116,34 +120,6 @@ public:
#endif
#endif
-typedef llvm::PointerIntPair<ASTContext *, 1, bool> CXSourceLocationPtr;
-
-/// \brief Translate a Clang source location into a CIndex source location.
-static CXSourceLocation translateSourceLocation(ASTContext &Context,
- SourceLocation Loc,
- bool AtEnd = false) {
- CXSourceLocationPtr Ptr(&Context, AtEnd);
- CXSourceLocation Result = { Ptr.getOpaqueValue(), Loc.getRawEncoding() };
- return Result;
-}
-
-/// \brief Translate a Clang source range into a CIndex source range.
-static CXSourceRange translateSourceRange(ASTContext &Context, SourceRange R) {
- CXSourceRange Result = { &Context,
- R.getBegin().getRawEncoding(),
- R.getEnd().getRawEncoding() };
- return Result;
-}
-
-static SourceLocation translateSourceLocation(CXSourceLocation L) {
- return SourceLocation::getFromRawEncoding(L.int_data);
-}
-
-static SourceRange translateSourceRange(CXSourceRange R) {
- return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data),
- SourceLocation::getFromRawEncoding(R.end_int_data));
-}
-
/// \brief The result of comparing two source ranges.
enum RangeComparisonResult {
/// \brief Either the ranges overlap or one of the ranges is invalid.
@@ -163,13 +139,57 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,
SourceRange R2) {
assert(R1.isValid() && "First range is invalid?");
assert(R2.isValid() && "Second range is invalid?");
- if (SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
+ if (R1.getEnd() == R2.getBegin() ||
+ SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
return RangeBefore;
- if (SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
+ if (R2.getEnd() == R1.getBegin() ||
+ SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
return RangeAfter;
return RangeOverlap;
}
+/// \brief Translate a Clang source range into a CIndex source range.
+///
+/// Clang internally represents ranges where the end location points to the
+/// start of the token at the end. However, for external clients it is more
+/// useful to have a CXSourceRange be a proper half-open interval. This routine
+/// does the appropriate translation.
+CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceRange R) {
+ // 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.
+
+ // We want the last character in this location, so we will adjust the
+ // instantiation location accordingly.
+
+ // If the location is from a macro instantiation, get the end of the
+ // instantiation range.
+ SourceLocation EndLoc = R.getEnd();
+ SourceLocation InstLoc = SM.getInstantiationLoc(EndLoc);
+ if (EndLoc.isMacroID())
+ InstLoc = SM.getInstantiationRange(EndLoc).second;
+
+ // Measure the length token we're pointing at, so we can adjust the physical
+ // location in the file to point at the last character.
+ //
+ // FIXME: This won't cope with trigraphs or escaped newlines well. For that,
+ // we actually need a preprocessor, which isn't currently available
+ // here. Eventually, we'll switch the pointer data of
+ // CXSourceLocation/CXSourceRange to a translation unit (CXXUnit), so that the
+ // preprocessor will be available here. At that point, we can use
+ // Preprocessor::getLocForEndOfToken().
+ if (InstLoc.isValid()) {
+ unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, LangOpts);
+ EndLoc = EndLoc.getFileLocWithOffset(Length);
+ }
+
+ CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
+ R.getBegin().getRawEncoding(),
+ EndLoc.getRawEncoding() };
+ return Result;
+}
//===----------------------------------------------------------------------===//
// Cursor visitor.
@@ -214,15 +234,9 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \brief Determine whether this particular source range comes before, comes
/// after, or overlaps the region of interest.
///
- /// \param R a source range retrieved from the abstract syntax tree.
+ /// \param R a half-open source range retrieved from the abstract syntax tree.
RangeComparisonResult CompareRegionOfInterest(SourceRange R);
- /// \brief Determine whether this particular source range comes before, comes
- /// after, or overlaps the region of interest.
- ///
- /// \param CXR a source range retrieved from a cursor.
- RangeComparisonResult CompareRegionOfInterest(CXSourceRange CXR);
-
public:
CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData,
unsigned MaxPCHLevel,
@@ -292,6 +306,8 @@ public:
// FIXME: LabelStmt label?
bool VisitIfStmt(IfStmt *S);
bool VisitSwitchStmt(SwitchStmt *S);
+ bool VisitWhileStmt(WhileStmt *S);
+ bool VisitForStmt(ForStmt *S);
// Expression visitors
bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
@@ -302,20 +318,9 @@ public:
} // end anonymous namespace
RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
- assert(RegionOfInterest.isValid() && "RangeCompare called with invalid range");
- if (R.isInvalid())
- return RangeOverlap;
-
- // Move the end of the input range to the end of the last token in that
- // range.
- R.setEnd(TU->getPreprocessor().getLocForEndOfToken(R.getEnd(), 1));
return RangeCompare(TU->getSourceManager(), R, RegionOfInterest);
}
-RangeComparisonResult CursorVisitor::CompareRegionOfInterest(CXSourceRange CXR) {
- return CompareRegionOfInterest(translateSourceRange(CXR));
-}
-
/// \brief Visit the given cursor and, if requested by the visitor,
/// its children.
///
@@ -343,9 +348,9 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
// If we have a range of interest, and this cursor doesn't intersect with it,
// we're done.
if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) {
- CXSourceRange Range = clang_getCursorExtent(Cursor);
- if (translateSourceRange(Range).isInvalid() ||
- CompareRegionOfInterest(Range))
+ SourceRange Range =
+ cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor));
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
return false;
}
@@ -360,7 +365,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return VisitChildren(Cursor);
}
- llvm_unreachable("Silly GCC, we can't get here");
+ return false;
}
/// \brief Visit the children of the given cursor.
@@ -432,12 +437,15 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
for (DeclContext::decl_iterator
I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+ CXCursor Cursor = MakeCXCursor(*I, TU);
+
if (RegionOfInterest.isValid()) {
- SourceRange R = (*I)->getSourceRange();
- if (R.isInvalid())
+ SourceRange Range =
+ cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor));
+ if (Range.isInvalid())
continue;
-
- switch (CompareRegionOfInterest(R)) {
+
+ switch (CompareRegionOfInterest(Range)) {
case RangeBefore:
// This declaration comes before the region of interest; skip it.
continue;
@@ -452,7 +460,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
}
}
- if (Visit(MakeCXCursor(*I, TU), true))
+ if (Visit(Cursor, true))
return true;
}
@@ -783,7 +791,7 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
bool CursorVisitor::VisitStmt(Stmt *S) {
for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end();
Child != ChildEnd; ++Child) {
- if (Visit(MakeCXCursor(*Child, StmtParent, TU)))
+ if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU)))
return true;
}
@@ -793,7 +801,7 @@ bool CursorVisitor::VisitStmt(Stmt *S) {
bool CursorVisitor::VisitDeclStmt(DeclStmt *S) {
for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
- if (Visit(MakeCXCursor(*D, TU)))
+ if (*D && Visit(MakeCXCursor(*D, TU)))
return true;
}
@@ -804,12 +812,12 @@ bool CursorVisitor::VisitIfStmt(IfStmt *S) {
if (VarDecl *Var = S->getConditionVariable()) {
if (Visit(MakeCXCursor(Var, TU)))
return true;
- } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
- return true;
+ }
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
if (S->getThen() && Visit(MakeCXCursor(S->getThen(), StmtParent, TU)))
return true;
-
if (S->getElse() && Visit(MakeCXCursor(S->getElse(), StmtParent, TU)))
return true;
@@ -820,9 +828,42 @@ bool CursorVisitor::VisitSwitchStmt(SwitchStmt *S) {
if (VarDecl *Var = S->getConditionVariable()) {
if (Visit(MakeCXCursor(Var, TU)))
return true;
- } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ }
+
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
+ if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitWhileStmt(WhileStmt *S) {
+ if (VarDecl *Var = S->getConditionVariable()) {
+ if (Visit(MakeCXCursor(Var, TU)))
+ return true;
+ }
+
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
+ if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU)))
return true;
+ return false;
+}
+
+bool CursorVisitor::VisitForStmt(ForStmt *S) {
+ if (S->getInit() && Visit(MakeCXCursor(S->getInit(), StmtParent, TU)))
+ return true;
+ if (VarDecl *Var = S->getConditionVariable()) {
+ if (Visit(MakeCXCursor(Var, TU)))
+ return true;
+ }
+
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
+ if (S->getInc() && Visit(MakeCXCursor(S->getInc(), StmtParent, TU)))
+ return true;
if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU)))
return true;
@@ -868,37 +909,59 @@ CXString CIndexer::createCXString(const char *String, bool DupString){
return Str;
}
+CXString CIndexer::createCXString(llvm::StringRef String, bool DupString) {
+ CXString Result;
+ if (DupString || (!String.empty() && String.data()[String.size()] != 0)) {
+ char *Spelling = (char *)malloc(String.size() + 1);
+ memmove(Spelling, String.data(), String.size());
+ Spelling[String.size()] = 0;
+ Result.Spelling = Spelling;
+ Result.MustFreeString = 1;
+ } else {
+ Result.Spelling = String.data();
+ Result.MustFreeString = 0;
+ }
+ return Result;
+}
+
extern "C" {
-CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
- int displayDiagnostics) {
+CXIndex clang_createIndex(int excludeDeclarationsFromPCH) {
CIndexer *CIdxr = new CIndexer();
if (excludeDeclarationsFromPCH)
CIdxr->setOnlyLocalDecls();
- if (displayDiagnostics)
- CIdxr->setDisplayDiagnostics();
return CIdxr;
}
void clang_disposeIndex(CXIndex CIdx) {
- assert(CIdx && "Passed null CXIndex");
- delete static_cast<CIndexer *>(CIdx);
+ if (CIdx)
+ delete static_cast<CIndexer *>(CIdx);
}
void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) {
- assert(CIdx && "Passed null CXIndex");
- CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
- CXXIdx->setUseExternalASTGeneration(value);
+ if (CIdx) {
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ CXXIdx->setUseExternalASTGeneration(value);
+ }
}
-// FIXME: need to pass back error info.
CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
- const char *ast_filename) {
- assert(CIdx && "Passed null CXIndex");
+ const char *ast_filename,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
+ if (!CIdx)
+ return 0;
+
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
- return ASTUnit::LoadFromPCHFile(ast_filename, CXXIdx->getDiags(),
- CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true);
+ // 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());
}
CXTranslationUnit
@@ -907,10 +970,21 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
int num_command_line_args,
const char **command_line_args,
unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files) {
- assert(CIdx && "Passed null CXIndex");
+ struct CXUnsavedFile *unsaved_files,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
+ if (!CIdx)
+ return 0;
+
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
@@ -932,7 +1006,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
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);
@@ -940,16 +1014,15 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
llvm::OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
- CXXIdx->getDiags(),
+ *Diags,
CXXIdx->getClangResourcesPath(),
CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true,
RemappedFiles.data(),
RemappedFiles.size()));
// 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();
@@ -1004,6 +1077,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
argv.push_back(arg);
}
+ // Generate a temporary name for the diagnostics file.
+ char tmpFileResults[L_tmpnam];
+ char *tmpResultsFileName = tmpnam(tmpFileResults);
+ llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
+ TemporaryFiles.push_back(DiagnosticsFile);
+ argv.push_back("-fdiagnostics-binary");
+
// Add the null terminator.
argv.push_back(NULL);
@@ -1011,30 +1091,39 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
std::string ErrMsg;
- const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DevNull, NULL };
+ const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DiagnosticsFile,
+ NULL };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
- /* redirects */ !CXXIdx->getDisplayDiagnostics() ? &Redirects[0] : NULL,
+ /* redirects */ &Redirects[0],
/* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
- if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg
- << '\n' << "Arguments: \n";
+ if (!ErrMsg.empty()) {
+ std::string AllArgs;
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
- I!=E; ++I) {
+ I != E; ++I) {
+ AllArgs += ' ';
if (*I)
- llvm::errs() << ' ' << *I << '\n';
+ AllArgs += *I;
}
- llvm::errs() << '\n';
+
+ Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
}
- ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, CXXIdx->getDiags(),
+ // FIXME: Parse the (redirected) standard error to emit diagnostics.
+
+ ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, *Diags,
CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true,
RemappedFiles.data(),
RemappedFiles.size());
if (ATU)
ATU->unlinkTemporaryFile();
+ // FIXME: Currently we don't report diagnostics on invalid ASTs.
+ if (ATU)
+ ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
+ num_unsaved_files, unsaved_files,
+ ATU->getASTContext().getLangOptions());
+
for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
TemporaryFiles[i].eraseFromDisk();
@@ -1042,12 +1131,14 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
}
void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
- assert(CTUnit && "Passed null CXTranslationUnit");
- delete static_cast<ASTUnit *>(CTUnit);
+ if (CTUnit)
+ delete static_cast<ASTUnit *>(CTUnit);
}
CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
- assert(CTUnit && "Passed null CXTranslationUnit");
+ if (!CTUnit)
+ return CIndexer::createCXString("");
+
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
return CIndexer::createCXString(CXXUnit->getOriginalSourceFileName().c_str(),
true);
@@ -1066,12 +1157,14 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
extern "C" {
CXSourceLocation clang_getNullLocation() {
- CXSourceLocation Result = { 0, 0 };
+ CXSourceLocation Result = { { 0, 0 }, 0 };
return Result;
}
unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
- return loc1.ptr_data == loc2.ptr_data && loc1.int_data == loc2.int_data;
+ return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
+ loc1.ptr_data[1] == loc2.ptr_data[1] &&
+ loc1.int_data == loc2.int_data);
}
CXSourceLocation clang_getLocation(CXTranslationUnit tu,
@@ -1087,67 +1180,46 @@ CXSourceLocation clang_getLocation(CXTranslationUnit tu,
static_cast<const FileEntry *>(file),
line, column);
- return translateSourceLocation(CXXUnit->getASTContext(), SLoc, false);
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+}
+
+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;
}
void clang_getInstantiationLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
- unsigned *column) {
- CXSourceLocationPtr Ptr
- = CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data);
+ unsigned *column,
+ unsigned *offset) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
- if (!Ptr.getPointer() || Loc.isInvalid()) {
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
if (file)
*file = 0;
if (line)
*line = 0;
if (column)
*column = 0;
+ if (offset)
+ *offset = 0;
return;
}
- // 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 =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
-
- if (Ptr.getInt()) {
- // We want the last character in this location, so we will adjust
- // the instantiation location accordingly.
-
- // If the location is from a macro instantiation, get the end of
- // the instantiation range.
- if (Loc.isMacroID())
- InstLoc = SM.getInstantiationRange(Loc).second;
-
- // Measure the length token we're pointing at, so we can adjust
- // the physical location in the file to point at the last
- // character.
- // FIXME: This won't cope with trigraphs or escaped newlines
- // well. For that, we actually need a preprocessor, which isn't
- // currently available here. Eventually, we'll switch the pointer
- // data of CXSourceLocation/CXSourceRange to a translation unit
- // (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());
- if (Length > 0)
- InstLoc = InstLoc.getFileLocWithOffset(Length - 1);
- }
if (file)
*file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc));
@@ -1155,18 +1227,19 @@ void clang_getInstantiationLocation(CXSourceLocation location,
*line = SM.getInstantiationLineNumber(InstLoc);
if (column)
*column = SM.getInstantiationColumnNumber(InstLoc);
+ if (offset)
+ *offset = SM.getDecomposedLoc(InstLoc).second;
}
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));
- Ptr.setInt(true);
- CXSourceLocation Result = { Ptr.getOpaqueValue(), range.end_int_data };
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.end_int_data };
return Result;
}
@@ -1181,7 +1254,6 @@ const char *clang_getFileName(CXFile SFile) {
if (!SFile)
return 0;
- assert(SFile && "Passed null CXFile");
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
return FEnt->getName();
}
@@ -1190,7 +1262,6 @@ time_t clang_getFileTime(CXFile SFile) {
if (!SFile)
return 0;
- assert(SFile && "Passed null CXFile");
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
return FEnt->getModificationTime();
}
@@ -1230,6 +1301,18 @@ static Decl *getDeclFromExpr(Stmt *E) {
return 0;
}
+static SourceLocation getLocationFromExpr(Expr *E) {
+ if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
+ return /*FIXME:*/Msg->getLeftLoc();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getLocation();
+ if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
+ return Member->getMemberLoc();
+ if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
+ return Ivar->getLocation();
+ return E->getLocStart();
+}
+
extern "C" {
unsigned clang_visitChildren(CXCursor parent,
@@ -1274,7 +1357,6 @@ static CXString getDeclSpelling(Decl *D) {
}
CXString clang_getCursorSpelling(CXCursor C) {
- assert(getCursorDecl(C) && "CXCursor has null decl");
if (clang_isTranslationUnit(C.kind))
return clang_getTranslationUnitSpelling(C.data[2]);
@@ -1314,7 +1396,10 @@ CXString clang_getCursorSpelling(CXCursor C) {
return CIndexer::createCXString("");
}
- return getDeclSpelling(getCursorDecl(C));
+ if (clang_isDeclaration(C.kind))
+ return getDeclSpelling(getCursorDecl(C));
+
+ return CIndexer::createCXString("");
}
const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) {
@@ -1373,11 +1458,10 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
- SourceLocation SLoc = translateSourceLocation(Loc);
+ SourceLocation SLoc = cxloc::translateSourceLocation(Loc);
CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
if (SLoc.isValid()) {
- SourceRange RegionOfInterest(SLoc,
- CXXUnit->getPreprocessor().getLocForEndOfToken(SLoc, 1));
+ SourceRange RegionOfInterest(SLoc, SLoc.getFileLocWithOffset(1));
// FIXME: Would be great to have a "hint" cursor, then walk from that
// hint cursor upward until we find a cursor whose source range encloses
@@ -1426,42 +1510,30 @@ CXCursorKind clang_getCursorKind(CXCursor C) {
return C.kind;
}
-static SourceLocation getLocationFromExpr(Expr *E) {
- if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
- return /*FIXME:*/Msg->getLeftLoc();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return DRE->getLocation();
- if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
- return Member->getMemberLoc();
- if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
- return Ivar->getLocation();
- return E->getLocStart();
-}
-
CXSourceLocation clang_getCursorLocation(CXCursor C) {
if (clang_isReference(C.kind)) {
switch (C.kind) {
case CXCursor_ObjCSuperClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCSuperClassRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCProtocolRef: {
std::pair<ObjCProtocolDecl *, SourceLocation> P
= getCursorObjCProtocolRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCClassRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_TypeRef: {
std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
default:
@@ -1471,19 +1543,17 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
}
if (clang_isExpression(C.kind))
- return translateSourceLocation(getCursorContext(C),
+ 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();
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
Loc = Class->getClassLoc();
- return translateSourceLocation(D->getASTContext(), Loc);
+ return cxloc::translateSourceLocation(D->getASTContext(), Loc);
}
CXSourceRange clang_getCursorExtent(CXCursor C) {
@@ -1492,25 +1562,25 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
case CXCursor_ObjCSuperClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCSuperClassRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCProtocolRef: {
std::pair<ObjCProtocolDecl *, SourceLocation> P
= getCursorObjCProtocolRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCClassRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
case CXCursor_TypeRef: {
std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
default:
@@ -1520,20 +1590,18 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
}
if (clang_isExpression(C.kind))
- return translateSourceRange(getCursorContext(C),
+ return cxloc::translateSourceRange(getCursorContext(C),
getCursorExpr(C)->getSourceRange());
if (clang_isStatement(C.kind))
- return translateSourceRange(getCursorContext(C),
+ 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 translateSourceRange(D->getASTContext(), D->getSourceRange());
+ return cxloc::translateSourceRange(D->getASTContext(), D->getSourceRange());
}
CXCursor clang_getCursorReferenced(CXCursor C) {
@@ -1643,7 +1711,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::CXXRecord:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
- if (TagDecl *Def = cast<TagDecl>(D)->getDefinition(D->getASTContext()))
+ if (TagDecl *Def = cast<TagDecl>(D)->getDefinition())
return MakeCXCursor(Def, CXXUnit);
return clang_getNullCursor();
@@ -1659,23 +1727,10 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
}
case Decl::Var: {
- VarDecl *Var = cast<VarDecl>(D);
-
- // Variables with initializers have definitions.
- const VarDecl *Def = 0;
- if (Var->getDefinition(Def))
- return MakeCXCursor(const_cast<VarDecl *>(Def), CXXUnit);
-
- // extern and private_extern variables are not definitions.
- if (Var->hasExternalStorage())
- return clang_getNullCursor();
-
- // In-line static data members do not have definitions.
- if (Var->isStaticDataMember() && !Var->isOutOfLine())
- return clang_getNullCursor();
-
- // All other variables are themselves definitions.
- return C;
+ // Ask the variable if it has a definition.
+ if (VarDecl *Def = cast<VarDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, CXXUnit);
+ return clang_getNullCursor();
}
case Decl::FunctionTemplate: {
@@ -1687,7 +1742,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ClassTemplate: {
if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl()
- ->getDefinition(D->getASTContext()))
+ ->getDefinition())
return MakeCXCursor(
cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(),
CXXUnit);
@@ -1843,6 +1898,247 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
} // end: extern "C"
//===----------------------------------------------------------------------===//
+// Token-based Operations.
+//===----------------------------------------------------------------------===//
+
+/* CXToken layout:
+ * int_data[0]: a CXTokenKind
+ * int_data[1]: starting token location
+ * int_data[2]: token length
+ * int_data[3]: reserved
+ * ptr_data: for identifiers and keywords, an IdentifierInfo*.
+ * otherwise unused.
+ */
+extern "C" {
+
+CXTokenKind clang_getTokenKind(CXToken CXTok) {
+ return static_cast<CXTokenKind>(CXTok.int_data[0]);
+}
+
+CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
+ switch (clang_getTokenKind(CXTok)) {
+ case CXToken_Identifier:
+ case CXToken_Keyword:
+ // We know we have an IdentifierInfo*, so use that.
+ return CIndexer::createCXString(
+ static_cast<IdentifierInfo *>(CXTok.ptr_data)->getNameStart());
+
+ case CXToken_Literal: {
+ // We have stashed the starting pointer in the ptr_data field. Use it.
+ const char *Text = static_cast<const char *>(CXTok.ptr_data);
+ return CIndexer::createCXString(llvm::StringRef(Text, CXTok.int_data[2]),
+ true);
+ }
+
+ case CXToken_Punctuation:
+ case CXToken_Comment:
+ break;
+ }
+
+ // We have to find the starting buffer pointer the hard way, by
+ // deconstructing the source location.
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit)
+ return CIndexer::createCXString("");
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
+ std::pair<FileID, unsigned> LocInfo
+ = CXXUnit->getSourceManager().getDecomposedLoc(Loc);
+ std::pair<const char *,const char *> Buffer
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first);
+
+ return CIndexer::createCXString(llvm::StringRef(Buffer.first+LocInfo.second,
+ CXTok.int_data[2]),
+ true);
+}
+
+CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit)
+ return clang_getNullLocation();
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(),
+ SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
+}
+
+CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit)
+ return clang_getNullRange();
+
+ return cxloc::translateSourceRange(CXXUnit->getASTContext(),
+ SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
+}
+
+void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
+ CXToken **Tokens, unsigned *NumTokens) {
+ if (Tokens)
+ *Tokens = 0;
+ if (NumTokens)
+ *NumTokens = 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit || !Tokens || !NumTokens)
+ return;
+
+ SourceRange R = cxloc::translateCXSourceRange(Range);
+ if (R.isInvalid())
+ return;
+
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(R.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(R.getEnd());
+
+ // Cannot tokenize across files.
+ if (BeginLocInfo.first != EndLocInfo.first)
+ return;
+
+ // Create a lexer
+ std::pair<const char *,const char *> Buffer
+ = SourceMgr.getBufferData(BeginLocInfo.first);
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOptions(),
+ Buffer.first, Buffer.first + BeginLocInfo.second, Buffer.second);
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens until we hit the end of the range.
+ const char *EffectiveBufferEnd = Buffer.first + EndLocInfo.second;
+ llvm::SmallVector<CXToken, 32> CXTokens;
+ Token Tok;
+ do {
+ // Lex the next token
+ Lex.LexFromRawLexer(Tok);
+ if (Tok.is(tok::eof))
+ break;
+
+ // Initialize the CXToken.
+ CXToken CXTok;
+
+ // - Common fields
+ CXTok.int_data[1] = Tok.getLocation().getRawEncoding();
+ CXTok.int_data[2] = Tok.getLength();
+ CXTok.int_data[3] = 0;
+
+ // - Kind-specific fields
+ if (Tok.isLiteral()) {
+ CXTok.int_data[0] = CXToken_Literal;
+ CXTok.ptr_data = (void *)Tok.getLiteralData();
+ } else if (Tok.is(tok::identifier)) {
+ // Lookup the identifier to determine whether we have a
+ std::pair<FileID, unsigned> LocInfo
+ = SourceMgr.getDecomposedLoc(Tok.getLocation());
+ const char *StartPos
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first +
+ LocInfo.second;
+ IdentifierInfo *II
+ = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos);
+ CXTok.int_data[0] = II->getTokenID() == tok::identifier?
+ CXToken_Identifier
+ : CXToken_Keyword;
+ CXTok.ptr_data = II;
+ } else if (Tok.is(tok::comment)) {
+ CXTok.int_data[0] = CXToken_Comment;
+ CXTok.ptr_data = 0;
+ } else {
+ CXTok.int_data[0] = CXToken_Punctuation;
+ CXTok.ptr_data = 0;
+ }
+ CXTokens.push_back(CXTok);
+ } while (Lex.getBufferLocation() <= EffectiveBufferEnd);
+
+ if (CXTokens.empty())
+ return;
+
+ *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size());
+ memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size());
+ *NumTokens = CXTokens.size();
+}
+
+typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
+
+enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ AnnotateTokensData *Data = static_cast<AnnotateTokensData *>(client_data);
+
+ // We only annotate the locations of declarations, simple
+ // references, and expressions which directly reference something.
+ CXCursorKind Kind = clang_getCursorKind(cursor);
+ if (clang_isDeclaration(Kind) || clang_isReference(Kind)) {
+ // Okay: We can annotate the location of this declaration with the
+ // declaration or reference
+ } else if (clang_isExpression(cursor.kind)) {
+ if (Kind != CXCursor_DeclRefExpr &&
+ Kind != CXCursor_MemberRefExpr &&
+ Kind != CXCursor_ObjCMessageExpr)
+ return CXChildVisit_Recurse;
+
+ CXCursor Referenced = clang_getCursorReferenced(cursor);
+ if (Referenced == cursor || Referenced == clang_getNullCursor())
+ return CXChildVisit_Recurse;
+
+ // Okay: we can annotate the location of this expression
+ } else {
+ // Nothing to annotate
+ return CXChildVisit_Recurse;
+ }
+
+ CXSourceLocation Loc = clang_getCursorLocation(cursor);
+ (*Data)[Loc.int_data] = cursor;
+ return CXChildVisit_Recurse;
+}
+
+void clang_annotateTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens,
+ CXCursor *Cursors) {
+ if (NumTokens == 0)
+ return;
+
+ // Any token we don't specifically annotate will have a NULL cursor.
+ for (unsigned I = 0; I != NumTokens; ++I)
+ Cursors[I] = clang_getNullCursor();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit || !Tokens)
+ return;
+
+ // Annotate all of the source locations in the region of interest that map
+ SourceRange RegionOfInterest;
+ RegionOfInterest.setBegin(
+ cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
+ SourceLocation End
+ = cxloc::translateSourceLocation(clang_getTokenLocation(TU,
+ Tokens[NumTokens - 1]));
+ RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End));
+ // FIXME: Would be great to have a "hint" cursor, then walk from that
+ // hint cursor upward until we find a cursor whose source range encloses
+ // the region of interest, rather than starting from the translation unit.
+ AnnotateTokensData Annotated;
+ CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
+ CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated,
+ Decl::MaxPCHLevel, RegionOfInterest);
+ AnnotateVis.VisitChildren(Parent);
+
+ for (unsigned I = 0; I != NumTokens; ++I) {
+ // Determine whether we saw a cursor at this token's location.
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ if (Pos == Annotated.end())
+ continue;
+
+ Cursors[I] = Pos->second;
+ }
+}
+
+void clang_disposeTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens) {
+ free(Tokens);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
// CXString Operations.
//===----------------------------------------------------------------------===//
@@ -1864,8 +2160,8 @@ void clang_disposeString(CXString string) {
extern "C" {
-const char *clang_getClangVersion() {
- return getClangFullVersion();
+CXString clang_getClangVersion() {
+ return CIndexer::createCXString(getClangFullVersion(), true);
}
} // end: extern "C"
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index d349086b9c11..2c738190b4ad 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -1,3 +1,4 @@
+_clang_annotateTokens
_clang_codeComplete
_clang_createIndex
_clang_createTranslationUnit
@@ -5,6 +6,7 @@ _clang_createTranslationUnitFromSourceFile
_clang_disposeCodeCompleteResults
_clang_disposeIndex
_clang_disposeString
+_clang_disposeTokens
_clang_disposeTranslationUnit
_clang_equalCursors
_clang_equalLocations
@@ -23,17 +25,33 @@ _clang_getCursorReferenced
_clang_getCursorSpelling
_clang_getCursorUSR
_clang_getDefinitionSpellingAndExtent
+_clang_getDiagnosticFixItInsertion
+_clang_getDiagnosticFixItKind
+_clang_getDiagnosticFixItRemoval
+_clang_getDiagnosticFixItReplacement
+_clang_getDiagnosticLocation
+_clang_getDiagnosticNumFixIts
+_clang_getDiagnosticNumRanges
+_clang_getDiagnosticRange
+_clang_getDiagnosticSeverity
+_clang_getDiagnosticSpelling
_clang_getFile
_clang_getFileName
_clang_getFileTime
+_clang_getInclusions
_clang_getInstantiationLocation
_clang_getLocation
_clang_getNullCursor
_clang_getNullLocation
+_clang_getNullRange
_clang_getNumCompletionChunks
_clang_getRange
_clang_getRangeEnd
_clang_getRangeStart
+_clang_getTokenExtent
+_clang_getTokenKind
+_clang_getTokenLocation
+_clang_getTokenSpelling
_clang_getTranslationUnitCursor
_clang_getTranslationUnitSpelling
_clang_isCursorDefinition
@@ -44,4 +62,5 @@ _clang_isReference
_clang_isStatement
_clang_isTranslationUnit
_clang_setUseExternalASTGeneration
+_clang_tokenize
_clang_visitChildren
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
index f3b60dc8b01a..4e41c5f1c7b5 100644
--- a/tools/CIndex/CIndexCodeCompletion.cpp
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
+#include "CIndexDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -176,6 +178,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief The memory buffer from which we parsed the results. We
/// retain this buffer because the completion strings point into it.
llvm::MemoryBuffer *Buffer;
+
+ LangOptions LangOpts;
};
CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
@@ -186,10 +190,19 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
struct CXUnsavedFile *unsaved_files,
const char *complete_filename,
unsigned complete_line,
- unsigned complete_column) {
+ unsigned complete_column,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
// The indexer, which is mainly used to determine where diagnostics go.
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);
+
// The set of temporary files that we've built.
std::vector<llvm::sys::Path> TemporaryFiles;
@@ -220,7 +233,8 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
argv.push_back("-no-code-completion-debug-printer");
argv.push_back("-Xclang");
argv.push_back("-code-completion-macros");
-
+ argv.push_back("-fdiagnostics-binary");
+
// Remap any unsaved files to temporary files.
std::vector<std::string> RemapArgs;
if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
@@ -256,31 +270,39 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
// Add the null terminator.
argv.push_back(NULL);
- // Generate a temporary name for the AST file.
+ // Generate a temporary name for the code-completion results file.
char tmpFile[L_tmpnam];
char *tmpFileName = tmpnam(tmpFile);
llvm::sys::Path ResultsFile(tmpFileName);
TemporaryFiles.push_back(ResultsFile);
+ // Generate a temporary name for the diagnostics file.
+ char tmpFileResults[L_tmpnam];
+ char *tmpResultsFileName = tmpnam(tmpFileResults);
+ llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
+ TemporaryFiles.push_back(DiagnosticsFile);
+
// Invoke 'clang'.
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
std::string ErrMsg;
- const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
+ const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
+ &DiagnosticsFile, 0 };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ &Redirects[0],
/* secondsToWait */ 0,
/* memoryLimits */ 0, &ErrMsg);
- if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_codeComplete: " << ErrMsg
- << '\n' << "Arguments: \n";
+ if (!ErrMsg.empty()) {
+ std::string AllArgs;
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
- I!=E; ++I) {
+ I != E; ++I) {
+ AllArgs += ' ';
if (*I)
- llvm::errs() << ' ' << *I << '\n';
+ AllArgs += *I;
}
- llvm::errs() << '\n';
+
+ Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
}
// Parse the resulting source file to find code-completion results.
@@ -319,6 +341,13 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
Results->Buffer = F;
}
+ // FIXME: The LangOptions we are passing here are not at all correct. However,
+ // in the current design we must pass something in so the SourceLocations have
+ // a LangOptions object to refer to.
+ ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
+ num_unsaved_files, unsaved_files,
+ Results->LangOpts);
+
for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
TemporaryFiles[i].eraseFromDisk();
diff --git a/tools/CIndex/CIndexDiagnostic.cpp b/tools/CIndex/CIndexDiagnostic.cpp
new file mode 100644
index 000000000000..d26094f7ee6f
--- /dev/null
+++ b/tools/CIndex/CIndexDiagnostic.cpp
@@ -0,0 +1,260 @@
+/*===-- 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"
+
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/Support/MemoryBuffer.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 *LangOptsPtr;
+
+ /// \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) {
+ assert(!LangOptsPtr && "Invalid state!");
+ LangOptsPtr = &LangOpts;
+}
+
+void CIndexDiagnosticClient::EndSourceFile() {
+ assert(LangOptsPtr && "Invalid state!");
+ LangOptsPtr = 0;
+}
+
+void CIndexDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ if (!Callback)
+ return;
+
+ assert((LangOptsPtr || Info.getLocation().isInvalid()) &&
+ "Missing language options with located diagnostic!");
+ CXStoredDiagnostic Stored = { this->LangOptsPtr, 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->LangOptsPtr,
+ 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);
+}
+
+unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid())
+ return 0;
+
+ return StoredDiag->Info.getNumRanges();
+}
+
+CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || Range >= StoredDiag->Info.getNumRanges() ||
+ StoredDiag->Info.getLocation().isInvalid())
+ return clang_getNullRange();
+
+ return translateSourceRange(StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ StoredDiag->Info.getRange(Range));
+}
+
+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) {
+ if (Location)
+ *Location = clang_getNullLocation();
+
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
+ return CIndexer::createCXString("");
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+
+ if (Location && StoredDiag->Info.getLocation().isValid())
+ *Location = translateSourceLocation(
+ StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ Hint.InsertionLoc);
+ 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->LangOptsPtr,
+ Hint.RemoveRange);
+}
+
+CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag,
+ unsigned FixIt,
+ CXSourceRange *Range) {
+ if (Range)
+ *Range = clang_getNullRange();
+
+ 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->LangOptsPtr,
+ Hint.RemoveRange);
+ return CIndexer::createCXString(Hint.CodeToInsert);
+}
+
+} // end extern "C"
+
+void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+ Diagnostic &Diags,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ const LangOptions &LangOpts) {
+ using llvm::MemoryBuffer;
+ using llvm::StringRef;
+ MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
+ if (!F)
+ return;
+
+ // Enter the unsaved files into the file manager.
+ SourceManager SourceMgr;
+ FileManager FileMgr;
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
+ unsaved_files[I].Length,
+ 0);
+ if (!File) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << unsaved_files[I].Filename;
+ return;
+ }
+
+ MemoryBuffer *Buffer
+ = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
+ unsaved_files[I].Contents + unsaved_files[I].Length);
+ if (!Buffer)
+ return;
+
+ SourceMgr.overrideFileContents(File, Buffer);
+ }
+
+ Diags.getClient()->BeginSourceFile(LangOpts, 0);
+
+ // Parse the diagnostics, emitting them one by one until we've
+ // exhausted the data.
+ StringRef Buffer = F->getBuffer();
+ const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
+ while (Memory != MemoryEnd) {
+ DiagnosticBuilder DB = Diags.Deserialize(FileMgr, SourceMgr,
+ Memory, MemoryEnd);
+ if (!DB.isActive())
+ return;
+ }
+
+ Diags.getClient()->EndSourceFile();
+}
diff --git a/tools/CIndex/CIndexDiagnostic.h b/tools/CIndex/CIndexDiagnostic.h
new file mode 100644
index 000000000000..9f7ae51a1083
--- /dev/null
+++ b/tools/CIndex/CIndexDiagnostic.h
@@ -0,0 +1,66 @@
+/*===-- 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 llvm { namespace sys {
+class Path;
+} }
+
+namespace clang {
+
+class Diagnostic;
+class LangOptions;
+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;
+ const LangOptions *LangOptsPtr;
+
+public:
+ CIndexDiagnosticClient(CXDiagnosticCallback Callback,
+ CXClientData ClientData)
+ : Callback(Callback), ClientData(ClientData), LangOptsPtr(0) { }
+
+ virtual ~CIndexDiagnosticClient();
+
+ virtual void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP);
+
+ virtual void EndSourceFile();
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+};
+
+/// \brief Given the path to a file that contains binary, serialized
+/// diagnostics produced by Clang, emit those diagnostics via the
+/// given diagnostic engine.
+void ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+ Diagnostic &Diags,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ const LangOptions &LangOpts);
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
diff --git a/tools/CIndex/CIndexInclusionStack.cpp b/tools/CIndex/CIndexInclusionStack.cpp
new file mode 100644
index 000000000000..4a884e588432
--- /dev/null
+++ b/tools/CIndex/CIndexInclusionStack.cpp
@@ -0,0 +1,65 @@
+//===- CIndexInclusionStack.cpp - Clang-C Source Indexing Library ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a callback mechanism for clients to get the inclusion
+// stack from a translation unit.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CXSourceLocation.h"
+#include "clang/AST/DeclVisitor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+extern "C" {
+void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
+ CXClientData clientData) {
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ SourceManager &SM = CXXUnit->getSourceManager();
+ ASTContext &Ctx = CXXUnit->getASTContext();
+
+ llvm::SmallVector<CXSourceLocation, 10> InclusionStack;
+ unsigned i = SM.sloc_loaded_entry_size();
+ unsigned n = SM.sloc_entry_size();
+
+ // In the case where all the SLocEntries are in an external source, traverse
+ // those SLocEntries as well. This is the case where we are looking
+ // at the inclusion stack of an AST/PCH file.
+ if (i >= n)
+ i = 0;
+
+ for ( ; i < n ; ++i) {
+
+ const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i);
+
+ if (!SL.isFile())
+ continue;
+
+ const SrcMgr::FileInfo &FI = SL.getFile();
+ if (!FI.getContentCache()->Entry)
+ continue;
+
+ // Build the inclusion stack.
+ SourceLocation L = FI.getIncludeLoc();
+ InclusionStack.clear();
+ while (L.isValid()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(L);
+ InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L));
+ L = PLoc.getIncludeLoc();
+ }
+
+ // Callback to the client.
+ // FIXME: We should have a function to construct CXFiles.
+ CB((CXFile) FI.getContentCache()->Entry,
+ InclusionStack.data(), InclusionStack.size(), clientData);
+ }
+}
+} // end extern C
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
index fd605fb68d1b..a992dbf12a00 100644
--- a/tools/CIndex/CIndexUSRs.cpp
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -74,7 +74,7 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
void USRGenerator::VisitNamedDecl(NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
const std::string &s = D->getNameAsString();
- assert(!s.empty());
+// assert(!s.empty());
Out << "@^" << s;
}
diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp
index 53636a4ff351..0774ae2f3722 100644
--- a/tools/CIndex/CIndexer.cpp
+++ b/tools/CIndex/CIndexer.cpp
@@ -69,7 +69,7 @@ const llvm::sys::Path& CIndexer::getClangPath() {
// We now have the CIndex directory, locate clang relative to it.
CIndexPath.eraseComponent();
- CIndexPath.eraseComponent();
+ CIndexPath.appendComponent("..");
CIndexPath.appendComponent("bin");
CIndexPath.appendComponent("clang");
#endif
@@ -95,16 +95,38 @@ std::string CIndexer::getClangResourcesPath() {
return P.str();
}
+static llvm::sys::Path GetTemporaryPath() {
+ // FIXME: This is lame; sys::Path should provide this function (in particular,
+ // it should know how to find the temporary files dir).
+ std::string Error;
+ const char *TmpDir = ::getenv("TMPDIR");
+ if (!TmpDir)
+ TmpDir = ::getenv("TEMP");
+ if (!TmpDir)
+ TmpDir = ::getenv("TMP");
+ if (!TmpDir)
+ TmpDir = "/tmp";
+ llvm::sys::Path P(TmpDir);
+ P.appendComponent("remap");
+ if (P.makeUnique(false, &Error))
+ return llvm::sys::Path("");
+
+ // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837.
+ P.eraseFromDisk(false, 0);
+
+ return P;
+}
+
bool clang::RemapFiles(unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files,
std::vector<std::string> &RemapArgs,
std::vector<llvm::sys::Path> &TemporaryFiles) {
for (unsigned i = 0; i != num_unsaved_files; ++i) {
- char tmpFile[L_tmpnam];
- char *tmpFileName = tmpnam(tmpFile);
-
// Write the contents of this unsaved file into the temporary file.
- llvm::sys::Path SavedFile(tmpFileName);
+ llvm::sys::Path SavedFile(GetTemporaryPath());
+ if (SavedFile.empty())
+ return true;
+
std::string ErrorInfo;
llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
if (!ErrorInfo.empty())
@@ -120,7 +142,7 @@ bool clang::RemapFiles(unsigned num_unsaved_files,
// Remap the file.
std::string RemapArg = unsaved_files[i].Filename;
RemapArg += ';';
- RemapArg += tmpFileName;
+ RemapArg += SavedFile.str();
RemapArgs.push_back("-Xclang");
RemapArgs.push_back("-remap-file");
RemapArgs.push_back("-Xclang");
diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h
index d01454f9dc64..b83e2b7f326c 100644
--- a/tools/CIndex/CIndexer.h
+++ b/tools/CIndex/CIndexer.h
@@ -18,36 +18,20 @@
#include "clang-c/Index.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/ASTUnit.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/System/Path.h"
#include <vector>
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) { }
/// \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
@@ -55,20 +39,11 @@ public:
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
- bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
- void setDisplayDiagnostics(bool Display = true) {
- DisplayDiagnostics = Display;
- }
-
bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
void setUseExternalASTGeneration(bool Value) {
UseExternalASTGeneration = Value;
}
- Diagnostic &getDiags() {
- return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
- }
-
/// \brief Get the path of the clang binary.
const llvm::sys::Path& getClangPath();
@@ -76,6 +51,8 @@ public:
std::string getClangResourcesPath();
static CXString createCXString(const char *String, bool DupString = false);
+ static CXString createCXString(llvm::StringRef String,
+ bool DupString = false);
};
namespace clang {
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
index 730eaafb5a2e..26e1b3bb905c 100644
--- a/tools/CIndex/CMakeLists.txt
+++ b/tools/CIndex/CMakeLists.txt
@@ -21,6 +21,8 @@ set( LLVM_LINK_COMPONENTS
add_clang_library(CIndex
CIndex.cpp
CIndexCodeCompletion.cpp
+ CIndexDiagnostic.cpp
+ CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
CXCursor.cpp
diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp
index 63d9bc9f2e9a..ec1477eb8a27 100644
--- a/tools/CIndex/CXCursor.cpp
+++ b/tools/CIndex/CXCursor.cpp
@@ -29,6 +29,7 @@ CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
}
static CXCursorKind GetCursorKind(Decl *D) {
+ assert(D && "Invalid arguments!");
switch (D->getKind()) {
case Decl::Enum: return CXCursor_EnumDecl;
case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
@@ -72,11 +73,13 @@ static CXCursorKind GetCursorKind(Decl *D) {
}
CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) {
+ assert(D && TU && "Invalid arguments!");
CXCursor C = { GetCursorKind(D), { D, 0, TU } };
return C;
}
CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
+ assert(S && TU && "Invalid arguments!");
CXCursorKind K = CXCursor_NotImplemented;
switch (S->getStmtClass()) {
@@ -112,7 +115,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
K = CXCursor_UnexposedStmt;
break;
- case Stmt::ExprClass:
case Stmt::PredefinedExprClass:
case Stmt::IntegerLiteralClass:
case Stmt::FloatingLiteralClass:
@@ -123,12 +125,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
case Stmt::UnaryOperatorClass:
case Stmt::SizeOfAlignOfExprClass:
case Stmt::ArraySubscriptExprClass:
- case Stmt::CastExprClass:
case Stmt::BinaryOperatorClass:
case Stmt::CompoundAssignOperatorClass:
case Stmt::ConditionalOperatorClass:
case Stmt::ImplicitCastExprClass:
- case Stmt::ExplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CompoundLiteralExprClass:
case Stmt::ExtVectorElementExprClass:
@@ -162,6 +162,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
case Stmt::UnaryTypeTraitExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXBindReferenceExprClass:
case Stmt::CXXExprWithTemporariesClass:
case Stmt::CXXUnresolvedConstructExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
@@ -214,6 +215,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
SourceLocation Loc,
ASTUnit *TU) {
+ assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCSuperClassRef, { Super, RawLoc, TU } };
return C;
@@ -230,6 +232,7 @@ cxcursor::getCursorObjCSuperClassRef(CXCursor C) {
CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super,
SourceLocation Loc,
ASTUnit *TU) {
+ assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCProtocolRef, { Super, RawLoc, TU } };
return C;
@@ -246,6 +249,7 @@ cxcursor::getCursorObjCProtocolRef(CXCursor C) {
CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
SourceLocation Loc,
ASTUnit *TU) {
+ assert(Class && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } };
return C;
@@ -261,6 +265,7 @@ cxcursor::getCursorObjCClassRef(CXCursor C) {
CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
ASTUnit *TU) {
+ assert(Type && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_TypeRef, { Type, RawLoc, TU } };
return C;
diff --git a/tools/CIndex/CXCursor.h b/tools/CIndex/CXCursor.h
index 546dd7f48543..30fb26c936bf 100644
--- a/tools/CIndex/CXCursor.h
+++ b/tools/CIndex/CXCursor.h
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_CXCURSOR_H
-#define LLVM_CLANG_CXCursor_H
+#define LLVM_CLANG_CXCURSOR_H
#include "clang-c/Index.h"
#include "clang/Basic/SourceLocation.h"
diff --git a/tools/CIndex/CXSourceLocation.h b/tools/CIndex/CXSourceLocation.h
new file mode 100644
index 000000000000..8bfc6f9da7ab
--- /dev/null
+++ b/tools/CIndex/CXSourceLocation.h
@@ -0,0 +1,76 @@
+//===- CXSourceLocation.h - CXSourceLocations Utilities ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines routines for manipulating CXSourceLocations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CXSOURCELOCATION_H
+#define LLVM_CLANG_CXSOURCELOCATION_H
+
+#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 {
+
+class ASTContext;
+
+namespace cxloc {
+
+/// \brief Translate a Clang source location into a CIndex source location.
+static inline CXSourceLocation
+translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
+ SourceLocation Loc) {
+ CXSourceLocation Result = { { (void*) &SM, (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) {
+ return translateSourceLocation(Context.getSourceManager(),
+ Context.getLangOptions(),
+ Loc);
+}
+
+/// \brief Translate a Clang source range into a CIndex source range.
+///
+/// Clang internally represents ranges where the end location points to the
+/// start of the token at the end. However, for external clients it is more
+/// useful to have a CXSourceRange be a proper half-open interval. This routine
+/// does the appropriate translation.
+CXSourceRange translateSourceRange(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceRange R);
+
+/// \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);
+}
+
+static inline SourceRange translateCXSourceRange(CXSourceRange R) {
+ return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data),
+ SourceLocation::getFromRawEncoding(R.end_int_data));
+}
+
+
+}} // end namespace: clang::cxloc
+
+#endif
diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile
index 7bdbba172f2c..3e288623e5eb 100644
--- a/tools/CIndex/Makefile
+++ b/tools/CIndex/Makefile
@@ -11,7 +11,6 @@ LEVEL = ../../../..
LIBRARYNAME = CIndex
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
# Include this here so we can get the configuration of the targets
# that have been configured for construction. We have to do this
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 06e24053aa0a..e9ba174275a4 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -10,7 +10,6 @@ LEVEL = ../../../..
TOOLNAME = c-index-test
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
NO_INSTALL = 1
# No plugins, optimize startup time.
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 4ef390413972..d4771c77f503 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -28,10 +28,20 @@ char *basename(const char* path)
extern char *basename(const char *);
#endif
+static void PrintDiagnosticCallback(CXDiagnostic Diagnostic,
+ CXClientData ClientData);
+
+
+static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
+ unsigned end_line, unsigned end_column) {
+ fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
+ end_line, end_column);
+}
+
static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
CXTranslationUnit *TU) {
- *TU = clang_createTranslationUnit(Idx, file);
+ *TU = clang_createTranslationUnit(Idx, file, PrintDiagnosticCallback, stderr);
if (!TU) {
fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
return 0;
@@ -151,7 +161,7 @@ static void PrintCursor(CXCursor Cursor) {
Referenced = clang_getCursorReferenced(Cursor);
if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
CXSourceLocation Loc = clang_getCursorLocation(Referenced);
- clang_getInstantiationLocation(Loc, 0, &line, &column);
+ clang_getInstantiationLocation(Loc, 0, &line, &column, 0);
printf(":%d:%d", line, column);
}
@@ -164,7 +174,7 @@ static const char* GetCursorSource(CXCursor Cursor) {
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
const char *source;
CXFile file;
- clang_getInstantiationLocation(Loc, &file, 0, 0);
+ clang_getInstantiationLocation(Loc, &file, 0, 0, 0);
source = clang_getFileName(file);
if (!source)
return "<invalid loc>";
@@ -172,6 +182,131 @@ static const char* GetCursorSource(CXCursor Cursor) {
}
/******************************************************************************/
+/* Callbacks. */
+/******************************************************************************/
+
+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) {
+ unsigned i, n;
+ unsigned printed_any_ranges = 0;
+
+ fprintf(out, "%s:%d:%d:", clang_getFileName(file), line, column);
+
+ n = clang_getDiagnosticNumRanges(Diagnostic);
+ for (i = 0; i != n; ++i) {
+ CXFile start_file, end_file;
+ CXSourceRange range = clang_getDiagnosticRange(Diagnostic, i);
+
+ unsigned start_line, start_column, end_line, end_column;
+ clang_getInstantiationLocation(clang_getRangeStart(range),
+ &start_file, &start_line, &start_column,0);
+ clang_getInstantiationLocation(clang_getRangeEnd(range),
+ &end_file, &end_line, &end_column, 0);
+
+ if (start_file != end_file || start_file != file)
+ continue;
+
+ PrintExtent(out, start_line, start_column, end_line, end_column);
+ printed_any_ranges = 1;
+ }
+ if (printed_any_ranges)
+ fprintf(out, ":");
+
+ fprintf(out, " ");
+ }
+
+ /* 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);
+
+ if (file) {
+ unsigned i, num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
+ for (i = 0; i != num_fixits; ++i) {
+ switch (clang_getDiagnosticFixItKind(Diagnostic, i)) {
+ case CXFixIt_Insertion: {
+ CXSourceLocation insertion_loc;
+ CXFile insertion_file;
+ unsigned insertion_line, insertion_column;
+ text = clang_getDiagnosticFixItInsertion(Diagnostic, i, &insertion_loc);
+ clang_getInstantiationLocation(insertion_loc, &insertion_file,
+ &insertion_line, &insertion_column, 0);
+ if (insertion_file == file)
+ fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
+ clang_getCString(text), insertion_line, insertion_column);
+ clang_disposeString(text);
+ break;
+ }
+
+ case CXFixIt_Removal: {
+ CXFile start_file, end_file;
+ unsigned start_line, start_column, end_line, end_column;
+ CXSourceRange remove_range
+ = clang_getDiagnosticFixItRemoval(Diagnostic, i);
+ clang_getInstantiationLocation(clang_getRangeStart(remove_range),
+ &start_file, &start_line, &start_column,
+ 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(remove_range),
+ &end_file, &end_line, &end_column, 0);
+ if (start_file == file && end_file == file) {
+ fprintf(out, "FIX-IT: Remove ");
+ PrintExtent(out, start_line, start_column, end_line, end_column);
+ fprintf(out, "\n");
+ }
+ break;
+ }
+
+ case CXFixIt_Replacement: {
+ CXFile start_file, end_file;
+ unsigned start_line, start_column, end_line, end_column;
+ CXSourceRange remove_range;
+ text = clang_getDiagnosticFixItReplacement(Diagnostic, i,&remove_range);
+ clang_getInstantiationLocation(clang_getRangeStart(remove_range),
+ &start_file, &start_line, &start_column,
+ 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(remove_range),
+ &end_file, &end_line, &end_column, 0);
+ if (start_file == end_file) {
+ fprintf(out, "FIX-IT: Replace ");
+ PrintExtent(out, start_line, start_column, end_line, end_column);
+ fprintf(out, " with \"%s\"\n", clang_getCString(text));
+ }
+ clang_disposeString(text);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/******************************************************************************/
/* Logic for testing traversal. */
/******************************************************************************/
@@ -183,14 +318,14 @@ static void PrintCursorExtent(CXCursor C) {
unsigned begin_line, begin_column, end_line, end_column;
clang_getInstantiationLocation(clang_getRangeStart(extent),
- &begin_file, &begin_line, &begin_column);
+ &begin_file, &begin_line, &begin_column, 0);
clang_getInstantiationLocation(clang_getRangeEnd(extent),
- &end_file, &end_line, &end_column);
+ &end_file, &end_line, &end_column, 0);
if (!begin_file || !end_file)
return;
- printf(" [Extent=%d:%d:%d:%d]", begin_line, begin_column,
- end_line, end_column);
+ printf(" Extent=");
+ PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
}
/* Data used by all of the visitors. */
@@ -207,7 +342,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
unsigned line, column;
- clang_getInstantiationLocation(Loc, 0, &line, &column);
+ clang_getInstantiationLocation(Loc, 0, &line, &column, 0);
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
GetCursorSource(Cursor), line, column);
PrintCursor(Cursor);
@@ -251,7 +386,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
curColumn++;
Loc = clang_getCursorLocation(Cursor);
- clang_getInstantiationLocation(Loc, &file, 0, 0);
+ clang_getInstantiationLocation(Loc, &file, 0, 0, 0);
source = clang_getFileName(file);
if (source) {
CXSourceLocation RefLoc
@@ -297,56 +432,93 @@ enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
}
/******************************************************************************/
+/* Inclusion stack testing. */
+/******************************************************************************/
+
+void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
+ unsigned includeStackLen, CXClientData data) {
+
+ unsigned i;
+ printf("file: %s\nincluded by:\n", clang_getFileName(includedFile));
+ for (i = 0; i < includeStackLen; ++i) {
+ CXFile includingFile;
+ unsigned line, column;
+ clang_getInstantiationLocation(includeStack[i], &includingFile, &line,
+ &column, 0);
+ printf(" %s:%d:%d\n", clang_getFileName(includingFile), line, column);
+ }
+ printf("\n");
+}
+
+void PrintInclusionStack(CXTranslationUnit TU) {
+ clang_getInclusions(TU, InclusionVisitor, NULL);
+}
+
+/******************************************************************************/
/* Loading ASTs/source. */
/******************************************************************************/
static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
const char *filter, const char *prefix,
- CXCursorVisitor Visitor) {
- enum CXCursorKind K = CXCursor_NotImplemented;
- enum CXCursorKind *ck = &K;
- VisitorData Data;
+ CXCursorVisitor Visitor,
+ PostVisitTU PV) {
if (prefix)
FileCheckPrefix = prefix;
+
+ if (Visitor) {
+ enum CXCursorKind K = CXCursor_NotImplemented;
+ enum CXCursorKind *ck = &K;
+ VisitorData Data;
- /* Perform some simple filtering. */
- if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
- else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
- else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
- else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
- else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
- else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
- else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
- else {
- fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
- return 1;
+ /* Perform some simple filtering. */
+ if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
+ else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
+ else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
+ else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
+ else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
+ else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
+ else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
+ else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
+ else {
+ fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
+ return 1;
+ }
+
+ Data.TU = TU;
+ Data.Filter = ck;
+ clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
}
- Data.TU = TU;
- Data.Filter = ck;
- clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
+ if (PV)
+ PV(TU);
+
clang_disposeTranslationUnit(TU);
return 0;
}
int perform_test_load_tu(const char *file, const char *filter,
- const char *prefix,
- CXCursorVisitor Visitor) {
+ const char *prefix, CXCursorVisitor Visitor,
+ PostVisitTU PV) {
CXIndex Idx;
CXTranslationUnit TU;
+ int result;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
- !strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnostics */ 1);
+ !strcmp(filter, "local") ? 1 : 0);
- if (!CreateTranslationUnit(Idx, file, &TU))
+ if (!CreateTranslationUnit(Idx, file, &TU)) {
+ clang_disposeIndex(Idx);
return 1;
+ }
- return perform_test_load(Idx, TU, filter, prefix, Visitor);
+ result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV);
+ clang_disposeIndex(Idx);
+ return result;
}
-int perform_test_load_source(int argc, const char **argv, const char *filter,
- CXCursorVisitor Visitor) {
+int perform_test_load_source(int argc, const char **argv,
+ const char *filter, CXCursorVisitor Visitor,
+ PostVisitTU PV) {
const char *UseExternalASTs =
getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
CXIndex Idx;
@@ -356,27 +528,32 @@ int perform_test_load_source(int argc, const char **argv, const char *filter,
int result;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
- !strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnostics */ 1);
+ !strcmp(filter, "local") ? 1 : 0);
if (UseExternalASTs && strlen(UseExternalASTs))
clang_setUseExternalASTGeneration(Idx, 1);
- if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files))
+ if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
+ clang_disposeIndex(Idx);
return -1;
+ }
TU = clang_createTranslationUnitFromSourceFile(Idx, 0,
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");
+ clang_disposeIndex(Idx);
return 1;
}
- result = perform_test_load(Idx, TU, filter, NULL, Visitor);
+ result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
free_remapped_files(unsaved_files, num_unsaved_files);
+ clang_disposeIndex(Idx);
return result;
}
@@ -391,8 +568,8 @@ static void print_cursor_file_scan(CXCursor cursor,
printf("// %s: ", FileCheckPrefix);
if (prefix)
printf("-%s", prefix);
- printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
- start_line, start_col, end_line, end_col);
+ PrintExtent(stdout, start_line, start_col, end_line, end_col);
+ printf(" ");
PrintCursor(cursor);
printf("\n");
}
@@ -402,15 +579,12 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
CXIndex Idx;
CXTranslationUnit TU;
FILE *fp;
- unsigned line;
- CXCursor prevCursor;
+ CXCursor prevCursor = clang_getNullCursor();
CXFile file;
- unsigned printed;
- unsigned start_line, start_col, last_line, last_col;
- size_t i;
+ unsigned line = 1, col = 1;
+ unsigned start_line = 1, start_col = 1;
- if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnostics */ 1))) {
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -423,52 +597,34 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
return 1;
}
- line = 0;
- prevCursor = clang_getNullCursor();
- printed = 0;
- start_line = last_line = 1;
- start_col = last_col = 1;
-
file = clang_getFile(TU, source_file);
- while (!feof(fp)) {
- size_t len = 0;
- int c;
+ for (;;) {
+ CXCursor cursor;
+ int c = fgetc(fp);
- while ((c = fgetc(fp)) != EOF) {
- len++;
- if (c == '\n')
- break;
+ if (c == '\n') {
+ ++line;
+ col = 1;
+ } else
+ ++col;
+
+ /* Check the cursor at this position, and dump the previous one if we have
+ * found something new.
+ */
+ cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
+ if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
+ prevCursor.kind != CXCursor_InvalidFile) {
+ print_cursor_file_scan(prevCursor, start_line, start_col,
+ line, col, prefix);
+ start_line = line;
+ start_col = col;
}
+ if (c == EOF)
+ break;
- ++line;
-
- for (i = 0; i < len ; ++i) {
- CXCursor cursor;
- cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, i+1));
-
- if (!clang_equalCursors(cursor, prevCursor) &&
- prevCursor.kind != CXCursor_InvalidFile) {
- print_cursor_file_scan(prevCursor, start_line, start_col,
- last_line, last_col, prefix);
- printed = 1;
- start_line = line;
- start_col = (unsigned) i+1;
- }
- else {
- printed = 0;
- }
-
- prevCursor = cursor;
- last_line = line;
- last_col = (unsigned) i+1;
- }
+ prevCursor = cursor;
}
- if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
- print_cursor_file_scan(prevCursor, start_line, start_col,
- last_line, last_col, prefix);
- }
-
fclose(fp);
return 0;
}
@@ -481,42 +637,62 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
on failure. If successful, the pointer *filename will contain newly-allocated
memory (that will be owned by the caller) to store the file name. */
int parse_file_line_column(const char *input, char **filename, unsigned *line,
- unsigned *column) {
+ unsigned *column, unsigned *second_line,
+ unsigned *second_column) {
/* Find the second colon. */
- const char *second_colon = strrchr(input, ':'), *first_colon;
+ const char *last_colon = strrchr(input, ':');
+ unsigned values[4], i;
+ unsigned num_values = (second_line && second_column)? 4 : 2;
+
char *endptr = 0;
- if (!second_colon || second_colon == input) {
- fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
+ if (!last_colon || last_colon == input) {
+ if (num_values == 4)
+ fprintf(stderr, "could not parse filename:line:column:line:column in "
+ "'%s'\n", input);
+ else
+ fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
return 1;
}
- /* Parse the column number. */
- *column = strtol(second_colon + 1, &endptr, 10);
- if (*endptr != 0) {
- fprintf(stderr, "could not parse column in '%s'\n", input);
- return 1;
- }
+ for (i = 0; i != num_values; ++i) {
+ const char *prev_colon;
- /* Find the first colon. */
- first_colon = second_colon - 1;
- while (first_colon != input && *first_colon != ':')
- --first_colon;
- if (first_colon == input) {
- fprintf(stderr, "could not parse line in '%s'\n", input);
- return 1;
- }
+ /* Parse the next line or column. */
+ values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
+ if (*endptr != 0 && *endptr != ':') {
+ fprintf(stderr, "could not parse %s in '%s'\n",
+ (i % 2 ? "column" : "line"), input);
+ return 1;
+ }
+
+ if (i + 1 == num_values)
+ break;
- /* Parse the line number. */
- *line = strtol(first_colon + 1, &endptr, 10);
- if (*endptr != ':') {
- fprintf(stderr, "could not parse line in '%s'\n", input);
- return 1;
+ /* Find the previous colon. */
+ prev_colon = last_colon - 1;
+ while (prev_colon != input && *prev_colon != ':')
+ --prev_colon;
+ if (prev_colon == input) {
+ fprintf(stderr, "could not parse %s in '%s'\n",
+ (i % 2 == 0? "column" : "line"), input);
+ return 1;
+ }
+
+ last_colon = prev_colon;
}
+
+ *line = values[0];
+ *column = values[1];
+ if (second_line && second_column) {
+ *second_line = values[2];
+ *second_column = values[3];
+ }
+
/* Copy the file name. */
- *filename = (char*)malloc(first_colon - input + 1);
- memcpy(*filename, input, first_colon - input);
- (*filename)[first_colon - input] = 0;
+ *filename = (char*)malloc(last_colon - input + 1);
+ memcpy(*filename, input, last_colon - input);
+ (*filename)[last_colon - input] = 0;
return 0;
}
@@ -595,18 +771,21 @@ int perform_code_completion(int argc, const char **argv) {
CXCodeCompleteResults *results = 0;
input += strlen("-code-completion-at=");
- if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
+ if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
+ 0, 0)))
return errorCode;
if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
return -1;
- CIdx = clang_createIndex(0, 0);
+ CIdx = clang_createIndex(0);
results = clang_codeComplete(CIdx,
argv[argc - 1], argc - num_unsaved_files - 3,
argv + num_unsaved_files + 2,
num_unsaved_files, unsaved_files,
- filename, line, column);
+ filename, line, column,
+ PrintDiagnosticCallback, stderr);
+
if (results) {
unsigned i, n = results->NumResults;
for (i = 0; i != n; ++i)
@@ -650,7 +829,7 @@ int inspect_cursor_at(int argc, const char **argv) {
const char *input = argv[Loc + 1] + strlen("-cursor-at=");
if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
&Locations[Loc].line,
- &Locations[Loc].column)))
+ &Locations[Loc].column, 0, 0)))
return errorCode;
}
@@ -658,12 +837,14 @@ int inspect_cursor_at(int argc, const char **argv) {
&num_unsaved_files))
return -1;
- CIdx = clang_createIndex(0, 1);
+ CIdx = clang_createIndex(0);
TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 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;
@@ -689,6 +870,111 @@ int inspect_cursor_at(int argc, const char **argv) {
return 0;
}
+int perform_token_annotation(int argc, const char **argv) {
+ const char *input = argv[1];
+ char *filename = 0;
+ unsigned line, second_line;
+ unsigned column, second_column;
+ CXIndex CIdx;
+ CXTranslationUnit TU = 0;
+ int errorCode;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ CXToken *tokens;
+ unsigned num_tokens;
+ CXSourceRange range;
+ CXSourceLocation startLoc, endLoc;
+ CXFile file = 0;
+ CXCursor *cursors = 0;
+ unsigned i;
+
+ input += strlen("-test-annotate-tokens=");
+ if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
+ &second_line, &second_column)))
+ return errorCode;
+
+ if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
+ return -1;
+
+ CIdx = clang_createIndex(0);
+ TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
+ argc - num_unsaved_files - 3,
+ argv + num_unsaved_files + 2,
+ num_unsaved_files,
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
+ if (!TU) {
+ fprintf(stderr, "unable to parse input\n");
+ clang_disposeIndex(CIdx);
+ free(filename);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return -1;
+ }
+ errorCode = 0;
+
+ file = clang_getFile(TU, filename);
+ if (!file) {
+ fprintf(stderr, "file %s is not in this translation unit\n", filename);
+ errorCode = -1;
+ goto teardown;
+ }
+
+ startLoc = clang_getLocation(TU, file, line, column);
+ if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
+ fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
+ column);
+ errorCode = -1;
+ goto teardown;
+ }
+
+ endLoc = clang_getLocation(TU, file, second_line, second_column);
+ if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
+ fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
+ second_line, second_column);
+ errorCode = -1;
+ goto teardown;
+ }
+
+ range = clang_getRange(startLoc, endLoc);
+ clang_tokenize(TU, range, &tokens, &num_tokens);
+ cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
+ clang_annotateTokens(TU, tokens, num_tokens, cursors);
+ for (i = 0; i != num_tokens; ++i) {
+ const char *kind = "<unknown>";
+ CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
+ CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
+ unsigned start_line, start_column, end_line, end_column;
+
+ switch (clang_getTokenKind(tokens[i])) {
+ case CXToken_Punctuation: kind = "Punctuation"; break;
+ case CXToken_Keyword: kind = "Keyword"; break;
+ case CXToken_Identifier: kind = "Identifier"; break;
+ case CXToken_Literal: kind = "Literal"; break;
+ case CXToken_Comment: kind = "Comment"; break;
+ }
+ clang_getInstantiationLocation(clang_getRangeStart(extent),
+ 0, &start_line, &start_column, 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(extent),
+ 0, &end_line, &end_column, 0);
+ printf("%s: \"%s\" ", kind, clang_getCString(spelling));
+ PrintExtent(stdout, start_line, start_column, end_line, end_column);
+ if (!clang_isInvalid(cursors[i].kind)) {
+ printf(" ");
+ PrintCursor(cursors[i]);
+ }
+ printf("\n");
+ }
+ free(cursors);
+
+ teardown:
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(CIdx);
+ free(filename);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return errorCode;
+}
+
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -712,8 +998,11 @@ static void print_usage(void) {
" c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
"[FileCheck prefix]\n"
" c-index-test -test-load-source <symbol filter> {<args>}*\n"
- " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n");
+ " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n");
fprintf(stderr,
+ " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
+ " c-index-test -test-inclusion-stack-source {<args>}*\n"
+ " c-index-test -test-inclusion-stack-tu <AST file>\n\n"
" <symbol filter> values:\n%s",
" all - load all symbols, including those from PCH\n"
" local - load all symbols except those in PCH\n"
@@ -733,17 +1022,26 @@ int main(int argc, const char **argv) {
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
- return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I);
+ return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
+ NULL);
}
else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 17);
if (I)
- return perform_test_load_source(argc - 3, argv + 3, argv[2], I);
+ return perform_test_load_source(argc - 3, argv + 3, argv[2], I, NULL);
}
else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
return perform_file_scan(argv[2], argv[3],
argc >= 5 ? argv[4] : 0);
-
+ else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
+ return perform_token_annotation(argc, argv);
+ else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
+ PrintInclusionStack);
+ else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
+ return perform_test_load_tu(argv[2], "all", NULL, NULL,
+ PrintInclusionStack);
+
print_usage();
return 1;
}
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 90fb09c0d9a8..c4320b0c905c 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,12 +1,13 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
- clangDriver
clangFrontend
+ clangDriver
clangCodeGen
+ clangSema
+ clangChecker
clangAnalysis
clangRewrite
- clangSema
clangAST
clangParse
clangLex
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 6ec82918c075..e5a9280a0cbe 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -13,7 +13,6 @@ ifndef CLANG_IS_PRODUCTION
TOOLALIAS = clang++
endif
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
# Clang tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
@@ -24,9 +23,9 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
-USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangAnalysis.a \
- clangRewrite.a clangSema.a clangAST.a clangParse.a \
- clangLex.a clangBasic.a
+USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \
+ clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \
+ clangParse.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index d2f1017c2151..05fb6984d416 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -51,7 +51,7 @@ void LLVMErrorHandler(void *UserData, const std::string &Message) {
exit(1);
}
-static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
switch (CI.getFrontendOpts().ProgramAction) {
@@ -70,6 +70,7 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
case EmitHTML: return new HTMLPrintAction();
case EmitLLVM: return new EmitLLVMAction();
case EmitLLVMOnly: return new EmitLLVMOnlyAction();
+ case EmitObj: return new EmitObjAction();
case FixIt: return new FixItAction();
case GeneratePCH: return new GeneratePCHAction();
case GeneratePTH: return new GeneratePTHAction();
@@ -111,6 +112,21 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
}
}
+static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+ // Create the underlying action.
+ FrontendAction *Act = CreateFrontendBaseAction(CI);
+ if (!Act)
+ return 0;
+
+ // If there are any AST files to merge, create a frontend action
+ // adaptor to perform the merge.
+ if (!CI.getFrontendOpts().ASTMergeFiles.empty())
+ Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0],
+ CI.getFrontendOpts().ASTMergeFiles.size());
+
+ return Act;
+}
+
// FIXME: Define the need for this testing away.
static int cc1_test(Diagnostic &Diags,
const char **ArgBegin, const char **ArgEnd) {
@@ -179,7 +195,9 @@ static int cc1_test(Diagnostic &Diags,
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
- CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ CompilerInstance Clang;
+
+ Clang.setLLVMContext(new llvm::LLVMContext);
// Run clang -cc1 test.
if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") {
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index f19dcb4718cb..8c64d3ffefda 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -403,7 +403,7 @@ if ($Status) { exit($Status >> 8); }
# Get the analysis options.
my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
-if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
+if (!defined($Analyses)) { $Analyses = '-analyzer-check-objc-mem'; }
# Get the store model.
my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
@@ -597,9 +597,12 @@ if ($Action eq 'compile' or $Action eq 'link') {
}
}
+ # FileLang still not defined? Skip the file.
next if (!defined $FileLang);
+
+ # Language not accepted?
next if (!defined $LangsAccepted{$FileLang});
-
+
my @CmdArgs;
my @AnalyzeArgs;
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index f978a888be83..432456b15fe7 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -82,52 +82,45 @@ sub DieDiag {
# Find 'clang'
my $ClangSB = Cwd::realpath("$RealBin/bin/clang");
-my $ClangCXXSB;
if (!defined $ClangSB || ! -x $ClangSB) {
$ClangSB = Cwd::realpath("$RealBin/clang");
- if (defined $ClangSB) { $ClangCXXSB = $ClangSB . "++"; }
}
-my $Clang = $ClangSB;
-my $ClangCXX = $ClangCXXSB;
-# Default to looking for 'clang' in the path.
-if (!defined $Clang || ! -x $Clang) {
- $Clang = "clang";
- $ClangCXX = "clang++";
+my $Clang;
+if (!defined $ClangSB || ! -x $ClangSB) {
+ # Default to looking for 'clang' in the path.
+ $Clang = `which clang`;
+ chomp $Clang;
+ if ($Clang eq "") {
+ DieDiag("No 'clang' executable found in path.");
+ }
+}
+else {
+ $Clang = $ClangSB;
}
+my $ClangCXX = $Clang . "++";
my %AvailableAnalyses;
# Query clang for analysis options.
-open(PIPE, "-|", $Clang, "-cc1", "--help") or
+open(PIPE, "-|", $Clang, "-cc1", "-help") or
DieDiag("Cannot execute '$Clang'\n");
-my $FoundAnalysis = 0;
-
while(<PIPE>) {
- if ($FoundAnalysis == 0) {
- if (/Checks and Analyses/) {
- $FoundAnalysis = 1;
- }
- next;
- }
- if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
- next if ($1 =~ /-dump/ or $1 =~ /-view/
- or $1 =~ /-warn-uninit/);
- $AvailableAnalyses{$1} = $2;
+ if (/(-analyzer-check-[^\s]+)/) {
+ $AvailableAnalyses{$1} = 1;
next;
}
- last;
}
close (PIPE);
my %AnalysesDefaultEnabled = (
- '-warn-dead-stores' => 1,
- '-checker-cfref' => 1,
- '-warn-objc-methodsigs' => 1,
+ '-analyzer-check-dead-stores' => 1,
+ '-analyzer-check-objc-mem' => 1,
+ '-analyzer-check-objc-methodsigs' => 1,
# Do not enable the missing -dealloc check by default.
- # '-warn-objc-missing-dealloc' => 1,
- '-warn-objc-unused-ivars' => 1,
- '-warn-security-syntactic' => 1
+ # '-analyzer-check-objc-missing-dealloc' => 1,
+ '-analyzer-check-objc-unused-ivars' => 1,
+ '-analyzer-check-security-syntactic' => 1
);
##----------------------------------------------------------------------------##
@@ -853,10 +846,6 @@ sub RunBuildCommand {
# When 'CC' is set, xcodebuild uses it to do all linking, even if we are
# linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
# when linking such files.
- if (!defined $ENV{'CCC_CXX'}) {
- $ENV{'CCC_CXX'} = 'g++';
- }
- $ENV{'LDPLUSPLUS'} = $ENV{'CCC_CXX'};
}
return (system(@$Args) >> 8);
@@ -951,7 +940,7 @@ ENDTEXT
print " ";
}
- print " $Analysis $AvailableAnalyses{$Analysis}\n";
+ print " $Analysis\n";
}
print <<ENDTEXT
@@ -1203,7 +1192,7 @@ if (!defined $CmdCXX || ! -x $CmdCXX) {
if (!defined $ClangSB || ! -x $ClangSB) {
Diag("'clang' executable not found in '$RealBin/bin'.\n");
- Diag("Using 'clang' from path.\n");
+ Diag("Using 'clang' from path: $Clang\n");
}
$ENV{'CC'} = $Cmd;
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
new file mode 100755
index 000000000000..cc068a56adf9
--- /dev/null
+++ b/tools/scan-build/set-xcode-analyzer
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import re
+import tempfile
+import shutil
+import stat
+from AppKit import *
+
+def FindClangSpecs(path):
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
+ yield os.path.join(root, f)
+
+def ModifySpec(path, pathToChecker):
+ t = tempfile.NamedTemporaryFile(delete=False)
+ foundAnalyzer = False
+ with open(path) as f:
+ for line in f:
+ if not foundAnalyzer:
+ if line.find("Static Analyzer") >= 0:
+ foundAnalyzer = True
+ else:
+ m = re.search('^(\s*ExecPath\s*=\s*")', line)
+ if m:
+ line = "".join([m.group(0), pathToChecker, '";\n'])
+ t.write(line)
+ t.close()
+ print "(+) processing:", path
+ try:
+ shutil.copy(t.name, path)
+ os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
+ except IOError, why:
+ print " (-) Cannot update file:", why, "\n"
+ except OSError, why:
+ print " (-) Cannot update file:", why, "\n"
+ os.unlink(t.name)
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser('usage: %prog [options]')
+ parser.set_description(__doc__)
+ parser.add_option("--use-checker-build", dest="path",
+ help="Use the Clang located at the provided absolute path, e.g. /Users/foo/checker-1")
+ parser.add_option("--use-xcode-clang", action="store_const",
+ const="$(CLANG)", dest="default",
+ help="Use the Clang bundled with Xcode")
+ (options, args) = parser.parse_args()
+ if options.path is None and options.default is None:
+ parser.error("You must specify a version of Clang to use for static analysis. Specify '-h' for details")
+
+ # determine if Xcode is running
+ for x in NSWorkspace.sharedWorkspace().runningApplications():
+ if x.localizedName().find("Xcode") >= 0:
+ print "(-) You must quit Xcode first before modifying its configuration files."
+ return
+
+ if options.path:
+ # Expand tildes.
+ path = os.path.expanduser(options.path)
+ if not path.endswith("clang"):
+ print "(+) Using Clang bundled with checker build:", path
+ path = os.path.join(path, "bin", "clang");
+ else:
+ print "(+) Using Clang located at:", path
+ else:
+ print "(+) Using the Clang bundled with Xcode"
+ path = options.default
+
+ for x in FindClangSpecs('/Developer'):
+ ModifySpec(x, path)
+
+if __name__ == '__main__':
+ main()
+