diff options
Diffstat (limited to 'tools/CIndex/CIndex.cpp')
-rw-r--r-- | tools/CIndex/CIndex.cpp | 1920 |
1 files changed, 1319 insertions, 601 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" + |