diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/CIndex/CIndex.cpp | 1167 | ||||
-rw-r--r-- | tools/CIndex/CIndex.exports | 7 | ||||
-rw-r--r-- | tools/CIndex/CIndexCodeCompletion.cpp | 371 | ||||
-rw-r--r-- | tools/CIndex/CIndexUSRs.cpp | 203 | ||||
-rw-r--r-- | tools/CIndex/CIndexer.cpp | 96 | ||||
-rw-r--r-- | tools/CIndex/CIndexer.h | 88 | ||||
-rw-r--r-- | tools/CIndex/CMakeLists.txt | 7 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 125 | ||||
-rw-r--r-- | tools/driver/cc1_main.cpp | 99 |
9 files changed, 1330 insertions, 833 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 9b2355d..86e0ddc 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -7,49 +7,116 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Clang-C Source Indexing library. +// This file implements the main API hooks in the Clang-C Source Indexing +// library. // //===----------------------------------------------------------------------===// -#include "clang-c/Index.h" -#include "clang/AST/Decl.h" +#include "CIndexer.h" + #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Version.h" -#include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Index/ASTLocation.h" -#include "clang/Index/Indexer.h" -#include "clang/Index/Program.h" -#include "clang/Index/Utils.h" -#include "clang/Sema/CodeCompleteConsumer.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Config/config.h" -#include "llvm/Support/Compiler.h" +#include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" #include "llvm/System/Program.h" +// Needed to define L_TMPNAM on some systems. #include <cstdio> -#include <vector> -#include <sstream> - -#ifdef LLVM_ON_WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#else -#include <dlfcn.h> -#endif using namespace clang; using namespace idx; +//===----------------------------------------------------------------------===// +// Crash Reporting. +//===----------------------------------------------------------------------===// + +#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 +static unsigned crashtracer_counter = 0; +static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 }; +static const char *crashtracer_strings[NUM_CRASH_STRINGS] = { 0 }; +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) + slot = 0; + } + crashtracer_strings[slot] = str; + crashtracer_counter_id[slot] = ++crashtracer_counter; + + // We need to create an aggregate string because multiple threads + // may be in this method at one time. The crash reporter string + // will attempt to overapproximate the set of in-flight invocations + // of this function. Race conditions can still cause this goal + // to not be achieved. + { + llvm::raw_svector_ostream Out(AggStr); + for (unsigned i = 0; i < NUM_CRASH_STRINGS; ++i) + if (crashtracer_strings[i]) Out << crashtracer_strings[i] << '\n'; + } + __crashreporter_info__ = agg_crashtracer_strings[slot] = AggStr.c_str(); + return slot; +} + +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) + if (agg_crashtracer_strings[i] && + crashtracer_counter_id[i] > max_value) { + max_slot = i; + max_value = crashtracer_counter_id[i]; + } + + __crashreporter_info__ = agg_crashtracer_strings[max_slot]; +} + +namespace { +class ArgsCrashTracerInfo { + llvm::SmallString<1024> CrashString; + llvm::SmallString<1024> AggregateString; + unsigned crashtracerSlot; +public: + ArgsCrashTracerInfo(llvm::SmallVectorImpl<const char*> &Args) + : crashtracerSlot(0) + { + { + llvm::raw_svector_ostream Out(CrashString); + Out << "ClangCIndex [createTranslationUnitFromSourceFile]: clang"; + for (llvm::SmallVectorImpl<const char*>::iterator I=Args.begin(), + E=Args.end(); I!=E; ++I) + Out << ' ' << *I; + } + crashtracerSlot = SetCrashTracerInfo(CrashString.c_str(), + AggregateString); + } + + ~ArgsCrashTracerInfo() { + ResetCrashTracerInfo(crashtracerSlot); + } +}; +} +#endif +#endif + +//===----------------------------------------------------------------------===// +// Visitors. +//===----------------------------------------------------------------------===// + namespace { -static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) -{ +static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) { NamedDecl *D = DRE->getDecl(); if (isa<VarDecl>(D)) return CXCursor_VarRef; @@ -97,18 +164,14 @@ public: }; #endif -/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted -/// warnings and errors. -class VISIBILITY_HIDDEN IgnoreDiagnosticsClient : public DiagnosticClient { -public: - virtual ~IgnoreDiagnosticsClient() {} - virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {} -}; - // Translation Unit Visitor. + class TUVisitor : public DeclVisitor<TUVisitor> { - CXTranslationUnit TUnit; - CXTranslationUnitIterator Callback; +public: + typedef void (*Iterator)(void *, CXCursor, CXClientData); +private: + void *Root; // CXDecl or CXTranslationUnit + Iterator Callback; // CXTranslationUnitIterator or CXDeclIterator. CXClientData CData; // MaxPCHLevel - the maximum PCH level of declarations that we will pass on @@ -125,45 +188,60 @@ class TUVisitor : public DeclVisitor<TUVisitor> { if (ND->isImplicit()) return; - CXCursor C = { CK, ND, 0 }; - Callback(TUnit, C, CData); + CXCursor C = { CK, ND, 0, 0 }; + Callback(Root, C, CData); } + public: - TUVisitor(CXTranslationUnit CTU, - CXTranslationUnitIterator cback, CXClientData D, - unsigned MaxPCHLevel) : - TUnit(CTU), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} + TUVisitor(void *root, Iterator cback, CXClientData D, unsigned MaxPCHLevel) : + Root(root), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} + + void VisitDeclContext(DeclContext *DC); + void VisitFunctionDecl(FunctionDecl *ND); + void VisitObjCCategoryDecl(ObjCCategoryDecl *ND); + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND); + void VisitObjCImplementationDecl(ObjCImplementationDecl *ND); + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND); + void VisitObjCProtocolDecl(ObjCProtocolDecl *ND); + void VisitTagDecl(TagDecl *ND); + void VisitTranslationUnitDecl(TranslationUnitDecl *D); + void VisitTypedefDecl(TypedefDecl *ND); + void VisitVarDecl(VarDecl *ND); +}; - void VisitTranslationUnitDecl(TranslationUnitDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); - } - void VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) - Visit(*I); - } +void TUVisitor::VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + I != E; ++I) + Visit(*I); +} + +void TUVisitor::VisitFunctionDecl(FunctionDecl *ND) { + Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn + : CXCursor_FunctionDecl, ND); +} + +void TUVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + Call(CXCursor_ObjCCategoryDecl, ND); +} - void VisitFunctionDecl(FunctionDecl *ND) { - Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn - : CXCursor_FunctionDecl, ND); - } - void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { - Call(CXCursor_ObjCCategoryDecl, ND); - } - void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) { - Call(CXCursor_ObjCCategoryDefn, ND); - } - void VisitObjCImplementationDecl(ObjCImplementationDecl *ND) { - Call(CXCursor_ObjCClassDefn, ND); - } - void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) { - Call(CXCursor_ObjCInterfaceDecl, ND); - } - void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) { - Call(CXCursor_ObjCProtocolDecl, ND); - } - void VisitTagDecl(TagDecl *ND) { - switch (ND->getTagKind()) { +void TUVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) { + Call(CXCursor_ObjCCategoryDefn, ND); +} + +void TUVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *ND) { + Call(CXCursor_ObjCClassDefn, ND); +} + +void TUVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) { + Call(CXCursor_ObjCInterfaceDecl, ND); +} + +void TUVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *ND) { + Call(CXCursor_ObjCProtocolDecl, ND); +} + +void TUVisitor::VisitTagDecl(TagDecl *ND) { + switch (ND->getTagKind()) { case TagDecl::TK_struct: Call(CXCursor_StructDecl, ND); break; @@ -176,16 +254,20 @@ public: case TagDecl::TK_enum: Call(CXCursor_EnumDecl, ND); break; - } } - void VisitTypedefDecl(TypedefDecl *ND) { - Call(CXCursor_TypedefDecl, ND); - } - void VisitVarDecl(VarDecl *ND) { - Call(CXCursor_VarDecl, ND); - } -}; +} + +void TUVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); +} + +void TUVisitor::VisitTypedefDecl(TypedefDecl *ND) { + Call(CXCursor_TypedefDecl, ND); +} +void TUVisitor::VisitVarDecl(VarDecl *ND) { + Call(CXCursor_VarDecl, ND); +} // Declaration visitor. class CDeclVisitor : public DeclVisitor<CDeclVisitor> { @@ -207,7 +289,7 @@ class CDeclVisitor : public DeclVisitor<CDeclVisitor> { if (ND->getPCHLevel() > MaxPCHLevel) return; - CXCursor C = { CK, ND, 0 }; + CXCursor C = { CK, ND, 0, 0 }; Callback(CDecl, C, CData); } public: @@ -215,188 +297,112 @@ public: unsigned MaxPCHLevel) : CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} - void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { - // Issue callbacks for the containing class. - Call(CXCursor_ObjCClassRef, ND); - // FIXME: Issue callbacks for protocol refs. - VisitDeclContext(dyn_cast<DeclContext>(ND)); - } - void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { - // Issue callbacks for super class. - if (D->getSuperClass()) - Call(CXCursor_ObjCSuperClassRef, D); - - for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); I != E; ++I) - Call(CXCursor_ObjCProtocolRef, *I); - VisitDeclContext(dyn_cast<DeclContext>(D)); - } - void VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), - E = PID->protocol_end(); I != E; ++I) - Call(CXCursor_ObjCProtocolRef, *I); - - VisitDeclContext(dyn_cast<DeclContext>(PID)); - } - void VisitTagDecl(TagDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); - } - void VisitObjCImplementationDecl(ObjCImplementationDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); - } - void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); - } - void VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) - Visit(*I); - } - void VisitEnumConstantDecl(EnumConstantDecl *ND) { - Call(CXCursor_EnumConstantDecl, ND); - } - void VisitFieldDecl(FieldDecl *ND) { - Call(CXCursor_FieldDecl, ND); - } - void VisitVarDecl(VarDecl *ND) { - Call(CXCursor_VarDecl, ND); - } - void VisitParmVarDecl(ParmVarDecl *ND) { - Call(CXCursor_ParmDecl, ND); - } - void VisitObjCPropertyDecl(ObjCPropertyDecl *ND) { - Call(CXCursor_ObjCPropertyDecl, ND); - } - void VisitObjCIvarDecl(ObjCIvarDecl *ND) { - Call(CXCursor_ObjCIvarDecl, ND); - } - void VisitFunctionDecl(FunctionDecl *ND) { - if (ND->isThisDeclarationADefinition()) { - VisitDeclContext(dyn_cast<DeclContext>(ND)); -#if 0 - // Not currently needed. - CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody()); - CRefVisitor RVisit(CDecl, Callback, CData); - RVisit.Visit(Body); -#endif - } - } - void VisitObjCMethodDecl(ObjCMethodDecl *ND) { - if (ND->getBody()) { - Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn - : CXCursor_ObjCClassMethodDefn, ND); - VisitDeclContext(dyn_cast<DeclContext>(ND)); - } else - Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl - : CXCursor_ObjCClassMethodDecl, ND); - } + void VisitDeclContext(DeclContext *DC); + void VisitEnumConstantDecl(EnumConstantDecl *ND); + void VisitFieldDecl(FieldDecl *ND); + void VisitFunctionDecl(FunctionDecl *ND); + void VisitObjCCategoryDecl(ObjCCategoryDecl *ND); + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + void VisitObjCImplementationDecl(ObjCImplementationDecl *D); + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + void VisitObjCIvarDecl(ObjCIvarDecl *ND); + void VisitObjCMethodDecl(ObjCMethodDecl *ND); + void VisitObjCPropertyDecl(ObjCPropertyDecl *ND); + void VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + void VisitParmVarDecl(ParmVarDecl *ND); + void VisitTagDecl(TagDecl *D); + void VisitVarDecl(VarDecl *ND); }; +} // end anonymous namespace -class CIndexer : public Indexer { - DiagnosticOptions DiagOpts; - IgnoreDiagnosticsClient IgnoreDiagClient; - llvm::OwningPtr<Diagnostic> TextDiags; - Diagnostic IgnoreDiags; - bool UseExternalASTGeneration; - bool OnlyLocalDecls; - bool DisplayDiagnostics; - - llvm::sys::Path ClangPath; - -public: - explicit CIndexer(Program *prog) : Indexer(*prog), - IgnoreDiags(&IgnoreDiagClient), - UseExternalASTGeneration(false), - OnlyLocalDecls(false), - DisplayDiagnostics(false) { - TextDiags.reset( - CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); - } +void CDeclVisitor::VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) + Visit(*I); +} - virtual ~CIndexer() { delete &getProgram(); } +void CDeclVisitor::VisitEnumConstantDecl(EnumConstantDecl *ND) { + Call(CXCursor_EnumConstantDecl, ND); +} - /// \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 - /// declarations. - bool getOnlyLocalDecls() const { return OnlyLocalDecls; } - void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; } +void CDeclVisitor::VisitFieldDecl(FieldDecl *ND) { + Call(CXCursor_FieldDecl, ND); +} - bool getDisplayDiagnostics() const { return DisplayDiagnostics; } - void setDisplayDiagnostics(bool Display = true) { - DisplayDiagnostics = Display; +void CDeclVisitor::VisitFunctionDecl(FunctionDecl *ND) { + if (ND->isThisDeclarationADefinition()) { + VisitDeclContext(dyn_cast<DeclContext>(ND)); +#if 0 + // Not currently needed. + CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody()); + CRefVisitor RVisit(CDecl, Callback, CData); + RVisit.Visit(Body); +#endif } +} - bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; } - void setUseExternalASTGeneration(bool Value) { - UseExternalASTGeneration = Value; - } +void CDeclVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + // Issue callbacks for the containing class. + Call(CXCursor_ObjCClassRef, ND); + // FIXME: Issue callbacks for protocol refs. + VisitDeclContext(dyn_cast<DeclContext>(ND)); +} - Diagnostic &getDiags() { - return DisplayDiagnostics ? *TextDiags : IgnoreDiags; - } +void CDeclVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); +} - /// \brief Get the path of the clang binary. - const llvm::sys::Path& getClangPath(); +void CDeclVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); +} - /// \brief Get the path of the clang resource files. - std::string getClangResourcesPath(); -}; +void CDeclVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Issue callbacks for super class. + if (D->getSuperClass()) + Call(CXCursor_ObjCSuperClassRef, D); + + for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); I != E; ++I) + Call(CXCursor_ObjCProtocolRef, *I); + VisitDeclContext(dyn_cast<DeclContext>(D)); +} -const llvm::sys::Path& CIndexer::getClangPath() { - // Did we already compute the path? - if (!ClangPath.empty()) - return ClangPath; - - // Find the location where this library lives (libCIndex.dylib). -#ifdef LLVM_ON_WIN32 - MEMORY_BASIC_INFORMATION mbi; - char path[MAX_PATH]; - VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi, - sizeof(mbi)); - GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH); - - llvm::sys::Path CIndexPath(path); - - CIndexPath.eraseComponent(); - CIndexPath.appendComponent("clang"); - CIndexPath.appendSuffix("exe"); - CIndexPath.makeAbsolute(); -#else - // This silly cast below avoids a C++ warning. - Dl_info info; - if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0) - assert(0 && "Call to dladdr() failed"); - - llvm::sys::Path CIndexPath(info.dli_fname); - - // We now have the CIndex directory, locate clang relative to it. - CIndexPath.eraseComponent(); - CIndexPath.eraseComponent(); - CIndexPath.appendComponent("bin"); - CIndexPath.appendComponent("clang"); -#endif +void CDeclVisitor::VisitObjCIvarDecl(ObjCIvarDecl *ND) { + Call(CXCursor_ObjCIvarDecl, ND); +} - // Cache our result. - ClangPath = CIndexPath; - return ClangPath; +void CDeclVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { + if (ND->getBody()) { + Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn + : CXCursor_ObjCClassMethodDefn, ND); + VisitDeclContext(dyn_cast<DeclContext>(ND)); + } else + Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl + : CXCursor_ObjCClassMethodDecl, ND); } -std::string CIndexer::getClangResourcesPath() { - llvm::sys::Path P = getClangPath(); +void CDeclVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *ND) { + Call(CXCursor_ObjCPropertyDecl, ND); +} - if (!P.empty()) { - P.eraseComponent(); // Remove /clang from foo/bin/clang - P.eraseComponent(); // Remove /bin from foo/bin +void CDeclVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I) + Call(CXCursor_ObjCProtocolRef, *I); + + VisitDeclContext(dyn_cast<DeclContext>(PID)); +} - // Get foo/lib/clang/<version>/include - P.appendComponent("lib"); - P.appendComponent("clang"); - P.appendComponent(CLANG_VERSION_STRING); - } +void CDeclVisitor::VisitParmVarDecl(ParmVarDecl *ND) { + Call(CXCursor_ParmDecl, ND); +} - return P.str(); +void CDeclVisitor::VisitTagDecl(TagDecl *D) { + VisitDeclContext(dyn_cast<DeclContext>(D)); } +void CDeclVisitor::VisitVarDecl(VarDecl *ND) { + Call(CXCursor_VarDecl, ND); } static SourceLocation getLocationFromCursor(CXCursor C, @@ -463,7 +469,7 @@ static SourceLocation getLocationFromCursor(CXCursor C, } } -static CXString createCXString(const char *String, bool DupString = false) { +CXString CIndexer::createCXString(const char *String, bool DupString){ CXString Str; if (DupString) { Str.Spelling = strdup(String); @@ -476,7 +482,6 @@ static CXString createCXString(const char *String, bool DupString = false) { } extern "C" { - CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics) { CIndexer *CIdxr = new CIndexer(new Program()); @@ -529,13 +534,18 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, command_line_args + num_command_line_args); unsigned NumErrors = CXXIdx->getDiags().getNumErrors(); + +#ifdef USE_CRASHTRACER + ArgsCrashTracerInfo ACTI(Args); +#endif + llvm::OwningPtr<ASTUnit> Unit( ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(), CXXIdx->getDiags(), CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), /* UseBumpAllocator = */ true)); - + // FIXME: Until we have broader testing, just drop the entire AST if we // encountered an error. if (NumErrors != CXXIdx->getDiags().getNumErrors()) @@ -621,7 +631,8 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { assert(CTUnit && "Passed null CXTranslationUnit"); ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); - return createCXString(CXXUnit->getOriginalSourceFileName().c_str(), true); + return CIndexer::createCXString(CXXUnit->getOriginalSourceFileName().c_str(), + true); } void clang_loadTranslationUnit(CXTranslationUnit CTUnit, @@ -665,61 +676,41 @@ void clang_loadDeclaration(CXDecl Dcl, static_cast<Decl *>(Dcl)->getPCHLevel()); DVisit.Visit(static_cast<Decl *>(Dcl)); } +} // end: extern "C" -// Some notes on CXEntity: -// -// - Since the 'ordinary' namespace includes functions, data, typedefs, -// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one -// entity for 2 different types). For example: -// -// module1.m: @interface Foo @end Foo *x; -// module2.m: void Foo(int); -// -// - Since the unique name spans translation units, static data/functions -// within a CXTranslationUnit are *not* currently represented by entities. -// As a result, there will be no entity for the following: -// -// module.m: static void Foo() { } -// - - -const char *clang_getDeclarationName(CXEntity) { - return ""; -} - -const char *clang_getURI(CXEntity) { - return ""; -} - -CXEntity clang_getEntity(const char *URI) { - return 0; -} - -// +//===----------------------------------------------------------------------===// // CXDecl Operations. -// +//===----------------------------------------------------------------------===// -CXEntity clang_getEntityFromDecl(CXDecl) { - return 0; +static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr, + SourceLocation SLoc) { + FileID FID; + if (SLoc.isFileID()) + FID = SMgr.getFileID(SLoc); + else + FID = SMgr.getDecomposedSpellingLoc(SLoc).first; + return SMgr.getFileEntryForID(FID); } +extern "C" { CXString clang_getDeclSpelling(CXDecl AnonDecl) { assert(AnonDecl && "Passed null CXDecl"); NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) - return createCXString(OMD->getSelector().getAsString().c_str(), true); + return CIndexer::createCXString(OMD->getSelector().getAsString().c_str(), + true); if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(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 createCXString(CIMP->getIdentifier()->getNameStart()); + return CIndexer::createCXString(CIMP->getIdentifier()->getNameStart()); if (ND->getIdentifier()) - return createCXString(ND->getIdentifier()->getNameStart()); + return CIndexer::createCXString(ND->getIdentifier()->getNameStart()); - return createCXString(""); + return CIndexer::createCXString(""); } unsigned clang_getDeclLine(CXDecl AnonDecl) { @@ -735,23 +726,67 @@ unsigned clang_getDeclColumn(CXDecl AnonDecl) { SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); return SourceMgr.getSpellingColumnNumber(ND->getLocation()); } + +CXDeclExtent clang_getDeclExtent(CXDecl AnonDecl) { + assert(AnonDecl && "Passed null CXDecl"); + NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); + SourceManager &SM = ND->getASTContext().getSourceManager(); + SourceRange R = ND->getSourceRange(); + + SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); + SourceLocation End = SM.getInstantiationLoc(R.getEnd()); + + if (!Begin.isValid()) { + CXDeclExtent extent = { { 0, 0 }, { 0, 0 } }; + return extent; + } + + // FIXME: This is largely copy-paste from + ///TextDiagnosticPrinter::HighlightRange. When it is clear that this is + // what we want the two routines should be refactored. + + // If the End location and the start location are the same and are a macro + // location, then the range was something that came from a macro expansion + // or _Pragma. If this is an object-like macro, the best we can do is to + // get the range. If this is a function-like macro, we'd also like to + // get the arguments. + if (Begin == End && R.getEnd().isMacroID()) + End = SM.getInstantiationRange(R.getEnd()).second; + + assert(SM.getFileID(Begin) == SM.getFileID(End)); + unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); + unsigned EndLineNo = SM.getInstantiationLineNumber(End); + + // Compute the column number of the start. Keep the column based at 1. + unsigned StartColNo = SM.getInstantiationColumnNumber(Begin); + + // Compute the column number of the end. + unsigned EndColNo = SM.getInstantiationColumnNumber(End); + if (EndColNo) { + // Offset the end column by 1 so that we point to the last character + // in the last token. + --EndColNo; + + // Add in the length of the token, so that we cover multi-char tokens. + ASTContext &Ctx = ND->getTranslationUnitDecl()->getASTContext(); + const LangOptions &LOpts = Ctx.getLangOptions(); + + EndColNo += Lexer::MeasureTokenLength(End, SM, LOpts); + } + + // Package up the line/column data and return to the caller. + CXDeclExtent extent = { { StartLineNo, StartColNo }, + { EndLineNo, EndColNo } }; + return extent; +} const char *clang_getDeclSource(CXDecl AnonDecl) { assert(AnonDecl && "Passed null CXDecl"); FileEntry *FEnt = static_cast<FileEntry *>(clang_getDeclSourceFile(AnonDecl)); - assert (FEnt && "Cannot find FileEntry for Decl"); + assert(FEnt && "Cannot find FileEntry for Decl"); return clang_getFileName(FEnt); } -static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr, - SourceLocation SLoc) { - FileID FID; - if (SLoc.isFileID()) - FID = SMgr.getFileID(SLoc); - else - FID = SMgr.getDecomposedSpellingLoc(SLoc).first; - return SMgr.getFileEntryForID(FID); -} CXFile clang_getDeclSourceFile(CXDecl AnonDecl) { assert(AnonDecl && "Passed null CXDecl"); @@ -759,7 +794,13 @@ CXFile clang_getDeclSourceFile(CXDecl AnonDecl) { SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); return (void *)getFileEntryFromSourceLocation(SourceMgr, ND->getLocation()); } +} // end: extern "C" +//===----------------------------------------------------------------------===// +// CXFile Operations. +//===----------------------------------------------------------------------===// + +extern "C" { const char *clang_getFileName(CXFile SFile) { assert(SFile && "Passed null CXFile"); FileEntry *FEnt = static_cast<FileEntry *>(SFile); @@ -771,7 +812,67 @@ time_t clang_getFileTime(CXFile SFile) { FileEntry *FEnt = static_cast<FileEntry *>(SFile); return FEnt->getModificationTime(); } +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// CXCursor Operations. +//===----------------------------------------------------------------------===// + +static enum CXCursorKind TranslateKind(Decl *D) { + switch (D->getKind()) { + case Decl::Function: return CXCursor_FunctionDecl; + case Decl::Typedef: return CXCursor_TypedefDecl; + case Decl::Enum: return CXCursor_EnumDecl; + case Decl::EnumConstant: return CXCursor_EnumConstantDecl; + case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class + case Decl::Field: return CXCursor_FieldDecl; + case Decl::Var: return CXCursor_VarDecl; + case Decl::ParmVar: return CXCursor_ParmDecl; + case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; + case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; + case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; + case Decl::ObjCMethod: { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D); + if (MD->isInstanceMethod()) + return CXCursor_ObjCInstanceMethodDecl; + return CXCursor_ObjCClassMethodDecl; + } + default: break; + } + return CXCursor_NotImplemented; +} + + +static CXCursor MakeCXCursor(CXCursorKind K, Decl *D) { + CXCursor C = { K, D, 0, 0 }; + return C; +} + +static CXCursor MakeCXCursor(CXCursorKind K, Decl *D, Stmt *S) { + assert(clang_isReference(K)); + CXCursor C = { K, D, S, 0 }; + return C; +} + +static Decl *getDeclFromExpr(Stmt *E) { + if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) + return RefExpr->getDecl(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl(); + if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) + return RE->getDecl(); + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) + return getDeclFromExpr(CE->getCallee()); + if (CastExpr *CE = dyn_cast<CastExpr>(E)) + return getDeclFromExpr(CE->getSubExpr()); + if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) + return OME->getMethodDecl(); + + return 0; +} +extern "C" { CXString clang_getCursorSpelling(CXCursor C) { assert(C.decl && "CXCursor has null decl"); NamedDecl *ND = static_cast<NamedDecl *>(C.decl); @@ -781,28 +882,29 @@ CXString clang_getCursorSpelling(CXCursor C) { case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); assert(OID && "clang_getCursorLine(): Missing interface decl"); - return createCXString(OID->getSuperClass()->getIdentifier() - ->getNameStart()); + return CIndexer::createCXString(OID->getSuperClass()->getIdentifier() + ->getNameStart()); } case CXCursor_ObjCClassRef: { if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) - return createCXString(OID->getIdentifier()->getNameStart()); + return CIndexer::createCXString(OID->getIdentifier()->getNameStart()); ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND); assert(OCD && "clang_getCursorLine(): Missing category decl"); - return createCXString(OCD->getClassInterface()->getIdentifier() + return CIndexer::createCXString(OCD->getClassInterface()->getIdentifier() ->getNameStart()); } case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); assert(OID && "clang_getCursorLine(): Missing protocol decl"); - return createCXString(OID->getIdentifier()->getNameStart()); + return CIndexer::createCXString(OID->getIdentifier()->getNameStart()); } case CXCursor_ObjCSelectorRef: { ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( static_cast<Stmt *>(C.stmt)); assert(OME && "clang_getCursorLine(): Missing message expr"); - return createCXString(OME->getSelector().getAsString().c_str(), true); + return CIndexer::createCXString(OME->getSelector().getAsString().c_str(), + true); } case CXCursor_VarRef: case CXCursor_FunctionRef: @@ -810,10 +912,11 @@ CXString clang_getCursorSpelling(CXCursor C) { DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( static_cast<Stmt *>(C.stmt)); assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return createCXString(DRE->getDecl()->getIdentifier()->getNameStart()); + return CIndexer::createCXString(DRE->getDecl()->getIdentifier() + ->getNameStart()); } default: - return createCXString("<not implemented>"); + return CIndexer::createCXString("<not implemented>"); } } return clang_getDeclSpelling(C.decl); @@ -860,33 +963,6 @@ const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) { } } -static enum CXCursorKind TranslateKind(Decl *D) { - switch (D->getKind()) { - case Decl::Function: return CXCursor_FunctionDecl; - case Decl::Typedef: return CXCursor_TypedefDecl; - case Decl::Enum: return CXCursor_EnumDecl; - case Decl::EnumConstant: return CXCursor_EnumConstantDecl; - case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class - case Decl::Field: return CXCursor_FieldDecl; - case Decl::Var: return CXCursor_VarDecl; - case Decl::ParmVar: return CXCursor_ParmDecl; - case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; - case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; - case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; - case Decl::ObjCMethod: { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D); - if (MD->isInstanceMethod()) - return CXCursor_ObjCInstanceMethodDecl; - return CXCursor_ObjCClassMethodDecl; - } - default: break; - } - return CXCursor_NotImplemented; -} -// -// CXCursor Operations. -// - CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, unsigned line, unsigned column) { assert(CTUnit && "Passed null CXTranslationUnit"); @@ -895,17 +971,17 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, FileManager &FMgr = CXXUnit->getFileManager(); const FileEntry *File = FMgr.getFile(source_name, source_name+strlen(source_name)); - if (!File) { - CXCursor C = { CXCursor_InvalidFile, 0, 0 }; - return C; - } + if (!File) + return clang_getNullCursor(); + SourceLocation SLoc = CXXUnit->getSourceManager().getLocation(File, line, column); ASTLocation LastLoc = CXXUnit->getLastASTLocation(); - ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc, &LastLoc); + + // FIXME: This doesn't look thread-safe. if (ALoc.isValid()) CXXUnit->setLastASTLocation(ALoc); @@ -915,50 +991,40 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, Stmt *Stm = ALoc.dyn_AsStmt(); if (Dcl) { if (Stm) { - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) { - CXCursor C = { TranslateDeclRefExpr(DRE), Dcl, Stm }; - return C; - } else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) { - CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp }; - return C; - } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) + return MakeCXCursor(TranslateDeclRefExpr(DRE), Dcl, Stm); + else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) + return MakeCXCursor(CXCursor_ObjCSelectorRef, Dcl, MExp); // Fall through...treat as a decl, not a ref. } if (ALoc.isNamedRef()) { if (isa<ObjCInterfaceDecl>(Dcl)) { - CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl() }; + CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl(), 0 }; return C; } if (isa<ObjCProtocolDecl>(Dcl)) { - CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl() }; + CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl(), 0 }; return C; } } - CXCursor C = { TranslateKind(Dcl), Dcl, 0 }; - return C; + return MakeCXCursor(TranslateKind(Dcl), Dcl); } - CXCursor C = { CXCursor_NoDeclFound, 0, 0 }; - return C; + return MakeCXCursor(CXCursor_NoDeclFound, 0); } CXCursor clang_getNullCursor(void) { - CXCursor C; - C.kind = CXCursor_InvalidFile; - C.decl = NULL; - C.stmt = NULL; - return C; + return MakeCXCursor(CXCursor_InvalidFile, 0); } unsigned clang_equalCursors(CXCursor X, CXCursor Y) { - return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt; + return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt && + X.referringDecl == Y.referringDecl; } CXCursor clang_getCursorFromDecl(CXDecl AnonDecl) { assert(AnonDecl && "Passed null CXDecl"); NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - - CXCursor C = { TranslateKind(ND), ND, 0 }; - return C; + return MakeCXCursor(TranslateKind(ND), ND); } unsigned clang_isInvalid(enum CXCursorKind K) { @@ -981,24 +1047,6 @@ CXCursorKind clang_getCursorKind(CXCursor C) { return C.kind; } -static Decl *getDeclFromExpr(Stmt *E) { - if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) - return RefExpr->getDecl(); - if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) - return ME->getMemberDecl(); - if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) - return RE->getDecl(); - - if (CallExpr *CE = dyn_cast<CallExpr>(E)) - return getDeclFromExpr(CE->getCallee()); - if (CastExpr *CE = dyn_cast<CastExpr>(E)) - return getDeclFromExpr(CE->getSubExpr()); - if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) - return OME->getMethodDecl(); - - return 0; -} - CXDecl clang_getCursorDecl(CXCursor C) { if (clang_isDeclaration(C.kind)) return C.decl; @@ -1024,21 +1072,12 @@ unsigned clang_getCursorLine(CXCursor C) { SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); return SourceMgr.getSpellingLineNumber(SLoc); } - -const char *clang_getCString(CXString string) { - return string.Spelling; -} - -void clang_disposeString(CXString string) { - if (string.MustFreeString) - free((void*)string.Spelling); -} - + unsigned clang_getCursorColumn(CXCursor C) { assert(C.decl && "CXCursor has null decl"); NamedDecl *ND = static_cast<NamedDecl *>(C.decl); SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - + SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); return SourceMgr.getSpellingColumnNumber(SLoc); } @@ -1047,22 +1086,22 @@ const char *clang_getCursorSource(CXCursor C) { assert(C.decl && "CXCursor has null decl"); NamedDecl *ND = static_cast<NamedDecl *>(C.decl); SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - + SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); - + if (SLoc.isFileID()) { const char *bufferName = SourceMgr.getBufferName(SLoc); return bufferName[0] == '<' ? NULL : bufferName; } - + // Retrieve the file in which the macro was instantiated, then provide that // buffer name. // FIXME: Do we want to give specific macro-instantiation information? const llvm::MemoryBuffer *Buffer - = SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first); + = SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first); if (!Buffer) return 0; - + return Buffer->getBufferIdentifier(); } @@ -1070,9 +1109,10 @@ CXFile clang_getCursorSourceFile(CXCursor C) { assert(C.decl && "CXCursor has null decl"); NamedDecl *ND = static_cast<NamedDecl *>(C.decl); SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - - return (void *)getFileEntryFromSourceLocation(SourceMgr, - getLocationFromCursor(C,SourceMgr, ND)); + + return (void *) + getFileEntryFromSourceLocation(SourceMgr, getLocationFromCursor(C,SourceMgr, + ND)); } void clang_getDefinitionSpellingAndExtent(CXCursor C, @@ -1086,7 +1126,7 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, NamedDecl *ND = static_cast<NamedDecl *>(C.decl); FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); - + SourceManager &SM = FD->getASTContext().getSourceManager(); *startBuf = SM.getCharacterData(Body->getLBracLoc()); *endBuf = SM.getCharacterData(Body->getRBracLoc()); @@ -1095,329 +1135,20 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, *endLine = SM.getSpellingLineNumber(Body->getRBracLoc()); *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc()); } + +} // end: extern "C" -enum CXCompletionChunkKind -clang_getCompletionChunkKind(CXCompletionString completion_string, - unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; - if (!CCStr || chunk_number >= CCStr->size()) - return CXCompletionChunk_Text; - - switch ((*CCStr)[chunk_number].Kind) { - case CodeCompletionString::CK_TypedText: - return CXCompletionChunk_TypedText; - case CodeCompletionString::CK_Text: - return CXCompletionChunk_Text; - case CodeCompletionString::CK_Optional: - return CXCompletionChunk_Optional; - case CodeCompletionString::CK_Placeholder: - return CXCompletionChunk_Placeholder; - case CodeCompletionString::CK_Informative: - return CXCompletionChunk_Informative; - case CodeCompletionString::CK_ResultType: - return CXCompletionChunk_ResultType; - case CodeCompletionString::CK_CurrentParameter: - return CXCompletionChunk_CurrentParameter; - case CodeCompletionString::CK_LeftParen: - return CXCompletionChunk_LeftParen; - case CodeCompletionString::CK_RightParen: - return CXCompletionChunk_RightParen; - case CodeCompletionString::CK_LeftBracket: - return CXCompletionChunk_LeftBracket; - case CodeCompletionString::CK_RightBracket: - return CXCompletionChunk_RightBracket; - case CodeCompletionString::CK_LeftBrace: - return CXCompletionChunk_LeftBrace; - case CodeCompletionString::CK_RightBrace: - return CXCompletionChunk_RightBrace; - case CodeCompletionString::CK_LeftAngle: - return CXCompletionChunk_LeftAngle; - case CodeCompletionString::CK_RightAngle: - return CXCompletionChunk_RightAngle; - case CodeCompletionString::CK_Comma: - return CXCompletionChunk_Comma; - } - - // Should be unreachable, but let's be careful. - return CXCompletionChunk_Text; -} - -const char *clang_getCompletionChunkText(CXCompletionString completion_string, - unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; - if (!CCStr || chunk_number >= CCStr->size()) - return 0; - - switch ((*CCStr)[chunk_number].Kind) { - case CodeCompletionString::CK_TypedText: - case CodeCompletionString::CK_Text: - case CodeCompletionString::CK_Placeholder: - case CodeCompletionString::CK_CurrentParameter: - case CodeCompletionString::CK_Informative: - case CodeCompletionString::CK_LeftParen: - case CodeCompletionString::CK_RightParen: - case CodeCompletionString::CK_LeftBracket: - case CodeCompletionString::CK_RightBracket: - case CodeCompletionString::CK_LeftBrace: - case CodeCompletionString::CK_RightBrace: - case CodeCompletionString::CK_LeftAngle: - case CodeCompletionString::CK_RightAngle: - case CodeCompletionString::CK_Comma: - case CodeCompletionString::CK_ResultType: - return (*CCStr)[chunk_number].Text; - - case CodeCompletionString::CK_Optional: - // Note: treated as an empty text block. - return ""; - } - - // Should be unreachable, but let's be careful. - return 0; -} - -CXCompletionString -clang_getCompletionChunkCompletionString(CXCompletionString completion_string, - unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; - if (!CCStr || chunk_number >= CCStr->size()) - return 0; - - switch ((*CCStr)[chunk_number].Kind) { - case CodeCompletionString::CK_TypedText: - case CodeCompletionString::CK_Text: - case CodeCompletionString::CK_Placeholder: - case CodeCompletionString::CK_CurrentParameter: - case CodeCompletionString::CK_Informative: - case CodeCompletionString::CK_LeftParen: - case CodeCompletionString::CK_RightParen: - case CodeCompletionString::CK_LeftBracket: - case CodeCompletionString::CK_RightBracket: - case CodeCompletionString::CK_LeftBrace: - case CodeCompletionString::CK_RightBrace: - case CodeCompletionString::CK_LeftAngle: - case CodeCompletionString::CK_RightAngle: - case CodeCompletionString::CK_Comma: - case CodeCompletionString::CK_ResultType: - return 0; - - case CodeCompletionString::CK_Optional: - // Note: treated as an empty text block. - return (*CCStr)[chunk_number].Optional; - } - - // Should be unreachable, but let's be careful. - return 0; -} - -unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; - return CCStr? CCStr->size() : 0; -} - -static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, - unsigned &Value) { - if (Memory + sizeof(unsigned) > MemoryEnd) - return true; - - memmove(&Value, Memory, sizeof(unsigned)); - Memory += sizeof(unsigned); - return false; -} - -/// \brief The CXCodeCompleteResults structure we allocate internally; -/// the client only sees the initial CXCodeCompleteResults structure. -struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { - /// \brief The memory buffer from which we parsed the results. We - /// retain this buffer because the completion strings point into it. - llvm::MemoryBuffer *Buffer; -}; - -CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, - const char *source_filename, - int num_command_line_args, - const char **command_line_args, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - const char *complete_filename, - unsigned complete_line, - unsigned complete_column) { - // The indexer, which is mainly used to determine where diagnostics go. - CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); - - // The set of temporary files that we've built. - std::vector<llvm::sys::Path> TemporaryFiles; - - // Build up the arguments for invoking 'clang'. - std::vector<const char *> argv; - - // First add the complete path to the 'clang' executable. - llvm::sys::Path ClangPath = CXXIdx->getClangPath(); - argv.push_back(ClangPath.c_str()); - - // Add the '-fsyntax-only' argument so that we only perform a basic - // syntax check of the code. - argv.push_back("-fsyntax-only"); - - // Add the appropriate '-code-completion-at=file:line:column' argument - // to perform code completion, with an "-Xclang" preceding it. - std::string code_complete_at; - code_complete_at += complete_filename; - code_complete_at += ":"; - code_complete_at += llvm::utostr(complete_line); - code_complete_at += ":"; - code_complete_at += llvm::utostr(complete_column); - argv.push_back("-Xclang"); - argv.push_back("-code-completion-at"); - argv.push_back("-Xclang"); - argv.push_back(code_complete_at.c_str()); - argv.push_back("-Xclang"); - argv.push_back("-no-code-completion-debug-printer"); - - std::vector<std::string> RemapArgs; - for (unsigned i = 0; i != num_unsaved_files; ++i) { - char tmpFile[L_tmpnam]; - char *tmpFileName = tmpnam(tmpFile); - - // Write the contents of this unsaved file into the temporary file. - llvm::sys::Path SavedFile(tmpFileName); - std::string ErrorInfo; - llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) - continue; - - OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); - OS.close(); - if (OS.has_error()) { - SavedFile.eraseFromDisk(); - continue; - } - - // Remap the file. - std::string RemapArg = unsaved_files[i].Filename; - RemapArg += ';'; - RemapArg += tmpFileName; - RemapArgs.push_back("-Xclang"); - RemapArgs.push_back("-remap-file"); - RemapArgs.push_back("-Xclang"); - RemapArgs.push_back(RemapArg); - TemporaryFiles.push_back(SavedFile); - } - - // 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()); - - // Add the source file name (FIXME: later, we'll want to build temporary - // file from the buffer, or just feed the source text via standard input). - if (source_filename) - argv.push_back(source_filename); - - // 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]) { - if (strcmp(arg, "-o") == 0) { - ++i; // Also skip the matching argument. - continue; - } - if (strcmp(arg, "-emit-ast") == 0 || - strcmp(arg, "-c") == 0 || - strcmp(arg, "-fsyntax-only") == 0) { - continue; - } - - // Keep the argument. - argv.push_back(arg); - } - - // Add the null terminator. - argv.push_back(NULL); - - // Generate a temporary name for the AST file. - char tmpFile[L_tmpnam]; - char *tmpFileName = tmpnam(tmpFile); - llvm::sys::Path ResultsFile(tmpFileName); - TemporaryFiles.push_back(ResultsFile); - - // Invoke 'clang'. - llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null - // on Unix or NUL (Windows). - std::string ErrMsg; - const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 }; - llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, - /* redirects */ &Redirects[0], - /* secondsToWait */ 0, - /* memoryLimits */ 0, &ErrMsg); - - if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) { - llvm::errs() << "clang_codeComplete: " << ErrMsg - << '\n' << "Arguments: \n"; - for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); - I!=E; ++I) { - if (*I) - llvm::errs() << ' ' << *I << '\n'; - } - llvm::errs() << '\n'; - } - - // Parse the resulting source file to find code-completion results. - using llvm::MemoryBuffer; - using llvm::StringRef; - AllocatedCXCodeCompleteResults *Results = 0; - if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { - llvm::SmallVector<CXCompletionResult, 4> CompletionResults; - StringRef Buffer = F->getBuffer(); - for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size(); - Str < StrEnd;) { - unsigned KindValue; - if (ReadUnsigned(Str, StrEnd, KindValue)) - break; - - CodeCompletionString *CCStr - = CodeCompletionString::Deserialize(Str, StrEnd); - if (!CCStr) - continue; - - if (!CCStr->empty()) { - // Vend the code-completion result to the caller. - CXCompletionResult Result; - Result.CursorKind = (CXCursorKind)KindValue; - Result.CompletionString = CCStr; - CompletionResults.push_back(Result); - } - }; - - // Allocate the results. - Results = new AllocatedCXCodeCompleteResults; - Results->Results = new CXCompletionResult [CompletionResults.size()]; - Results->NumResults = CompletionResults.size(); - memcpy(Results->Results, CompletionResults.data(), - CompletionResults.size() * sizeof(CXCompletionResult)); - Results->Buffer = F; - } - - for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) - TemporaryFiles[i].eraseFromDisk(); +//===----------------------------------------------------------------------===// +// CXString Operations. +//===----------------------------------------------------------------------===// - return Results; +extern "C" { +const char *clang_getCString(CXString string) { + return string.Spelling; } -void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { - if (!ResultsIn) - return; - - AllocatedCXCodeCompleteResults *Results - = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); - - for (unsigned I = 0, N = Results->NumResults; I != N; ++I) - delete (CXCompletionString *)Results->Results[I].CompletionString; - delete [] Results->Results; - - Results->Results = 0; - Results->NumResults = 0; - delete Results->Buffer; - Results->Buffer = 0; - delete Results; +void clang_disposeString(CXString string) { + if (string.MustFreeString && string.Spelling) + free((void*)string.Spelling); } - -} // end extern "C" +} // end: extern "C" diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index e925df9..a695ba2 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -22,20 +22,21 @@ _clang_getCursorSource _clang_getCursorSourceFile _clang_getCursorSpelling _clang_getDeclColumn +_clang_getDeclExtent _clang_getDeclLine +_clang_getDeclExtent _clang_getDeclSource _clang_getDeclSourceFile _clang_getDeclSpelling -_clang_getDeclarationName +_clang_getDeclUSR +_clang_getDeclaration _clang_getDefinitionSpellingAndExtent -_clang_getEntity _clang_getEntityFromDecl _clang_getFileName _clang_getFileTime _clang_getNullCursor _clang_getNumCompletionChunks _clang_getTranslationUnitSpelling -_clang_getURI _clang_isDeclaration _clang_isDefinition _clang_isInvalid diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp new file mode 100644 index 0000000..f70479b --- /dev/null +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -0,0 +1,371 @@ +//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Clang-C Source Indexing library hooks for +// code completion. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Program.h" + +using namespace clang; + +extern "C" { + +enum CXCompletionChunkKind +clang_getCompletionChunkKind(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return CXCompletionChunk_Text; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + return CXCompletionChunk_TypedText; + case CodeCompletionString::CK_Text: + return CXCompletionChunk_Text; + case CodeCompletionString::CK_Optional: + return CXCompletionChunk_Optional; + case CodeCompletionString::CK_Placeholder: + return CXCompletionChunk_Placeholder; + case CodeCompletionString::CK_Informative: + return CXCompletionChunk_Informative; + case CodeCompletionString::CK_ResultType: + return CXCompletionChunk_ResultType; + case CodeCompletionString::CK_CurrentParameter: + return CXCompletionChunk_CurrentParameter; + case CodeCompletionString::CK_LeftParen: + return CXCompletionChunk_LeftParen; + case CodeCompletionString::CK_RightParen: + return CXCompletionChunk_RightParen; + case CodeCompletionString::CK_LeftBracket: + return CXCompletionChunk_LeftBracket; + case CodeCompletionString::CK_RightBracket: + return CXCompletionChunk_RightBracket; + case CodeCompletionString::CK_LeftBrace: + return CXCompletionChunk_LeftBrace; + case CodeCompletionString::CK_RightBrace: + return CXCompletionChunk_RightBrace; + case CodeCompletionString::CK_LeftAngle: + return CXCompletionChunk_LeftAngle; + case CodeCompletionString::CK_RightAngle: + return CXCompletionChunk_RightAngle; + case CodeCompletionString::CK_Comma: + return CXCompletionChunk_Comma; + case CodeCompletionString::CK_Colon: + return CXCompletionChunk_Colon; + case CodeCompletionString::CK_SemiColon: + return CXCompletionChunk_SemiColon; + case CodeCompletionString::CK_Equal: + return CXCompletionChunk_Equal; + case CodeCompletionString::CK_HorizontalSpace: + return CXCompletionChunk_HorizontalSpace; + case CodeCompletionString::CK_VerticalSpace: + return CXCompletionChunk_VerticalSpace; + } + + // Should be unreachable, but let's be careful. + return CXCompletionChunk_Text; +} + +const char *clang_getCompletionChunkText(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return 0; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + case CodeCompletionString::CK_Text: + case CodeCompletionString::CK_Placeholder: + case CodeCompletionString::CK_CurrentParameter: + case CodeCompletionString::CK_Informative: + case CodeCompletionString::CK_LeftParen: + case CodeCompletionString::CK_RightParen: + case CodeCompletionString::CK_LeftBracket: + case CodeCompletionString::CK_RightBracket: + case CodeCompletionString::CK_LeftBrace: + case CodeCompletionString::CK_RightBrace: + case CodeCompletionString::CK_LeftAngle: + case CodeCompletionString::CK_RightAngle: + case CodeCompletionString::CK_Comma: + case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: + return (*CCStr)[chunk_number].Text; + + case CodeCompletionString::CK_Optional: + // Note: treated as an empty text block. + return ""; + } + + // Should be unreachable, but let's be careful. + return 0; +} + +CXCompletionString +clang_getCompletionChunkCompletionString(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return 0; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + case CodeCompletionString::CK_Text: + case CodeCompletionString::CK_Placeholder: + case CodeCompletionString::CK_CurrentParameter: + case CodeCompletionString::CK_Informative: + case CodeCompletionString::CK_LeftParen: + case CodeCompletionString::CK_RightParen: + case CodeCompletionString::CK_LeftBracket: + case CodeCompletionString::CK_RightBracket: + case CodeCompletionString::CK_LeftBrace: + case CodeCompletionString::CK_RightBrace: + case CodeCompletionString::CK_LeftAngle: + case CodeCompletionString::CK_RightAngle: + case CodeCompletionString::CK_Comma: + case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: + return 0; + + case CodeCompletionString::CK_Optional: + // Note: treated as an empty text block. + return (*CCStr)[chunk_number].Optional; + } + + // Should be unreachable, but let's be careful. + return 0; +} + +unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? CCStr->size() : 0; +} + +static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, + unsigned &Value) { + if (Memory + sizeof(unsigned) > MemoryEnd) + return true; + + memmove(&Value, Memory, sizeof(unsigned)); + Memory += sizeof(unsigned); + return false; +} + +/// \brief The CXCodeCompleteResults structure we allocate internally; +/// the client only sees the initial CXCodeCompleteResults structure. +struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { + /// \brief The memory buffer from which we parsed the results. We + /// retain this buffer because the completion strings point into it. + llvm::MemoryBuffer *Buffer; +}; + +CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, + const char *source_filename, + int num_command_line_args, + const char **command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + const char *complete_filename, + unsigned complete_line, + unsigned complete_column) { + // The indexer, which is mainly used to determine where diagnostics go. + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + + // The set of temporary files that we've built. + std::vector<llvm::sys::Path> TemporaryFiles; + + // Build up the arguments for invoking 'clang'. + std::vector<const char *> argv; + + // First add the complete path to the 'clang' executable. + llvm::sys::Path ClangPath = CXXIdx->getClangPath(); + argv.push_back(ClangPath.c_str()); + + // Add the '-fsyntax-only' argument so that we only perform a basic + // syntax check of the code. + argv.push_back("-fsyntax-only"); + + // Add the appropriate '-code-completion-at=file:line:column' argument + // to perform code completion, with an "-Xclang" preceding it. + std::string code_complete_at; + code_complete_at += complete_filename; + code_complete_at += ":"; + code_complete_at += llvm::utostr(complete_line); + code_complete_at += ":"; + code_complete_at += llvm::utostr(complete_column); + argv.push_back("-Xclang"); + argv.push_back("-code-completion-at"); + argv.push_back("-Xclang"); + argv.push_back(code_complete_at.c_str()); + argv.push_back("-Xclang"); + argv.push_back("-no-code-completion-debug-printer"); + argv.push_back("-Xclang"); + argv.push_back("-code-completion-macros"); + + std::vector<std::string> RemapArgs; + for (unsigned i = 0; i != num_unsaved_files; ++i) { + char tmpFile[L_tmpnam]; + char *tmpFileName = tmpnam(tmpFile); + + // Write the contents of this unsaved file into the temporary file. + llvm::sys::Path SavedFile(tmpFileName); + std::string ErrorInfo; + llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + continue; + + OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); + OS.close(); + if (OS.has_error()) { + SavedFile.eraseFromDisk(); + continue; + } + + // Remap the file. + std::string RemapArg = unsaved_files[i].Filename; + RemapArg += ';'; + RemapArg += tmpFileName; + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back("-remap-file"); + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back(RemapArg); + TemporaryFiles.push_back(SavedFile); + } + + // 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()); + + // Add the source file name (FIXME: later, we'll want to build temporary + // file from the buffer, or just feed the source text via standard input). + if (source_filename) + argv.push_back(source_filename); + + // 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]) { + if (strcmp(arg, "-o") == 0) { + ++i; // Also skip the matching argument. + continue; + } + if (strcmp(arg, "-emit-ast") == 0 || + strcmp(arg, "-c") == 0 || + strcmp(arg, "-fsyntax-only") == 0) { + continue; + } + + // Keep the argument. + argv.push_back(arg); + } + + // Add the null terminator. + argv.push_back(NULL); + + // Generate a temporary name for the AST file. + char tmpFile[L_tmpnam]; + char *tmpFileName = tmpnam(tmpFile); + llvm::sys::Path ResultsFile(tmpFileName); + TemporaryFiles.push_back(ResultsFile); + + // Invoke 'clang'. + llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null + // on Unix or NUL (Windows). + std::string ErrMsg; + const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 }; + llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, + /* redirects */ &Redirects[0], + /* secondsToWait */ 0, + /* memoryLimits */ 0, &ErrMsg); + + if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) { + llvm::errs() << "clang_codeComplete: " << ErrMsg + << '\n' << "Arguments: \n"; + for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); + I!=E; ++I) { + if (*I) + llvm::errs() << ' ' << *I << '\n'; + } + llvm::errs() << '\n'; + } + + // Parse the resulting source file to find code-completion results. + using llvm::MemoryBuffer; + using llvm::StringRef; + AllocatedCXCodeCompleteResults *Results = 0; + if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { + llvm::SmallVector<CXCompletionResult, 4> CompletionResults; + StringRef Buffer = F->getBuffer(); + for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size(); + Str < StrEnd;) { + unsigned KindValue; + if (ReadUnsigned(Str, StrEnd, KindValue)) + break; + + CodeCompletionString *CCStr + = CodeCompletionString::Deserialize(Str, StrEnd); + if (!CCStr) + continue; + + if (!CCStr->empty()) { + // Vend the code-completion result to the caller. + CXCompletionResult Result; + Result.CursorKind = (CXCursorKind)KindValue; + Result.CompletionString = CCStr; + CompletionResults.push_back(Result); + } + }; + + // Allocate the results. + Results = new AllocatedCXCodeCompleteResults; + Results->Results = new CXCompletionResult [CompletionResults.size()]; + Results->NumResults = CompletionResults.size(); + memcpy(Results->Results, CompletionResults.data(), + CompletionResults.size() * sizeof(CXCompletionResult)); + Results->Buffer = F; + } + + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + TemporaryFiles[i].eraseFromDisk(); + + return Results; +} + +void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { + if (!ResultsIn) + return; + + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + + for (unsigned I = 0, N = Results->NumResults; I != N; ++I) + delete (CXCompletionString *)Results->Results[I].CompletionString; + delete [] Results->Results; + + Results->Results = 0; + Results->NumResults = 0; + delete Results->Buffer; + Results->Buffer = 0; + delete Results; +} + +} // end extern "C" diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp new file mode 100644 index 0000000..549c650 --- /dev/null +++ b/tools/CIndex/CIndexUSRs.cpp @@ -0,0 +1,203 @@ +//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the generation and use of USRs from CXEntities. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "clang/AST/DeclVisitor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +// Some notes on CXEntity: +// +// - Since the 'ordinary' namespace includes functions, data, typedefs, +// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one +// entity for 2 different types). For example: +// +// module1.m: @interface Foo @end Foo *x; +// module2.m: void Foo(int); +// +// - Since the unique name spans translation units, static data/functions +// within a CXTranslationUnit are *not* currently represented by entities. +// As a result, there will be no entity for the following: +// +// module.m: static void Foo() { } +// + +static inline Entity GetEntity(const CXEntity &E) { + return Entity::getFromOpaquePtr(E.data); +} + +static inline ASTUnit *GetTranslationUnit(CXTranslationUnit TU) { + return (ASTUnit*) TU; +} + +static inline ASTContext &GetASTContext(CXTranslationUnit TU) { + return GetTranslationUnit(TU)->getASTContext(); +} + +static inline CXEntity NullCXEntity() { + CXEntity CE; + CE.index = NULL; + CE.data = NULL; + return CE; +} + +static inline CXEntity MakeEntity(CXIndex CIdx, const Entity &E) { + CXEntity CE; + CE.index = CIdx; + CE.data = E.getAsOpaquePtr(); + return CE; +} + +static inline Program &GetProgram(CXIndex CIdx) { + return ((CIndexer*) CIdx)->getProgram(); +} + +//===----------------------------------------------------------------------===// +// USR generation. +//===----------------------------------------------------------------------===// + +namespace { +class USRGenerator : public DeclVisitor<USRGenerator> { + llvm::raw_ostream &Out; +public: + USRGenerator(llvm::raw_ostream &out) : Out(out) {} + + void VisitBlockDecl(BlockDecl *D); + void VisitDeclContext(DeclContext *D); + void VisitFunctionDecl(FunctionDecl *D); + void VisitNamedDecl(NamedDecl *D); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitObjCContainerDecl(ObjCContainerDecl *CD); + void VisitObjCMethodDecl(ObjCMethodDecl *MD); + void VisitObjCPropertyDecl(ObjCPropertyDecl *D); + void VisitRecordDecl(RecordDecl *D); + void VisitTypedefDecl(TypedefDecl *D); +}; +} // end anonymous namespace + +void USRGenerator::VisitBlockDecl(BlockDecl *D) { + VisitDeclContext(D->getDeclContext()); + // FIXME: Better support for anonymous blocks. + Out << "@B^anon"; +} + +void USRGenerator::VisitDeclContext(DeclContext *DC) { + if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) + Visit(D); +} + +void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { + VisitDeclContext(D->getDeclContext()); + Out << "@F^" << D->getNameAsString(); +} + +void USRGenerator::VisitNamedDecl(NamedDecl *D) { + VisitDeclContext(D->getDeclContext()); + const std::string &s = D->getNameAsString(); + assert(!s.empty()); + Out << "@^" << s; +} + +void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { + VisitDeclContext(D->getDeclContext()); + Out << "@N^" << D->getNameAsString(); +} + +void USRGenerator::VisitRecordDecl(RecordDecl *D) { + VisitDeclContext(D->getDeclContext()); + Out << "@S^"; + // FIXME: Better support for anonymous structures. + const std::string &s = D->getNameAsString(); + if (s.empty()) + Out << "^anon"; + else + Out << s; +} + +void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { + Visit(cast<Decl>(D->getDeclContext())); + Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); + Out << DeclarationName(D->getSelector()).getAsString(); +} + +void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { + switch (D->getKind()) { + default: + assert(false && "Invalid ObjC container."); + case Decl::ObjCInterface: + case Decl::ObjCImplementation: + Out << "objc(cs)" << D->getName(); + break; + case Decl::ObjCCategory: { + ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); + Out << "objc(cy)" << CD->getClassInterface()->getName() + << '_' << CD->getName(); + break; + } + case Decl::ObjCCategoryImpl: { + ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); + Out << "objc(cy)" << CD->getClassInterface()->getName() + << '_' << CD->getName(); + break; + } + case Decl::ObjCProtocol: + Out << "objc(pl)" << cast<ObjCProtocolDecl>(D)->getName(); + break; + } +} + +void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + Visit(cast<Decl>(D->getDeclContext())); + Out << "(py)" << D->getName(); +} + +void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { + DeclContext *DC = D->getDeclContext(); + if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) + Visit(DCN); + Out << "typedef@" << D->getName(); +} + +extern "C" { + +/// clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any) +/// in a specified translation unit. +CXDecl clang_getDeclaration(CXEntity CE, CXTranslationUnit TU) { + return (CXDecl) GetEntity(CE).getDecl(GetASTContext(TU)); +} + + +CXEntity clang_getEntityFromDecl(CXIndex CIdx, CXDecl CE) { + if (Decl *D = (Decl *) CE) + return MakeEntity(CIdx, Entity::get(D, GetProgram(CIdx))); + return NullCXEntity(); +} + +// FIXME: This is a skeleton implementation. It will be overhauled. +CXString clang_getDeclUSR(CXDecl D) { + assert(D && "Null CXDecl passed to clang_getDeclUSR()"); + llvm::SmallString<1024> StrBuf; + { + llvm::raw_svector_ostream Out(StrBuf); + USRGenerator UG(Out); + UG.Visit(static_cast<Decl*>(D)); + } + + if (StrBuf.empty()) + return CIndexer::createCXString(NULL); + + // Return a copy of the string that must be disposed by the caller. + return CIndexer::createCXString(StrBuf.c_str(), true); +} + +} // end extern "C" diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp new file mode 100644 index 0000000..f26c8ce --- /dev/null +++ b/tools/CIndex/CIndexer.cpp @@ -0,0 +1,96 @@ +//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Clang-C Source Indexing library. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Program.h" + +#include <cstdio> +#include <vector> +#include <sstream> + +#ifdef LLVM_ON_WIN32 +#include <windows.h> +#else +#include <dlfcn.h> +#endif + +using namespace clang; +using namespace idx; + +const llvm::sys::Path& CIndexer::getClangPath() { + // Did we already compute the path? + if (!ClangPath.empty()) + return ClangPath; + + // Find the location where this library lives (libCIndex.dylib). +#ifdef LLVM_ON_WIN32 + MEMORY_BASIC_INFORMATION mbi; + char path[MAX_PATH]; + VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi, + sizeof(mbi)); + GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH); + + llvm::sys::Path CIndexPath(path); + + CIndexPath.eraseComponent(); + CIndexPath.appendComponent("clang"); + CIndexPath.appendSuffix("exe"); + CIndexPath.makeAbsolute(); +#else + // This silly cast below avoids a C++ warning. + Dl_info info; + if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0) + assert(0 && "Call to dladdr() failed"); + + llvm::sys::Path CIndexPath(info.dli_fname); + + // We now have the CIndex directory, locate clang relative to it. + CIndexPath.eraseComponent(); + CIndexPath.eraseComponent(); + CIndexPath.appendComponent("bin"); + CIndexPath.appendComponent("clang"); +#endif + + // Cache our result. + ClangPath = CIndexPath; + return ClangPath; +} + +std::string CIndexer::getClangResourcesPath() { + llvm::sys::Path P = getClangPath(); + + if (!P.empty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang/<version>/include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + } + + return P.str(); +} diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h new file mode 100644 index 0000000..4f3cd8b --- /dev/null +++ b/tools/CIndex/CIndexer.h @@ -0,0 +1,88 @@ +//===- CIndexer.h - Clang-C Source Indexing Library -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CIndexer, a subclass of Indexer that provides extra +// functionality needed by the CIndex library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CINDEXER_H +#define LLVM_CLANG_CINDEXER_H + +#include "clang-c/Index.h" +#include "clang/Index/ASTLocation.h" +#include "clang/Index/Indexer.h" +#include "clang/Index/Program.h" +#include "clang/Index/Utils.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/System/Path.h" + +using namespace clang; + +/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted +/// warnings and errors. +class IgnoreDiagnosticsClient : public DiagnosticClient { +public: + virtual ~IgnoreDiagnosticsClient() {} + virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {} +}; + +class CIndexer : public Indexer { + DiagnosticOptions DiagOpts; + IgnoreDiagnosticsClient IgnoreDiagClient; + llvm::OwningPtr<Diagnostic> TextDiags; + Diagnostic IgnoreDiags; + bool UseExternalASTGeneration; + bool OnlyLocalDecls; + bool DisplayDiagnostics; + + llvm::sys::Path ClangPath; + +public: + explicit CIndexer(Program *prog) : Indexer(*prog), + IgnoreDiags(&IgnoreDiagClient), + UseExternalASTGeneration(false), + OnlyLocalDecls(false), + DisplayDiagnostics(false) { + TextDiags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); + } + + virtual ~CIndexer() { delete &getProgram(); } + + /// \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 + /// declarations. + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; } + + bool getDisplayDiagnostics() const { return DisplayDiagnostics; } + void setDisplayDiagnostics(bool Display = true) { + DisplayDiagnostics = Display; + } + + bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; } + void setUseExternalASTGeneration(bool Value) { + UseExternalASTGeneration = Value; + } + + Diagnostic &getDiags() { + return DisplayDiagnostics ? *TextDiags : IgnoreDiags; + } + + /// \brief Get the path of the clang binary. + const llvm::sys::Path& getClangPath(); + + /// \brief Get the path of the clang resource files. + std::string getClangResourcesPath(); + + static CXString createCXString(const char *String, bool DupString = false); +}; + +#endif diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt index a3ff3db..52f847e 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -19,7 +19,12 @@ set( LLVM_LINK_COMPONENTS core ) -add_clang_library(CIndex CIndex.cpp) +add_clang_library(CIndex + CIndex.cpp + CIndexCodeCompletion.cpp + CIndexUSRs.cpp + CIndexer.cpp +) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # FIXME: Deal with LLVM_SUBMIT_VERSION? diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 33013f3..01a0d43 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -70,16 +70,30 @@ static const char* GetCursorSource(CXCursor Cursor) { /* Logic for testing clang_loadTranslationUnit(). */ /******************************************************************************/ +static const char *FileCheckPrefix = "CHECK"; + +static void PrintDeclExtent(CXDecl Dcl) { + CXSourceExtent extent = clang_getDeclExtent(Dcl); + printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column, + extent.end.line, extent.end.column); +} + static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) { if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { CXString string; - printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor), - clang_getCursorLine(Cursor), - clang_getCursorColumn(Cursor)); + printf("// %s: %s:%d:%d: ", FileCheckPrefix, + GetCursorSource(Cursor), + clang_getCursorLine(Cursor), + clang_getCursorColumn(Cursor)); PrintCursor(Cursor); + string = clang_getDeclSpelling(Dcl); - printf(" [Context=%s]\n", clang_getCString(string)); + printf(" [Context=%s]", clang_getCString(string)); clang_disposeString(string); + + PrintDeclExtent(clang_getCursorDecl(Cursor)); + + printf("\n"); } } @@ -87,15 +101,19 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, CXClientData Filter) { if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { CXString string; - printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor), - clang_getCursorLine(Cursor), - clang_getCursorColumn(Cursor)); + printf("// %s: %s:%d:%d: ", FileCheckPrefix, + GetCursorSource(Cursor), clang_getCursorLine(Cursor), + clang_getCursorColumn(Cursor)); PrintCursor(Cursor); string = clang_getTranslationUnitSpelling(Unit); - printf(" [Context=%s]\n", + printf(" [Context=%s]", basename(clang_getCString(string))); clang_disposeString(string); + + PrintDeclExtent(Cursor.decl); + printf("\n"); + clang_loadDeclaration(Cursor.decl, DeclVisitor, 0); } } @@ -130,7 +148,7 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, /* Nothing found here; that's fine. */ } else if (Ref.kind != CXCursor_FunctionDecl) { CXString string; - printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref), + printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref), curLine, curColumn); PrintCursor(Ref); string = clang_getDeclSpelling(Ref.decl); @@ -141,12 +159,45 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, } } +/******************************************************************************/ +/* USR testing. */ +/******************************************************************************/ + +static void USRDeclVisitor(CXDecl D, CXCursor C, CXClientData Filter) { + if (!Filter || (C.kind == *(enum CXCursorKind *)Filter)) { + CXString USR = clang_getDeclUSR(C.decl); + if (!USR.Spelling) { + clang_disposeString(USR); + return; + } + printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling); + PrintDeclExtent(C.decl); + printf("\n"); + clang_disposeString(USR); + } +} + +static void USRVisitor(CXTranslationUnit Unit, CXCursor Cursor, + CXClientData Filter) { + if (Cursor.decl) { + /* USRDeclVisitor(Unit, Cursor.decl, Cursor, Filter);*/ + clang_loadDeclaration(Cursor.decl, USRDeclVisitor, 0); + } +} + +/******************************************************************************/ +/* Loading ASTs/source. */ +/******************************************************************************/ + static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, - const char *filter) { + const char *filter, const char *prefix, + CXTranslationUnitIterator Visitor) { enum CXCursorKind K = CXCursor_NotImplemented; - CXTranslationUnitIterator Visitor = TranslationUnitVisitor; enum CXCursorKind *ck = &K; + if (prefix) + FileCheckPrefix = prefix; + /* Perform some simple filtering. */ if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL; else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl; @@ -165,7 +216,9 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, return 0; } -int perform_test_load_tu(const char *file, const char *filter) { +int perform_test_load_tu(const char *file, const char *filter, + const char *prefix, + CXTranslationUnitIterator Visitor) { CXIndex Idx; CXTranslationUnit TU; Idx = clang_createIndex(/* excludeDeclsFromPCH */ @@ -175,10 +228,11 @@ int perform_test_load_tu(const char *file, const char *filter) { if (!CreateTranslationUnit(Idx, file, &TU)) return 1; - return perform_test_load(Idx, TU, filter); + return perform_test_load(Idx, TU, filter, prefix, Visitor); } -int perform_test_load_source(int argc, const char **argv, const char *filter) { +int perform_test_load_source(int argc, const char **argv, const char *filter, + CXTranslationUnitIterator Visitor) { const char *UseExternalASTs = getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); CXIndex Idx; @@ -196,7 +250,7 @@ int perform_test_load_source(int argc, const char **argv, const char *filter) { return 1; } - return perform_test_load(Idx, TU, filter); + return perform_test_load(Idx, TU, filter, NULL, Visitor); } /******************************************************************************/ @@ -207,7 +261,7 @@ static void print_cursor_file_scan(CXCursor cursor, unsigned start_line, unsigned start_col, unsigned end_line, unsigned end_col, const char *prefix) { - printf("// CHECK"); + printf("// %s: ", FileCheckPrefix); if (prefix) printf("-%s", prefix); printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ", @@ -356,6 +410,11 @@ clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) { case CXCompletionChunk_RightAngle: return "RightAngle"; case CXCompletionChunk_Comma: return "Comma"; case CXCompletionChunk_ResultType: return "ResultType"; + case CXCompletionChunk_Colon: return "Colon"; + case CXCompletionChunk_SemiColon: return "SemiColon"; + case CXCompletionChunk_Equal: return "Equal"; + case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; + case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; } return "Unknown"; @@ -531,14 +590,26 @@ int perform_code_completion(int argc, const char **argv) { /* Command line processing. */ /******************************************************************************/ +static CXTranslationUnitIterator GetVisitor(const char *s) { + if (s[0] == '\0') + return TranslationUnitVisitor; + if (strcmp(s, "-usrs") == 0) + return USRVisitor; + return NULL; +} + static void print_usage(void) { fprintf(stderr, "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n" " c-index-test -test-file-scan <AST file> <source file> " "[FileCheck prefix]\n" - " c-index-test -test-load-tu <AST file> <symbol filter>\n\n" - " c-index-test -test-load-source <symbol filter> {<args>}*\n\n" - " <symbol filter> options for -test-load-tu and -test-load-source:\n%s", + " c-index-test -test-load-tu <AST file> <symbol filter> " + "[FileCheck prefix]\n" + " c-index-test -test-load-tu-usrs <AST file> <symbol filter> " + "[FileCheck prefix]\n" + " c-index-test -test-load-source <symbol filter> {<args>}*\n" + " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n" + " <symbol filter> values:\n%s", " all - load all symbols, including those from PCH\n" " local - load all symbols except those in PCH\n" " category - only load ObjC categories (non-PCH)\n" @@ -552,11 +623,17 @@ static void print_usage(void) { int main(int argc, const char **argv) { if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) return perform_code_completion(argc, argv); - if (argc == 4 && strcmp(argv[1], "-test-load-tu") == 0) - return perform_test_load_tu(argv[2], argv[3]); - if (argc >= 4 && strcmp(argv[1], "-test-load-source") == 0) - return perform_test_load_source(argc - 3, argv + 3, argv[2]); - if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) + else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) { + CXTranslationUnitIterator I = GetVisitor(argv[1] + 13); + if (I) + return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I); + } + else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { + CXTranslationUnitIterator I = GetVisitor(argv[1] + 17); + if (I) + return perform_test_load_source(argc - 3, argv + 3, argv[2], I); + } + else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) return perform_file_scan(argv[2], argv[3], argc >= 5 ? argv[4] : 0); diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index eb1f60c..d2f1017 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -14,10 +14,6 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/CC1Options.h" @@ -30,7 +26,6 @@ #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/ErrorHandling.h" @@ -38,8 +33,6 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" #include "llvm/System/Signals.h" #include "llvm/Target/TargetSelect.h" #include <cstdio> @@ -207,13 +200,13 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, Diags); // Infer the builtin include path if unspecified. - if (Clang.getInvocation().getHeaderSearchOpts().UseBuiltinIncludes && - Clang.getInvocation().getHeaderSearchOpts().ResourceDir.empty()) - Clang.getInvocation().getHeaderSearchOpts().ResourceDir = + if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && + Clang.getHeaderSearchOpts().ResourceDir.empty()) + Clang.getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(Argv0, MainAddr); // Honor -help. - if (Clang.getInvocation().getFrontendOpts().ShowHelp) { + if (Clang.getFrontendOpts().ShowHelp) { llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1OptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1", "LLVM 'Clang' Compiler: http://clang.llvm.org"); @@ -223,7 +216,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // Honor -version. // // FIXME: Use a better -version message? - if (Clang.getInvocation().getFrontendOpts().ShowVersion) { + if (Clang.getFrontendOpts().ShowVersion) { llvm::cl::PrintVersionMessage(); return 0; } @@ -249,86 +242,18 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error; } - // If there were any errors in processing arguments, exit now. - if (Clang.getDiagnostics().getNumErrors()) - return 1; - - // Create the target instance. - Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), - Clang.getTargetOpts())); - if (!Clang.hasTarget()) - return 1; - - // Inform the target of the language options - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); - - // Validate/process some options - if (Clang.getHeaderSearchOpts().Verbose) - llvm::errs() << "clang -cc1 version " CLANG_VERSION_STRING - << " based upon " << PACKAGE_STRING - << " hosted on " << llvm::sys::getHostTriple() << "\n"; - - if (Clang.getFrontendOpts().ShowTimers) - Clang.createFrontendTimer(); - - for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) { - const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second; - - // If we aren't using an AST file, setup the file and source managers and - // the preprocessor. - bool IsAST = - Clang.getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; - if (!IsAST) { - if (!i) { - // Create a file manager object to provide access to and cache the - // filesystem. - Clang.createFileManager(); - - // Create the source manager. - Clang.createSourceManager(); - } else { - // Reset the ID tables if we are reusing the SourceManager. - Clang.getSourceManager().clearIDTables(); - } - - // Create the preprocessor. - Clang.createPreprocessor(); - } - + // If there were errors in processing arguments, don't do anything else. + bool Success = false; + if (!Clang.getDiagnostics().getNumErrors()) { + // Create and execute the frontend action. llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(Clang)); - if (!Act) - break; - - if (Act->BeginSourceFile(Clang, InFile, IsAST)) { - Act->Execute(); - Act->EndSourceFile(); - } + if (Act) + Success = Clang.ExecuteAction(*Act); } - if (Clang.getDiagnosticOpts().ShowCarets) - if (unsigned NumDiagnostics = Clang.getDiagnostics().getNumDiagnostics()) - fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics, - (NumDiagnostics == 1 ? "" : "s")); - - if (Clang.getFrontendOpts().ShowStats) { - Clang.getFileManager().PrintStats(); - fprintf(stderr, "\n"); - } - - // Return the appropriate status when verifying diagnostics. - // - // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need - // this. - if (Clang.getDiagnosticOpts().VerifyDiagnostics) - return static_cast<VerifyDiagnosticsClient&>( - Clang.getDiagnosticClient()).HadErrors(); - // Managed static deconstruction. Useful for making things like // -time-passes usable. llvm::llvm_shutdown(); - return (Clang.getDiagnostics().getNumErrors() != 0); + return !Success; } |