diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-01-23 11:10:26 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-01-23 11:10:26 +0000 |
commit | 2fce988e86bc01829142e4362d4eff1af0925147 (patch) | |
tree | c69d3f4f13d508570bb5257a6aea735f88bdf09c /tools/CIndex | |
parent | a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824 (diff) | |
download | FreeBSD-src-2fce988e86bc01829142e4362d4eff1af0925147.zip FreeBSD-src-2fce988e86bc01829142e4362d4eff1af0925147.tar.gz |
Update clang to r94309.
Diffstat (limited to 'tools/CIndex')
-rw-r--r-- | tools/CIndex/CIndex.cpp | 1920 | ||||
-rw-r--r-- | tools/CIndex/CIndex.exports | 39 | ||||
-rw-r--r-- | tools/CIndex/CIndexCodeCompletion.cpp | 31 | ||||
-rw-r--r-- | tools/CIndex/CIndexUSRs.cpp | 134 | ||||
-rw-r--r-- | tools/CIndex/CIndexer.cpp | 37 | ||||
-rw-r--r-- | tools/CIndex/CIndexer.h | 30 | ||||
-rw-r--r-- | tools/CIndex/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tools/CIndex/CXCursor.cpp | 305 | ||||
-rw-r--r-- | tools/CIndex/CXCursor.h | 88 | ||||
-rw-r--r-- | tools/CIndex/Makefile | 2 |
10 files changed, 1848 insertions, 742 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 86e0ddc..84f908d 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -13,10 +13,14 @@ //===----------------------------------------------------------------------===// #include "CIndexer.h" +#include "CXCursor.h" +#include "clang/Basic/Version.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Program.h" @@ -24,6 +28,7 @@ #include <cstdio> using namespace clang; +using namespace clang::cxcursor; using namespace idx; //===----------------------------------------------------------------------===// @@ -111,362 +116,744 @@ public: #endif #endif -//===----------------------------------------------------------------------===// -// Visitors. -//===----------------------------------------------------------------------===// +typedef llvm::PointerIntPair<ASTContext *, 1, bool> CXSourceLocationPtr; -namespace { -static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) { - NamedDecl *D = DRE->getDecl(); - if (isa<VarDecl>(D)) - return CXCursor_VarRef; - else if (isa<FunctionDecl>(D)) - return CXCursor_FunctionRef; - else if (isa<EnumConstantDecl>(D)) - return CXCursor_EnumConstantRef; - else - return CXCursor_NotImplemented; +/// \brief Translate a Clang source location into a CIndex source location. +static CXSourceLocation translateSourceLocation(ASTContext &Context, + SourceLocation Loc, + bool AtEnd = false) { + CXSourceLocationPtr Ptr(&Context, AtEnd); + CXSourceLocation Result = { Ptr.getOpaqueValue(), Loc.getRawEncoding() }; + return Result; } -#if 0 -// Will be useful one day. -class CRefVisitor : public StmtVisitor<CRefVisitor> { - CXDecl CDecl; - CXDeclIterator Callback; - CXClientData CData; - - void Call(enum CXCursorKind CK, Stmt *SRef) { - CXCursor C = { CK, CDecl, SRef }; - Callback(CDecl, C, CData); - } +/// \brief Translate a Clang source range into a CIndex source range. +static CXSourceRange translateSourceRange(ASTContext &Context, SourceRange R) { + CXSourceRange Result = { &Context, + R.getBegin().getRawEncoding(), + R.getEnd().getRawEncoding() }; + return Result; +} -public: - CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) : - CDecl(C), Callback(cback), CData(D) {} +static SourceLocation translateSourceLocation(CXSourceLocation L) { + return SourceLocation::getFromRawEncoding(L.int_data); +} - void VisitStmt(Stmt *S) { - for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); - C != CEnd; ++C) - Visit(*C); - } - void VisitDeclRefExpr(DeclRefExpr *Node) { - Call(TranslateDeclRefExpr(Node), Node); - } - void VisitMemberExpr(MemberExpr *Node) { - Call(CXCursor_MemberRef, Node); - } - void VisitObjCMessageExpr(ObjCMessageExpr *Node) { - Call(CXCursor_ObjCSelectorRef, Node); - } - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { - Call(CXCursor_ObjCIvarRef, Node); - } +static SourceRange translateSourceRange(CXSourceRange R) { + return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data), + SourceLocation::getFromRawEncoding(R.end_int_data)); +} + +/// \brief The result of comparing two source ranges. +enum RangeComparisonResult { + /// \brief Either the ranges overlap or one of the ranges is invalid. + RangeOverlap, + + /// \brief The first range ends before the second range starts. + RangeBefore, + + /// \brief The first range starts after the second range ends. + RangeAfter }; -#endif -// Translation Unit Visitor. +/// \brief Compare two source ranges to determine their relative position in +/// the translation unit. +static RangeComparisonResult RangeCompare(SourceManager &SM, + SourceRange R1, + SourceRange R2) { + assert(R1.isValid() && "First range is invalid?"); + assert(R2.isValid() && "Second range is invalid?"); + if (SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) + return RangeBefore; + if (SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) + return RangeAfter; + return RangeOverlap; +} -class TUVisitor : public DeclVisitor<TUVisitor> { -public: - typedef void (*Iterator)(void *, CXCursor, CXClientData); -private: - void *Root; // CXDecl or CXTranslationUnit - Iterator Callback; // CXTranslationUnitIterator or CXDeclIterator. - CXClientData CData; +//===----------------------------------------------------------------------===// +// Cursor visitor. +//===----------------------------------------------------------------------===// + +namespace { + +// Cursor visitor. +class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, + public TypeLocVisitor<CursorVisitor, bool>, + public StmtVisitor<CursorVisitor, bool> +{ + /// \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. unsigned MaxPCHLevel; - void Call(enum CXCursorKind CK, NamedDecl *ND) { - // Filter any declarations that have a PCH level greater than what we allow. - if (ND->getPCHLevel() > MaxPCHLevel) - return; + /// \brief When valid, a source range to which the cursor should restrict + /// its search. + SourceRange RegionOfInterest; + + using DeclVisitor<CursorVisitor, bool>::Visit; + using TypeLocVisitor<CursorVisitor, bool>::Visit; + using StmtVisitor<CursorVisitor, bool>::Visit; + + /// \brief Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. + /// + /// \param R a source range retrieved from the abstract syntax tree. + RangeComparisonResult CompareRegionOfInterest(SourceRange R); + + /// \brief Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. + /// + /// \param CXR a source range retrieved from a cursor. + RangeComparisonResult CompareRegionOfInterest(CXSourceRange CXR); + +public: + CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, + unsigned MaxPCHLevel, + SourceRange RegionOfInterest = SourceRange()) + : TU(TU), Visitor(Visitor), ClientData(ClientData), + MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest) + { + Parent.kind = CXCursor_NoDeclFound; + Parent.data[0] = 0; + Parent.data[1] = 0; + Parent.data[2] = 0; + StmtParent = 0; + } + + bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); + bool VisitChildren(CXCursor Parent); + + // Declaration visitors + bool VisitDeclContext(DeclContext *DC); + bool VisitTranslationUnitDecl(TranslationUnitDecl *D); + bool VisitTypedefDecl(TypedefDecl *D); + bool VisitTagDecl(TagDecl *D); + bool VisitEnumConstantDecl(EnumConstantDecl *D); + bool VisitDeclaratorDecl(DeclaratorDecl *DD); + bool VisitFunctionDecl(FunctionDecl *ND); + bool VisitFieldDecl(FieldDecl *D); + bool VisitVarDecl(VarDecl *); + bool VisitObjCMethodDecl(ObjCMethodDecl *ND); + bool VisitObjCContainerDecl(ObjCContainerDecl *D); + bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); + bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + bool VisitObjCImplDecl(ObjCImplDecl *D); + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); + // FIXME: ObjCPropertyDecl requires TypeSourceInfo, getter/setter locations, + // etc. + // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. + bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); + bool VisitObjCClassDecl(ObjCClassDecl *D); + + // Type visitors + // FIXME: QualifiedTypeLoc doesn't provide any location information + bool VisitBuiltinTypeLoc(BuiltinTypeLoc TL); + bool VisitTypedefTypeLoc(TypedefTypeLoc TL); + bool VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL); + bool VisitTagTypeLoc(TagTypeLoc TL); + // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information + bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); + bool VisitPointerTypeLoc(PointerTypeLoc TL); + bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL); + bool VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL); + bool VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL); + bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL); + bool VisitFunctionTypeLoc(FunctionTypeLoc TL); + bool VisitArrayTypeLoc(ArrayTypeLoc TL); + // FIXME: Implement for TemplateSpecializationTypeLoc + // FIXME: Implement visitors here when the unimplemented TypeLocs get + // implemented + bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); + bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL); + + // Statement visitors + bool VisitStmt(Stmt *S); + bool VisitDeclStmt(DeclStmt *S); + // FIXME: LabelStmt label? + bool VisitIfStmt(IfStmt *S); + bool VisitSwitchStmt(SwitchStmt *S); + + // Expression visitors + bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + bool VisitExplicitCastExpr(ExplicitCastExpr *E); + bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); +}; + +} // end anonymous namespace - // Filter any implicit declarations (since the source info will be bogus). - if (ND->isImplicit()) - return; +RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { + assert(RegionOfInterest.isValid() && "RangeCompare called with invalid range"); + if (R.isInvalid()) + return RangeOverlap; + + // Move the end of the input range to the end of the last token in that + // range. + R.setEnd(TU->getPreprocessor().getLocForEndOfToken(R.getEnd(), 1)); + return RangeCompare(TU->getSourceManager(), R, RegionOfInterest); +} + +RangeComparisonResult CursorVisitor::CompareRegionOfInterest(CXSourceRange CXR) { + return CompareRegionOfInterest(translateSourceRange(CXR)); +} + +/// \brief Visit the given cursor and, if requested by the visitor, +/// its children. +/// +/// \param Cursor the cursor to visit. +/// +/// \param CheckRegionOfInterest if true, then the caller already checked that +/// this cursor is within the region of interest. +/// +/// \returns true if the visitation should be aborted, false if it +/// should continue. +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"); + if (D->getPCHLevel() > MaxPCHLevel) + return false; + + if (D->isImplicit()) + return false; + } - CXCursor C = { CK, ND, 0, 0 }; - Callback(Root, C, CData); + // If we have a range of interest, and this cursor doesn't intersect with it, + // we're done. + if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { + CXSourceRange Range = clang_getCursorExtent(Cursor); + if (translateSourceRange(Range).isInvalid() || + CompareRegionOfInterest(Range)) + return false; } + + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: + return true; -public: - 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); -}; + case CXChildVisit_Continue: + return false; -void TUVisitor::VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); - I != E; ++I) - Visit(*I); + case CXChildVisit_Recurse: + return VisitChildren(Cursor); + } + + llvm_unreachable("Silly GCC, we can't get here"); } + +/// \brief Visit the children of the given cursor. +/// +/// \returns true if the visitation should be aborted, false if it +/// should continue. +bool CursorVisitor::VisitChildren(CXCursor Cursor) { + if (clang_isReference(Cursor.kind)) { + // By definition, references have no children. + return false; + } -void TUVisitor::VisitFunctionDecl(FunctionDecl *ND) { - Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn - : CXCursor_FunctionDecl, ND); + // Set the Parent field to Cursor, then back to its old value once we're + // done. + class SetParentRAII { + CXCursor &Parent; + Decl *&StmtParent; + CXCursor OldParent; + + public: + SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) + : 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); + } + + 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() && + RegionOfInterest.isInvalid()) { + const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls(); + for (std::vector<Decl*>::const_iterator it = TLDs.begin(), + ie = TLDs.end(); it != ie; ++it) { + if (Visit(MakeCXCursor(*it, CXXUnit), true)) + return true; + } + } else { + return VisitDeclContext( + CXXUnit->getASTContext().getTranslationUnitDecl()); + } + + return false; + } + + // Nothing to visit at the moment. + return false; } + +bool CursorVisitor::VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { + if (RegionOfInterest.isValid()) { + SourceRange R = (*I)->getSourceRange(); + if (R.isInvalid()) + continue; + + switch (CompareRegionOfInterest(R)) { + 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(MakeCXCursor(*I, TU), true)) + return true; + } -void TUVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { - Call(CXCursor_ObjCCategoryDecl, ND); + return false; } -void TUVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) { - Call(CXCursor_ObjCCategoryDefn, ND); +bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + llvm_unreachable("Translation units are visited directly by Visit()"); + return false; } -void TUVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *ND) { - Call(CXCursor_ObjCClassDefn, ND); +bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) { + if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + +bool CursorVisitor::VisitTagDecl(TagDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { + if (Expr *Init = D->getInitExpr()) + return Visit(MakeCXCursor(Init, StmtParent, TU)); + return false; +} + +bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { + if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return false; } + +bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { + if (VisitDeclaratorDecl(ND)) + return true; + + if (ND->isThisDeclarationADefinition() && + Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) + return true; -void TUVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) { - Call(CXCursor_ObjCInterfaceDecl, ND); -} + return false; +} -void TUVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *ND) { - Call(CXCursor_ObjCProtocolDecl, ND); +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; -void TUVisitor::VisitTagDecl(TagDecl *ND) { - switch (ND->getTagKind()) { - case TagDecl::TK_struct: - Call(CXCursor_StructDecl, ND); - break; - case TagDecl::TK_class: - Call(CXCursor_ClassDecl, ND); - break; - case TagDecl::TK_union: - Call(CXCursor_UnionDecl, ND); - break; - case TagDecl::TK_enum: - Call(CXCursor_EnumDecl, ND); - break; + 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 + // type. + 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; } + +bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(), + TU))) + return true; -void TUVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); + 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); } + +bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin(); + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; -void TUVisitor::VisitTypedefDecl(TypedefDecl *ND) { - Call(CXCursor_TypedefDecl, ND); + return VisitObjCContainerDecl(PID); } -void TUVisitor::VisitVarDecl(VarDecl *ND) { - Call(CXCursor_VarDecl, ND); +bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Issue callbacks for super class. + if (D->getSuperClass() && + Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), + 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); } -// Declaration visitor. -class CDeclVisitor : public DeclVisitor<CDeclVisitor> { - CXDecl CDecl; - CXDeclIterator Callback; - CXClientData CData; +bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) { + return VisitObjCContainerDecl(D); +} - // 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. - unsigned MaxPCHLevel; +bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + if (Visit(MakeCursorObjCClassRef(D->getCategoryDecl()->getClassInterface(), + D->getLocation(), TU))) + return true; + + return VisitObjCImplDecl(D); +} - void Call(enum CXCursorKind CK, NamedDecl *ND) { - // Disable the callback when the context is equal to the visiting decl. - if (CDecl == ND && !clang_isReference(CK)) - return; +bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { +#if 0 + // Issue callbacks for super class. + // FIXME: No source location information! + if (D->getSuperClass() && + Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), + D->getSuperClassLoc(), + TU))) + return true; +#endif + + return VisitObjCImplDecl(D); +} - // Filter any declarations that have a PCH level greater than what we allow. - if (ND->getPCHLevel() > MaxPCHLevel) - return; +bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { + ObjCForwardProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); + I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + 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; +} + +bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + ASTContext &Context = TU->getASTContext(); + + // Some builtin types (such as Objective-C's "id", "sel", and + // "Class") have associated declarations. Create cursors for those. + QualType VisitType; + switch (TL.getType()->getAs<BuiltinType>()->getKind()) { + case BuiltinType::Void: + case BuiltinType::Bool: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::Char_S: + case BuiltinType::SChar: + case BuiltinType::WChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::NullPtr: + case BuiltinType::Overload: + case BuiltinType::Dependent: + break; + + case BuiltinType::UndeducedAuto: // FIXME: Deserves a cursor? + break; + + case BuiltinType::ObjCId: + VisitType = Context.getObjCIdType(); + break; + + case BuiltinType::ObjCClass: + VisitType = Context.getObjCClassType(); + break; + + case BuiltinType::ObjCSel: + VisitType = Context.getObjCSelType(); + break; + } - CXCursor C = { CK, ND, 0, 0 }; - Callback(CDecl, C, CData); + if (!VisitType.isNull()) { + if (const TypedefType *Typedef = VisitType->getAs<TypedefType>()) + return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(), + TU)); } -public: - CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D, - unsigned MaxPCHLevel) : - CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} - - 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 -void CDeclVisitor::VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) - Visit(*I); + return false; } -void CDeclVisitor::VisitEnumConstantDecl(EnumConstantDecl *ND) { - Call(CXCursor_EnumConstantDecl, ND); +bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getTypedefDecl(), TL.getNameLoc(), TU)); } -void CDeclVisitor::VisitFieldDecl(FieldDecl *ND) { - Call(CXCursor_FieldDecl, ND); +bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } -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 CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); +} + +bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) + return true; + + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { + if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), + TU))) + return true; } -} -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)); + return false; } -void CDeclVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc())) + return true; + + if (TL.hasProtocolsAsWritten()) { + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { + if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), + TL.getProtocolLoc(I), + TU))) + return true; + } + } + + return false; } -void CDeclVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -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)); +bool CursorVisitor::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCIvarDecl(ObjCIvarDecl *ND) { - Call(CXCursor_ObjCIvarDecl, ND); +bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -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); +bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *ND) { - Call(CXCursor_ObjCPropertyDecl, ND); +bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), - E = PID->protocol_end(); I != E; ++I) - Call(CXCursor_ObjCProtocolRef, *I); +bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + if (Visit(TL.getResultLoc())) + return true; + + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (Visit(MakeCXCursor(TL.getArg(I), TU))) + return true; + + return false; +} + +bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { + if (Visit(TL.getElementLoc())) + return true; + + if (Expr *Size = TL.getSizeExpr()) + return Visit(MakeCXCursor(Size, StmtParent, TU)); + + return false; +} + +bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); +} + +bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + +bool CursorVisitor::VisitStmt(Stmt *S) { + for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end(); + Child != ChildEnd; ++Child) { + if (Visit(MakeCXCursor(*Child, StmtParent, TU))) + return true; + } - VisitDeclContext(dyn_cast<DeclContext>(PID)); + return false; } -void CDeclVisitor::VisitParmVarDecl(ParmVarDecl *ND) { - Call(CXCursor_ParmDecl, ND); +bool CursorVisitor::VisitDeclStmt(DeclStmt *S) { + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + if (Visit(MakeCXCursor(*D, TU))) + return true; + } + + return false; } -void CDeclVisitor::VisitTagDecl(TagDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitIfStmt(IfStmt *S) { + if (VarDecl *Var = S->getConditionVariable()) { + if (Visit(MakeCXCursor(Var, TU))) + return true; + } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU))) + return true; + + if (S->getThen() && Visit(MakeCXCursor(S->getThen(), StmtParent, TU))) + return true; + + if (S->getElse() && Visit(MakeCXCursor(S->getElse(), StmtParent, TU))) + return true; + + return false; } -void CDeclVisitor::VisitVarDecl(VarDecl *ND) { - Call(CXCursor_VarDecl, ND); +bool CursorVisitor::VisitSwitchStmt(SwitchStmt *S) { + if (VarDecl *Var = S->getConditionVariable()) { + if (Visit(MakeCXCursor(Var, TU))) + return true; + } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU))) + return true; + + if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU))) + return true; + + return false; } -static SourceLocation getLocationFromCursor(CXCursor C, - SourceManager &SourceMgr, - NamedDecl *ND) { - if (clang_isReference(C.kind)) { - switch (C.kind) { - case CXCursor_ObjCClassRef: { - if (isa<ObjCInterfaceDecl>(ND)) { - // FIXME: This is a hack (storing the parent decl in the stmt slot). - NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt); - return parentDecl->getLocation(); - } - ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing category decl"); - return OID->getClassInterface()->getLocation(); - } - case CXCursor_ObjCSuperClassRef: { - ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing interface decl"); - return OID->getSuperClassLoc(); - } - case CXCursor_ObjCProtocolRef: { - ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing protocol decl"); - return OID->getLocation(); - } - case CXCursor_ObjCSelectorRef: { - ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( - static_cast<Stmt *>(C.stmt)); - assert(OME && "clang_getCursorLine(): Missing message expr"); - return OME->getLeftLoc(); /* FIXME: should be a range */ - } - case CXCursor_VarRef: - case CXCursor_FunctionRef: - case CXCursor_EnumConstantRef: { - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( - static_cast<Stmt *>(C.stmt)); - assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return DRE->getLocation(); - } - default: - return SourceLocation(); - } - } else { // We have a declaration or a definition. - SourceLocation SLoc; - switch (ND->getKind()) { - case Decl::ObjCInterface: { - SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc(); - break; - } - case Decl::ObjCProtocol: { - SLoc = ND->getLocation(); /* FIXME: need to get the name location. */ - break; - } - default: { - SLoc = ND->getLocation(); - break; - } - } - if (SLoc.isInvalid()) - return SourceLocation(); - return SourceMgr.getSpellingLoc(SLoc); // handles macro instantiations. +bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + if (E->isArgumentType()) { + if (TypeSourceInfo *TSInfo = E->getArgumentTypeInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; } + + return VisitExpr(E); +} + +bool CursorVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { + if (TypeSourceInfo *TSInfo = E->getTypeInfoAsWritten()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return VisitCastExpr(E); +} + +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){ @@ -484,7 +871,7 @@ CXString CIndexer::createCXString(const char *String, bool DupString){ extern "C" { CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics) { - CIndexer *CIdxr = new CIndexer(new Program()); + CIndexer *CIdxr = new CIndexer(); if (excludeDeclarationsFromPCH) CIdxr->setOnlyLocalDecls(); if (displayDiagnostics) @@ -518,10 +905,22 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args) { + const char **command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files) { assert(CIdx && "Passed null CXIndex"); CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + llvm::SmallVector<ASTUnit::RemappedFile, 4> 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); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + if (!CXXIdx->getUseExternalASTGeneration()) { llvm::SmallVector<const char *, 16> Args; @@ -544,7 +943,9 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, CXXIdx->getDiags(), CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), - /* UseBumpAllocator = */ true)); + /* UseBumpAllocator = */ true, + RemappedFiles.data(), + RemappedFiles.size())); // FIXME: Until we have broader testing, just drop the entire AST if we // encountered an error. @@ -575,6 +976,17 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, char astTmpFile[L_tmpnam]; argv.push_back(tmpnam(astTmpFile)); + // Remap any unsaved files to temporary files. + std::vector<llvm::sys::Path> TemporaryFiles; + std::vector<std::string> 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]) { @@ -615,11 +1027,17 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, llvm::errs() << '\n'; } - // Finally, we create the translation unit from the ast file. - ASTUnit *ATU = static_cast<ASTUnit *>( - clang_createTranslationUnit(CIdx, astTmpFile)); + ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, CXXIdx->getDiags(), + CXXIdx->getOnlyLocalDecls(), + /* UseBumpAllocator = */ true, + RemappedFiles.data(), + RemappedFiles.size()); if (ATU) ATU->unlinkTemporaryFile(); + + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + TemporaryFiles[i].eraseFromDisk(); + return ATU; } @@ -635,165 +1053,123 @@ CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { true); } -void clang_loadTranslationUnit(CXTranslationUnit CTUnit, - CXTranslationUnitIterator callback, - CXClientData CData) { - assert(CTUnit && "Passed null CXTranslationUnit"); - ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); - ASTContext &Ctx = CXXUnit->getASTContext(); - - 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; - } - - TUVisitor DVisit(CTUnit, callback, CData, PCHLevel); - - // If using a non-AST based ASTUnit, iterate over the stored list of top-level - // decls. - if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls()) { - const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls(); - for (std::vector<Decl*>::const_iterator it = TLDs.begin(), - ie = TLDs.end(); it != ie; ++it) { - DVisit.Visit(*it); - } - } else - DVisit.Visit(Ctx.getTranslationUnitDecl()); +CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { + CXCursor Result = { CXCursor_TranslationUnit, { 0, 0, TU } }; + return Result; } -void clang_loadDeclaration(CXDecl Dcl, - CXDeclIterator callback, - CXClientData CData) { - assert(Dcl && "Passed null CXDecl"); - - CDeclVisitor DVisit(Dcl, callback, CData, - static_cast<Decl *>(Dcl)->getPCHLevel()); - DVisit.Visit(static_cast<Decl *>(Dcl)); -} } // end: extern "C" //===----------------------------------------------------------------------===// -// CXDecl Operations. +// CXSourceLocation and CXSourceRange Operations. //===----------------------------------------------------------------------===// -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 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 CIndexer::createCXString(CIMP->getIdentifier()->getNameStart()); - - if (ND->getIdentifier()) - return CIndexer::createCXString(ND->getIdentifier()->getNameStart()); - - return CIndexer::createCXString(""); +CXSourceLocation clang_getNullLocation() { + CXSourceLocation Result = { 0, 0 }; + return Result; } -unsigned clang_getDeclLine(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return SourceMgr.getSpellingLineNumber(ND->getLocation()); +unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { + return loc1.ptr_data == loc2.ptr_data && loc1.int_data == loc2.int_data; } -unsigned clang_getDeclColumn(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return SourceMgr.getSpellingColumnNumber(ND->getLocation()); -} +CXSourceLocation clang_getLocation(CXTranslationUnit tu, + CXFile file, + unsigned line, + unsigned column) { + if (!tu) + return clang_getNullLocation(); -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()); + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu); + SourceLocation SLoc + = CXXUnit->getSourceManager().getLocation( + static_cast<const FileEntry *>(file), + line, column); + + return translateSourceLocation(CXXUnit->getASTContext(), SLoc, false); +} - if (!Begin.isValid()) { - CXDeclExtent extent = { { 0, 0 }, { 0, 0 } }; - return extent; +CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { + if (begin.ptr_data != end.ptr_data) { + CXSourceRange Result = { 0, 0, 0 }; + return Result; } + CXSourceRange Result = { begin.ptr_data, begin.int_data, end.int_data }; + return Result; +} + +void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column) { + CXSourceLocationPtr Ptr + = CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data); + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!Ptr.getPointer() || Loc.isInvalid()) { + if (file) + *file = 0; + if (line) + *line = 0; + if (column) + *column = 0; + return; + } + // FIXME: This is largely copy-paste from ///TextDiagnosticPrinter::HighlightRange. When it is clear that this is - // what we want the two routines should be refactored. - - // 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); + // what we want the two routines should be refactored. + ASTContext &Context = *Ptr.getPointer(); + SourceManager &SM = Context.getSourceManager(); + SourceLocation InstLoc = SM.getInstantiationLoc(Loc); + + if (Ptr.getInt()) { + // We want the last character in this location, so we will adjust + // the instantiation location accordingly. + + // If the location is from a macro instantiation, get the end of + // the instantiation range. + if (Loc.isMacroID()) + InstLoc = SM.getInstantiationRange(Loc).second; + + // Measure the length token we're pointing at, so we can adjust + // the physical location in the file to point at the last + // character. + // FIXME: This won't cope with trigraphs or escaped newlines + // well. For that, we actually need a preprocessor, which isn't + // currently available here. Eventually, we'll switch the pointer + // data of CXSourceLocation/CXSourceRange to a translation unit + // (CXXUnit), so that the preprocessor will be available here. At + // that point, we can use Preprocessor::getLocForEndOfToken(). + unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, + Context.getLangOptions()); + if (Length > 0) + InstLoc = InstLoc.getFileLocWithOffset(Length - 1); } - // Package up the line/column data and return to the caller. - CXDeclExtent extent = { { StartLineNo, StartColNo }, - { EndLineNo, EndColNo } }; - return extent; + if (file) + *file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc)); + if (line) + *line = SM.getInstantiationLineNumber(InstLoc); + if (column) + *column = SM.getInstantiationColumnNumber(InstLoc); } -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"); - return clang_getFileName(FEnt); +CXSourceLocation clang_getRangeStart(CXSourceRange range) { + CXSourceLocation Result = { range.ptr_data, range.begin_int_data }; + return Result; } - -CXFile clang_getDeclSourceFile(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return (void *)getFileEntryFromSourceLocation(SourceMgr, ND->getLocation()); +CXSourceLocation clang_getRangeEnd(CXSourceRange range) { + llvm::PointerIntPair<ASTContext *, 1, bool> Ptr; + Ptr.setPointer(static_cast<ASTContext *>(range.ptr_data)); + Ptr.setInt(true); + CXSourceLocation Result = { Ptr.getOpaqueValue(), range.end_int_data }; + return Result; } + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -802,58 +1178,40 @@ CXFile clang_getDeclSourceFile(CXDecl AnonDecl) { extern "C" { const char *clang_getFileName(CXFile SFile) { + if (!SFile) + return 0; + assert(SFile && "Passed null CXFile"); FileEntry *FEnt = static_cast<FileEntry *>(SFile); return FEnt->getName(); } time_t clang_getFileTime(CXFile SFile) { + if (!SFile) + return 0; + assert(SFile && "Passed null CXFile"); FileEntry *FEnt = static_cast<FileEntry *>(SFile); return FEnt->getModificationTime(); } + +CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) { + if (!tu) + return 0; + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu); + + FileManager &FMgr = CXXUnit->getFileManager(); + const FileEntry *File = FMgr.getFile(file_name, file_name+strlen(file_name)); + return const_cast<FileEntry *>(File); +} + } // 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(); @@ -873,53 +1231,90 @@ static Decl *getDeclFromExpr(Stmt *E) { } extern "C" { + +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); +} + +static CXString getDeclSpelling(Decl *D) { + NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D); + if (!ND) + return CIndexer::createCXString(""); + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) + 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 CIndexer::createCXString(CIMP->getIdentifier()->getNameStart()); + + if (ND->getIdentifier()) + return CIndexer::createCXString(ND->getIdentifier()->getNameStart()); + + return CIndexer::createCXString(""); +} + CXString clang_getCursorSpelling(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + assert(getCursorDecl(C) && "CXCursor has null decl"); + if (clang_isTranslationUnit(C.kind)) + return clang_getTranslationUnitSpelling(C.data[2]); if (clang_isReference(C.kind)) { switch (C.kind) { case CXCursor_ObjCSuperClassRef: { - ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing interface decl"); - return CIndexer::createCXString(OID->getSuperClass()->getIdentifier() - ->getNameStart()); + ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first; + return CIndexer::createCXString(Super->getIdentifier()->getNameStart()); } case CXCursor_ObjCClassRef: { - if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) - return CIndexer::createCXString(OID->getIdentifier()->getNameStart()); - - ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND); - assert(OCD && "clang_getCursorLine(): Missing category decl"); - return CIndexer::createCXString(OCD->getClassInterface()->getIdentifier() - ->getNameStart()); + ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; + return CIndexer::createCXString(Class->getIdentifier()->getNameStart()); } case CXCursor_ObjCProtocolRef: { - ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing protocol decl"); + ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first; + assert(OID && "getCursorSpelling(): Missing protocol decl"); 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 CIndexer::createCXString(OME->getSelector().getAsString().c_str(), + case CXCursor_TypeRef: { + TypeDecl *Type = getCursorTypeRef(C).first; + assert(Type && "Missing type decl"); + + return CIndexer::createCXString( + getCursorContext(C).getTypeDeclType(Type).getAsString().c_str(), true); } - case CXCursor_VarRef: - case CXCursor_FunctionRef: - case CXCursor_EnumConstantRef: { - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( - static_cast<Stmt *>(C.stmt)); - assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return CIndexer::createCXString(DRE->getDecl()->getIdentifier() - ->getNameStart()); - } + default: return CIndexer::createCXString("<not implemented>"); } } - return clang_getDeclSpelling(C.decl); + + if (clang_isExpression(C.kind)) { + Decl *D = getDeclFromExpr(getCursorExpr(C)); + if (D) + return getDeclSpelling(D); + return CIndexer::createCXString(""); + } + + return getDeclSpelling(getCursorDecl(C)); } const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) { @@ -941,90 +1336,66 @@ const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) { case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl"; case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl"; case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl"; - case CXCursor_FunctionDefn: return "FunctionDefn"; - case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn"; - case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn"; - case CXCursor_ObjCClassDefn: return "ObjCClassDefn"; - case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn"; + 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_ObjCSelectorRef: return "ObjCSelectorRef"; - - case CXCursor_VarRef: return "VarRef"; - case CXCursor_FunctionRef: return "FunctionRef"; - case CXCursor_EnumConstantRef: return "EnumConstantRef"; - case CXCursor_MemberRef: return "MemberRef"; - + 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"; - default: return "<not implemented>"; + case CXCursor_TranslationUnit: return "TranslationUnit"; } + + llvm_unreachable("Unhandled CXCursorKind"); + return NULL; } -CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, - unsigned line, unsigned column) { - assert(CTUnit && "Passed null CXTranslationUnit"); - ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); - - FileManager &FMgr = CXXUnit->getFileManager(); - const FileEntry *File = FMgr.getFile(source_name, - source_name+strlen(source_name)); - if (!File) +enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + CXCursor *BestCursor = static_cast<CXCursor *>(client_data); + *BestCursor = cursor; + return CXChildVisit_Recurse; +} + +CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { + if (!TU) return clang_getNullCursor(); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); - 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); - - Decl *Dcl = ALoc.getParentDecl(); - if (ALoc.isNamedRef()) - Dcl = ALoc.AsNamedRef().ND; - Stmt *Stm = ALoc.dyn_AsStmt(); - if (Dcl) { - if (Stm) { - 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(), 0 }; - return C; - } - if (isa<ObjCProtocolDecl>(Dcl)) { - CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl(), 0 }; - return C; - } - } - return MakeCXCursor(TranslateKind(Dcl), Dcl); + SourceLocation SLoc = translateSourceLocation(Loc); + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); + if (SLoc.isValid()) { + SourceRange RegionOfInterest(SLoc, + CXXUnit->getPreprocessor().getLocForEndOfToken(SLoc, 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, + Decl::MaxPCHLevel, RegionOfInterest); + CursorVis.VisitChildren(Parent); } - return MakeCXCursor(CXCursor_NoDeclFound, 0); + return Result; } CXCursor clang_getNullCursor(void) { - return MakeCXCursor(CXCursor_InvalidFile, 0); + return MakeCXCursorInvalid(CXCursor_InvalidFile); } unsigned clang_equalCursors(CXCursor X, CXCursor Y) { - 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); - return MakeCXCursor(TranslateKind(ND), ND); + return X == Y; } unsigned clang_isInvalid(enum CXCursorKind K) { @@ -1039,80 +1410,413 @@ unsigned clang_isReference(enum CXCursorKind K) { return K >= CXCursor_FirstRef && K <= CXCursor_LastRef; } -unsigned clang_isDefinition(enum CXCursorKind K) { - return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn; +unsigned clang_isExpression(enum CXCursorKind K) { + return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr; +} + +unsigned clang_isStatement(enum CXCursorKind K) { + return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt; +} + +unsigned clang_isTranslationUnit(enum CXCursorKind K) { + return K == CXCursor_TranslationUnit; } CXCursorKind clang_getCursorKind(CXCursor C) { return C.kind; } -CXDecl clang_getCursorDecl(CXCursor C) { - if (clang_isDeclaration(C.kind)) - return C.decl; +static SourceLocation getLocationFromExpr(Expr *E) { + if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) + return /*FIXME:*/Msg->getLeftLoc(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return DRE->getLocation(); + if (MemberExpr *Member = dyn_cast<MemberExpr>(E)) + return Member->getMemberLoc(); + if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) + return Ivar->getLocation(); + return E->getLocStart(); +} +CXSourceLocation clang_getCursorLocation(CXCursor C) { if (clang_isReference(C.kind)) { - if (C.stmt) { - if (C.kind == CXCursor_ObjCClassRef || - C.kind == CXCursor_ObjCProtocolRef) - return static_cast<Stmt *>(C.stmt); - else - return getDeclFromExpr(static_cast<Stmt *>(C.stmt)); - } else - return C.decl; + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCSuperClassRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCProtocolRef: { + std::pair<ObjCProtocolDecl *, SourceLocation> P + = getCursorObjCProtocolRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCClassRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_TypeRef: { + std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } } - return 0; -} -unsigned clang_getCursorLine(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + if (clang_isExpression(C.kind)) + return translateSourceLocation(getCursorContext(C), + getLocationFromExpr(getCursorExpr(C))); + + if (!getCursorDecl(C)) { + CXSourceLocation empty = { 0, 0 }; + return empty; + } - SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); - return SourceMgr.getSpellingLineNumber(SLoc); + Decl *D = getCursorDecl(C); + SourceLocation Loc = D->getLocation(); + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D)) + Loc = Class->getClassLoc(); + return translateSourceLocation(D->getASTContext(), Loc); } + +CXSourceRange clang_getCursorExtent(CXCursor C) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCSuperClassRef(C); + return translateSourceRange(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCProtocolRef: { + std::pair<ObjCProtocolDecl *, SourceLocation> P + = getCursorObjCProtocolRef(C); + return translateSourceRange(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCClassRef(C); + + return translateSourceRange(P.first->getASTContext(), P.second); + } + + case CXCursor_TypeRef: { + std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); + return translateSourceRange(P.first->getASTContext(), P.second); + } + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } + } + + if (clang_isExpression(C.kind)) + return translateSourceRange(getCursorContext(C), + getCursorExpr(C)->getSourceRange()); + + if (clang_isStatement(C.kind)) + return translateSourceRange(getCursorContext(C), + getCursorStmt(C)->getSourceRange()); -unsigned clang_getCursorColumn(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + if (!getCursorDecl(C)) { + CXSourceRange empty = { 0, 0, 0 }; + return empty; + } - SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); - return SourceMgr.getSpellingColumnNumber(SLoc); + Decl *D = getCursorDecl(C); + return translateSourceRange(D->getASTContext(), D->getSourceRange()); } -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(); +CXCursor clang_getCursorReferenced(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); - SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); + ASTUnit *CXXUnit = getCursorASTUnit(C); + if (clang_isDeclaration(C.kind)) + return C; - if (SLoc.isFileID()) { - const char *bufferName = SourceMgr.getBufferName(SLoc); - return bufferName[0] == '<' ? NULL : bufferName; + if (clang_isExpression(C.kind)) { + Decl *D = getDeclFromExpr(getCursorExpr(C)); + if (D) + return MakeCXCursor(D, CXXUnit); + return clang_getNullCursor(); } + + if (!clang_isReference(C.kind)) + return clang_getNullCursor(); - // 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); - if (!Buffer) - return 0; + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + return MakeCXCursor(getCursorObjCSuperClassRef(C).first, CXXUnit); + + case CXCursor_ObjCProtocolRef: { + return MakeCXCursor(getCursorObjCProtocolRef(C).first, CXXUnit); + + case CXCursor_ObjCClassRef: + return MakeCXCursor(getCursorObjCClassRef(C).first, CXXUnit); + + 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 Buffer->getBufferIdentifier(); + return clang_getNullCursor(); } -CXFile clang_getCursorSourceFile(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); +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); + WasReference = true; + } + + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + 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. + case Decl::Namespace: + case Decl::Typedef: + case Decl::TemplateTypeParm: + case Decl::EnumConstant: + case Decl::Field: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: + case Decl::ImplicitParam: + case Decl::ParmVar: + case Decl::NonTypeTemplateParm: + case Decl::TemplateTemplateParm: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::FileScopeAsm: + case Decl::StaticAssert: + case Decl::Block: + return C; + + // Declaration kinds that don't make any sense here, but are + // nonetheless harmless. + case Decl::TranslationUnit: + case Decl::Template: + case Decl::ObjCContainer: + break; + + // Declaration kinds for which the definition is not resolvable. + case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: + break; + + case Decl::UsingDirective: + return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(), + CXXUnit); + + case Decl::NamespaceAlias: + return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), CXXUnit); + + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + if (TagDecl *Def = cast<TagDecl>(D)->getDefinition(D->getASTContext())) + return MakeCXCursor(Def, CXXUnit); + return clang_getNullCursor(); + + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: { + const FunctionDecl *Def = 0; + if (cast<FunctionDecl>(D)->getBody(Def)) + return MakeCXCursor(const_cast<FunctionDecl *>(Def), CXXUnit); + return clang_getNullCursor(); + } + + case Decl::Var: { + VarDecl *Var = cast<VarDecl>(D); + + // Variables with initializers have definitions. + const VarDecl *Def = 0; + if (Var->getDefinition(Def)) + return MakeCXCursor(const_cast<VarDecl *>(Def), CXXUnit); + + // extern and private_extern variables are not definitions. + if (Var->hasExternalStorage()) + return clang_getNullCursor(); + + // In-line static data members do not have definitions. + if (Var->isStaticDataMember() && !Var->isOutOfLine()) + return clang_getNullCursor(); + + // All other variables are themselves definitions. + return C; + } + + case Decl::FunctionTemplate: { + const FunctionDecl *Def = 0; + if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def)) + return MakeCXCursor(Def->getDescribedFunctionTemplate(), CXXUnit); + return clang_getNullCursor(); + } + + case Decl::ClassTemplate: { + if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl() + ->getDefinition(D->getASTContext())) + return MakeCXCursor( + cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), + CXXUnit); + return clang_getNullCursor(); + } + + case Decl::Using: { + UsingDecl *Using = cast<UsingDecl>(D); + CXCursor Def = clang_getNullCursor(); + 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(), + CXXUnit)); + } + + return Def; + } + + case Decl::UsingShadow: + return clang_getCursorDefinition( + MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(), + CXXUnit)); + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D); + if (Method->isThisDeclarationADefinition()) + return C; + + // Dig out the method definition in the associated + // @implementation, if we have it. + // FIXME: The ASTs should make finding the definition easier. + if (ObjCInterfaceDecl *Class + = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) + if (ObjCImplementationDecl *ClassImpl = Class->getImplementation()) + if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Def->isThisDeclarationADefinition()) + return MakeCXCursor(Def, CXXUnit); + + return clang_getNullCursor(); + } + + case Decl::ObjCCategory: + if (ObjCCategoryImplDecl *Impl + = cast<ObjCCategoryDecl>(D)->getImplementation()) + return MakeCXCursor(Impl, CXXUnit); + return clang_getNullCursor(); + + case Decl::ObjCProtocol: + if (!cast<ObjCProtocolDecl>(D)->isForwardDecl()) + return C; + return clang_getNullCursor(); + + case Decl::ObjCInterface: + // There are two notions of a "definition" for an Objective-C + // class: the interface and its implementation. When we resolved a + // reference to an Objective-C class, produce the @interface as + // the definition; when we were provided with the interface, + // produce the @implementation as the definition. + if (WasReference) { + if (!cast<ObjCInterfaceDecl>(D)->isForwardDecl()) + return C; + } else if (ObjCImplementationDecl *Impl + = cast<ObjCInterfaceDecl>(D)->getImplementation()) + return MakeCXCursor(Impl, CXXUnit); + return clang_getNullCursor(); - return (void *) - getFileEntryFromSourceLocation(SourceMgr, getLocationFromCursor(C,SourceMgr, - ND)); + case Decl::ObjCProperty: + // FIXME: We don't really know where to find the + // ObjCPropertyImplDecls that implement this property. + return clang_getNullCursor(); + + case Decl::ObjCCompatibleAlias: + if (ObjCInterfaceDecl *Class + = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface()) + if (!Class->isForwardDecl()) + return MakeCXCursor(Class, CXXUnit); + + return clang_getNullCursor(); + + case Decl::ObjCForwardProtocol: { + ObjCForwardProtocolDecl *Forward = cast<ObjCForwardProtocolDecl>(D); + if (Forward->protocol_size() == 1) + return clang_getCursorDefinition( + MakeCXCursor(*Forward->protocol_begin(), + CXXUnit)); + + // FIXME: Cannot return multiple definitions. + return clang_getNullCursor(); + } + + case Decl::ObjCClass: { + ObjCClassDecl *Class = cast<ObjCClassDecl>(D); + if (Class->size() == 1) { + ObjCInterfaceDecl *IFace = Class->begin()->getInterface(); + if (!IFace->isForwardDecl()) + return MakeCXCursor(IFace, CXXUnit); + return clang_getNullCursor(); + } + + // FIXME: Cannot return multiple definitions. + return clang_getNullCursor(); + } + + case Decl::Friend: + if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, CXXUnit)); + return clang_getNullCursor(); + + case Decl::FriendTemplate: + if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, CXXUnit)); + return clang_getNullCursor(); + } + + return clang_getNullCursor(); +} + +unsigned clang_isCursorDefinition(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + return clang_getCursorDefinition(C) == C; } void clang_getDefinitionSpellingAndExtent(CXCursor C, @@ -1122,8 +1826,8 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, unsigned *startColumn, unsigned *endLine, unsigned *endColumn) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + assert(getCursorDecl(C) && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C)); FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); @@ -1151,4 +1855,18 @@ void clang_disposeString(CXString string) { if (string.MustFreeString && string.Spelling) free((void*)string.Spelling); } + } // end: extern "C" + +//===----------------------------------------------------------------------===// +// Misc. utility functions. +//===----------------------------------------------------------------------===// + +extern "C" { + +const char *clang_getClangVersion() { + return getClangFullVersion(); +} + +} // end: extern "C" + diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index a695ba2..d349086 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -7,40 +7,41 @@ _clang_disposeIndex _clang_disposeString _clang_disposeTranslationUnit _clang_equalCursors +_clang_equalLocations +_clang_getClangVersion _clang_getCString _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText _clang_getCursor -_clang_getCursorColumn -_clang_getCursorDecl -_clang_getCursorFromDecl +_clang_getCursorDefinition +_clang_getCursorExtent _clang_getCursorKind _clang_getCursorKindSpelling -_clang_getCursorLine -_clang_getCursorSource -_clang_getCursorSourceFile +_clang_getCursorLocation +_clang_getCursorReferenced _clang_getCursorSpelling -_clang_getDeclColumn -_clang_getDeclExtent -_clang_getDeclLine -_clang_getDeclExtent -_clang_getDeclSource -_clang_getDeclSourceFile -_clang_getDeclSpelling -_clang_getDeclUSR -_clang_getDeclaration +_clang_getCursorUSR _clang_getDefinitionSpellingAndExtent -_clang_getEntityFromDecl +_clang_getFile _clang_getFileName _clang_getFileTime +_clang_getInstantiationLocation +_clang_getLocation _clang_getNullCursor +_clang_getNullLocation _clang_getNumCompletionChunks +_clang_getRange +_clang_getRangeEnd +_clang_getRangeStart +_clang_getTranslationUnitCursor _clang_getTranslationUnitSpelling +_clang_isCursorDefinition _clang_isDeclaration -_clang_isDefinition +_clang_isExpression _clang_isInvalid _clang_isReference -_clang_loadDeclaration -_clang_loadTranslationUnit +_clang_isStatement +_clang_isTranslationUnit _clang_setUseExternalASTGeneration +_clang_visitChildren diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp index f70479b..f3b60dc 100644 --- a/tools/CIndex/CIndexCodeCompletion.cpp +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -221,35 +221,10 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, argv.push_back("-Xclang"); argv.push_back("-code-completion-macros"); + // Remap any unsaved files to temporary files. 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); - } + 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. diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp index 549c650..fd605fb 100644 --- a/tools/CIndex/CIndexUSRs.cpp +++ b/tools/CIndex/CIndexUSRs.cpp @@ -12,56 +12,11 @@ //===----------------------------------------------------------------------===// #include "CIndexer.h" +#include "CXCursor.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. //===----------------------------------------------------------------------===// @@ -69,18 +24,22 @@ static inline Program &GetProgram(CXIndex CIdx) { namespace { class USRGenerator : public DeclVisitor<USRGenerator> { llvm::raw_ostream &Out; + bool IgnoreResults; public: - USRGenerator(llvm::raw_ostream &out) : Out(out) {} + USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {} + + bool ignoreResults() const { return IgnoreResults; } void VisitBlockDecl(BlockDecl *D); void VisitDeclContext(DeclContext *D); + void VisitFieldDecl(FieldDecl *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 VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); }; } // end anonymous namespace @@ -96,6 +55,17 @@ void USRGenerator::VisitDeclContext(DeclContext *DC) { Visit(D); } +void USRGenerator::VisitFieldDecl(FieldDecl *D) { + const std::string &s = D->getNameAsString(); + if (s.empty()) { + // Bit fields can be anonymous. + IgnoreResults = true; + return; + } + VisitDeclContext(D->getDeclContext()); + Out << "@^FI^" << s; +} + void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { VisitDeclContext(D->getDeclContext()); Out << "@F^" << D->getNameAsString(); @@ -113,17 +83,6 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { 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)"); @@ -141,13 +100,13 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { case Decl::ObjCCategory: { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); Out << "objc(cy)" << CD->getClassInterface()->getName() - << '_' << CD->getName(); + << '^' << CD->getName(); break; } case Decl::ObjCCategoryImpl: { ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); Out << "objc(cy)" << CD->getClassInterface()->getName() - << '_' << CD->getName(); + << '^' << CD->getName(); break; } case Decl::ObjCProtocol: @@ -161,6 +120,27 @@ void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { Out << "(py)" << D->getName(); } +void USRGenerator::VisitTagDecl(TagDecl *D) { + VisitDeclContext(D->getDeclContext()); + switch (D->getTagKind()) { + case TagDecl::TK_struct: Out << "@S^"; break; + case TagDecl::TK_class: Out << "@C^"; break; + case TagDecl::TK_union: Out << "@U^"; break; + case TagDecl::TK_enum: Out << "@E^"; break; + } + + // FIXME: Better support for anonymous structures and enums. + const std::string &s = D->getNameAsString(); + if (s.empty()) { + if (TypedefDecl *TD = D->getTypedefForAnonDecl()) + Out << "^anontd^" << TD->getNameAsString(); + else + Out << "^anon"; + } + else + Out << s; +} + void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { DeclContext *DC = D->getDeclContext(); if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) @@ -168,36 +148,32 @@ void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { 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()"); +static CXString ConstructUSR(Decl *D) { llvm::SmallString<1024> StrBuf; { llvm::raw_svector_ostream Out(StrBuf); USRGenerator UG(Out); UG.Visit(static_cast<Decl*>(D)); + if (UG.ignoreResults()) + return CIndexer::createCXString(NULL); } 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); } + +extern "C" { + +CXString clang_getCursorUSR(CXCursor C) { + if (Decl *D = cxcursor::getCursorDecl(C)) + return ConstructUSR(D); + + return CIndexer::createCXString(NULL); +} + } // end extern "C" diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp index f26c8ce..53636a4 100644 --- a/tools/CIndex/CIndexer.cpp +++ b/tools/CIndex/CIndexer.cpp @@ -94,3 +94,40 @@ std::string CIndexer::getClangResourcesPath() { return P.str(); } + +bool clang::RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles) { + for (unsigned i = 0; i != num_unsaved_files; ++i) { + char tmpFile[L_tmpnam]; + char *tmpFileName = tmpnam(tmpFile); + + // Write the contents of this unsaved file into the temporary file. + llvm::sys::Path SavedFile(tmpFileName); + std::string ErrorInfo; + llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + return true; + + OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); + OS.close(); + if (OS.has_error()) { + SavedFile.eraseFromDisk(); + return true; + } + + // 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); + } + + return false; +} + diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h index 4f3cd8b..d01454f 100644 --- a/tools/CIndex/CIndexer.h +++ b/tools/CIndex/CIndexer.h @@ -16,13 +16,10 @@ #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" +#include <vector> using namespace clang; @@ -34,7 +31,7 @@ public: virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {} }; -class CIndexer : public Indexer { +class CIndexer { DiagnosticOptions DiagOpts; IgnoreDiagnosticsClient IgnoreDiagClient; llvm::OwningPtr<Diagnostic> TextDiags; @@ -46,16 +43,12 @@ class CIndexer : public Indexer { llvm::sys::Path ClangPath; public: - explicit CIndexer(Program *prog) : Indexer(*prog), - IgnoreDiags(&IgnoreDiagClient), - UseExternalASTGeneration(false), - OnlyLocalDecls(false), - DisplayDiagnostics(false) { + CIndexer() : 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. @@ -85,4 +78,17 @@ public: static CXString createCXString(const char *String, bool DupString = false); }; +namespace clang { + /** + * \brief Given a set of "unsaved" files, create temporary files and + * construct the clang -cc1 argument list needed to perform the remapping. + * + * \returns true if an error occurred. + */ + bool RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles); +} + #endif diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt index 52f847e..730eaaf 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -3,8 +3,7 @@ set(SHARED_LIBRARY TRUE) set(LLVM_NO_RTTI 1) set(LLVM_USED_LIBS - clangIndex - clangFrontend + clangFrontend clangDriver clangSema clangAnalysis @@ -24,6 +23,7 @@ add_clang_library(CIndex CIndexCodeCompletion.cpp CIndexUSRs.cpp CIndexer.cpp + CXCursor.cpp ) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp new file mode 100644 index 0000000..63d9bc9 --- /dev/null +++ b/tools/CIndex/CXCursor.cpp @@ -0,0 +1,305 @@ +//===- CXCursor.cpp - Routines for manipulating CXCursors -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. It should be the +// only file that has internal knowledge of the encoding of the data in +// CXCursor. +// +//===----------------------------------------------------------------------===// + +#include "CXCursor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) { + assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid); + CXCursor C = { K, { 0, 0, 0 } }; + return C; +} + +static CXCursorKind GetCursorKind(Decl *D) { + switch (D->getKind()) { + case Decl::Enum: return CXCursor_EnumDecl; + case Decl::EnumConstant: return CXCursor_EnumConstantDecl; + case Decl::Field: return CXCursor_FieldDecl; + case Decl::Function: + return CXCursor_FunctionDecl; + case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; + case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; + case Decl::ObjCClass: + // FIXME + return CXCursor_UnexposedDecl; + case Decl::ObjCForwardProtocol: + // FIXME + return CXCursor_UnexposedDecl; + case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; + case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; + case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; + case Decl::ObjCMethod: + return cast<ObjCMethodDecl>(D)->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; + case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl; + case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; + case Decl::ParmVar: return CXCursor_ParmDecl; + case Decl::Typedef: return CXCursor_TypedefDecl; + case Decl::Var: return CXCursor_VarDecl; + default: + if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + switch (TD->getTagKind()) { + case TagDecl::TK_struct: return CXCursor_StructDecl; + case TagDecl::TK_class: return CXCursor_ClassDecl; + case TagDecl::TK_union: return CXCursor_UnionDecl; + case TagDecl::TK_enum: return CXCursor_EnumDecl; + } + } + + return CXCursor_UnexposedDecl; + } + + llvm_unreachable("Invalid Decl"); + return CXCursor_NotImplemented; +} + +CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) { + CXCursor C = { GetCursorKind(D), { D, 0, TU } }; + return C; +} + +CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) { + CXCursorKind K = CXCursor_NotImplemented; + + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; + + case Stmt::NullStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::LabelStmtClass: + case Stmt::IfStmtClass: + case Stmt::SwitchStmtClass: + case Stmt::WhileStmtClass: + case Stmt::DoStmtClass: + case Stmt::ForStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::BreakStmtClass: + case Stmt::ReturnStmtClass: + case Stmt::DeclStmtClass: + case Stmt::SwitchCaseClass: + case Stmt::AsmStmtClass: + case Stmt::ObjCAtTryStmtClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtThrowStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCForCollectionStmtClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXTryStmtClass: + K = CXCursor_UnexposedStmt; + break; + + case Stmt::ExprClass: + case Stmt::PredefinedExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::FloatingLiteralClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::StringLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::ParenExprClass: + case Stmt::UnaryOperatorClass: + case Stmt::SizeOfAlignOfExprClass: + case Stmt::ArraySubscriptExprClass: + case Stmt::CastExprClass: + case Stmt::BinaryOperatorClass: + case Stmt::CompoundAssignOperatorClass: + case Stmt::ConditionalOperatorClass: + case Stmt::ImplicitCastExprClass: + case Stmt::ExplicitCastExprClass: + case Stmt::CStyleCastExprClass: + case Stmt::CompoundLiteralExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::InitListExprClass: + case Stmt::DesignatedInitExprClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::ParenListExprClass: + case Stmt::VAArgExprClass: + case Stmt::AddrLabelExprClass: + case Stmt::StmtExprClass: + case Stmt::TypesCompatibleExprClass: + case Stmt::ChooseExprClass: + case Stmt::GNUNullExprClass: + case Stmt::CXXNamedCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: + case Stmt::CXXTypeidExprClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXThisExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXZeroInitValueExprClass: + case Stmt::CXXNewExprClass: + case Stmt::CXXDeleteExprClass: + case Stmt::CXXPseudoDestructorExprClass: + case Stmt::UnresolvedLookupExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::UnresolvedMemberExprClass: + case Stmt::ObjCStringLiteralClass: + case Stmt::ObjCEncodeExprClass: + case Stmt::ObjCSelectorExprClass: + case Stmt::ObjCProtocolExprClass: + case Stmt::ObjCImplicitSetterGetterRefExprClass: + case Stmt::ObjCSuperExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::BlockExprClass: + K = CXCursor_UnexposedExpr; + break; + case Stmt::DeclRefExprClass: + case Stmt::BlockDeclRefExprClass: + // FIXME: UnresolvedLookupExpr? + // FIXME: DependentScopeDeclRefExpr? + K = CXCursor_DeclRefExpr; + break; + + case Stmt::MemberExprClass: + case Stmt::ObjCIvarRefExprClass: + case Stmt::ObjCPropertyRefExprClass: + // FIXME: UnresolvedMemberExpr? + // FIXME: CXXDependentScopeMemberExpr? + K = CXCursor_MemberRefExpr; + break; + + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXTemporaryObjectExprClass: + // FIXME: CXXUnresolvedConstructExpr + // FIXME: ObjCImplicitSetterGetterRefExpr? + K = CXCursor_CallExpr; + break; + + case Stmt::ObjCMessageExprClass: + K = CXCursor_ObjCMessageExpr; + break; + } + + CXCursor C = { K, { Parent, S, TU } }; + return C; +} + +CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCSuperClassRef, { Super, RawLoc, TU } }; + return C; +} + +std::pair<ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCSuperClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCSuperClassRef); + return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super, + SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCProtocolRef, { Super, RawLoc, TU } }; + return C; +} + +std::pair<ObjCProtocolDecl *, SourceLocation> +cxcursor::getCursorObjCProtocolRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCProtocolRef); + return std::make_pair(static_cast<ObjCProtocolDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, + SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } }; + return C; +} + +std::pair<ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCClassRef); + return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_TypeRef, { Type, RawLoc, TU } }; + return C; +} + +std::pair<TypeDecl *, SourceLocation> +cxcursor::getCursorTypeRef(CXCursor C) { + assert(C.kind == CXCursor_TypeRef); + return std::make_pair(static_cast<TypeDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +Decl *cxcursor::getCursorDecl(CXCursor Cursor) { + return (Decl *)Cursor.data[0]; +} + +Expr *cxcursor::getCursorExpr(CXCursor Cursor) { + return dyn_cast_or_null<Expr>(getCursorStmt(Cursor)); +} + +Stmt *cxcursor::getCursorStmt(CXCursor Cursor) { + if (Cursor.kind == CXCursor_ObjCSuperClassRef || + Cursor.kind == CXCursor_ObjCProtocolRef || + Cursor.kind == CXCursor_ObjCClassRef) + return 0; + + return (Stmt *)Cursor.data[1]; +} + +ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { + return getCursorASTUnit(Cursor)->getASTContext(); +} + +ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) { + return static_cast<ASTUnit *>(Cursor.data[2]); +} + +bool cxcursor::operator==(CXCursor X, CXCursor Y) { + return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] && + X.data[2] == Y.data[2]; +} diff --git a/tools/CIndex/CXCursor.h b/tools/CIndex/CXCursor.h new file mode 100644 index 0000000..546dd7f --- /dev/null +++ b/tools/CIndex/CXCursor.h @@ -0,0 +1,88 @@ +//===- CXCursor.h - Routines for manipulating CXCursors -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXCURSOR_H +#define LLVM_CLANG_CXCursor_H + +#include "clang-c/Index.h" +#include "clang/Basic/SourceLocation.h" +#include <utility> + +namespace clang { + +class ASTContext; +class ASTUnit; +class Decl; +class Expr; +class NamedDecl; +class ObjCInterfaceDecl; +class ObjCProtocolDecl; +class Stmt; +class TypeDecl; + +namespace cxcursor { + +CXCursor MakeCXCursorInvalid(CXCursorKind K); +CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent, ASTUnit *TU); +CXCursor MakeCXCursor(clang::Decl *D, ASTUnit *TU); + +/// \brief Create an Objective-C superclass reference at the given location. +CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack an ObjCSuperClassRef cursor into the interface it references +/// and optionally the location where the reference occurred. +std::pair<ObjCInterfaceDecl *, SourceLocation> + getCursorObjCSuperClassRef(CXCursor C); + +/// \brief Create an Objective-C protocol reference at the given location. +CXCursor MakeCursorObjCProtocolRef(ObjCProtocolDecl *Proto, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references +/// and optionally the location where the reference occurred. +std::pair<ObjCProtocolDecl *, SourceLocation> + getCursorObjCProtocolRef(CXCursor C); + +/// \brief Create an Objective-C class reference at the given location. +CXCursor MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack an ObjCClassRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<ObjCInterfaceDecl *, SourceLocation> + getCursorObjCClassRef(CXCursor C); + +/// \brief Create a type reference at the given location. +CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU); + +/// \brief Unpack a TypeRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); + +Decl *getCursorDecl(CXCursor Cursor); +Expr *getCursorExpr(CXCursor Cursor); +Stmt *getCursorStmt(CXCursor Cursor); +ASTContext &getCursorContext(CXCursor Cursor); +ASTUnit *getCursorASTUnit(CXCursor Cursor); + +bool operator==(CXCursor X, CXCursor Y); + +inline bool operator!=(CXCursor X, CXCursor Y) { + return !(X == Y); +} + +}} // end namespace: clang::cxcursor + +#endif diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile index 94f0467..7bdbba1 100644 --- a/tools/CIndex/Makefile +++ b/tools/CIndex/Makefile @@ -22,7 +22,7 @@ LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 LINK_COMPONENTS := bitreader mc core -USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangSema.a \ +USEDLIBS = clangFrontend.a clangDriver.a clangSema.a \ clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a include $(LEVEL)/Makefile.common |