From 53992adde3eda3ccf9da63bc7e45673f043de18f Mon Sep 17 00:00:00 2001 From: rdivacky Date: Thu, 27 May 2010 15:17:06 +0000 Subject: Update clang to r104832. --- tools/libclang/CIndex.cpp | 525 ++++++++++++++++++++++++-------- tools/libclang/CIndexCodeCompletion.cpp | 51 +++- tools/libclang/CIndexUSRs.cpp | 429 ++++++++++++++++++-------- tools/libclang/CMakeLists.txt | 1 + tools/libclang/CXCursor.cpp | 10 +- tools/libclang/CXTypes.cpp | 249 +++++++++++++++ tools/libclang/Makefile | 2 +- tools/libclang/libclang.darwin.exports | 9 + tools/libclang/libclang.exports | 10 + 9 files changed, 1022 insertions(+), 264 deletions(-) create mode 100644 tools/libclang/CXTypes.cpp (limited to 'tools/libclang') diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index f9f7351..a077589 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -44,11 +44,11 @@ using namespace clang::cxstring; // Crash Reporting. //===----------------------------------------------------------------------===// -#ifdef __APPLE__ -#define USE_CRASHTRACER +#ifdef USE_CRASHTRACER #include "clang/Analysis/Support/SaveAndRestore.h" // Integrate with crash reporter. -extern "C" const char *__crashreporter_info__; +static const char *__crashreporter_info__ = 0; +asm(".desc ___crashreporter_info__, 0x10"); #define NUM_CRASH_STRINGS 32 static unsigned crashtracer_counter = 0; static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 }; @@ -152,6 +152,23 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, return RangeOverlap; } +/// \brief Determine if a source location falls within, before, or after a +/// a given source range. +static RangeComparisonResult LocationCompare(SourceManager &SM, + SourceLocation L, SourceRange R) { + assert(R.isValid() && "First range is invalid?"); + assert(L.isValid() && "Second range is invalid?"); + if (L == R.getBegin()) + return RangeOverlap; + if (L == R.getEnd()) + return RangeAfter; + if (SM.isBeforeInTranslationUnit(L, R.getBegin())) + return RangeBefore; + if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) + return RangeAfter; + return RangeOverlap; +} + /// \brief Translate a Clang source range into a CIndex source range. /// /// Clang internally represents ranges where the end location points to the @@ -222,6 +239,27 @@ class CursorVisitor : public DeclVisitor, /// \param R a half-open source range retrieved from the abstract syntax tree. RangeComparisonResult CompareRegionOfInterest(SourceRange R); + 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); + } + }; + public: CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, unsigned MaxPCHLevel, @@ -259,6 +297,7 @@ public: bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); @@ -268,6 +307,8 @@ public: // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); bool VisitObjCClassDecl(ObjCClassDecl *D); + bool VisitLinkageSpecDecl(LinkageSpecDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); // Type visitors // FIXME: QualifiedTypeLoc doesn't provide any location information @@ -277,6 +318,7 @@ public: bool VisitTagTypeLoc(TagTypeLoc TL); // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); bool VisitPointerTypeLoc(PointerTypeLoc TL); bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL); @@ -297,8 +339,10 @@ public: // FIXME: LabelStmt label? bool VisitIfStmt(IfStmt *S); bool VisitSwitchStmt(SwitchStmt *S); + bool VisitCaseStmt(CaseStmt *S); bool VisitWhileStmt(WhileStmt *S); bool VisitForStmt(ForStmt *S); +// bool VisitSwitchCase(SwitchCase *S); // Expression visitors bool VisitBlockExpr(BlockExpr *B); @@ -417,26 +461,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { // 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); + SetParentRAII SetParent(Parent, StmtParent, Cursor); if (clang_isDeclaration(Cursor.kind)) { Decl *D = getCursorDecl(Cursor); @@ -504,7 +529,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { - CXCursor Cursor = MakeCXCursor(*I, TU); + Decl *D = *I; + if (D->getLexicalDeclContext() != DC) + continue; + + CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { SourceRange Range = @@ -642,6 +671,40 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { return VisitObjCContainerDecl(PID); } +bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { + // FIXME: This implements a workaround with @property declarations also being + // installed in the DeclContext for the @interface. Eventually this code + // should be removed. + ObjCCategoryDecl *CDecl = dyn_cast(PD->getDeclContext()); + if (!CDecl || !CDecl->IsClassExtension()) + return false; + + ObjCInterfaceDecl *ID = CDecl->getClassInterface(); + if (!ID) + return false; + + IdentifierInfo *PropertyId = PD->getIdentifier(); + ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(cast(ID), PropertyId); + + if (!prevDecl) + return false; + + // Visit synthesized methods since they will be skipped when visiting + // the @interface. + if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + return false; +} + bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Issue callbacks for super class. if (D->getSuperClass() && @@ -705,6 +768,14 @@ bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) { return false; } +bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + return VisitDeclContext(D); +} + bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { ASTContext &Context = TU->getASTContext(); @@ -780,6 +851,13 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) return true; + return false; +} + +bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) + return true; + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), TU))) @@ -790,19 +868,7 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } 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; + return Visit(TL.getPointeeLoc()); } bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { @@ -861,13 +927,60 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { bool CursorVisitor::VisitStmt(Stmt *S) { for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end(); Child != ChildEnd; ++Child) { - if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU))) - return true; + if (Stmt *C = *Child) + if (Visit(MakeCXCursor(C, StmtParent, TU))) + return true; } return false; } +bool CursorVisitor::VisitCaseStmt(CaseStmt *S) { + // Specially handle CaseStmts because they can be nested, e.g.: + // + // case 1: + // case 2: + // + // In this case the second CaseStmt is the child of the first. Walking + // these recursively can blow out the stack. + CXCursor Cursor = MakeCXCursor(S, StmtParent, TU); + while (true) { + // Set the Parent field to Cursor, then back to its old value once we're + // done. + SetParentRAII SetParent(Parent, StmtParent, Cursor); + + if (Stmt *LHS = S->getLHS()) + if (Visit(MakeCXCursor(LHS, StmtParent, TU))) + return true; + if (Stmt *RHS = S->getRHS()) + if (Visit(MakeCXCursor(RHS, StmtParent, TU))) + return true; + if (Stmt *SubStmt = S->getSubStmt()) { + if (!isa(SubStmt)) + return Visit(MakeCXCursor(SubStmt, StmtParent, TU)); + + // Specially handle 'CaseStmt' so that we don't blow out the stack. + CaseStmt *CS = cast(SubStmt); + Cursor = MakeCXCursor(CS, StmtParent, TU); + if (RegionOfInterest.isValid()) { + SourceRange Range = CS->getSourceRange(); + if (Range.isInvalid() || CompareRegionOfInterest(Range)) + return false; + } + + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: return true; + case CXChildVisit_Continue: return false; + case CXChildVisit_Recurse: + // Perform tail-recursion manually. + S = CS; + continue; + } + } + return false; + } +} + bool CursorVisitor::VisitDeclStmt(DeclStmt *S) { for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { @@ -1089,8 +1202,6 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, RemappedFiles.size(), /*CaptureDiagnostics=*/true)); - // FIXME: Until we have broader testing, just drop the entire AST if we - // encountered an error. if (NumErrors != Diags->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. if (CXXIdx->getDisplayDiagnostics() && Unit.get()) { @@ -1368,6 +1479,16 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) { return Result; } +unsigned clang_isFromMainFile(CXSourceLocation loc) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(loc.int_data); + if (!loc.ptr_data[0] || Loc.isInvalid()) + return 0; + + const SourceManager &SM = + *static_cast(loc.ptr_data[0]); + return SM.isFromMainFile(Loc) ? 1 : 0; +} + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -1474,10 +1595,11 @@ static CXString getDeclSpelling(Decl *D) { // ObjCCategoryImplDecl returns the category name. return createCXString(CIMP->getIdentifier()->getNameStart()); - if (ND->getIdentifier()) - return createCXString(ND->getIdentifier()->getNameStart()); - - return createCXString(""); + llvm::SmallString<1024> S; + llvm::raw_svector_ostream os(S); + ND->printName(os); + + return createCXString(os.str()); } CXString clang_getCursorSpelling(CXCursor C) { @@ -1615,12 +1737,18 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("attribute(ibaction)"); case CXCursor_IBOutletAttr: return createCXString("attribute(iboutlet)"); + case CXCursor_IBOutletCollectionAttr: + return createCXString("attribute(iboutletcollection)"); case CXCursor_PreprocessingDirective: return createCXString("preprocessing directive"); case CXCursor_MacroDefinition: return createCXString("macro definition"); case CXCursor_MacroInstantiation: return createCXString("macro instantiation"); + case CXCursor_Namespace: + return createCXString("Namespace"); + case CXCursor_LinkageSpec: + return createCXString("LinkageSpec"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -1763,7 +1891,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), L); } - if (!getCursorDecl(C)) + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) return clang_getNullLocation(); Decl *D = getCursorDecl(C); @@ -1829,7 +1957,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) { return cxloc::translateSourceRange(getCursorContext(C), R); } - if (!getCursorDecl(C)) + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) return clang_getNullRange(); Decl *D = getCursorDecl(C); @@ -2286,9 +2414,15 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, const char *StartPos = Buf.data() + LocInfo.second; IdentifierInfo *II = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos); - CXTok.int_data[0] = II->getTokenID() == tok::identifier? - CXToken_Identifier - : CXToken_Keyword; + + if (II->getObjCKeywordID() != tok::objc_not_keyword) { + CXTok.int_data[0] = CXToken_Keyword; + } + else { + CXTok.int_data[0] = II->getTokenID() == tok::identifier? + CXToken_Identifier + : CXToken_Keyword; + } CXTok.ptr_data = II; } else if (Tok.is(tok::comment)) { CXTok.int_data[0] = CXToken_Comment; @@ -2308,62 +2442,214 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, *NumTokens = CXTokens.size(); } +void clang_disposeTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens) { + free(Tokens); +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Token annotation APIs. +//===----------------------------------------------------------------------===// + typedef llvm::DenseMap AnnotateTokensData; +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data); +namespace { +class AnnotateTokensWorker { + AnnotateTokensData &Annotated; + CXToken *Tokens; + CXCursor *Cursors; + unsigned NumTokens; + unsigned TokIdx; + CursorVisitor AnnotateVis; + SourceManager &SrcMgr; + + bool MoreTokens() const { return TokIdx < NumTokens; } + unsigned NextToken() const { return TokIdx; } + void AdvanceToken() { ++TokIdx; } + SourceLocation GetTokenLoc(unsigned tokI) { + return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]); + } -enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, - CXCursor parent, - CXClientData client_data) { - AnnotateTokensData *Data = static_cast(client_data); - - // We only annotate the locations of declarations, simple - // references, and expressions which directly reference something. - CXCursorKind Kind = clang_getCursorKind(cursor); - if (clang_isDeclaration(Kind) || clang_isReference(Kind)) { - // Okay: We can annotate the location of this declaration with the - // declaration or reference - } else if (clang_isExpression(cursor.kind)) { - if (Kind != CXCursor_DeclRefExpr && - Kind != CXCursor_MemberRefExpr && - Kind != CXCursor_ObjCMessageExpr) - return CXChildVisit_Recurse; - - CXCursor Referenced = clang_getCursorReferenced(cursor); - if (Referenced == cursor || Referenced == clang_getNullCursor()) - return CXChildVisit_Recurse; - - // Okay: we can annotate the location of this expression - } else if (clang_isPreprocessing(cursor.kind)) { - // We can always annotate a preprocessing directive/macro instantiation. - } else { - // Nothing to annotate - return CXChildVisit_Recurse; +public: + AnnotateTokensWorker(AnnotateTokensData &annotated, + CXToken *tokens, CXCursor *cursors, unsigned numTokens, + ASTUnit *CXXUnit, SourceRange RegionOfInterest) + : Annotated(annotated), Tokens(tokens), Cursors(cursors), + NumTokens(numTokens), TokIdx(0), + AnnotateVis(CXXUnit, AnnotateTokensVisitor, this, + Decl::MaxPCHLevel, RegionOfInterest), + SrcMgr(CXXUnit->getSourceManager()) {} + + void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } + enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); + void AnnotateTokens(CXCursor parent); +}; +} + +void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) { + // Walk the AST within the region of interest, annotating tokens + // along the way. + VisitChildren(parent); + + for (unsigned I = 0 ; I < TokIdx ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + if (Pos != Annotated.end()) + Cursors[I] = Pos->second; } + // Finish up annotating any tokens left. + if (!MoreTokens()) + return; + + const CXCursor &C = clang_getNullCursor(); + for (unsigned I = TokIdx ; I < NumTokens ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second; + } +} + +enum CXChildVisitResult +AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { CXSourceLocation Loc = clang_getCursorLocation(cursor); - (*Data)[Loc.int_data] = cursor; - return CXChildVisit_Recurse; + // We can always annotate a preprocessing directive/macro instantiation. + if (clang_isPreprocessing(cursor.kind)) { + Annotated[Loc.int_data] = cursor; + return CXChildVisit_Recurse; + } + + CXSourceRange cursorExtent = clang_getCursorExtent(cursor); + SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent); + + if (cursorRange.isInvalid()) + return CXChildVisit_Continue; + + SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data); + + // Adjust the annotated range based specific declarations. + const enum CXCursorKind cursorK = clang_getCursorKind(cursor); + if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) { + Decl *D = cxcursor::getCursorDecl(cursor); + // Don't visit synthesized ObjC methods, since they have no syntatic + // representation in the source. + if (const ObjCMethodDecl *MD = dyn_cast(D)) { + if (MD->isSynthesized()) + return CXChildVisit_Continue; + } + if (const DeclaratorDecl *DD = dyn_cast(D)) { + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) { + TypeLoc TL = TI->getTypeLoc(); + SourceLocation TLoc = TL.getSourceRange().getBegin(); + if (TLoc.isValid() && + SrcMgr.isBeforeInTranslationUnit(TLoc, L)) + cursorRange.setBegin(TLoc); + } + } + } + + const enum CXCursorKind K = clang_getCursorKind(parent); + const CXCursor updateC = + (clang_isInvalid(K) || K == CXCursor_TranslationUnit || + L.isMacroID()) + ? clang_getNullCursor() : parent; + + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + Cursors[I] = updateC; + AdvanceToken(); + continue; + case RangeAfter: + return CXChildVisit_Continue; + case RangeOverlap: + break; + } + break; + } + + // Visit children to get their cursor information. + const unsigned BeforeChildren = NextToken(); + VisitChildren(cursor); + const unsigned AfterChildren = NextToken(); + + // Adjust 'Last' to the last token within the extent of the cursor. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + assert(0 && "Infeasible"); + case RangeAfter: + break; + case RangeOverlap: + Cursors[I] = updateC; + AdvanceToken(); + continue; + } + break; + } + const unsigned Last = NextToken(); + + // Scan the tokens that are at the beginning of the cursor, but are not + // capture by the child cursors. + + // For AST elements within macros, rely on a post-annotate pass to + // to correctly annotate the tokens with cursors. Otherwise we can + // get confusing results of having tokens that map to cursors that really + // are expanded by an instantiation. + if (L.isMacroID()) + cursor = clang_getNullCursor(); + + for (unsigned I = BeforeChildren; I != AfterChildren; ++I) { + if (!clang_isInvalid(clang_getCursorKind(Cursors[I]))) + break; + Cursors[I] = cursor; + } + // Scan the tokens that are at the end of the cursor, but are not captured + // but the child cursors. + for (unsigned I = AfterChildren; I != Last; ++I) + Cursors[I] = cursor; + + TokIdx = Last; + return CXChildVisit_Continue; } +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + return static_cast(client_data)->Visit(cursor, parent); +} + +extern "C" { + void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, unsigned NumTokens, CXCursor *Cursors) { - if (NumTokens == 0) - return; - // Any token we don't specifically annotate will have a NULL cursor. - for (unsigned I = 0; I != NumTokens; ++I) - Cursors[I] = clang_getNullCursor(); + if (NumTokens == 0 || !Tokens || !Cursors) + return; ASTUnit *CXXUnit = static_cast(TU); - if (!CXXUnit || !Tokens) + if (!CXXUnit) { + // Any token we don't specifically annotate will have a NULL cursor. + const CXCursor &C = clang_getNullCursor(); + for (unsigned I = 0; I != NumTokens; ++I) + Cursors[I] = C; return; + } ASTUnit::ConcurrencyCheck Check(*CXXUnit); // Determine the region of interest, which contains all of the tokens. SourceRange RegionOfInterest; - RegionOfInterest.setBegin( - cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0]))); + RegionOfInterest.setBegin(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, Tokens[0]))); + SourceLocation End = cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[NumTokens - 1])); @@ -2373,14 +2659,14 @@ void clang_annotateTokens(CXTranslationUnit TU, // region of interest to the corresponding cursors. AnnotateTokensData Annotated; - // Relex the tokens within the source range to look for preprocessing + // Relex the tokens within the source range to look for preprocessing // directives. SourceManager &SourceMgr = CXXUnit->getSourceManager(); std::pair BeginLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); std::pair EndLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); - + llvm::StringRef Buffer; bool Invalid = false; if (BeginLocInfo.first == EndLocInfo.first && @@ -2388,16 +2674,16 @@ void clang_annotateTokens(CXTranslationUnit TU, !Invalid) { Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), CXXUnit->getASTContext().getLangOptions(), - Buffer.begin(), Buffer.data() + BeginLocInfo.second, + Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); Lex.SetCommentRetentionState(true); - - // Lex tokens in raw mode until we hit the end of the range, to avoid + + // Lex tokens in raw mode until we hit the end of the range, to avoid // entering #includes or expanding macros. while (true) { Token Tok; Lex.LexFromRawLexer(Tok); - + reprocess: if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { // We have found a preprocessing directive. Gobble it up so that we @@ -2410,51 +2696,35 @@ void clang_annotateTokens(CXTranslationUnit TU, std::vector Locations; do { Locations.push_back(Tok.getLocation()); - Lex.LexFromRawLexer(Tok); + Lex.LexFromRawLexer(Tok); } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof)); - + using namespace cxcursor; CXCursor Cursor = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), Locations.back()), - CXXUnit); + CXXUnit); for (unsigned I = 0, N = Locations.size(); I != N; ++I) { Annotated[Locations[I].getRawEncoding()] = Cursor; } - + if (Tok.isAtStartOfLine()) goto reprocess; - + continue; } - + if (Tok.is(tok::eof)) break; } } - - // Annotate all of the source locations in the region of interest that map to - // a specific cursor. - CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); - CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated, - Decl::MaxPCHLevel, RegionOfInterest); - AnnotateVis.VisitChildren(Parent); - - for (unsigned I = 0; I != NumTokens; ++I) { - // Determine whether we saw a cursor at this token's location. - AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); - if (Pos == Annotated.end()) - continue; - - Cursors[I] = Pos->second; - } -} -void clang_disposeTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens) { - free(Tokens); + // Annotate all of the source locations in the region of interest that map to + // a specific cursor. + AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens, + CXXUnit, RegionOfInterest); + W.AnnotateTokens(clang_getTranslationUnitCursor(CXXUnit)); } - } // end: extern "C" //===----------------------------------------------------------------------===// @@ -2540,6 +2810,21 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { } } // end: extern "C" + +//===----------------------------------------------------------------------===// +// C++ AST instrospection. +//===----------------------------------------------------------------------===// + +extern "C" { +unsigned clang_CXXMethod_isStatic(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + CXXMethodDecl *D = dyn_cast(cxcursor::getCursorDecl(C)); + return (D && D->isStatic()) ? 1 : 0; +} + +} // end: extern "C" + //===----------------------------------------------------------------------===// // CXString Operations. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index a21614c..481a375 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -37,12 +37,27 @@ using namespace clang; using namespace clang::cxstring; +namespace { + /// \brief Stored representation of a completion string. + /// + /// This is the representation behind a CXCompletionString. + class CXStoredCodeCompletionString : public CodeCompletionString { + unsigned Priority; + + public: + CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } + + unsigned getPriority() const { return Priority; } + }; +} + extern "C" { enum CXCompletionChunkKind clang_getCompletionChunkKind(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return CXCompletionChunk_Text; @@ -97,7 +112,8 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, CXString clang_getCompletionChunkText(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return createCXString(0); @@ -121,9 +137,12 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_SemiColon: case CodeCompletionString::CK_Equal: case CodeCompletionString::CK_HorizontalSpace: - case CodeCompletionString::CK_VerticalSpace: return createCXString((*CCStr)[chunk_number].Text, false); + case CodeCompletionString::CK_VerticalSpace: + // FIXME: Temporary hack until we figure out how to handle vertical space. + return createCXString(" "); + case CodeCompletionString::CK_Optional: // Note: treated as an empty text block. return createCXString(""); @@ -137,7 +156,8 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, CXCompletionString clang_getCompletionChunkCompletionString(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return 0; @@ -174,10 +194,17 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string, } unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; return CCStr? CCStr->size() : 0; } +unsigned clang_getCompletionPriority(CXCompletionString completion_string) { + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; + return CCStr? CCStr->getPriority() : CCP_Unlikely; +} + static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, unsigned &Value) { if (Memory + sizeof(unsigned) > MemoryEnd) @@ -223,7 +250,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { for (unsigned I = 0, N = NumResults; I != N; ++I) - delete (CodeCompletionString *)Results[I].CompletionString; + delete (CXStoredCodeCompletionString *)Results[I].CompletionString; delete [] Results; delete Buffer; @@ -373,10 +400,16 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, if (ReadUnsigned(Str, StrEnd, KindValue)) break; - CodeCompletionString *CCStr - = CodeCompletionString::Deserialize(Str, StrEnd); - if (!CCStr) + unsigned Priority; + if (ReadUnsigned(Str, StrEnd, Priority)) + break; + + CXStoredCodeCompletionString *CCStr + = new CXStoredCodeCompletionString(Priority); + if (!CCStr->Deserialize(Str, StrEnd)) { + delete CCStr; continue; + } if (!CCStr->empty()) { // Vend the code-completion result to the caller. diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index f3c74e8..e98fd26 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -28,12 +28,33 @@ using namespace clang::cxstring; namespace { class USRGenerator : public DeclVisitor { - llvm::raw_ostream &Out; + llvm::SmallString<1024> Buf; + llvm::raw_svector_ostream Out; bool IgnoreResults; ASTUnit *AU; + bool generatedLoc; public: - USRGenerator(ASTUnit *au, llvm::raw_ostream &out) - : Out(out), IgnoreResults(false), AU(au) {} + USRGenerator(const CXCursor *C = 0) + : Out(Buf), + IgnoreResults(false), + AU(C ? cxcursor::getCursorASTUnit(*C) : 0), + generatedLoc(false) + { + // Add the USR space prefix. + Out << "c:"; + } + + llvm::StringRef str() { + return Out.str(); + } + + USRGenerator* operator->() { return this; } + + template + llvm::raw_svector_ostream &operator<<(const T &x) { + Out << x; + return Out; + } bool ignoreResults() const { return IgnoreResults; } @@ -52,10 +73,14 @@ public: void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); void VisitVarDecl(VarDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D) { + IgnoreResults = true; + return; + } /// Generate the string component containing the location of the /// declaration. - void GenLoc(const Decl *D); + bool GenLoc(const Decl *D); /// String generation methods used both by the visitation methods /// and from other clients that want to directly generate USRs. These @@ -63,10 +88,6 @@ public: /// of an AST element), but only the fragments concerning the AST element /// itself. - /// Generate a USR fragment for a named declaration. This does - /// not include the USR component for the parent. - void GenNamedDecl(llvm::StringRef name); - /// Generate a USR for an Objective-C class. void GenObjCClass(llvm::StringRef cls); /// Generate a USR for an Objective-C class category. @@ -81,31 +102,12 @@ public: void GenObjCProperty(llvm::StringRef prop); /// Generate a USR for an Objective-C protocol. void GenObjCProtocol(llvm::StringRef prot); -}; -class StringUSRGenerator { -private: - llvm::SmallString<1024> StrBuf; - llvm::raw_svector_ostream Out; - USRGenerator UG; -public: - StringUSRGenerator(const CXCursor *C = 0) - : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) { - // Add the USR space prefix. - Out << "c:"; - } - - llvm::StringRef str() { - return Out.str(); - } + void VisitType(QualType T); - USRGenerator* operator->() { return &UG; } - - template - llvm::raw_svector_ostream &operator<<(const T &x) { - Out << x; - return Out; - } + /// Emit a Decl's name using NamedDecl::printName() and return true if + /// the decl had no name. + bool EmitDeclName(const NamedDecl *D); }; } // end anonymous namespace @@ -114,56 +116,91 @@ public: // Generating USRs from ASTS. //===----------------------------------------------------------------------===// +bool USRGenerator::EmitDeclName(const NamedDecl *D) { + Out.flush(); + const unsigned startSize = Buf.size(); + D->printName(Out); + Out.flush(); + const unsigned endSize = Buf.size(); + return startSize == endSize; +} + +static bool InAnonymousNamespace(const Decl *D) { + if (const NamespaceDecl *ND = dyn_cast(D->getDeclContext())) + return ND->isAnonymousNamespace(); + return false; +} + +static inline bool ShouldGenerateLocation(const NamedDecl *D) { + return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D); +} + void USRGenerator::VisitDeclContext(DeclContext *DC) { if (NamedDecl *D = dyn_cast(DC)) Visit(D); } void USRGenerator::VisitFieldDecl(FieldDecl *D) { - const std::string &s = D->getNameAsString(); - if (s.empty()) { + VisitDeclContext(D->getDeclContext()); + Out << (isa(D) ? "@" : "@FI@"); + if (EmitDeclName(D)) { // Bit fields can be anonymous. IgnoreResults = true; return; } - VisitDeclContext(D->getDeclContext()); - Out << (isa(D) ? "@" : "@FI@") << s; } void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { - if (D->getLinkage() != ExternalLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - } - else - VisitDeclContext(D->getDeclContext()); + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + Out << "@F@"; + D->printName(Out); + + ASTContext &Ctx = AU->getASTContext(); + if (!Ctx.getLangOptions().CPlusPlus || D->isExternC()) + return; - Out << "@F@" << D; + // Mangle in type information for the arguments. + for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); + I != E; ++I) { + Out << '#'; + if (ParmVarDecl *PD = *I) + VisitType(PD->getType()); + } + if (D->isVariadic()) + Out << '.'; + Out << '#'; + if (CXXMethodDecl *MD = dyn_cast(D)) { + if (MD->isStatic()) + Out << 'S'; + if (unsigned quals = MD->getTypeQualifiers()) + Out << (char)('0' + quals); + } } void USRGenerator::VisitNamedDecl(NamedDecl *D) { VisitDeclContext(D->getDeclContext()); - const std::string &s = D->getNameAsString(); - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, e.g.: - // void (*f)(void *); - // In this case, don't generate a USR. - if (s.empty()) + Out << "@"; + + if (EmitDeclName(D)) { + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, + // e.g.: void (*f)(void *); + // In this case, don't generate a USR. IgnoreResults = true; - else - GenNamedDecl(s); + } } void USRGenerator::VisitVarDecl(VarDecl *D) { // VarDecls can be declared 'extern' within a function or method body, // but their enclosing DeclContext is the function, not the TU. We need // to check the storage class to correctly generate the USR. - if (D->getLinkage() != ExternalLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - } + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); // Variables always have simple names. llvm::StringRef s = D->getName(); @@ -175,18 +212,28 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { if (s.empty()) IgnoreResults = true; else - GenNamedDecl(s); + Out << '@' << s; } void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isAnonymousNamespace()) { + Out << "@aN"; + return; + } + VisitDeclContext(D->getDeclContext()); - Out << "@N@" << D; + if (!IgnoreResults) + Out << "@N@" << D->getName(); } void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { Visit(cast(D->getDeclContext())); - GenObjCMethod(DeclarationName(D->getSelector()).getAsString(), - D->isInstanceMethod()); + // Ideally we would use 'GenObjCMethod', but this is such a hot path + // for Objective-C code that we don't want to use + // DeclarationName::getAsString(). + Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); + DeclarationName N(D->getSelector()); + N.printName(Out); } void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) { @@ -258,59 +305,56 @@ void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { } void USRGenerator::VisitTagDecl(TagDecl *D) { + // Add the location of the tag decl to handle resolution across + // translation units. + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + D = D->getCanonicalDecl(); 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; - } - const std::string &s = D->getNameAsString(); - const TypedefDecl *TD = 0; - if (s.empty()) { - TD = D->getTypedefForAnonDecl(); - Out << (TD ? 'A' : 'a'); + switch (D->getTagKind()) { + case TTK_Struct: Out << "@S"; break; + case TTK_Class: Out << "@C"; break; + case TTK_Union: Out << "@U"; break; + case TTK_Enum: Out << "@E"; break; } - // Add the location of the tag decl to handle resolution across - // translation units. - if (D->getLinkage() == NoLinkage) { - Out << '@'; - GenLoc(D); - if (IgnoreResults) - return; - } + Out << '@'; + Out.flush(); + assert(Buf.size() > 0); + const unsigned off = Buf.size() - 1; - if (s.empty()) { - if (TD) + if (EmitDeclName(D)) { + if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) { + Buf[off] = 'A'; Out << '@' << TD; + } + else + Buf[off] = 'a'; } - else - Out << '@' << s; } void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; DeclContext *DC = D->getDeclContext(); if (NamedDecl *DCN = dyn_cast(DC)) Visit(DCN); Out << "@T@"; - if (D->getLinkage() == NoLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - Out << '@'; - } Out << D->getName(); } -void USRGenerator::GenLoc(const Decl *D) { +bool USRGenerator::GenLoc(const Decl *D) { + if (generatedLoc) + return IgnoreResults; + generatedLoc = true; + const SourceManager &SM = AU->getSourceManager(); SourceLocation L = D->getLocStart(); if (L.isInvalid()) { IgnoreResults = true; - return; + return true; } L = SM.getInstantiationLoc(L); const std::pair &Decomposed = SM.getDecomposedLoc(L); @@ -322,21 +366,145 @@ void USRGenerator::GenLoc(const Decl *D) { else { // This case really isn't interesting. IgnoreResults = true; - return; + return true; } Out << '@' << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':' << SM.getColumnNumber(Decomposed.first, Decomposed.second); + + return IgnoreResults; +} + +void USRGenerator::VisitType(QualType T) { + // This method mangles in USR information for types. It can possibly + // just reuse the naming-mangling logic used by codegen, although the + // requirements for USRs might not be the same. + ASTContext &Ctx = AU->getASTContext(); + + do { + T = Ctx.getCanonicalType(T); + Qualifiers Q = T.getQualifiers(); + unsigned qVal = 0; + if (Q.hasConst()) + qVal |= 0x1; + if (Q.hasVolatile()) + qVal |= 0x2; + if (Q.hasRestrict()) + qVal |= 0x4; + if(qVal) + Out << ((char) ('0' + qVal)); + + // Mangle in ObjC GC qualifiers? + + if (const PointerType *PT = T->getAs()) { + Out << '*'; + T = PT->getPointeeType(); + continue; + } + if (const ReferenceType *RT = T->getAs()) { + Out << '&'; + T = RT->getPointeeType(); + continue; + } + if (const FunctionProtoType *FT = T->getAs()) { + Out << 'F'; + VisitType(FT->getResultType()); + for (FunctionProtoType::arg_type_iterator + I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { + VisitType(*I); + } + if (FT->isVariadic()) + Out << '.'; + return; + } + if (const BlockPointerType *BT = T->getAs()) { + Out << 'B'; + T = BT->getPointeeType(); + continue; + } + if (const BuiltinType *BT = T->getAs()) { + unsigned char c = '\0'; + switch (BT->getKind()) { + case BuiltinType::Void: + c = 'v'; break; + case BuiltinType::Bool: + c = 'b'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: + c = 'c'; break; + case BuiltinType::Char16: + c = 'q'; break; + case BuiltinType::Char32: + c = 'w'; break; + case BuiltinType::UShort: + c = 's'; break; + case BuiltinType::UInt: + c = 'i'; break; + case BuiltinType::ULong: + c = 'l'; break; + case BuiltinType::ULongLong: + c = 'k'; break; + case BuiltinType::UInt128: + c = 'j'; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + c = 'C'; break; + case BuiltinType::WChar: + c = 'W'; break; + case BuiltinType::Short: + c = 'S'; break; + case BuiltinType::Int: + c = 'I'; break; + case BuiltinType::Long: + c = 'L'; break; + case BuiltinType::LongLong: + c = 'K'; break; + case BuiltinType::Int128: + c = 'J'; break; + case BuiltinType::Float: + c = 'f'; break; + case BuiltinType::Double: + c = 'd'; break; + case BuiltinType::LongDouble: + c = 'D'; break; + case BuiltinType::NullPtr: + c = 'n'; break; + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UndeducedAuto: + IgnoreResults = true; + return; + case BuiltinType::ObjCId: + c = 'o'; break; + case BuiltinType::ObjCClass: + c = 'O'; break; + case BuiltinType::ObjCSel: + c = 'e'; break; + } + Out << c; + return; + } + if (const ComplexType *CT = T->getAs()) { + Out << '<'; + T = CT->getElementType(); + continue; + } + if (const TagType *TT = T->getAs()) { + Out << '$'; + VisitTagDecl(TT->getDecl()); + return; + } + + // Unhandled type. + Out << ' '; + break; + } while (true); } //===----------------------------------------------------------------------===// // General purpose USR generation methods. //===----------------------------------------------------------------------===// -void USRGenerator::GenNamedDecl(llvm::StringRef name) { - Out << "@" << name; -} - void USRGenerator::GenObjCClass(llvm::StringRef cls) { Out << "objc(cs)" << cls; } @@ -346,7 +514,7 @@ void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) { } void USRGenerator::GenObjCIvar(llvm::StringRef ivar) { - GenNamedDecl(ivar); + Out << '@' << ivar; } void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) { @@ -383,6 +551,7 @@ static CXString getDeclCursorUSR(const CXCursor &C) { // Generate USRs for all entities with external linkage. break; case NoLinkage: + case UniqueExternalLinkage: // We allow enums, typedefs, and structs that have no linkage to // have USRs that are anchored to the file they were defined in // (e.g., the header). This is a little gross, but in principal @@ -390,27 +559,27 @@ static CXString getDeclCursorUSR(const CXCursor &C) { // are referred to across multiple translation units. if (isa(ND) || isa(ND) || isa(ND) || isa(ND) || - isa(ND)) + isa(ND) || isa(ND)) break; // Fall-through. case InternalLinkage: if (isa(ND)) break; - case UniqueExternalLinkage: - return createCXString(""); } - StringUSRGenerator SUG(&C); - SUG->Visit(D); + USRGenerator UG(&C); + UG->Visit(D); - if (SUG->ignoreResults()) + if (UG->ignoreResults()) return createCXString(""); +#if 0 // For development testing. - // assert(SUG.str().size() > 2); + assert(UG.str().size() > 2); +#endif // Return a copy of the string that must be disposed by the caller. - return createCXString(SUG.str(), true); + return createCXString(UG.str(), true); } extern "C" { @@ -422,56 +591,56 @@ CXString clang_getCursorUSR(CXCursor C) { return getDeclCursorUSR(C); if (K == CXCursor_MacroDefinition) { - StringUSRGenerator SUG(&C); - SUG << "macro@" - << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); - return createCXString(SUG.str(), true); + USRGenerator UG(&C); + UG << "macro@" + << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); + return createCXString(UG.str(), true); } return createCXString(""); } CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCIvar(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCIvar(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCMethod(const char *name, unsigned isInstanceMethod, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCMethod(name, isInstanceMethod); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCMethod(name, isInstanceMethod); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCClass(const char *name) { - StringUSRGenerator SUG; - SUG->GenObjCClass(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCClass(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCProtocol(const char *name) { - StringUSRGenerator SUG; - SUG->GenObjCProtocol(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCProtocol(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCCategory(const char *class_name, const char *category_name) { - StringUSRGenerator SUG; - SUG->GenObjCCategory(class_name, category_name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCCategory(class_name, category_name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCProperty(const char *property, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCProperty(property); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCProperty(property); + return createCXString(UG.str(), true); } } // end extern "C" diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index d3de94a..62c9738 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(libclang CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp + CXTypes.cpp ../../include/clang-c/Index.h ) set_target_properties(libclang PROPERTIES OUTPUT_NAME clang) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index c8eb482..f7192dd 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -56,13 +56,14 @@ static CXCursorKind GetCursorKind(Decl *D) { case Decl::ParmVar: return CXCursor_ParmDecl; case Decl::Typedef: return CXCursor_TypedefDecl; case Decl::Var: return CXCursor_VarDecl; + case Decl::Namespace: return CXCursor_Namespace; default: if (TagDecl *TD = dyn_cast(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; + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_EnumDecl; } } @@ -79,6 +80,7 @@ static CXCursorKind GetCursorKind(const Attr *A) { default: break; case Attr::IBActionKind: return CXCursor_IBActionAttr; case Attr::IBOutletKind: return CXCursor_IBOutletAttr; + case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr; } return CXCursor_UnexposedAttr; diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXTypes.cpp new file mode 100644 index 0000000..137370a --- /dev/null +++ b/tools/libclang/CXTypes.cpp @@ -0,0 +1,249 @@ +//===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--------------------------------------------------------------------===// +// +// This file implements the 'CXTypes' API hooks in the Clang-C library. +// +//===--------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Frontend/ASTUnit.h" + +using namespace clang; + +static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { +#define BTCASE(K) case BuiltinType::K: return CXType_##K + switch (BT->getKind()) { + BTCASE(Void); + BTCASE(Bool); + BTCASE(Char_U); + BTCASE(UChar); + BTCASE(Char16); + BTCASE(Char32); + BTCASE(UShort); + BTCASE(UInt); + BTCASE(ULong); + BTCASE(ULongLong); + BTCASE(UInt128); + BTCASE(Char_S); + BTCASE(SChar); + BTCASE(WChar); + BTCASE(Short); + BTCASE(Int); + BTCASE(Long); + BTCASE(LongLong); + BTCASE(Int128); + BTCASE(Float); + BTCASE(Double); + BTCASE(LongDouble); + BTCASE(NullPtr); + BTCASE(Overload); + BTCASE(Dependent); + BTCASE(ObjCId); + BTCASE(ObjCClass); + BTCASE(ObjCSel); + default: + return CXType_Unexposed; + } +#undef BTCASE +} + +static CXTypeKind GetTypeKind(QualType T) { + Type *TP = T.getTypePtr(); + if (!TP) + return CXType_Invalid; + +#define TKCASE(K) case Type::K: return CXType_##K + switch (TP->getTypeClass()) { + case Type::Builtin: + return GetBuiltinTypeKind(cast(TP)); + TKCASE(Complex); + TKCASE(Pointer); + TKCASE(BlockPointer); + TKCASE(LValueReference); + TKCASE(RValueReference); + TKCASE(Record); + TKCASE(Enum); + TKCASE(Typedef); + TKCASE(ObjCInterface); + TKCASE(ObjCObjectPointer); + default: + return CXType_Unexposed; + } +#undef TKCASE +} + +static CXType MakeCXType(QualType T, ASTUnit *TU) { + CXTypeKind TK = GetTypeKind(T); + CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; + return CT; +} + +static inline QualType GetQualType(CXType CT) { + return QualType::getFromOpaquePtr(CT.data[0]); +} + +static inline ASTUnit* GetASTU(CXType CT) { + return static_cast(CT.data[1]); +} + +extern "C" { + +CXType clang_getCursorType(CXCursor C) { + ASTUnit *AU = cxcursor::getCursorASTUnit(C); + + if (clang_isExpression(C.kind)) { + QualType T = cxcursor::getCursorExpr(C)->getType(); + return MakeCXType(T, AU); + } + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (TypeDecl *TD = dyn_cast(D)) + return MakeCXType(QualType(TD->getTypeForDecl(), 0), AU); + if (ObjCInterfaceDecl *ID = dyn_cast(D)) + return MakeCXType(QualType(ID->getTypeForDecl(), 0), AU); + if (ValueDecl *VD = dyn_cast(D)) + return MakeCXType(VD->getType(), AU); + + return MakeCXType(QualType(), AU); + } + + return MakeCXType(QualType(), AU); +} + +CXType clang_getCanonicalType(CXType CT) { + if (CT.kind == CXType_Invalid) + return CT; + + QualType T = GetQualType(CT); + + if (T.isNull()) + return MakeCXType(QualType(), GetASTU(CT)); + + ASTUnit *AU = GetASTU(CT); + return MakeCXType(AU->getASTContext().getCanonicalType(T), AU); +} + +CXType clang_getPointeeType(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + + if (!TP) + return MakeCXType(QualType(), GetASTU(CT)); + + switch (TP->getTypeClass()) { + case Type::Pointer: + T = cast(TP)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast(TP)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast(TP)->getPointeeType(); + break; + case Type::ObjCObjectPointer: + T = cast(TP)->getPointeeType(); + break; + default: + T = QualType(); + break; + } + return MakeCXType(T, GetASTU(CT)); +} + +CXCursor clang_getTypeDeclaration(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + Decl *D = 0; + + switch (TP->getTypeClass()) { + case Type::Typedef: + D = cast(TP)->getDecl(); + break; + case Type::ObjCObject: + D = cast(TP)->getInterface(); + break; + case Type::ObjCInterface: + D = cast(TP)->getDecl(); + break; + case Type::Record: + case Type::Enum: + D = cast(TP)->getDecl(); + break; + default: + break; + } + + if (!D) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(D, GetASTU(CT)); +} + +CXString clang_getTypeKindSpelling(enum CXTypeKind K) { + const char *s = 0; +#define TKIND(X) case CXType_##X: s = "" #X ""; break + switch (K) { + TKIND(Invalid); + TKIND(Unexposed); + TKIND(Void); + TKIND(Bool); + TKIND(Char_U); + TKIND(UChar); + TKIND(Char16); + TKIND(Char32); + TKIND(UShort); + TKIND(UInt); + TKIND(ULong); + TKIND(ULongLong); + TKIND(UInt128); + TKIND(Char_S); + TKIND(SChar); + TKIND(WChar); + TKIND(Short); + TKIND(Int); + TKIND(Long); + TKIND(LongLong); + TKIND(Int128); + TKIND(Float); + TKIND(Double); + TKIND(LongDouble); + TKIND(NullPtr); + TKIND(Overload); + TKIND(Dependent); + TKIND(ObjCId); + TKIND(ObjCClass); + TKIND(ObjCSel); + TKIND(Complex); + TKIND(Pointer); + TKIND(BlockPointer); + TKIND(LValueReference); + TKIND(RValueReference); + TKIND(Record); + TKIND(Enum); + TKIND(Typedef); + TKIND(ObjCInterface); + TKIND(ObjCObjectPointer); + } +#undef TKIND + return cxstring::createCXString(s); +} + +unsigned clang_equalTypes(CXType A, CXType B) { + return A.data[0] == B.data[0] && A.data[1] == B.data[1];; +} + +} // end: extern "C" diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index a7877bf..ff0fa33 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -50,6 +50,6 @@ ifeq ($(HOST_OS),Darwin) ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -no-undefined -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index b361168..a9f4f07 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -1,3 +1,4 @@ +_clang_CXXMethod_isStatic _clang_annotateTokens _clang_codeComplete _clang_codeCompleteGetDiagnostic @@ -21,12 +22,15 @@ _clang_disposeTranslationUnit _clang_enableStackTraces _clang_equalCursors _clang_equalLocations +_clang_equalTypes _clang_formatDiagnostic _clang_getCString +_clang_getCanonicalType _clang_getClangVersion _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText +_clang_getCompletionPriority _clang_getCursor _clang_getCursorDefinition _clang_getCursorExtent @@ -37,6 +41,7 @@ _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced _clang_getCursorSpelling +_clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent _clang_getDiagnostic @@ -58,6 +63,7 @@ _clang_getNullLocation _clang_getNullRange _clang_getNumCompletionChunks _clang_getNumDiagnostics +_clang_getPointeeType _clang_getRange _clang_getRangeEnd _clang_getRangeStart @@ -67,9 +73,12 @@ _clang_getTokenLocation _clang_getTokenSpelling _clang_getTranslationUnitCursor _clang_getTranslationUnitSpelling +_clang_getTypeDeclaration +_clang_getTypeKindSpelling _clang_isCursorDefinition _clang_isDeclaration _clang_isExpression +_clang_isFromMainFile _clang_isInvalid _clang_isPreprocessing _clang_isReference diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 991bb06..b09e6ac 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -1,3 +1,4 @@ +clang_CXXMethod_isStatic clang_annotateTokens clang_codeComplete clang_codeCompleteGetDiagnostic @@ -21,12 +22,15 @@ clang_disposeTranslationUnit clang_enableStackTraces clang_equalCursors clang_equalLocations +clang_equalTypes clang_formatDiagnostic clang_getCString +clang_getCanonicalType clang_getClangVersion clang_getCompletionChunkCompletionString clang_getCompletionChunkKind clang_getCompletionChunkText +clang_getCompletionPriority clang_getCursor clang_getCursorDefinition clang_getCursorExtent @@ -37,6 +41,7 @@ clang_getCursorLinkage clang_getCursorLocation clang_getCursorReferenced clang_getCursorSpelling +clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent clang_getDiagnostic @@ -58,6 +63,7 @@ clang_getNullLocation clang_getNullRange clang_getNumCompletionChunks clang_getNumDiagnostics +clang_getPointeeType clang_getRange clang_getRangeEnd clang_getRangeStart @@ -67,9 +73,12 @@ clang_getTokenLocation clang_getTokenSpelling clang_getTranslationUnitCursor clang_getTranslationUnitSpelling +clang_getTypeDeclaration +clang_getTypeKindSpelling clang_isCursorDefinition clang_isDeclaration clang_isExpression +clang_isFromMainFile clang_isInvalid clang_isPreprocessing clang_isReference @@ -79,3 +88,4 @@ clang_isUnexposed clang_setUseExternalASTGeneration clang_tokenize clang_visitChildren + -- cgit v1.1