From df90325d4c0a65ee64d2dae3ed9b5b34f7418533 Mon Sep 17 00:00:00 2001 From: rdivacky Date: Wed, 3 Mar 2010 17:28:16 +0000 Subject: Update clang to 97654. --- tools/CIndex/CIndex.cpp | 808 +++++++++++++++++++--------------- tools/CIndex/CIndex.exports | 14 +- tools/CIndex/CIndexCodeCompletion.cpp | 104 +++-- tools/CIndex/CIndexDiagnostic.cpp | 327 +++++++------- tools/CIndex/CIndexDiagnostic.h | 48 +- tools/CIndex/CIndexUSRs.cpp | 10 +- tools/CIndex/CIndexer.h | 23 +- tools/CIndex/CMakeLists.txt | 1 + tools/CIndex/CXCursor.cpp | 17 + tools/CIndex/CXCursor.h | 6 +- tools/c-index-test/c-index-test.c | 468 ++++++++++---------- tools/driver/cc1_main.cpp | 3 +- tools/driver/driver.cpp | 66 ++- tools/scan-build/ccc-analyzer | 2 + 14 files changed, 1050 insertions(+), 847 deletions(-) (limited to 'tools') diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index f9995eb..6fc7b53 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -27,12 +27,14 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Program.h" +#include "llvm/System/Signals.h" // Needed to define L_TMPNAM on some systems. #include using namespace clang; using namespace clang::cxcursor; +using namespace clang::cxstring; using namespace idx; //===----------------------------------------------------------------------===// @@ -40,12 +42,11 @@ using namespace idx; //===----------------------------------------------------------------------===// #ifdef __APPLE__ -#ifndef NDEBUG #define USE_CRASHTRACER #include "clang/Analysis/Support/SaveAndRestore.h" // Integrate with crash reporter. extern "C" const char *__crashreporter_info__; -#define NUM_CRASH_STRINGS 16 +#define NUM_CRASH_STRINGS 32 static unsigned crashtracer_counter = 0; static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 }; static const char *crashtracer_strings[NUM_CRASH_STRINGS] = { 0 }; @@ -53,7 +54,7 @@ static const char *agg_crashtracer_strings[NUM_CRASH_STRINGS] = { 0 }; static unsigned SetCrashTracerInfo(const char *str, llvm::SmallString<1024> &AggStr) { - + unsigned slot = 0; while (crashtracer_strings[slot]) { if (++slot == NUM_CRASH_STRINGS) @@ -68,7 +69,7 @@ static unsigned SetCrashTracerInfo(const char *str, // of this function. Race conditions can still cause this goal // to not be achieved. { - llvm::raw_svector_ostream Out(AggStr); + llvm::raw_svector_ostream Out(AggStr); for (unsigned i = 0; i < NUM_CRASH_STRINGS; ++i) if (crashtracer_strings[i]) Out << crashtracer_strings[i] << '\n'; } @@ -79,7 +80,7 @@ static unsigned SetCrashTracerInfo(const char *str, static void ResetCrashTracerInfo(unsigned slot) { unsigned max_slot = 0; unsigned max_value = 0; - + crashtracer_strings[slot] = agg_crashtracer_strings[slot] = 0; for (unsigned i = 0 ; i < NUM_CRASH_STRINGS; ++i) @@ -111,31 +112,30 @@ public: crashtracerSlot = SetCrashTracerInfo(CrashString.c_str(), AggregateString); } - + ~ArgsCrashTracerInfo() { ResetCrashTracerInfo(crashtracerSlot); } }; } #endif -#endif /// \brief The result of comparing two source ranges. enum RangeComparisonResult { /// \brief Either the ranges overlap or one of the ranges is invalid. RangeOverlap, - + /// \brief The first range ends before the second range starts. RangeBefore, - + /// \brief The first range starts after the second range ends. RangeAfter }; -/// \brief Compare two source ranges to determine their relative position in +/// \brief Compare two source ranges to determine their relative position in /// the translation unit. -static RangeComparisonResult RangeCompare(SourceManager &SM, - SourceRange R1, +static RangeComparisonResult RangeCompare(SourceManager &SM, + SourceRange R1, SourceRange R2) { assert(R1.isValid() && "First range is invalid?"); assert(R2.isValid() && "Second range is invalid?"); @@ -154,7 +154,7 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, /// 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, +CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R) { // FIXME: This is largely copy-paste from @@ -196,7 +196,7 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, //===----------------------------------------------------------------------===// namespace { - + // Cursor visitor. class CursorVisitor : public DeclVisitor, public TypeLocVisitor, @@ -204,20 +204,20 @@ class CursorVisitor : public DeclVisitor, { /// \brief The translation unit we are traversing. ASTUnit *TU; - + /// \brief The parent cursor whose children we are traversing. CXCursor Parent; - + /// \brief The declaration that serves at the parent of any statement or /// expression nodes. Decl *StmtParent; - + /// \brief The visitor function. CXCursorVisitor Visitor; - + /// \brief The opaque client data, to be passed along to the visitor. CXClientData ClientData; - + // MaxPCHLevel - the maximum PCH level of declarations that we will pass on // to the visitor. Declarations with a PCH level greater than this value will // be suppressed. @@ -226,22 +226,22 @@ class CursorVisitor : public DeclVisitor, /// \brief When valid, a source range to which the cursor should restrict /// its search. SourceRange RegionOfInterest; - + using DeclVisitor::Visit; using TypeLocVisitor::Visit; using StmtVisitor::Visit; - - /// \brief Determine whether this particular source range comes before, comes - /// after, or overlaps the region of interest. + + /// \brief Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. /// /// \param R a half-open source range retrieved from the abstract syntax tree. - RangeComparisonResult CompareRegionOfInterest(SourceRange R); - + RangeComparisonResult CompareRegionOfInterest(SourceRange R); + public: - CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, - unsigned MaxPCHLevel, + CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, + unsigned MaxPCHLevel, SourceRange RegionOfInterest = SourceRange()) - : TU(TU), Visitor(Visitor), ClientData(ClientData), + : TU(TU), Visitor(Visitor), ClientData(ClientData), MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest) { Parent.kind = CXCursor_NoDeclFound; @@ -250,11 +250,12 @@ public: Parent.data[2] = 0; StmtParent = 0; } - + bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); bool VisitChildren(CXCursor Parent); - + // Declaration visitors + bool VisitAttributes(Decl *D); bool VisitDeclContext(DeclContext *DC); bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTypedefDecl(TypedefDecl *D); @@ -299,7 +300,7 @@ public: // implemented bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL); - + // Statement visitors bool VisitStmt(Stmt *S); bool VisitDeclStmt(DeclStmt *S); @@ -308,13 +309,13 @@ public: bool VisitSwitchStmt(SwitchStmt *S); bool VisitWhileStmt(WhileStmt *S); bool VisitForStmt(ForStmt *S); - + // Expression visitors bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); bool VisitExplicitCastExpr(ExplicitCastExpr *E); bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); }; - + } // end anonymous namespace RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { @@ -334,7 +335,7 @@ RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { if (clang_isInvalid(Cursor.kind)) return false; - + if (clang_isDeclaration(Cursor.kind)) { Decl *D = getCursorDecl(Cursor); assert(D && "Invalid declaration cursor"); @@ -353,7 +354,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { if (Range.isInvalid() || CompareRegionOfInterest(Range)) return false; } - + switch (Visitor(Cursor, Parent, ClientData)) { case CXChildVisit_Break: return true; @@ -372,13 +373,13 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { /// /// \returns true if the visitation should be aborted, false if it /// should continue. -bool CursorVisitor::VisitChildren(CXCursor Cursor) { +bool CursorVisitor::VisitChildren(CXCursor Cursor) { if (clang_isReference(Cursor.kind)) { // By definition, references have no children. return false; } - - // Set the Parent field to Cursor, then back to its old value once we're + + // Set the Parent field to Cursor, then back to its old value once we're // done. class SetParentRAII { CXCursor &Parent; @@ -387,31 +388,31 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { public: SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) - : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) + : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) { Parent = NewParent; if (clang_isDeclaration(Parent.kind)) StmtParent = getCursorDecl(Parent); } - + ~SetParentRAII() { Parent = OldParent; if (clang_isDeclaration(Parent.kind)) StmtParent = getCursorDecl(Parent); } } SetParent(Parent, StmtParent, Cursor); - + if (clang_isDeclaration(Cursor.kind)) { Decl *D = getCursorDecl(Cursor); assert(D && "Invalid declaration cursor"); - return Visit(D); + return VisitAttributes(D) || Visit(D); } - + if (clang_isStatement(Cursor.kind)) return Visit(getCursorStmt(Cursor)); if (clang_isExpression(Cursor.kind)) return Visit(getCursorExpr(Cursor)); - + if (clang_isTranslationUnit(Cursor.kind)) { ASTUnit *CXXUnit = getCursorASTUnit(Cursor); if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && @@ -426,10 +427,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { return VisitDeclContext( CXXUnit->getASTContext().getTranslationUnitDecl()); } - + return false; } - + // Nothing to visit at the moment. return false; } @@ -437,6 +438,7 @@ 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()) { @@ -449,21 +451,21 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { case RangeBefore: // This declaration comes before the region of interest; skip it. continue; - + case RangeAfter: // This declaration comes after the region of interest; we're done. return false; - + case RangeOverlap: // This declaration overlaps the region of interest; visit it. break; - } + } } - + if (Visit(Cursor, true)) return true; } - + return false; } @@ -475,7 +477,7 @@ bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) { if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) return Visit(TSInfo->getTypeLoc()); - + return false; } @@ -504,45 +506,45 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { if (ND->isThisDeclarationADefinition() && Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) return true; - + return false; } bool CursorVisitor::VisitFieldDecl(FieldDecl *D) { if (VisitDeclaratorDecl(D)) return true; - + if (Expr *BitWidth = D->getBitWidth()) return Visit(MakeCXCursor(BitWidth, StmtParent, TU)); - + return false; } bool CursorVisitor::VisitVarDecl(VarDecl *D) { if (VisitDeclaratorDecl(D)) return true; - + if (Expr *Init = D->getInit()) return Visit(MakeCXCursor(Init, StmtParent, TU)); - + return false; } bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { // FIXME: We really need a TypeLoc covering Objective-C method declarations. - // At the moment, we don't have information about locations in the return + // At the moment, we don't have information about locations in the return // type. - for (ObjCMethodDecl::param_iterator P = ND->param_begin(), + for (ObjCMethodDecl::param_iterator P = ND->param_begin(), PEnd = ND->param_end(); P != PEnd; ++P) { if (Visit(MakeCXCursor(*P, TU))) return true; } - + if (ND->isThisDeclarationADefinition() && Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) return true; - + return false; } @@ -554,13 +556,13 @@ bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(), TU))) return true; - + ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), E = ND->protocol_end(); I != E; ++I, ++PL) if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) return true; - + return VisitObjCContainerDecl(ND); } @@ -570,7 +572,7 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { E = PID->protocol_end(); I != E; ++I, ++PL) if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) return true; - + return VisitObjCContainerDecl(PID); } @@ -578,16 +580,16 @@ bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Issue callbacks for super class. if (D->getSuperClass() && Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), - D->getSuperClassLoc(), + D->getSuperClassLoc(), TU))) return true; - + ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I, ++PL) if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) return true; - + return VisitObjCContainerDecl(D); } @@ -596,10 +598,10 @@ bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) { } bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - if (Visit(MakeCursorObjCClassRef(D->getCategoryDecl()->getClassInterface(), + if (Visit(MakeCursorObjCClassRef(D->getCategoryDecl()->getClassInterface(), D->getLocation(), TU))) return true; - + return VisitObjCImplDecl(D); } @@ -609,11 +611,11 @@ bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { // FIXME: No source location information! if (D->getSuperClass() && Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), - D->getSuperClassLoc(), + D->getSuperClassLoc(), TU))) return true; #endif - + return VisitObjCImplDecl(D); } @@ -624,15 +626,15 @@ bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { I != E; ++I, ++PL) if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) return true; - - return false; + + return false; } bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) { for (ObjCClassDecl::iterator C = D->begin(), CEnd = D->end(); C != CEnd; ++C) if (Visit(MakeCursorObjCClassRef(C->getInterface(), C->getLocation(), TU))) return true; - + return false; } @@ -662,8 +664,8 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { case BuiltinType::Long: case BuiltinType::LongLong: case BuiltinType::Int128: - case BuiltinType::Float: - case BuiltinType::Double: + case BuiltinType::Float: + case BuiltinType::Double: case BuiltinType::LongDouble: case BuiltinType::NullPtr: case BuiltinType::Overload: @@ -688,7 +690,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { if (!VisitType.isNull()) { if (const TypedefType *Typedef = VisitType->getAs()) - return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(), + return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(), TU)); } @@ -726,13 +728,13 @@ bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { if (TL.hasProtocolsAsWritten()) { for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { - if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), + if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), TU))) return true; } } - + return false; } @@ -749,11 +751,11 @@ bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { } bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { - return Visit(TL.getPointeeLoc()); + return Visit(TL.getPointeeLoc()); } bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { - return Visit(TL.getPointeeLoc()); + return Visit(TL.getPointeeLoc()); } bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) { @@ -794,7 +796,7 @@ bool CursorVisitor::VisitStmt(Stmt *S) { if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU))) return true; } - + return false; } @@ -804,7 +806,7 @@ bool CursorVisitor::VisitDeclStmt(DeclStmt *S) { if (*D && Visit(MakeCXCursor(*D, TU))) return true; } - + return false; } @@ -812,8 +814,8 @@ bool CursorVisitor::VisitIfStmt(IfStmt *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->getThen() && Visit(MakeCXCursor(S->getThen(), StmtParent, TU))) @@ -828,13 +830,13 @@ bool CursorVisitor::VisitSwitchStmt(SwitchStmt *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; } @@ -842,8 +844,8 @@ 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))) @@ -858,15 +860,15 @@ bool CursorVisitor::VisitForStmt(ForStmt *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->getInc() && Visit(MakeCXCursor(S->getInc(), StmtParent, TU))) return true; if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU))) return true; - + return false; } @@ -874,10 +876,10 @@ bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (E->isArgumentType()) { if (TypeSourceInfo *TSInfo = E->getArgumentTypeInfo()) return Visit(TSInfo->getTypeLoc()); - + return false; } - + return VisitExpr(E); } @@ -885,7 +887,7 @@ bool CursorVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { if (TypeSourceInfo *TSInfo = E->getTypeInfoAsWritten()) if (Visit(TSInfo->getTypeLoc())) return true; - + return VisitCastExpr(E); } @@ -893,42 +895,26 @@ bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { if (TypeSourceInfo *TSInfo = E->getTypeSourceInfo()) if (Visit(TSInfo->getTypeLoc())) return true; - + return VisitExpr(E); } -CXString CIndexer::createCXString(const char *String, bool DupString){ - CXString Str; - if (DupString) { - Str.Spelling = strdup(String); - Str.MustFreeString = 1; - } else { - Str.Spelling = String; - Str.MustFreeString = 0; - } - return Str; -} +bool CursorVisitor::VisitAttributes(Decl *D) { + for (const Attr *A = D->getAttrs(); A; A = A->getNext()) + if (Visit(MakeCXCursor(A, D, TU))) + return true; -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; + return false; } extern "C" { -CXIndex clang_createIndex(int excludeDeclarationsFromPCH) { +CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics) { CIndexer *CIdxr = new CIndexer(); if (excludeDeclarationsFromPCH) CIdxr->setOnlyLocalDecls(); + if (displayDiagnostics) + CIdxr->setDisplayDiagnostics(); return CIdxr; } @@ -945,23 +931,19 @@ void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) { } CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, - const char *ast_filename, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data) { + const char *ast_filename) { if (!CIdx) return 0; - + CIndexer *CXXIdx = static_cast(CIdx); // Configure the diagnostics. DiagnosticOptions DiagOpts; llvm::OwningPtr 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()); + CXXIdx->getOnlyLocalDecls(), + 0, 0, true); } CXTranslationUnit @@ -970,31 +952,27 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, int num_command_line_args, const char **command_line_args, unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data) { + struct CXUnsavedFile *unsaved_files) { if (!CIdx) return 0; - + CIndexer *CXXIdx = static_cast(CIdx); // Configure the diagnostics. DiagnosticOptions DiagOpts; llvm::OwningPtr Diags; Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); - CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data); - Diags->setClient(&DiagClient); - + llvm::SmallVector RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { - const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, - unsaved_files[I].Contents + unsaved_files[I].Length, - unsaved_files[I].Filename); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(unsaved_files[I].Contents, + unsaved_files[I].Contents + unsaved_files[I].Length, + unsaved_files[I].Filename); RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, Buffer)); } - + if (!CXXIdx->getUseExternalASTGeneration()) { llvm::SmallVector Args; @@ -1007,23 +985,42 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, command_line_args + num_command_line_args); unsigned NumErrors = Diags->getNumErrors(); - + #ifdef USE_CRASHTRACER ArgsCrashTracerInfo ACTI(Args); #endif - + llvm::OwningPtr Unit( ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(), - *Diags, + *Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), - RemappedFiles.size())); - + RemappedFiles.size(), + /*CaptureDiagnostics=*/true)); + // FIXME: Until we have broader testing, just drop the entire AST if we // encountered an error. - if (NumErrors != Diags->getNumErrors()) + if (NumErrors != Diags->getNumErrors()) { + if (CXXIdx->getDisplayDiagnostics()) { + for (ASTUnit::diag_iterator D = Unit->diag_begin(), + DEnd = Unit->diag_end(); + D != DEnd; ++D) { + CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOptions()); + CXString Msg = clang_formatDiagnostic(&Diag, + clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); + } +#ifdef LLVM_ON_WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif + } return 0; + } return Unit.take(); } @@ -1054,12 +1051,12 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, std::vector RemapArgs; if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) return 0; - + // The pointers into the elements of RemapArgs are stable because we // won't be adding anything to RemapArgs after this point. for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) argv.push_back(RemapArgs[i].c_str()); - + // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. for (int i = 0; i < num_command_line_args; ++i) if (const char *arg = command_line_args[i]) { @@ -1105,27 +1102,62 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, if (*I) AllArgs += *I; } - - Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg; - } - // FIXME: Parse the (redirected) standard error to emit diagnostics. + Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; + } ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, *Diags, CXXIdx->getOnlyLocalDecls(), 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(); + RemappedFiles.size(), + /*CaptureDiagnostics=*/true); + if (ATU) { + LoadSerializedDiagnostics(DiagnosticsFile, + num_unsaved_files, unsaved_files, + ATU->getFileManager(), + ATU->getSourceManager(), + ATU->getDiagnostics()); + } else if (CXXIdx->getDisplayDiagnostics()) { + // We failed to load the ASTUnit, but we can still deserialize the + // diagnostics and emit them. + FileManager FileMgr; + SourceManager SourceMgr; + // FIXME: Faked LangOpts! + LangOptions LangOpts; + llvm::SmallVector Diags; + LoadSerializedDiagnostics(DiagnosticsFile, + num_unsaved_files, unsaved_files, + FileMgr, SourceMgr, Diags); + for (llvm::SmallVector::iterator D = Diags.begin(), + DEnd = Diags.end(); + D != DEnd; ++D) { + CXStoredDiagnostic Diag(*D, LangOpts); + CXString Msg = clang_formatDiagnostic(&Diag, + clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); + } + +#ifdef LLVM_ON_WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif + } + + if (ATU) { + // Make the translation unit responsible for destroying all temporary files. + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + ATU->addTemporaryFile(TemporaryFiles[i]); + ATU->addTemporaryFile(llvm::sys::Path(ATU->getPCHFileName())); + } else { + // Destroy all of the temporary files now; they can't be referenced any + // longer. + llvm::sys::Path(astTmpFile).eraseFromDisk(); + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + TemporaryFiles[i].eraseFromDisk(); + } return ATU; } @@ -1137,11 +1169,10 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { if (!CTUnit) - return CIndexer::createCXString(""); - + return createCXString(""); + ASTUnit *CXXUnit = static_cast(CTUnit); - return CIndexer::createCXString(CXXUnit->getOriginalSourceFileName().c_str(), - true); + return createCXString(CXXUnit->getOriginalSourceFileName(), true); } CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { @@ -1173,13 +1204,13 @@ CXSourceLocation clang_getLocation(CXTranslationUnit tu, unsigned column) { if (!tu) return clang_getNullLocation(); - + ASTUnit *CXXUnit = static_cast(tu); SourceLocation SLoc = CXXUnit->getSourceManager().getLocation( - static_cast(file), + static_cast(file), line, column); - + return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); } @@ -1192,8 +1223,8 @@ CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { 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[0], begin.ptr_data[1] }, + + CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] }, begin.int_data, end.int_data }; return Result; } @@ -1232,7 +1263,7 @@ void clang_getInstantiationLocation(CXSourceLocation location, } CXSourceLocation clang_getRangeStart(CXSourceRange range) { - CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, + CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, range.begin_int_data }; return Result; } @@ -1250,33 +1281,33 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) { //===----------------------------------------------------------------------===// extern "C" { -const char *clang_getFileName(CXFile SFile) { +CXString clang_getFileName(CXFile SFile) { if (!SFile) - return 0; - + return createCXString(NULL); + FileEntry *FEnt = static_cast(SFile); - return FEnt->getName(); + return createCXString(FEnt->getName()); } time_t clang_getFileTime(CXFile SFile) { if (!SFile) return 0; - + FileEntry *FEnt = static_cast(SFile); return FEnt->getModificationTime(); } - + CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) { if (!tu) return 0; - + ASTUnit *CXXUnit = static_cast(tu); - + FileManager &FMgr = CXXUnit->getFileManager(); const FileEntry *File = FMgr.getFile(file_name, file_name+strlen(file_name)); return const_cast(File); } - + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -1290,14 +1321,14 @@ static Decl *getDeclFromExpr(Stmt *E) { return ME->getMemberDecl(); if (ObjCIvarRefExpr *RE = dyn_cast(E)) return RE->getDecl(); - + if (CallExpr *CE = dyn_cast(E)) return getDeclFromExpr(CE->getCallee()); if (CastExpr *CE = dyn_cast(E)) return getDeclFromExpr(CE->getSubExpr()); if (ObjCMessageExpr *OME = dyn_cast(E)) return OME->getMethodDecl(); - + return 0; } @@ -1314,23 +1345,23 @@ static SourceLocation getLocationFromExpr(Expr *E) { } extern "C" { - -unsigned clang_visitChildren(CXCursor parent, + +unsigned clang_visitChildren(CXCursor parent, CXCursorVisitor visitor, CXClientData client_data) { ASTUnit *CXXUnit = getCursorASTUnit(parent); unsigned PCHLevel = Decl::MaxPCHLevel; - + // Set the PCHLevel to filter out unwanted decls if requested. if (CXXUnit->getOnlyLocalDecls()) { PCHLevel = 0; - + // If the main input was an AST, bump the level. if (CXXUnit->isMainFileAST()) ++PCHLevel; } - + CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel); return CursorVis.VisitChildren(parent); } @@ -1338,24 +1369,23 @@ unsigned clang_visitChildren(CXCursor parent, static CXString getDeclSpelling(Decl *D) { NamedDecl *ND = dyn_cast_or_null(D); if (!ND) - return CIndexer::createCXString(""); - + return createCXString(""); + if (ObjCMethodDecl *OMD = dyn_cast(ND)) - return CIndexer::createCXString(OMD->getSelector().getAsString().c_str(), - true); - + return createCXString(OMD->getSelector().getAsString()); + if (ObjCCategoryImplDecl *CIMP = dyn_cast(ND)) // No, this isn't the same as the code below. getIdentifier() is non-virtual // and returns different names. NamedDecl returns the class name and // ObjCCategoryImplDecl returns the category name. - return CIndexer::createCXString(CIMP->getIdentifier()->getNameStart()); - + return createCXString(CIMP->getIdentifier()->getNameStart()); + if (ND->getIdentifier()) - return CIndexer::createCXString(ND->getIdentifier()->getNameStart()); - - return CIndexer::createCXString(""); + return createCXString(ND->getIdentifier()->getNameStart()); + + return createCXString(""); } - + CXString clang_getCursorSpelling(CXCursor C) { if (clang_isTranslationUnit(C.kind)) return clang_getTranslationUnitSpelling(C.data[2]); @@ -1364,28 +1394,27 @@ CXString clang_getCursorSpelling(CXCursor C) { switch (C.kind) { case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first; - return CIndexer::createCXString(Super->getIdentifier()->getNameStart()); + return createCXString(Super->getIdentifier()->getNameStart()); } case CXCursor_ObjCClassRef: { ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; - return CIndexer::createCXString(Class->getIdentifier()->getNameStart()); + return createCXString(Class->getIdentifier()->getNameStart()); } case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first; assert(OID && "getCursorSpelling(): Missing protocol decl"); - return CIndexer::createCXString(OID->getIdentifier()->getNameStart()); + return createCXString(OID->getIdentifier()->getNameStart()); } case CXCursor_TypeRef: { TypeDecl *Type = getCursorTypeRef(C).first; assert(Type && "Missing type decl"); - return CIndexer::createCXString( - getCursorContext(C).getTypeDeclType(Type).getAsString().c_str(), - true); + return createCXString(getCursorContext(C).getTypeDeclType(Type). + getAsString()); } default: - return CIndexer::createCXString(""); + return createCXString(""); } } @@ -1393,85 +1422,125 @@ CXString clang_getCursorSpelling(CXCursor C) { Decl *D = getDeclFromExpr(getCursorExpr(C)); if (D) return getDeclSpelling(D); - return CIndexer::createCXString(""); + return createCXString(""); } if (clang_isDeclaration(C.kind)) return getDeclSpelling(getCursorDecl(C)); - - return CIndexer::createCXString(""); + + return createCXString(""); } -const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) { +CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { switch (Kind) { - case CXCursor_FunctionDecl: return "FunctionDecl"; - case CXCursor_TypedefDecl: return "TypedefDecl"; - case CXCursor_EnumDecl: return "EnumDecl"; - case CXCursor_EnumConstantDecl: return "EnumConstantDecl"; - case CXCursor_StructDecl: return "StructDecl"; - case CXCursor_UnionDecl: return "UnionDecl"; - case CXCursor_ClassDecl: return "ClassDecl"; - case CXCursor_FieldDecl: return "FieldDecl"; - case CXCursor_VarDecl: return "VarDecl"; - case CXCursor_ParmDecl: return "ParmDecl"; - case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl"; - case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl"; - case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl"; - case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl"; - case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl"; - case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl"; - case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl"; - case CXCursor_ObjCImplementationDecl: return "ObjCImplementationDecl"; - case CXCursor_ObjCCategoryImplDecl: return "ObjCCategoryImplDecl"; - case CXCursor_UnexposedDecl: return "UnexposedDecl"; - case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef"; - case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef"; - case CXCursor_ObjCClassRef: return "ObjCClassRef"; - case CXCursor_TypeRef: return "TypeRef"; - case CXCursor_UnexposedExpr: return "UnexposedExpr"; - case CXCursor_DeclRefExpr: return "DeclRefExpr"; - case CXCursor_MemberRefExpr: return "MemberRefExpr"; - case CXCursor_CallExpr: return "CallExpr"; - case CXCursor_ObjCMessageExpr: return "ObjCMessageExpr"; - case CXCursor_UnexposedStmt: return "UnexposedStmt"; - case CXCursor_InvalidFile: return "InvalidFile"; - case CXCursor_NoDeclFound: return "NoDeclFound"; - case CXCursor_NotImplemented: return "NotImplemented"; - case CXCursor_TranslationUnit: return "TranslationUnit"; + case CXCursor_FunctionDecl: + return createCXString("FunctionDecl"); + case CXCursor_TypedefDecl: + return createCXString("TypedefDecl"); + case CXCursor_EnumDecl: + return createCXString("EnumDecl"); + case CXCursor_EnumConstantDecl: + return createCXString("EnumConstantDecl"); + case CXCursor_StructDecl: + return createCXString("StructDecl"); + case CXCursor_UnionDecl: + return createCXString("UnionDecl"); + case CXCursor_ClassDecl: + return createCXString("ClassDecl"); + case CXCursor_FieldDecl: + return createCXString("FieldDecl"); + case CXCursor_VarDecl: + return createCXString("VarDecl"); + case CXCursor_ParmDecl: + return createCXString("ParmDecl"); + case CXCursor_ObjCInterfaceDecl: + return createCXString("ObjCInterfaceDecl"); + case CXCursor_ObjCCategoryDecl: + return createCXString("ObjCCategoryDecl"); + case CXCursor_ObjCProtocolDecl: + return createCXString("ObjCProtocolDecl"); + case CXCursor_ObjCPropertyDecl: + return createCXString("ObjCPropertyDecl"); + case CXCursor_ObjCIvarDecl: + return createCXString("ObjCIvarDecl"); + case CXCursor_ObjCInstanceMethodDecl: + return createCXString("ObjCInstanceMethodDecl"); + case CXCursor_ObjCClassMethodDecl: + return createCXString("ObjCClassMethodDecl"); + case CXCursor_ObjCImplementationDecl: + return createCXString("ObjCImplementationDecl"); + case CXCursor_ObjCCategoryImplDecl: + return createCXString("ObjCCategoryImplDecl"); + case CXCursor_UnexposedDecl: + return createCXString("UnexposedDecl"); + case CXCursor_ObjCSuperClassRef: + return createCXString("ObjCSuperClassRef"); + case CXCursor_ObjCProtocolRef: + return createCXString("ObjCProtocolRef"); + case CXCursor_ObjCClassRef: + return createCXString("ObjCClassRef"); + case CXCursor_TypeRef: + return createCXString("TypeRef"); + case CXCursor_UnexposedExpr: + return createCXString("UnexposedExpr"); + case CXCursor_DeclRefExpr: + return createCXString("DeclRefExpr"); + case CXCursor_MemberRefExpr: + return createCXString("MemberRefExpr"); + case CXCursor_CallExpr: + return createCXString("CallExpr"); + case CXCursor_ObjCMessageExpr: + return createCXString("ObjCMessageExpr"); + case CXCursor_UnexposedStmt: + return createCXString("UnexposedStmt"); + case CXCursor_InvalidFile: + return createCXString("InvalidFile"); + case CXCursor_NoDeclFound: + return createCXString("NoDeclFound"); + case CXCursor_NotImplemented: + return createCXString("NotImplemented"); + case CXCursor_TranslationUnit: + return createCXString("TranslationUnit"); + case CXCursor_UnexposedAttr: + return createCXString("UnexposedAttr"); + case CXCursor_IBActionAttr: + return createCXString("attribute(ibaction)"); + case CXCursor_IBOutletAttr: + return createCXString("attribute(iboutlet)"); } - + llvm_unreachable("Unhandled CXCursorKind"); - return NULL; + return createCXString(NULL); } -enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, - CXCursor parent, +enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, + CXCursor parent, CXClientData client_data) { CXCursor *BestCursor = static_cast(client_data); *BestCursor = cursor; return CXChildVisit_Recurse; } - + CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { if (!TU) return clang_getNullCursor(); - + ASTUnit *CXXUnit = static_cast(TU); SourceLocation SLoc = cxloc::translateSourceLocation(Loc); CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); if (SLoc.isValid()) { 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 // the region of interest, rather than starting from the translation unit. CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); - CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, + CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, Decl::MaxPCHLevel, RegionOfInterest); CursorVis.VisitChildren(Parent); } - return Result; + return Result; } CXCursor clang_getNullCursor(void) { @@ -1513,29 +1582,29 @@ CXCursorKind clang_getCursorKind(CXCursor C) { CXSourceLocation clang_getCursorLocation(CXCursor C) { if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { + case CXCursor_ObjCSuperClassRef: { std::pair P = getCursorObjCSuperClassRef(C); return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } - case CXCursor_ObjCProtocolRef: { + case CXCursor_ObjCProtocolRef: { std::pair P = getCursorObjCProtocolRef(C); return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } - case CXCursor_ObjCClassRef: { + case CXCursor_ObjCClassRef: { std::pair P = getCursorObjCClassRef(C); return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } - case CXCursor_TypeRef: { + case CXCursor_TypeRef: { std::pair P = getCursorTypeRef(C); return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } - + default: // FIXME: Need a way to enumerate all non-reference cases. llvm_unreachable("Missed a reference kind"); @@ -1543,7 +1612,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { } if (clang_isExpression(C.kind)) - return cxloc::translateSourceLocation(getCursorContext(C), + return cxloc::translateSourceLocation(getCursorContext(C), getLocationFromExpr(getCursorExpr(C))); if (!getCursorDecl(C)) @@ -1559,30 +1628,30 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { CXSourceRange clang_getCursorExtent(CXCursor C) { if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { + case CXCursor_ObjCSuperClassRef: { std::pair P = getCursorObjCSuperClassRef(C); return cxloc::translateSourceRange(P.first->getASTContext(), P.second); } - - case CXCursor_ObjCProtocolRef: { + + case CXCursor_ObjCProtocolRef: { std::pair P = getCursorObjCProtocolRef(C); return cxloc::translateSourceRange(P.first->getASTContext(), P.second); } - - case CXCursor_ObjCClassRef: { + + case CXCursor_ObjCClassRef: { std::pair P = getCursorObjCClassRef(C); - + return cxloc::translateSourceRange(P.first->getASTContext(), P.second); } - case CXCursor_TypeRef: { + case CXCursor_TypeRef: { std::pair P = getCursorTypeRef(C); return cxloc::translateSourceRange(P.first->getASTContext(), P.second); } - + default: // FIXME: Need a way to enumerate all non-reference cases. llvm_unreachable("Missed a reference kind"); @@ -1590,16 +1659,16 @@ CXSourceRange clang_getCursorExtent(CXCursor C) { } if (clang_isExpression(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), + return cxloc::translateSourceRange(getCursorContext(C), getCursorExpr(C)->getSourceRange()); if (clang_isStatement(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), + return cxloc::translateSourceRange(getCursorContext(C), getCursorStmt(C)->getSourceRange()); - + if (!getCursorDecl(C)) return clang_getNullRange(); - + Decl *D = getCursorDecl(C); return cxloc::translateSourceRange(D->getASTContext(), D->getSourceRange()); } @@ -1607,11 +1676,11 @@ CXSourceRange clang_getCursorExtent(CXCursor C) { CXCursor clang_getCursorReferenced(CXCursor C) { if (clang_isInvalid(C.kind)) return clang_getNullCursor(); - + ASTUnit *CXXUnit = getCursorASTUnit(C); if (clang_isDeclaration(C.kind)) return C; - + if (clang_isExpression(C.kind)) { Decl *D = getDeclFromExpr(getCursorExpr(C)); if (D) @@ -1621,36 +1690,36 @@ CXCursor clang_getCursorReferenced(CXCursor C) { if (!clang_isReference(C.kind)) return clang_getNullCursor(); - + switch (C.kind) { case CXCursor_ObjCSuperClassRef: return MakeCXCursor(getCursorObjCSuperClassRef(C).first, CXXUnit); - - case CXCursor_ObjCProtocolRef: { + + case CXCursor_ObjCProtocolRef: { return MakeCXCursor(getCursorObjCProtocolRef(C).first, CXXUnit); - - case CXCursor_ObjCClassRef: + + case CXCursor_ObjCClassRef: return MakeCXCursor(getCursorObjCClassRef(C).first, CXXUnit); - case CXCursor_TypeRef: + case CXCursor_TypeRef: return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit); - + default: // We would prefer to enumerate all non-reference cursor kinds here. llvm_unreachable("Unhandled reference cursor kind"); break; } } - + return clang_getNullCursor(); } CXCursor clang_getCursorDefinition(CXCursor C) { if (clang_isInvalid(C.kind)) return clang_getNullCursor(); - + ASTUnit *CXXUnit = getCursorASTUnit(C); - + bool WasReference = false; if (clang_isReference(C.kind) || clang_isExpression(C.kind)) { C = clang_getCursorReferenced(C); @@ -1663,7 +1732,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { Decl *D = getCursorDecl(C); if (!D) return clang_getNullCursor(); - + switch (D->getKind()) { // Declaration kinds that don't really separate the notions of // declaration and definition. @@ -1732,19 +1801,19 @@ CXCursor clang_getCursorDefinition(CXCursor C) { return MakeCXCursor(Def, CXXUnit); return clang_getNullCursor(); } - + case Decl::FunctionTemplate: { const FunctionDecl *Def = 0; if (cast(D)->getTemplatedDecl()->getBody(Def)) return MakeCXCursor(Def->getDescribedFunctionTemplate(), CXXUnit); return clang_getNullCursor(); } - + case Decl::ClassTemplate: { if (RecordDecl *Def = cast(D)->getTemplatedDecl() ->getDefinition()) return MakeCXCursor( - cast(Def)->getDescribedClassTemplate(), + cast(Def)->getDescribedClassTemplate(), CXXUnit); return clang_getNullCursor(); } @@ -1752,15 +1821,15 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Using: { UsingDecl *Using = cast(D); CXCursor Def = clang_getNullCursor(); - for (UsingDecl::shadow_iterator S = Using->shadow_begin(), - SEnd = Using->shadow_end(); + for (UsingDecl::shadow_iterator S = Using->shadow_begin(), + SEnd = Using->shadow_end(); S != SEnd; ++S) { if (Def != clang_getNullCursor()) { // FIXME: We have no way to return multiple results. return clang_getNullCursor(); } - Def = clang_getCursorDefinition(MakeCXCursor((*S)->getTargetDecl(), + Def = clang_getCursorDefinition(MakeCXCursor((*S)->getTargetDecl(), CXXUnit)); } @@ -1769,7 +1838,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::UsingShadow: return clang_getCursorDefinition( - MakeCXCursor(cast(D)->getTargetDecl(), + MakeCXCursor(cast(D)->getTargetDecl(), CXXUnit)); case Decl::ObjCMethod: { @@ -1815,7 +1884,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { = cast(D)->getImplementation()) return MakeCXCursor(Impl, CXXUnit); return clang_getNullCursor(); - + case Decl::ObjCProperty: // FIXME: We don't really know where to find the // ObjCPropertyImplDecls that implement this property. @@ -1826,14 +1895,14 @@ CXCursor clang_getCursorDefinition(CXCursor C) { = cast(D)->getClassInterface()) if (!Class->isForwardDecl()) return MakeCXCursor(Class, CXXUnit); - + return clang_getNullCursor(); case Decl::ObjCForwardProtocol: { ObjCForwardProtocolDecl *Forward = cast(D); if (Forward->protocol_size() == 1) return clang_getCursorDefinition( - MakeCXCursor(*Forward->protocol_begin(), + MakeCXCursor(*Forward->protocol_begin(), CXXUnit)); // FIXME: Cannot return multiple definitions. @@ -1885,7 +1954,7 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, NamedDecl *ND = static_cast(getCursorDecl(C)); FunctionDecl *FD = dyn_cast(ND); CompoundStmt *Body = dyn_cast(FD->getBody()); - + SourceManager &SM = FD->getASTContext().getSourceManager(); *startBuf = SM.getCharacterData(Body->getLBracLoc()); *endBuf = SM.getCharacterData(Body->getRBracLoc()); @@ -1894,7 +1963,11 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, *endLine = SM.getSpellingLineNumber(Body->getRBracLoc()); *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc()); } - + +void clang_enableStackTraces(void) { + llvm::sys::PrintStackTraceOnErrorSignal(); +} + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -1906,7 +1979,7 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, * int_data[1]: starting token location * int_data[2]: token length * int_data[3]: reserved - * ptr_data: for identifiers and keywords, an IdentifierInfo*. + * ptr_data: for identifiers and keywords, an IdentifierInfo*. * otherwise unused. */ extern "C" { @@ -1920,43 +1993,41 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) { case CXToken_Identifier: case CXToken_Keyword: // We know we have an IdentifierInfo*, so use that. - return CIndexer::createCXString( - static_cast(CXTok.ptr_data)->getNameStart()); + return createCXString(static_cast(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(CXTok.ptr_data); - return CIndexer::createCXString(llvm::StringRef(Text, CXTok.int_data[2]), - true); + return createCXString(llvm::StringRef(Text, CXTok.int_data[2])); } - + case CXToken_Punctuation: case CXToken_Comment: break; } - - // We have to find the starting buffer pointer the hard way, by + + // We have to find the starting buffer pointer the hard way, by // deconstructing the source location. ASTUnit *CXXUnit = static_cast(TU); if (!CXXUnit) - return CIndexer::createCXString(""); - + return createCXString(""); + SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]); std::pair LocInfo = CXXUnit->getSourceManager().getDecomposedLoc(Loc); std::pair Buffer = CXXUnit->getSourceManager().getBufferData(LocInfo.first); - return CIndexer::createCXString(llvm::StringRef(Buffer.first+LocInfo.second, - CXTok.int_data[2]), - true); + return createCXString(llvm::StringRef(Buffer.first+LocInfo.second, + CXTok.int_data[2])); } - + CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) { ASTUnit *CXXUnit = static_cast(TU); if (!CXXUnit) return clang_getNullLocation(); - + return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SourceLocation::getFromRawEncoding(CXTok.int_data[1])); } @@ -1965,44 +2036,44 @@ CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) { ASTUnit *CXXUnit = static_cast(TU); if (!CXXUnit) return clang_getNullRange(); - - return cxloc::translateSourceRange(CXXUnit->getASTContext(), + + 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(TU); if (!CXXUnit || !Tokens || !NumTokens) return; - + SourceRange R = cxloc::translateCXSourceRange(Range); if (R.isInvalid()) return; - + SourceManager &SourceMgr = CXXUnit->getSourceManager(); std::pair BeginLocInfo = SourceMgr.getDecomposedLoc(R.getBegin()); std::pair EndLocInfo = SourceMgr.getDecomposedLoc(R.getEnd()); - + // Cannot tokenize across files. if (BeginLocInfo.first != EndLocInfo.first) return; - - // Create a lexer + + // Create a lexer std::pair 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 CXTokens; @@ -2012,25 +2083,25 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, 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 + // Lookup the identifier to determine whether we have a std::pair LocInfo = SourceMgr.getDecomposedLoc(Tok.getLocation()); - const char *StartPos - = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first + + const char *StartPos + = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first + LocInfo.second; IdentifierInfo *II = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos); @@ -2047,10 +2118,10 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, } 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(); @@ -2058,8 +2129,8 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, typedef llvm::DenseMap AnnotateTokensData; -enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, - CXCursor parent, +enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, CXClientData client_data) { AnnotateTokensData *Data = static_cast(client_data); @@ -2078,13 +2149,13 @@ enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, 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; @@ -2104,12 +2175,12 @@ void clang_annotateTokens(CXTranslationUnit TU, if (!CXXUnit || !Tokens) return; - // Annotate all of the source locations in the region of interest that map + // 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, + = 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 @@ -2117,7 +2188,7 @@ void clang_annotateTokens(CXTranslationUnit TU, // the region of interest, rather than starting from the translation unit. AnnotateTokensData Annotated; CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); - CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated, + CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated, Decl::MaxPCHLevel, RegionOfInterest); AnnotateVis.VisitChildren(Parent); @@ -2131,11 +2202,30 @@ void clang_annotateTokens(CXTranslationUnit TU, } } -void clang_disposeTokens(CXTranslationUnit TU, +void clang_disposeTokens(CXTranslationUnit TU, CXToken *Tokens, unsigned NumTokens) { free(Tokens); } - + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Operations for querying linkage of a cursor. +//===----------------------------------------------------------------------===// + +extern "C" { +CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { + Decl *D = cxcursor::getCursorDecl(cursor); + if (NamedDecl *ND = dyn_cast_or_null(D)) + switch (ND->getLinkage()) { + case NoLinkage: return CXLinkage_NoLinkage; + case InternalLinkage: return CXLinkage_Internal; + case UniqueExternalLinkage: return CXLinkage_UniqueExternal; + case ExternalLinkage: return CXLinkage_External; + }; + + return CXLinkage_Invalid; +} } // end: extern "C" //===----------------------------------------------------------------------===// @@ -2154,15 +2244,43 @@ void clang_disposeString(CXString string) { } // end: extern "C" +namespace clang { namespace cxstring { +CXString createCXString(const char *String, bool DupString){ + CXString Str; + if (DupString) { + Str.Spelling = strdup(String); + Str.MustFreeString = 1; + } else { + Str.Spelling = String; + Str.MustFreeString = 0; + } + return Str; +} + +CXString 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; +} +}} + //===----------------------------------------------------------------------===// // Misc. utility functions. //===----------------------------------------------------------------------===// - + extern "C" { CXString clang_getClangVersion() { - return CIndexer::createCXString(getClangFullVersion(), true); + return createCXString(getClangFullVersion()); } } // end: extern "C" - diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 2c73819..e68060b 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -1,15 +1,21 @@ _clang_annotateTokens _clang_codeComplete +_clang_codeCompleteGetDiagnostic +_clang_codeCompleteGetNumDiagnostics _clang_createIndex _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile +_clang_defaultDiagnosticDisplayOptions _clang_disposeCodeCompleteResults +_clang_disposeDiagnostic _clang_disposeIndex _clang_disposeString _clang_disposeTokens _clang_disposeTranslationUnit +_clang_enableStackTraces _clang_equalCursors _clang_equalLocations +_clang_formatDiagnostic _clang_getClangVersion _clang_getCString _clang_getCompletionChunkCompletionString @@ -20,15 +26,14 @@ _clang_getCursorDefinition _clang_getCursorExtent _clang_getCursorKind _clang_getCursorKindSpelling +_clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced _clang_getCursorSpelling _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent -_clang_getDiagnosticFixItInsertion -_clang_getDiagnosticFixItKind -_clang_getDiagnosticFixItRemoval -_clang_getDiagnosticFixItReplacement +_clang_getDiagnostic +_clang_getDiagnosticFixIt _clang_getDiagnosticLocation _clang_getDiagnosticNumFixIts _clang_getDiagnosticNumRanges @@ -45,6 +50,7 @@ _clang_getNullCursor _clang_getNullLocation _clang_getNullRange _clang_getNumCompletionChunks +_clang_getNumDiagnostics _clang_getRange _clang_getRangeEnd _clang_getRangeStart diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp index 4e41c5f..3b7674e 100644 --- a/tools/CIndex/CIndexCodeCompletion.cpp +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -21,6 +21,7 @@ #include "llvm/System/Program.h" using namespace clang; +using namespace clang::cxstring; extern "C" { @@ -80,11 +81,11 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, return CXCompletionChunk_Text; } -const char *clang_getCompletionChunkText(CXCompletionString completion_string, - unsigned chunk_number) { +CXString clang_getCompletionChunkText(CXCompletionString completion_string, + unsigned chunk_number) { CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) - return 0; + return createCXString(0); switch ((*CCStr)[chunk_number].Kind) { case CodeCompletionString::CK_TypedText: @@ -107,17 +108,18 @@ const char *clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_Equal: case CodeCompletionString::CK_HorizontalSpace: case CodeCompletionString::CK_VerticalSpace: - return (*CCStr)[chunk_number].Text; + return createCXString((*CCStr)[chunk_number].Text, false); case CodeCompletionString::CK_Optional: // Note: treated as an empty text block. - return ""; + return createCXString(""); } // Should be unreachable, but let's be careful. - return 0; + return createCXString(0); } + CXCompletionString clang_getCompletionChunkCompletionString(CXCompletionString completion_string, unsigned chunk_number) { @@ -175,13 +177,43 @@ static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, /// \brief The CXCodeCompleteResults structure we allocate internally; /// the client only sees the initial CXCodeCompleteResults structure. struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { + AllocatedCXCodeCompleteResults(); + ~AllocatedCXCodeCompleteResults(); + /// \brief The memory buffer from which we parsed the results. We /// retain this buffer because the completion strings point into it. llvm::MemoryBuffer *Buffer; + /// \brief Diagnostics produced while performing code completion. + llvm::SmallVector Diagnostics; + + /// \brief Language options used to adjust source locations. LangOptions LangOpts; + + /// \brief Source manager, used for diagnostics. + SourceManager SourceMgr; + + /// \brief File manager, used for diagnostics. + FileManager FileMgr; + + /// \brief Temporary files that should be removed once we have finished + /// with the code-completion results. + std::vector TemporaryFiles; }; +AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() + : CXCodeCompleteResults(), Buffer(0) { } + +AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { + for (unsigned I = 0, N = NumResults; I != N; ++I) + delete (CodeCompletionString *)Results[I].CompletionString; + delete [] Results; + delete Buffer; + + for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) + TemporaryFiles[I].eraseFromDisk(); +} + CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, const char *source_filename, int num_command_line_args, @@ -190,9 +222,7 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, struct CXUnsavedFile *unsaved_files, const char *complete_filename, unsigned complete_line, - unsigned complete_column, - CXDiagnosticCallback diag_callback, - CXClientData diag_client_data) { + unsigned complete_column) { // The indexer, which is mainly used to determine where diagnostics go. CIndexer *CXXIdx = static_cast(CIdx); @@ -200,8 +230,6 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, DiagnosticOptions DiagOpts; llvm::OwningPtr 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 TemporaryFiles; @@ -302,13 +330,17 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, AllArgs += *I; } - Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg; + Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; } // Parse the resulting source file to find code-completion results. using llvm::MemoryBuffer; using llvm::StringRef; - AllocatedCXCodeCompleteResults *Results = 0; + AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; + Results->Results = 0; + Results->NumResults = 0; + Results->Buffer = 0; + // FIXME: Set Results->LangOpts! if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { llvm::SmallVector CompletionResults; StringRef Buffer = F->getBuffer(); @@ -333,7 +365,6 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, }; // Allocate the results. - Results = new AllocatedCXCodeCompleteResults; Results->Results = new CXCompletionResult [CompletionResults.size()]; Results->NumResults = CompletionResults.size(); memcpy(Results->Results, CompletionResults.data(), @@ -341,15 +372,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(); + LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, + Results->FileMgr, Results->SourceMgr, + Results->Diagnostics); + + // Make sure we delete temporary files when the code-completion results are + // destroyed. + Results->TemporaryFiles.swap(TemporaryFiles); return Results; } @@ -360,16 +389,29 @@ void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { AllocatedCXCodeCompleteResults *Results = static_cast(ResultsIn); + delete Results; +} - for (unsigned I = 0, N = Results->NumResults; I != N; ++I) - delete (CXCompletionString *)Results->Results[I].CompletionString; - delete [] Results->Results; +unsigned +clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results + = static_cast(ResultsIn); + if (!Results) + return 0; - Results->Results = 0; - Results->NumResults = 0; - delete Results->Buffer; - Results->Buffer = 0; - delete Results; + return Results->Diagnostics.size(); +} + +CXDiagnostic +clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, + unsigned Index) { + AllocatedCXCodeCompleteResults *Results + = static_cast(ResultsIn); + if (!Results || Index >= Results->Diagnostics.size()) + return 0; + + return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts); } + } // end extern "C" diff --git a/tools/CIndex/CIndexDiagnostic.cpp b/tools/CIndex/CIndexDiagnostic.cpp index d26094f..6aed49e 100644 --- a/tools/CIndex/CIndexDiagnostic.cpp +++ b/tools/CIndex/CIndexDiagnostic.cpp @@ -1,4 +1,4 @@ -/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface -----------*- C -*-===*\ +/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\ |* *| |* The LLVM Compiler Infrastructure *| |* *| @@ -15,206 +15,227 @@ #include "CXSourceLocation.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::cxloc; +using namespace clang::cxstring; +using namespace llvm; //----------------------------------------------------------------------------- -// Opaque data structures +// C Interface Routines //----------------------------------------------------------------------------- -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; - }; +extern "C" { + +unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { + ASTUnit *CXXUnit = static_cast(Unit); + return CXXUnit? CXXUnit->diag_size() : 0; } -//----------------------------------------------------------------------------- -// CIndex Diagnostic Client -//----------------------------------------------------------------------------- -CIndexDiagnosticClient::~CIndexDiagnosticClient() { } +CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { + ASTUnit *CXXUnit = static_cast(Unit); + if (!CXXUnit || Index >= CXXUnit->diag_size()) + return 0; -void CIndexDiagnosticClient::BeginSourceFile(const LangOptions &LangOpts, - const Preprocessor *PP) { - assert(!LangOptsPtr && "Invalid state!"); - LangOptsPtr = &LangOpts; + return new CXStoredDiagnostic(CXXUnit->diag_begin()[Index], + CXXUnit->getASTContext().getLangOptions()); } -void CIndexDiagnosticClient::EndSourceFile() { - assert(LangOptsPtr && "Invalid state!"); - LangOptsPtr = 0; +void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { + CXStoredDiagnostic *Stored = static_cast(Diagnostic); + delete Stored; } -void CIndexDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { - if (!Callback) - return; +CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { + if (!Diagnostic) + return createCXString(""); - assert((LangOptsPtr || Info.getLocation().isInvalid()) && - "Missing language options with located diagnostic!"); - CXStoredDiagnostic Stored = { this->LangOptsPtr, DiagLevel, Info }; - Callback(&Stored, ClientData); -} + CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); -//----------------------------------------------------------------------------- -// C Interface Routines -//----------------------------------------------------------------------------- -extern "C" { + // Ignore diagnostics that should be ignored. + if (Severity == CXDiagnostic_Ignored) + return createCXString(""); + + llvm::SmallString<256> Str; + llvm::raw_svector_ostream Out(Str); + if (Options & CXDiagnostic_DisplaySourceLocation) { + // Print source location (file:line), along with optional column + // and source ranges. + CXFile File; + unsigned Line, Column; + clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), + &File, &Line, &Column, 0); + if (File) { + CXString FName = clang_getFileName(File); + Out << clang_getCString(FName) << ":" << Line << ":"; + clang_disposeString(FName); + if (Options & CXDiagnostic_DisplayColumn) + Out << Column << ":"; + + if (Options & CXDiagnostic_DisplaySourceRanges) { + unsigned N = clang_getDiagnosticNumRanges(Diagnostic); + bool PrintedRange = false; + for (unsigned I = 0; I != N; ++I) { + CXFile StartFile, EndFile; + CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); + + unsigned StartLine, StartColumn, EndLine, EndColumn; + clang_getInstantiationLocation(clang_getRangeStart(Range), + &StartFile, &StartLine, &StartColumn, + 0); + clang_getInstantiationLocation(clang_getRangeEnd(Range), + &EndFile, &EndLine, &EndColumn, 0); + + if (StartFile != EndFile || StartFile != File) + continue; + + Out << "{" << StartLine << ":" << StartColumn << "-" + << EndLine << ":" << EndColumn << "}"; + PrintedRange = true; + } + if (PrintedRange) + Out << ":"; + } + } + + Out << " "; + } + + /* Print warning/error/etc. */ + switch (Severity) { + case CXDiagnostic_Ignored: assert(0 && "impossible"); break; + case CXDiagnostic_Note: Out << "note: "; break; + case CXDiagnostic_Warning: Out << "warning: "; break; + case CXDiagnostic_Error: Out << "error: "; break; + case CXDiagnostic_Fatal: Out << "fatal error: "; break; + } + + CXString Text = clang_getDiagnosticSpelling(Diagnostic); + if (clang_getCString(Text)) + Out << clang_getCString(Text); + else + Out << ""; + clang_disposeString(Text); + return createCXString(Out.str(), true); +} + +unsigned clang_defaultDiagnosticDisplayOptions() { + return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn; +} + enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag) return CXDiagnostic_Ignored; - - switch (StoredDiag->Level) { + + switch (StoredDiag->Diag.getLevel()) { 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(Diag); - if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid()) + if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) return clang_getNullLocation(); - - return translateSourceLocation(StoredDiag->Info.getLocation().getManager(), - *StoredDiag->LangOptsPtr, - StoredDiag->Info.getLocation()); + + return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(), + StoredDiag->LangOpts, + StoredDiag->Diag.getLocation()); } CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag) - return CIndexer::createCXString(""); - - llvm::SmallString<64> Spelling; - StoredDiag->Info.FormatDiagnostic(Spelling); - return CIndexer::createCXString(Spelling.str(), true); + return createCXString(""); + + return createCXString(StoredDiag->Diag.getMessage(), false); } unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid()) + if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) return 0; - - return StoredDiag->Info.getNumRanges(); + + return StoredDiag->Diag.range_size(); } - + CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag || Range >= StoredDiag->Info.getNumRanges() || - StoredDiag->Info.getLocation().isInvalid()) + if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || + StoredDiag->Diag.getLocation().isInvalid()) return clang_getNullRange(); - - return translateSourceRange(StoredDiag->Info.getLocation().getManager(), - *StoredDiag->LangOptsPtr, - StoredDiag->Info.getRange(Range)); + + return translateSourceRange(StoredDiag->Diag.getLocation().getManager(), + StoredDiag->LangOpts, + StoredDiag->Diag.range_begin()[Range]); } unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag) return 0; - - return StoredDiag->Info.getNumCodeModificationHints(); -} -enum CXFixItKind clang_getDiagnosticFixItKind(CXDiagnostic Diag, - unsigned FixIt) { - CXStoredDiagnostic *StoredDiag = static_cast(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; + return StoredDiag->Diag.fixit_size(); } -CXString clang_getDiagnosticFixItInsertion(CXDiagnostic Diag, - unsigned FixIt, - CXSourceLocation *Location) { - if (Location) - *Location = clang_getNullLocation(); - - CXStoredDiagnostic *StoredDiag = static_cast(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); -} +CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, + CXSourceRange *ReplacementRange) { + CXStoredDiagnostic *StoredDiag + = static_cast(Diagnostic); + if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || + StoredDiag->Diag.getLocation().isInvalid()) { + if (ReplacementRange) + *ReplacementRange = clang_getNullRange(); -CXSourceRange clang_getDiagnosticFixItRemoval(CXDiagnostic Diag, - unsigned FixIt) { - CXStoredDiagnostic *StoredDiag = static_cast(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); -} + return createCXString(""); + } -CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag, - unsigned FixIt, - CXSourceRange *Range) { - if (Range) - *Range = clang_getNullRange(); + const CodeModificationHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; + if (ReplacementRange) { + if (Hint.RemoveRange.isInvalid()) { + // Create an empty range that refers to a single source + // location (which is the insertion point). + CXSourceRange Range = { + { (void *)&StoredDiag->Diag.getLocation().getManager(), + (void *)&StoredDiag->LangOpts }, + Hint.InsertionLoc.getRawEncoding(), + Hint.InsertionLoc.getRawEncoding() + }; - CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() || - StoredDiag->Info.getLocation().isInvalid()) { - if (Range) - *Range = clang_getNullRange(); - - return CIndexer::createCXString(""); + *ReplacementRange = Range; + } else { + // Create a range that covers the entire replacement (or + // removal) range, adjusting the end of the range to point to + // the end of the token. + *ReplacementRange + = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), + StoredDiag->LangOpts, + Hint.RemoveRange); + } } - - const CodeModificationHint &Hint - = StoredDiag->Info.getCodeModificationHint(FixIt); - if (Range) - *Range = translateSourceRange(StoredDiag->Info.getLocation().getManager(), - *StoredDiag->LangOptsPtr, - Hint.RemoveRange); - return CIndexer::createCXString(Hint.CodeToInsert); + + return 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) { +void clang::LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + FileManager &FileMgr, + SourceManager &SourceMgr, + SmallVectorImpl &Diags) { using llvm::MemoryBuffer; using llvm::StringRef; MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str()); @@ -222,39 +243,41 @@ void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath, 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; + // FIXME: Hard to localize when we have no diagnostics engine! + Diags.push_back(StoredDiagnostic(Diagnostic::Fatal, + (Twine("could not remap from missing file ") + + unsaved_files[I].Filename).str())); + delete F; return; } MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, unsaved_files[I].Contents + unsaved_files[I].Length); - if (!Buffer) + if (!Buffer) { + delete F; 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; - } + StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr, + Memory, MemoryEnd); + if (!Stored) + break; - Diags.getClient()->EndSourceFile(); + Diags.push_back(Stored); + } + delete F; } diff --git a/tools/CIndex/CIndexDiagnostic.h b/tools/CIndex/CIndexDiagnostic.h index 9f7ae51..79a5df0 100644 --- a/tools/CIndex/CIndexDiagnostic.h +++ b/tools/CIndex/CIndexDiagnostic.h @@ -16,6 +16,7 @@ #include "clang-c/Index.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallVector.h" namespace llvm { namespace sys { class Path; @@ -26,40 +27,25 @@ 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 The storage behind a CXDiagnostic +struct CXStoredDiagnostic { + const StoredDiagnostic &Diag; + const LangOptions &LangOpts; + + CXStoredDiagnostic(const StoredDiagnostic &Diag, + const LangOptions &LangOpts) + : Diag(Diag), LangOpts(LangOpts) { } }; - + /// \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); +/// diagnostics produced by Clang, load those diagnostics. +void LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + FileManager &FileMgr, + SourceManager &SourceMgr, + llvm::SmallVectorImpl &Diags); } // end namespace clang diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp index a992dbf..922f4b3 100644 --- a/tools/CIndex/CIndexUSRs.cpp +++ b/tools/CIndex/CIndexUSRs.cpp @@ -17,6 +17,8 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" +using namespace clang::cxstring; + //===----------------------------------------------------------------------===// // USR generation. //===----------------------------------------------------------------------===// @@ -156,14 +158,14 @@ static CXString ConstructUSR(Decl *D) { USRGenerator UG(Out); UG.Visit(static_cast(D)); if (UG.ignoreResults()) - return CIndexer::createCXString(NULL); + return createCXString(NULL); } if (StrBuf.empty()) - return CIndexer::createCXString(NULL); + return createCXString(NULL); // Return a copy of the string that must be disposed by the caller. - return CIndexer::createCXString(StrBuf.c_str(), true); + return createCXString(StrBuf.str(), true); } @@ -173,7 +175,7 @@ CXString clang_getCursorUSR(CXCursor C) { if (Decl *D = cxcursor::getCursorDecl(C)) return ConstructUSR(D); - return CIndexer::createCXString(NULL); + return createCXString(NULL); } } // end extern "C" diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h index b83e2b7..1fa3ca9 100644 --- a/tools/CIndex/CIndexer.h +++ b/tools/CIndex/CIndexer.h @@ -24,14 +24,24 @@ using namespace clang; +namespace clang { +namespace cxstring { + CXString createCXString(const char *String, bool DupString = false); + CXString createCXString(llvm::StringRef String, bool DupString = true); +} +} + class CIndexer { bool UseExternalASTGeneration; bool OnlyLocalDecls; - + bool DisplayDiagnostics; + llvm::sys::Path ClangPath; public: - CIndexer() : UseExternalASTGeneration(false), OnlyLocalDecls(false) { } + CIndexer() + : UseExternalASTGeneration(false), OnlyLocalDecls(false), + DisplayDiagnostics(false) { } /// \brief Whether we only want to see "local" declarations (that did not /// come from a previous precompiled header). If false, we want to see all @@ -39,6 +49,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; @@ -49,10 +64,6 @@ public: /// \brief Get the path of the clang resource files. 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 26e1b3b..e94a786 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(CIndex CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp + ../../include/clang-c/Index.h ) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp index ec1477e..0fa73a5 100644 --- a/tools/CIndex/CXCursor.cpp +++ b/tools/CIndex/CXCursor.cpp @@ -72,6 +72,23 @@ static CXCursorKind GetCursorKind(Decl *D) { return CXCursor_NotImplemented; } +static CXCursorKind GetCursorKind(const Attr *A) { + assert(A && "Invalid arguments!"); + switch (A->getKind()) { + default: break; + case Attr::IBActionKind: return CXCursor_IBActionAttr; + case Attr::IBOutletKind: return CXCursor_IBOutletAttr; + } + + return CXCursor_UnexposedAttr; +} + +CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent, ASTUnit *TU) { + assert(A && Parent && TU && "Invalid arguments!"); + CXCursor C = { GetCursorKind(A), { Parent, (void*)A, TU } }; + return C; +} + CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) { assert(D && TU && "Invalid arguments!"); CXCursor C = { GetCursorKind(D), { D, 0, TU } }; diff --git a/tools/CIndex/CXCursor.h b/tools/CIndex/CXCursor.h index 30fb26c..934d5e2 100644 --- a/tools/CIndex/CXCursor.h +++ b/tools/CIndex/CXCursor.h @@ -22,6 +22,7 @@ namespace clang { class ASTContext; class ASTUnit; +class Attr; class Decl; class Expr; class NamedDecl; @@ -32,9 +33,10 @@ class TypeDecl; namespace cxcursor { -CXCursor MakeCXCursorInvalid(CXCursorKind K); -CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent, ASTUnit *TU); +CXCursor MakeCXCursor(const clang::Attr *A, clang::Decl *Parent, ASTUnit *TU); CXCursor MakeCXCursor(clang::Decl *D, ASTUnit *TU); +CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent, ASTUnit *TU); +CXCursor MakeCXCursorInvalid(CXCursorKind K); /// \brief Create an Objective-C superclass reference at the given location. CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index d4771c7..967afb7 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -28,10 +28,6 @@ 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, @@ -40,12 +36,12 @@ static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column, static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, CXTranslationUnit *TU) { - - *TU = clang_createTranslationUnit(Idx, file, PrintDiagnosticCallback, stderr); + + *TU = clang_createTranslationUnit(Idx, file); if (!TU) { fprintf(stderr, "Unable to load translation unit from '%s'!\n", file); return 0; - } + } return 1; } @@ -66,20 +62,20 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, int prefix_len = strlen("-remap-file="); *unsaved_files = 0; *num_unsaved_files = 0; - + /* Count the number of remapped files. */ for (arg = start_arg; arg < argc; ++arg) { if (strncmp(argv[arg], "-remap-file=", prefix_len)) break; - + ++*num_unsaved_files; } - + if (*num_unsaved_files == 0) return 0; - + *unsaved_files - = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * + = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * *num_unsaved_files); for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { struct CXUnsavedFile *unsaved = *unsaved_files + i; @@ -90,14 +86,14 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, FILE *to_file; const char *semi = strchr(arg_string, ';'); if (!semi) { - fprintf(stderr, + fprintf(stderr, "error: -remap-file=from;to argument is missing semicolon\n"); free_remapped_files(*unsaved_files, i); *unsaved_files = 0; *num_unsaved_files = 0; return -1; } - + /* Open the file that we're remapping to. */ to_file = fopen(semi + 1, "r"); if (!to_file) { @@ -108,12 +104,12 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, *num_unsaved_files = 0; return -1; } - + /* Determine the length of the file we're remapping to. */ fseek(to_file, 0, SEEK_END); unsaved->Length = ftell(to_file); fseek(to_file, 0, SEEK_SET); - + /* Read the contents of the file we're remapping to. */ contents = (char *)malloc(unsaved->Length + 1); if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { @@ -127,10 +123,10 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, } contents[unsaved->Length] = 0; unsaved->Contents = contents; - + /* Close the file. */ fclose(to_file); - + /* Copy the file name that we're remapping from. */ filename_len = semi - arg_string; filename = (char *)malloc(filename_len + 1); @@ -138,7 +134,7 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, filename[filename_len] = 0; unsaved->Filename = filename; } - + return 0; } @@ -147,17 +143,23 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, /******************************************************************************/ static void PrintCursor(CXCursor Cursor) { - if (clang_isInvalid(Cursor.kind)) - printf("Invalid Cursor => %s", clang_getCursorKindSpelling(Cursor.kind)); + if (clang_isInvalid(Cursor.kind)) { + CXString ks = clang_getCursorKindSpelling(Cursor.kind); + printf("Invalid Cursor => %s", clang_getCString(ks)); + clang_disposeString(ks); + } else { - CXString string; + CXString string, ks; CXCursor Referenced; unsigned line, column; + + ks = clang_getCursorKindSpelling(Cursor.kind); string = clang_getCursorSpelling(Cursor); - printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind), - clang_getCString(string)); + printf("%s=%s", clang_getCString(ks), + clang_getCString(string)); + clang_disposeString(ks); clang_disposeString(string); - + Referenced = clang_getCursorReferenced(Cursor); if (!clang_equalCursors(Referenced, clang_getNullCursor())) { CXSourceLocation Loc = clang_getCursorLocation(Referenced); @@ -170,15 +172,21 @@ static void PrintCursor(CXCursor Cursor) { } } -static const char* GetCursorSource(CXCursor Cursor) { +static const char* GetCursorSource(CXCursor Cursor) { CXSourceLocation Loc = clang_getCursorLocation(Cursor); - const char *source; + CXString source; CXFile file; clang_getInstantiationLocation(Loc, &file, 0, 0, 0); source = clang_getFileName(file); - if (!source) - return ""; - return basename(source); + if (!clang_getCString(source)) { + clang_disposeString(source); + return ""; + } + else { + const char *b = basename(clang_getCString(source)); + clang_disposeString(source); + return b; + } } /******************************************************************************/ @@ -187,122 +195,68 @@ static const char* GetCursorSource(CXCursor Cursor) { typedef void (*PostVisitTU)(CXTranslationUnit); -static void PrintDiagnosticCallback(CXDiagnostic Diagnostic, - CXClientData ClientData) { - FILE *out = (FILE *)ClientData; +void PrintDiagnostic(CXDiagnostic Diagnostic) { + FILE *out = stderr; CXFile file; - unsigned line, column; - CXString text; - enum CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(Diagnostic); + CXString Msg; + unsigned display_opts = CXDiagnostic_DisplaySourceLocation + | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; + unsigned i, num_fixits; - /* Ignore diagnostics that should be ignored. */ - if (severity == CXDiagnostic_Ignored) + if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; + + Msg = clang_formatDiagnostic(Diagnostic, display_opts); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); - /* 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, "\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; - } + &file, 0, 0, 0); + if (!file) + return; - 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; + num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); + for (i = 0; i != num_fixits; ++i) { + CXSourceRange range; + CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range); + CXSourceLocation start = clang_getRangeStart(range); + CXSourceLocation end = clang_getRangeEnd(range); + unsigned start_line, start_column, end_line, end_column; + CXFile start_file, end_file; + clang_getInstantiationLocation(start, &start_file, &start_line, + &start_column, 0); + clang_getInstantiationLocation(end, &end_file, &end_line, &end_column, 0); + if (clang_equalLocations(start, end)) { + /* Insertion. */ + if (start_file == file) + fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n", + clang_getCString(insertion_text), start_line, start_column); + } else if (strcmp(clang_getCString(insertion_text), "") == 0) { + /* Removal. */ + 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"); } + } else { + /* Replacement. */ + 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(insertion_text)); } + break; } + clang_disposeString(insertion_text); + } +} + +void PrintDiagnostics(CXTranslationUnit TU) { + int i, n = clang_getNumDiagnostics(TU); + for (i = 0; i != n; ++i) { + CXDiagnostic Diag = clang_getDiagnostic(TU, i); + PrintDiagnostic(Diag); + clang_disposeDiagnostic(Diag); } } @@ -316,7 +270,7 @@ static void PrintCursorExtent(CXCursor C) { CXSourceRange extent = clang_getCursorExtent(C); CXFile begin_file, end_file; unsigned begin_line, begin_column, end_line, end_column; - + clang_getInstantiationLocation(clang_getRangeStart(extent), &begin_file, &begin_line, &begin_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(extent), @@ -335,7 +289,7 @@ typedef struct { } VisitorData; -enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor, +enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor, CXCursor Parent, CXClientData ClientData) { VisitorData *Data = (VisitorData *)ClientData; @@ -347,14 +301,14 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor, GetCursorSource(Cursor), line, column); PrintCursor(Cursor); PrintCursorExtent(Cursor); - printf("\n"); + printf("\n"); return CXChildVisit_Recurse; } - + return CXChildVisit_Continue; } -static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor, +static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor, CXCursor Parent, CXClientData ClientData) { const char *startBuf, *endBuf; @@ -376,19 +330,20 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor, while (startBuf < endBuf) { CXSourceLocation Loc; CXFile file; - const char *source = 0; - + CXString source; + if (*startBuf == '\n') { startBuf++; curLine++; curColumn = 1; } else if (*startBuf != '\t') curColumn++; - + Loc = clang_getCursorLocation(Cursor); clang_getInstantiationLocation(Loc, &file, 0, 0, 0); + source = clang_getFileName(file); - if (source) { + if (clang_getCString(source)) { CXSourceLocation RefLoc = clang_getLocation(Data->TU, file, curLine, curColumn); Ref = clang_getCursor(Data->TU, RefLoc); @@ -401,9 +356,10 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor, printf("\n"); } } + clang_disposeString(source); startBuf++; } - + return CXChildVisit_Continue; } @@ -416,18 +372,19 @@ enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent, VisitorData *Data = (VisitorData *)ClientData; if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) { CXString USR = clang_getCursorUSR(C); - if (!USR.Spelling) { + if (!clang_getCString(USR)) { clang_disposeString(USR); return CXChildVisit_Continue; } - printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling); + printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), + clang_getCString(USR)); PrintCursorExtent(C); printf("\n"); clang_disposeString(USR); - + return CXChildVisit_Recurse; - } - + } + return CXChildVisit_Continue; } @@ -437,21 +394,55 @@ enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent, void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack, unsigned includeStackLen, CXClientData data) { - + unsigned i; - printf("file: %s\nincluded by:\n", clang_getFileName(includedFile)); + CXString fname; + + fname = clang_getFileName(includedFile); + printf("file: %s\nincluded by:\n", clang_getCString(fname)); + clang_disposeString(fname); + 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); + fname = clang_getFileName(includingFile); + printf(" %s:%d:%d\n", clang_getCString(fname), line, column); + clang_disposeString(fname); } printf("\n"); } void PrintInclusionStack(CXTranslationUnit TU) { - clang_getInclusions(TU, InclusionVisitor, NULL); + clang_getInclusions(TU, InclusionVisitor, NULL); +} + +/******************************************************************************/ +/* Linkage testing. */ +/******************************************************************************/ + +static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, + CXClientData d) { + const char *linkage = 0; + + if (clang_isInvalid(clang_getCursorKind(cursor))) + return CXChildVisit_Recurse; + + switch (clang_getCursorLinkage(cursor)) { + case CXLinkage_Invalid: break; + case CXLinkage_NoLinkage: linkage = "NoLinkage"; + case CXLinkage_Internal: linkage = "Internal"; + case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; + case CXLinkage_External: linkage = "External"; + } + + if (linkage) { + PrintCursor(cursor); + printf("linkage=%s\n", linkage); + } + + return CXChildVisit_Recurse; } /******************************************************************************/ @@ -462,15 +453,15 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, const char *filter, const char *prefix, CXCursorVisitor Visitor, PostVisitTU PV) { - + if (prefix) - FileCheckPrefix = 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, "none")) K = (enum CXCursorKind) ~0; @@ -484,15 +475,16 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, 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); } - + if (PV) PV(TU); + PrintDiagnostics(TU); clang_disposeTranslationUnit(TU); return 0; } @@ -503,9 +495,10 @@ int perform_test_load_tu(const char *file, const char *filter, CXIndex Idx; CXTranslationUnit TU; int result; - Idx = clang_createIndex(/* excludeDeclsFromPCH */ - !strcmp(filter, "local") ? 1 : 0); - + Idx = clang_createIndex(/* excludeDeclsFromPCH */ + !strcmp(filter, "local") ? 1 : 0, + /* displayDiagnosics=*/1); + if (!CreateTranslationUnit(Idx, file, &TU)) { clang_disposeIndex(Idx); return 1; @@ -526,9 +519,10 @@ int perform_test_load_source(int argc, const char **argv, struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; int result; - + Idx = clang_createIndex(/* excludeDeclsFromPCH */ - !strcmp(filter, "local") ? 1 : 0); + !strcmp(filter, "local") ? 1 : 0, + /* displayDiagnosics=*/1); if (UseExternalASTs && strlen(UseExternalASTs)) clang_setUseExternalASTGeneration(Idx, 1); @@ -538,13 +532,11 @@ int perform_test_load_source(int argc, const char **argv, return -1; } - TU = clang_createTranslationUnitFromSourceFile(Idx, 0, - argc - num_unsaved_files, + TU = clang_createTranslationUnitFromSourceFile(Idx, 0, + argc - num_unsaved_files, argv + num_unsaved_files, num_unsaved_files, - unsaved_files, - PrintDiagnosticCallback, - stderr); + unsaved_files); if (!TU) { fprintf(stderr, "Unable to load translation unit!\n"); clang_disposeIndex(Idx); @@ -583,20 +575,21 @@ static int perform_file_scan(const char *ast_file, const char *source_file, CXFile file; unsigned line = 1, col = 1; unsigned start_line = 1, start_col = 1; - - if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1))) { + + if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, + /* displayDiagnosics=*/1))) { fprintf(stderr, "Could not create Index\n"); return 1; } - + if (!CreateTranslationUnit(Idx, ast_file, &TU)) return 1; - + if ((fp = fopen(source_file, "r")) == NULL) { fprintf(stderr, "Could not open '%s'\n", source_file); return 1; } - + file = clang_getFile(TU, source_file); for (;;) { CXCursor cursor; @@ -624,7 +617,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file, prevCursor = cursor; } - + fclose(fp); return 0; } @@ -636,7 +629,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file, /* Parse file:line:column from the input string. Returns 0 on success, non-zero 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, +int parse_file_line_column(const char *input, char **filename, unsigned *line, unsigned *column, unsigned *second_line, unsigned *second_column) { /* Find the second colon. */ @@ -660,11 +653,11 @@ int parse_file_line_column(const char *input, char **filename, unsigned *line, /* 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", + fprintf(stderr, "could not parse %s in '%s'\n", (i % 2 ? "column" : "line"), input); return 1; } - + if (i + 1 == num_values) break; @@ -673,9 +666,9 @@ int parse_file_line_column(const char *input, char **filename, unsigned *line, while (prev_colon != input && *prev_colon != ':') --prev_colon; if (prev_colon == input) { - fprintf(stderr, "could not parse %s in '%s'\n", + fprintf(stderr, "could not parse %s in '%s'\n", (i % 2 == 0? "column" : "line"), input); - return 1; + return 1; } last_colon = prev_colon; @@ -683,7 +676,7 @@ int parse_file_line_column(const char *input, char **filename, unsigned *line, *line = values[0]; *column = values[1]; - + if (second_line && second_column) { *second_line = values[2]; *second_column = values[3]; @@ -721,40 +714,47 @@ clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) { case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; } - + return "Unknown"; } void print_completion_string(CXCompletionString completion_string, FILE *file) { int I, N; - + N = clang_getNumCompletionChunks(completion_string); for (I = 0; I != N; ++I) { - const char *text = 0; + CXString text; + const char *cstr; enum CXCompletionChunkKind Kind = clang_getCompletionChunkKind(completion_string, I); - + if (Kind == CXCompletionChunk_Optional) { fprintf(file, "{Optional "); print_completion_string( - clang_getCompletionChunkCompletionString(completion_string, I), + clang_getCompletionChunkCompletionString(completion_string, I), file); fprintf(file, "}"); continue; } - + text = clang_getCompletionChunkText(completion_string, I); - fprintf(file, "{%s %s}", + cstr = clang_getCString(text); + fprintf(file, "{%s %s}", clang_getCompletionChunkKindSpelling(Kind), - text? text : ""); + cstr ? cstr : ""); + clang_disposeString(text); } + } void print_completion_result(CXCompletionResult *completion_result, CXClientData client_data) { FILE *file = (FILE *)client_data; - fprintf(file, "%s:", - clang_getCursorKindSpelling(completion_result->CursorKind)); + CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind); + + fprintf(file, "%s:", clang_getCString(ks)); + clang_disposeString(ks); + print_completion_string(completion_result->CompletionString, file); fprintf(file, "\n"); } @@ -771,31 +771,36 @@ 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); - results = clang_codeComplete(CIdx, - argv[argc - 1], argc - num_unsaved_files - 3, - argv + num_unsaved_files + 2, + CIdx = clang_createIndex(0, 1); + 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, - PrintDiagnosticCallback, stderr); + filename, line, column); if (results) { unsigned i, n = results->NumResults; for (i = 0; i != n; ++i) print_completion_result(results->Results + i, stdout); + n = clang_codeCompleteGetNumDiagnostics(results); + for (i = 0; i != n; ++i) { + CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i); + PrintDiagnostic(diag); + clang_disposeDiagnostic(diag); + } clang_disposeCodeCompleteResults(results); } clang_disposeIndex(CIdx); free(filename); - + free_remapped_files(unsaved_files, num_unsaved_files); return 0; @@ -817,52 +822,51 @@ int inspect_cursor_at(int argc, const char **argv) { CursorSourceLocation *Locations = 0; unsigned NumLocations = 0, Loc; - /* Count the number of locations. */ + /* Count the number of locations. */ while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1]) ++NumLocations; - + /* Parse the locations. */ assert(NumLocations > 0 && "Unable to count locations?"); Locations = (CursorSourceLocation *)malloc( NumLocations * sizeof(CursorSourceLocation)); for (Loc = 0; Loc < NumLocations; ++Loc) { const char *input = argv[Loc + 1] + strlen("-cursor-at="); - if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename, - &Locations[Loc].line, + if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename, + &Locations[Loc].line, &Locations[Loc].column, 0, 0))) return errorCode; } - - if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files, + + if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files, &num_unsaved_files)) return -1; - - CIdx = clang_createIndex(0); + + CIdx = clang_createIndex(0, 1); TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], argc - num_unsaved_files - 2 - NumLocations, argv + num_unsaved_files + 1 + NumLocations, num_unsaved_files, - unsaved_files, - PrintDiagnosticCallback, - stderr); + unsaved_files); if (!TU) { fprintf(stderr, "unable to parse input\n"); return -1; } - + for (Loc = 0; Loc < NumLocations; ++Loc) { CXFile file = clang_getFile(TU, Locations[Loc].filename); if (!file) continue; - - Cursor = clang_getCursor(TU, - clang_getLocation(TU, file, Locations[Loc].line, - Locations[Loc].column)); + + Cursor = clang_getCursor(TU, + clang_getLocation(TU, file, Locations[Loc].line, + Locations[Loc].column)); PrintCursor(Cursor); printf("\n"); free(Locations[Loc].filename); } - + + PrintDiagnostics(TU); clang_disposeTranslationUnit(TU); clang_disposeIndex(CIdx); free(Locations); @@ -896,21 +900,19 @@ int perform_token_annotation(int argc, const char **argv) { if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) return -1; - CIdx = clang_createIndex(0); + CIdx = clang_createIndex(0, 1); TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], argc - num_unsaved_files - 3, argv + num_unsaved_files + 2, num_unsaved_files, - unsaved_files, - PrintDiagnosticCallback, - stderr); + unsaved_files); 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); @@ -922,18 +924,18 @@ int perform_token_annotation(int argc, const char **argv) { startLoc = clang_getLocation(TU, file, line, column); if (clang_equalLocations(clang_getNullLocation(), startLoc)) { - fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line, + fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line, column); errorCode = -1; - goto teardown; + 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, + fprintf(stderr, "invalid source location %s:%d:%d\n", filename, second_line, second_column); errorCode = -1; - goto teardown; + goto teardown; } range = clang_getRange(startLoc, endLoc); @@ -953,7 +955,7 @@ int perform_token_annotation(int argc, const char **argv) { case CXToken_Literal: kind = "Literal"; break; case CXToken_Comment: kind = "Comment"; break; } - clang_getInstantiationLocation(clang_getRangeStart(extent), + clang_getInstantiationLocation(clang_getRangeStart(extent), 0, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(extent), 0, &end_line, &end_column, 0); @@ -968,6 +970,7 @@ int perform_token_annotation(int argc, const char **argv) { free(cursors); teardown: + PrintDiagnostics(TU); clang_disposeTranslationUnit(TU); clang_disposeIndex(CIdx); free(filename); @@ -1002,7 +1005,8 @@ static void print_usage(void) { fprintf(stderr, " c-index-test -test-annotate-tokens= {}*\n" " c-index-test -test-inclusion-stack-source {}*\n" - " c-index-test -test-inclusion-stack-tu \n\n" + " c-index-test -test-inclusion-stack-tu \n" + " c-index-test -test-print-linkage-source {}*\n\n" " values:\n%s", " all - load all symbols, including those from PCH\n" " local - load all symbols except those in PCH\n" @@ -1015,6 +1019,7 @@ static void print_usage(void) { } int main(int argc, const char **argv) { + clang_enableStackTraces(); if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) return perform_code_completion(argc, argv); if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1]) @@ -1041,7 +1046,10 @@ int main(int argc, const char **argv) { else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0) return perform_test_load_tu(argv[2], "all", NULL, NULL, PrintInclusionStack); - + else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) + return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, + NULL); + print_usage(); return 1; } diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 05fb698..294a680 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -19,6 +19,7 @@ #include "clang/Driver/CC1Options.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/OptTable.h" +#include "clang/Frontend/CodeGenAction.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" @@ -30,10 +31,8 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Signals.h" #include "llvm/Target/TargetSelect.h" #include using namespace clang; diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index b6fc981..fa0f0c2 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -15,12 +15,15 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Option.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Config/config.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" @@ -28,38 +31,6 @@ using namespace clang; using namespace clang::driver; -class DriverDiagnosticPrinter : public DiagnosticClient { - std::string ProgName; - llvm::raw_ostream &OS; - -public: - DriverDiagnosticPrinter(const std::string _ProgName, - llvm::raw_ostream &_OS) - : ProgName(_ProgName), - OS(_OS) {} - - virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info); -}; - -void DriverDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { - OS << ProgName << ": "; - - switch (Level) { - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: OS << "note: "; break; - case Diagnostic::Warning: OS << "warning: "; break; - case Diagnostic::Error: OS << "error: "; break; - case Diagnostic::Fatal: OS << "fatal error: "; break; - } - - llvm::SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); - OS.write(OutStr.begin(), OutStr.size()); - OS << '\n'; -} - llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { if (!CanonicalPrefixes) return llvm::sys::Path(Argv0); @@ -71,7 +42,7 @@ llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { } static const char *SaveStringInSet(std::set &SavedStrings, - const std::string &S) { + llvm::StringRef S) { return SavedStrings.insert(S).first->c_str(); } @@ -87,8 +58,8 @@ static const char *SaveStringInSet(std::set &SavedStrings, /// /// '+': Add FOO as a new argument at the end of the command line. /// -/// 's/XXX/YYY/': Replace the literal argument XXX by YYY in the -/// command line. +/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command +/// line. /// /// 'xOPTION': Removes all instances of the literal argument OPTION. /// @@ -104,20 +75,34 @@ static const char *SaveStringInSet(std::set &SavedStrings, /// \param SavedStrings - Set to use for storing string representations. void ApplyOneQAOverride(llvm::raw_ostream &OS, std::vector &Args, - const std::string &Edit, + llvm::StringRef Edit, std::set &SavedStrings) { // This does not need to be efficient. if (Edit[0] == '^') { const char *Str = - SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos)); + SaveStringInSet(SavedStrings, Edit.substr(1)); OS << "### Adding argument " << Str << " at beginning\n"; Args.insert(Args.begin() + 1, Str); } else if (Edit[0] == '+') { const char *Str = - SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos)); + SaveStringInSet(SavedStrings, Edit.substr(1)); OS << "### Adding argument " << Str << " at end\n"; Args.push_back(Str); + } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") && + Edit.slice(2, Edit.size()-1).find('/') != llvm::StringRef::npos) { + llvm::StringRef MatchPattern = Edit.substr(2).split('/').first; + llvm::StringRef ReplPattern = Edit.substr(2).split('/').second; + ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1); + + for (unsigned i = 1, e = Args.size(); i != e; ++i) { + std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]); + + if (Repl != Args[i]) { + OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n"; + Args[i] = SaveStringInSet(SavedStrings, Repl); + } + } } else if (Edit[0] == 'x' || Edit[0] == 'X') { std::string Option = Edit.substr(1, std::string::npos); for (unsigned i = 1; i < Args.size();) { @@ -147,7 +132,7 @@ void ApplyOneQAOverride(llvm::raw_ostream &OS, ++i; } OS << "### Adding argument " << Edit << " at end\n"; - Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit)); + Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit.str())); } else { OS << "### Unrecognized edit: " << Edit << "\n"; } @@ -203,7 +188,8 @@ int main(int argc, const char **argv) { llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); - DriverDiagnosticPrinter DiagClient(Path.getBasename(), llvm::errs()); + TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); + DiagClient.setPrefix(Path.getBasename()); Diagnostic Diags(&DiagClient); diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer index 8c64d3f..e3db5ea 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/ccc-analyzer @@ -339,6 +339,8 @@ my %LinkerOptionMap = ( my %CompilerLinkerOptionMap = ( '-isysroot' => 1, '-arch' => 1, + '-m32' => 0, + '-m64' => 0, '-v' => 0, '-fpascal-strings' => 0, '-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '=' -- cgit v1.1