diff options
Diffstat (limited to 'tools/libclang')
-rw-r--r-- | tools/libclang/CIndex.cpp | 1131 | ||||
-rw-r--r-- | tools/libclang/CIndexCXX.cpp | 124 | ||||
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 306 | ||||
-rw-r--r-- | tools/libclang/CIndexDiagnostic.cpp | 27 | ||||
-rw-r--r-- | tools/libclang/CIndexUSRs.cpp | 237 | ||||
-rw-r--r-- | tools/libclang/CMakeLists.txt | 27 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 98 | ||||
-rw-r--r-- | tools/libclang/CXCursor.h | 28 | ||||
-rw-r--r-- | tools/libclang/CXType.cpp (renamed from tools/libclang/CXTypes.cpp) | 13 | ||||
-rw-r--r-- | tools/libclang/CXType.h | 29 | ||||
-rw-r--r-- | tools/libclang/Makefile | 26 | ||||
-rw-r--r-- | tools/libclang/libclang.darwin.exports | 19 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 19 |
13 files changed, 1840 insertions, 244 deletions
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 7f32a1c..5117f2c 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -14,6 +14,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "CXType.h" #include "CXSourceLocation.h" #include "CIndexDiagnostic.h" @@ -29,7 +30,9 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" #include "llvm/System/Program.h" #include "llvm/System/Signals.h" @@ -143,10 +146,10 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, SourceRange R2) { assert(R1.isValid() && "First range is invalid?"); assert(R2.isValid() && "Second range is invalid?"); - if (R1.getEnd() == R2.getBegin() || + if (R1.getEnd() != R2.getBegin() && SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) return RangeBefore; - if (R2.getEnd() == R1.getBegin() || + if (R2.getEnd() != R1.getBegin() && SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) return RangeAfter; return RangeOverlap; @@ -158,10 +161,8 @@ 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()) + if (L == R.getBegin() || L == R.getEnd()) return RangeOverlap; - if (L == R.getEnd()) - return RangeAfter; if (SM.isBeforeInTranslationUnit(L, R.getBegin())) return RangeBefore; if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) @@ -284,15 +285,24 @@ public: // Declaration visitors bool VisitAttributes(Decl *D); bool VisitBlockDecl(BlockDecl *B); + bool VisitCXXRecordDecl(CXXRecordDecl *D); bool VisitDeclContext(DeclContext *DC); bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTypedefDecl(TypedefDecl *D); bool VisitTagDecl(TagDecl *D); + bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); + bool VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); bool VisitEnumConstantDecl(EnumConstantDecl *D); bool VisitDeclaratorDecl(DeclaratorDecl *DD); bool VisitFunctionDecl(FunctionDecl *ND); bool VisitFieldDecl(FieldDecl *D); bool VisitVarDecl(VarDecl *); + bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + bool VisitClassTemplateDecl(ClassTemplateDecl *D); + bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); bool VisitObjCMethodDecl(ObjCMethodDecl *ND); bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); @@ -309,14 +319,28 @@ public: bool VisitObjCClassDecl(ObjCClassDecl *D); bool VisitLinkageSpecDecl(LinkageSpecDecl *D); bool VisitNamespaceDecl(NamespaceDecl *D); - + bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + bool VisitUsingDecl(UsingDecl *D); + bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + + // Name visitor + bool VisitDeclarationNameInfo(DeclarationNameInfo Name); + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); + + // Template visitors + bool VisitTemplateParameters(const TemplateParameterList *Params); + bool VisitTemplateName(TemplateName Name, SourceLocation Loc); + bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); + // Type visitors - // FIXME: QualifiedTypeLoc doesn't provide any location information + bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL); 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 VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL); bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); @@ -325,9 +349,9 @@ public: bool VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL); bool VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL); bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL); - bool VisitFunctionTypeLoc(FunctionTypeLoc TL); + bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); bool VisitArrayTypeLoc(ArrayTypeLoc TL); - // FIXME: Implement for TemplateSpecializationTypeLoc + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL); // FIXME: Implement visitors here when the unimplemented TypeLocs get // implemented bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); @@ -345,6 +369,8 @@ public: // bool VisitSwitchCase(SwitchCase *S); // Expression visitors + bool VisitDeclRefExpr(DeclRefExpr *E); + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); bool VisitBlockExpr(BlockExpr *B); bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); bool VisitExplicitCastExpr(ExplicitCastExpr *E); @@ -352,10 +378,30 @@ public: bool VisitObjCEncodeExpr(ObjCEncodeExpr *E); bool VisitOffsetOfExpr(OffsetOfExpr *E); bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + bool VisitMemberExpr(MemberExpr *E); + // FIXME: AddrLabelExpr (once we have cursors for labels) + bool VisitTypesCompatibleExpr(TypesCompatibleExpr *E); + bool VisitVAArgExpr(VAArgExpr *E); + // FIXME: InitListExpr (for the designators) + // FIXME: DesignatedInitExpr + bool VisitCXXTypeidExpr(CXXTypeidExpr *E); + bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { return false; } + // FIXME: CXXTemporaryObjectExpr has poor source-location information. + // FIXME: CXXScalarValueInitExpr has poor source-location information. + // FIXME: CXXNewExpr has poor source-location information + bool VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); + // FIXME: UnaryTypeTraitExpr has poor source-location information. + bool VisitOverloadExpr(OverloadExpr *E); + bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); + // FIXME: CXXUnresolvedConstructExpr has poor source-location information. + bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); + bool VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); }; } // end anonymous namespace +static SourceRange getRawCursorExtent(CXCursor C); + RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { return RangeCompare(TU->getSourceManager(), R, RegionOfInterest); } @@ -387,8 +433,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { // If we have a range of interest, and this cursor doesn't intersect with it, // we're done. if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { - SourceRange Range = - cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor)); + SourceRange Range = getRawCursorExtent(Cursor); if (Range.isInvalid() || CompareRegionOfInterest(Range)) return false; } @@ -478,10 +523,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { 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)) + for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(), + TLEnd = CXXUnit->top_level_end(); + TL != TLEnd; ++TL) { + if (Visit(MakeCXCursor(*TL, CXXUnit), true)) return true; } } else if (VisitDeclContext( @@ -520,7 +565,10 @@ bool CursorVisitor::VisitBlockDecl(BlockDecl *B) { if (Visit(B->getSignatureAsWritten()->getTypeLoc())) return true; - return Visit(MakeCXCursor(B->getBody(), StmtParent, TU)); + if (Stmt *Body = B->getBody()) + return Visit(MakeCXCursor(Body, StmtParent, TU)); + + return false; } bool CursorVisitor::VisitDeclContext(DeclContext *DC) { @@ -534,8 +582,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { - SourceRange Range = - cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor)); + SourceRange Range = getRawCursorExtent(Cursor); if (Range.isInvalid()) continue; @@ -577,6 +624,67 @@ bool CursorVisitor::VisitTagDecl(TagDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + bool ShouldVisitBody = false; + switch (D->getSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // Nothing to visit + return false; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + break; + + case TSK_ExplicitSpecialization: + ShouldVisitBody = true; + break; + } + + // Visit the template arguments used in the specialization. + if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) { + TypeLoc TL = SpecType->getTypeLoc(); + if (TemplateSpecializationTypeLoc *TSTLoc + = dyn_cast<TemplateSpecializationTypeLoc>(&TL)) { + for (unsigned I = 0, N = TSTLoc->getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TSTLoc->getArgLoc(I))) + return true; + } + } + + if (ShouldVisitBody && VisitCXXRecordDecl(D)) + return true; + + return false; +} + +bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the TagDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + // Visit the partial specialization arguments. + const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten(); + for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I) + if (VisitTemplateArgumentLoc(TemplateArgs[I])) + return true; + + return VisitCXXRecordDecl(D); +} + +bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + // Visit the default argument. + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo()) + if (Visit(DefArg->getTypeLoc())) + return true; + + return false; +} + bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { if (Expr *Init = D->getInitExpr()) return Visit(MakeCXCursor(Init, StmtParent, TU)); @@ -592,9 +700,37 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { } bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { - if (VisitDeclaratorDecl(ND)) - return true; - + if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) { + // Visit the function declaration's syntactic components in the order + // written. This requires a bit of work. + TypeLoc TL = TSInfo->getTypeLoc(); + FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL); + + // If we have a function declared directly (without the use of a typedef), + // visit just the return type. Otherwise, just visit the function's type + // now. + if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL->getResultLoc())) || + (!FTL && Visit(TL))) + return true; + + // Visit the nested-name-specifier, if present. + if (NestedNameSpecifier *Qualifier = ND->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, ND->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(ND->getNameInfo())) + return true; + + // FIXME: Visit explicitly-specified template arguments! + + // Visit the function parameters, if we have a function type. + if (FTL && VisitFunctionTypeLoc(*FTL, true)) + return true; + + // FIXME: Attributes? + } + if (ND->isThisDeclarationADefinition() && Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) return true; @@ -622,6 +758,46 @@ bool CursorVisitor::VisitVarDecl(VarDecl *D) { return false; } +bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; + + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + if (Expr *DefArg = D->getDefaultArgument()) + return Visit(MakeCXCursor(DefArg, StmtParent, TU)); + + return false; +} + +bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the FunctionDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitFunctionDecl(D->getTemplatedDecl()); +} + +bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the TagDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitCXXRecordDecl(D->getTemplatedDecl()); +} + +bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() && + VisitTemplateArgumentLoc(D->getDefaultArgument())) + return true; + + return false; +} + bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo()) if (Visit(TSInfo->getTypeLoc())) @@ -773,10 +949,207 @@ bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getQualifierRange())) + return true; + + return Visit(MakeCursorNamespaceRef(D->getAliasedNamespace(), + D->getTargetNameLoc(), TU)); +} + +bool CursorVisitor::VisitUsingDecl(UsingDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getTargetNestedNameDecl()) + if (VisitNestedNameSpecifier(Qualifier, D->getNestedNameRange())) + return true; + + // FIXME: Provide a multi-reference of some kind for all of the declarations + // that the using declaration refers to. We don't have this kind of cursor + // yet. + + return VisitDeclarationNameInfo(D->getNameInfo()); +} + +bool CursorVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getQualifierRange())) + return true; + + return Visit(MakeCursorNamespaceRef(D->getNominatedNamespaceAsWritten(), + D->getIdentLocation(), TU)); +} + +bool CursorVisitor::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getTargetNestedNameSpecifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getTargetNestedNameRange())) + return true; + + return VisitDeclarationNameInfo(D->getNameInfo()); +} + +bool CursorVisitor::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getTargetNestedNameSpecifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getTargetNestedNameRange())) + return true; + + return false; +} + +bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { + switch (Name.getName().getNameKind()) { + case clang::DeclarationName::Identifier: + case clang::DeclarationName::CXXLiteralOperatorName: + case clang::DeclarationName::CXXOperatorName: + case clang::DeclarationName::CXXUsingDirective: + return false; + + case clang::DeclarationName::CXXConstructorName: + case clang::DeclarationName::CXXDestructorName: + case clang::DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = Name.getNamedTypeInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case clang::DeclarationName::ObjCZeroArgSelector: + case clang::DeclarationName::ObjCOneArgSelector: + case clang::DeclarationName::ObjCMultiArgSelector: + // FIXME: Per-identifier location info? + return false; + } + + return false; +} + +bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range) { + // FIXME: This whole routine is a hack to work around the lack of proper + // source information in nested-name-specifiers (PR5791). Since we do have + // a beginning source location, we can visit the first component of the + // nested-name-specifier, if it's a single-token component. + if (!NNS) + return false; + + // Get the first component in the nested-name-specifier. + while (NestedNameSpecifier *Prefix = NNS->getPrefix()) + NNS = Prefix; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Namespace: + // FIXME: The token at this source location might actually have been a + // namespace alias, but we don't model that. Lame! + return Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(), + TU)); + + case NestedNameSpecifier::TypeSpec: { + // If the type has a form where we know that the beginning of the source + // range matches up with a reference cursor. Visit the appropriate reference + // cursor. + Type *T = NNS->getAsType(); + if (const TypedefType *Typedef = dyn_cast<TypedefType>(T)) + return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU)); + if (const TagType *Tag = dyn_cast<TagType>(T)) + return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU)); + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(T)) + return VisitTemplateName(TST->getTemplateName(), Range.getBegin()); + break; + } + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Identifier: + break; + } + + return false; +} + +bool CursorVisitor::VisitTemplateParameters( + const TemplateParameterList *Params) { + if (!Params) + return false; + + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (Visit(MakeCXCursor(*P, TU))) + return true; + } + + return false; +} + +bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { + switch (Name.getKind()) { + case TemplateName::Template: + return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU)); + + case TemplateName::OverloadedTemplate: + // FIXME: We need a way to return multiple lookup results in a single + // cursor. + return false; + + case TemplateName::DependentTemplate: + // FIXME: Visit nested-name-specifier. + return false; + + case TemplateName::QualifiedTemplate: + // FIXME: Visit nested-name-specifier. + return Visit(MakeCursorTemplateRef( + Name.getAsQualifiedTemplateName()->getDecl(), + Loc, TU)); + } + + return false; +} + +bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { + switch (TAL.getArgument().getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + return false; + + case TemplateArgument::Pack: + // FIXME: Implement when variadic templates come along. + return false; + + case TemplateArgument::Type: + if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case TemplateArgument::Declaration: + if (Expr *E = TAL.getSourceDeclExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + return false; + + case TemplateArgument::Expression: + if (Expr *E = TAL.getSourceExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + return false; + + case TemplateArgument::Template: + return VisitTemplateName(TAL.getArgument().getAsTemplate(), + TAL.getTemplateNameLoc()); + } + + return false; +} + bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + return Visit(TL.getUnqualifiedLoc()); +} + bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { ASTContext &Context = TU->getASTContext(); @@ -848,6 +1221,13 @@ bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } +bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + // FIXME: We can't visit the template template parameter, but there's + // no context information with which we can match up the depth/index in the + // type to the appropriate + return false; +} + bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) return true; @@ -892,8 +1272,9 @@ bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { return Visit(TL.getPointeeLoc()); } -bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - if (Visit(TL.getResultLoc())) +bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL, + bool SkipResultType) { + if (!SkipResultType && Visit(TL.getResultLoc())) return true; for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) @@ -914,6 +1295,21 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { return false; } +bool CursorVisitor::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + // Visit the template name. + if (VisitTemplateName(TL.getTypePtr()->getTemplateName(), + TL.getTemplateNameLoc())) + return true; + + // Visit the template arguments. + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TL.getArgLoc(I))) + return true; + + return false; +} + bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); } @@ -1054,6 +1450,56 @@ bool CursorVisitor::VisitForStmt(ForStmt *S) { return false; } +bool CursorVisitor::VisitDeclRefExpr(DeclRefExpr *E) { + // Visit nested-name-specifier, if present. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit declaration name. + if (VisitDeclarationNameInfo(E->getNameInfo())) + return true; + + // Visit explicitly-specified template arguments. + if (E->hasExplicitTemplateArgs()) { + ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); + for (TemplateArgumentLoc *Arg = Args.getTemplateArgs(), + *ArgEnd = Arg + Args.NumTemplateArgs; + Arg != ArgEnd; ++Arg) + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + + return false; +} + +bool CursorVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + if (Visit(MakeCXCursor(E->getArg(0), StmtParent, TU))) + return true; + + if (Visit(MakeCXCursor(E->getCallee(), StmtParent, TU))) + return true; + + for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) + if (Visit(MakeCXCursor(E->getArg(I), StmtParent, TU))) + return true; + + return false; +} + +bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { + if (D->isDefinition()) { + for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), + E = D->bases_end(); I != E; ++I) { + if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU))) + return true; + } + } + + return VisitTagDecl(D); +} + + bool CursorVisitor::VisitBlockExpr(BlockExpr *B) { return Visit(B->getBlockDecl()); } @@ -1077,6 +1523,34 @@ bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return VisitExpr(E); } +bool CursorVisitor::VisitMemberExpr(MemberExpr *E) { + // Visit the base expression. + if (Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + // Visit the nested-name-specifier + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getMemberNameInfo())) + return true; + + // Visit the explicitly-specified template arguments, if any. + if (E->hasExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = E->getTemplateArgs(), + *ArgEnd = Arg + E->getNumTemplateArgs(); + Arg != ArgEnd; + ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + return false; +} + bool CursorVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { if (TypeSourceInfo *TSInfo = E->getTypeInfoAsWritten()) if (Visit(TSInfo->getTypeLoc())) @@ -1093,6 +1567,143 @@ bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return VisitExpr(E); } +bool CursorVisitor::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { + return Visit(E->getArgTInfo1()->getTypeLoc()) || + Visit(E->getArgTInfo2()->getTypeLoc()); +} + +bool CursorVisitor::VisitVAArgExpr(VAArgExpr *E) { + if (Visit(E->getWrittenTypeInfo()->getTypeLoc())) + return true; + + return Visit(MakeCXCursor(E->getSubExpr(), StmtParent, TU)); +} + +bool CursorVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + if (E->isTypeOperand()) { + if (TypeSourceInfo *TSInfo = E->getTypeOperandSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; + } + + return VisitExpr(E); +} + +bool CursorVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + // Visit base expression. + if (Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the scope type that looks disturbingly like the nested-name-specifier + // but isn't. + if (TypeSourceInfo *TSInfo = E->getScopeTypeInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + // Visit the name of the type being destroyed. + if (TypeSourceInfo *TSInfo = E->getDestroyedTypeInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return false; +} + +bool CursorVisitor::VisitOverloadExpr(OverloadExpr *E) { + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getNameInfo())) + return true; + + // Visit the explicitly-specified template arguments. + if (const ExplicitTemplateArgumentList *ArgList + = E->getOptionalExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + // FIXME: We don't have a way to visit all of the declarations referenced + // here. + return false; +} + +bool CursorVisitor::VisitDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *E) { + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getNameInfo())) + return true; + + // Visit the explicitly-specified template arguments. + if (const ExplicitTemplateArgumentList *ArgList + = E->getOptionalExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + return false; +} + +bool CursorVisitor::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { + // Visit the base expression, if there is one. + if (!E->isImplicitAccess() && + Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getMemberNameInfo())) + return true; + + // Visit the explicitly-specified template arguments. + if (const ExplicitTemplateArgumentList *ArgList + = E->getOptionalExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + return false; +} + +bool CursorVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { + // Visit the base expression, if there is one. + if (!E->isImplicitAccess() && + Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + return VisitOverloadExpr(E); +} + bool CursorVisitor::VisitObjCMessageExpr(ObjCMessageExpr *E) { if (TypeSourceInfo *TSInfo = E->getClassReceiverTypeInfo()) if (Visit(TSInfo->getTypeLoc())) @@ -1107,8 +1718,9 @@ bool CursorVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { bool CursorVisitor::VisitAttributes(Decl *D) { - for (const Attr *A = D->getAttrs(); A; A = A->getNext()) - if (Visit(MakeCXCursor(A, D, TU))) + for (AttrVec::const_iterator i = D->attr_begin(), e = D->attr_end(); + i != e; ++i) + if (Visit(MakeCXCursor(*i, D, TU))) return true; return false; @@ -1117,6 +1729,10 @@ bool CursorVisitor::VisitAttributes(Decl *D) { extern "C" { CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics) { + // We use crash recovery to make some of our APIs more reliable, implicitly + // enable it. + llvm::CrashRecoveryContext::Enable(); + CIndexer *CIdxr = new CIndexer(); if (excludeDeclarationsFromPCH) CIdxr->setOnlyLocalDecls(); @@ -1128,6 +1744,8 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH, void clang_disposeIndex(CXIndex CIdx) { if (CIdx) delete static_cast<CIndexer *>(CIdx); + if (getenv("LIBCLANG_TIMING")) + llvm::TimerGroup::printAll(llvm::errs()); } void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) { @@ -1145,23 +1763,61 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); llvm::IntrusiveRefCntPtr<Diagnostic> Diags; - return ASTUnit::LoadFromPCHFile(ast_filename, Diags, + return ASTUnit::LoadFromASTFile(ast_filename, Diags, CXXIdx->getOnlyLocalDecls(), 0, 0, true); } +unsigned clang_defaultEditingTranslationUnitOptions() { + return CXTranslationUnit_PrecompiledPreamble; +} + CXTranslationUnit clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args, + const char * const *command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files) { + return clang_parseTranslationUnit(CIdx, source_filename, + command_line_args, num_command_line_args, + unsaved_files, num_unsaved_files, + CXTranslationUnit_DetailedPreprocessingRecord); +} + +struct ParseTranslationUnitInfo { + CXIndex CIdx; + const char *source_filename; + const char *const *command_line_args; + int num_command_line_args; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + unsigned options; + CXTranslationUnit result; +}; +static void clang_parseTranslationUnit_Impl(void *UserData) { + ParseTranslationUnitInfo *PTUI = + static_cast<ParseTranslationUnitInfo*>(UserData); + CXIndex CIdx = PTUI->CIdx; + const char *source_filename = PTUI->source_filename; + const char * const *command_line_args = PTUI->command_line_args; + int num_command_line_args = PTUI->num_command_line_args; + struct CXUnsavedFile *unsaved_files = PTUI->unsaved_files; + unsigned num_unsaved_files = PTUI->num_unsaved_files; + unsigned options = PTUI->options; + PTUI->result = 0; + if (!CIdx) - return 0; + return; CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + bool CompleteTranslationUnit + = ((options & CXTranslationUnit_Incomplete) == 0); + bool CacheCodeCompetionResults + = options & CXTranslationUnit_CacheCompletionResults; + // Configure the diagnostics. DiagnosticOptions DiagOpts; llvm::IntrusiveRefCntPtr<Diagnostic> Diags; @@ -1195,8 +1851,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, Args.insert(Args.end(), command_line_args, command_line_args + num_command_line_args); - Args.push_back("-Xclang"); - Args.push_back("-detailed-preprocessing-record"); + + // Do we need the detailed preprocessing record? + if (options & CXTranslationUnit_DetailedPreprocessingRecord) { + Args.push_back("-Xclang"); + Args.push_back("-detailed-preprocessing-record"); + } + unsigned NumErrors = Diags->getNumErrors(); #ifdef USE_CRASHTRACER @@ -1210,7 +1871,10 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), RemappedFiles.size(), - /*CaptureDiagnostics=*/true)); + /*CaptureDiagnostics=*/true, + PrecompilePreamble, + CompleteTranslationUnit, + CacheCodeCompetionResults)); if (NumErrors != Diags->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. @@ -1233,7 +1897,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, } } - return Unit.take(); + PTUI->result = Unit.take(); + return; } // Build up the arguments for invoking 'clang'. @@ -1269,7 +1934,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, std::vector<llvm::sys::Path> TemporaryFiles; std::vector<std::string> RemapArgs; if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) - return 0; + return; // The pointers into the elements of RemapArgs are stable because we // won't be adding anything to RemapArgs after this point. @@ -1300,9 +1965,12 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, TemporaryFiles.push_back(DiagnosticsFile); argv.push_back("-fdiagnostics-binary"); - argv.push_back("-Xclang"); - argv.push_back("-detailed-preprocessing-record"); - + // Do we need the detailed preprocessing record? + if (options & CXTranslationUnit_DetailedPreprocessingRecord) { + argv.push_back("-Xclang"); + argv.push_back("-detailed-preprocessing-record"); + } + // Add the null terminator. argv.push_back(NULL); @@ -1328,7 +1996,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; } - ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, Diags, + ASTUnit *ATU = ASTUnit::LoadFromASTFile(astTmpFile, Diags, CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), RemappedFiles.size(), @@ -1373,7 +2041,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, // Make the translation unit responsible for destroying all temporary files. for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) ATU->addTemporaryFile(TemporaryFiles[i]); - ATU->addTemporaryFile(llvm::sys::Path(ATU->getPCHFileName())); + ATU->addTemporaryFile(llvm::sys::Path(ATU->getASTFileName())); } else { // Destroy all of the temporary files now; they can't be referenced any // longer. @@ -1382,13 +2050,124 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, TemporaryFiles[i].eraseFromDisk(); } - return ATU; + PTUI->result = ATU; +} +CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args, + num_command_line_args, unsaved_files, num_unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!CRC.RunSafely(clang_parseTranslationUnit_Impl, &PTUI)) { + fprintf(stderr, "libclang: crash detected during parsing: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", options); + fprintf(stderr, "}\n"); + + return 0; + } + + return PTUI.result; +} + +unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { + return CXSaveTranslationUnit_None; +} + +int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, + unsigned options) { + if (!TU) + return 1; + + return static_cast<ASTUnit *>(TU)->Save(FileName); } void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { - if (CTUnit) + if (CTUnit) { + // If the translation unit has been marked as unsafe to free, just discard + // it. + if (static_cast<ASTUnit *>(CTUnit)->isUnsafeToFree()) + return; + delete static_cast<ASTUnit *>(CTUnit); + } +} + +unsigned clang_defaultReparseOptions(CXTranslationUnit TU) { + return CXReparse_None; +} + +struct ReparseTranslationUnitInfo { + CXTranslationUnit TU; + unsigned num_unsaved_files; + struct CXUnsavedFile *unsaved_files; + unsigned options; + int result; +}; +static void clang_reparseTranslationUnit_Impl(void *UserData) { + ReparseTranslationUnitInfo *RTUI = + static_cast<ReparseTranslationUnitInfo*>(UserData); + CXTranslationUnit TU = RTUI->TU; + unsigned num_unsaved_files = RTUI->num_unsaved_files; + struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files; + unsigned options = RTUI->options; + (void) options; + RTUI->result = 1; + + if (!TU) + return; + + llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + + if (!static_cast<ASTUnit *>(TU)->Reparse(RemappedFiles.data(), + RemappedFiles.size())) + RTUI->result = 0; } +int clang_reparseTranslationUnit(CXTranslationUnit TU, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options) { + ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!CRC.RunSafely(clang_reparseTranslationUnit_Impl, &RTUI)) { + fprintf(stderr, "libclang: crash detected during reparsing\n"); + static_cast<ASTUnit *>(TU)->setUnsafeToFree(true); + return 1; + } + + return RTUI.result; +} + CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { if (!CTUnit) @@ -1574,18 +2353,8 @@ unsigned clang_visitChildren(CXCursor parent, 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); + CursorVisitor CursorVis(CXXUnit, visitor, client_data, + CXXUnit->getMaxPCHLevel()); return CursorVis.VisitChildren(parent); } @@ -1603,6 +2372,9 @@ static CXString getDeclSpelling(Decl *D) { // ObjCCategoryImplDecl returns the category name. return createCXString(CIMP->getIdentifier()->getNameStart()); + if (isa<UsingDirectiveDecl>(D)) + return createCXString(""); + llvm::SmallString<1024> S; llvm::raw_svector_ostream os(S); ND->printName(os); @@ -1629,6 +2401,10 @@ CXString clang_getCursorSpelling(CXCursor C) { assert(OID && "getCursorSpelling(): Missing protocol decl"); return createCXString(OID->getIdentifier()->getNameStart()); } + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return createCXString(B->getType().getAsString()); + } case CXCursor_TypeRef: { TypeDecl *Type = getCursorTypeRef(C).first; assert(Type && "Missing type decl"); @@ -1636,6 +2412,19 @@ CXString clang_getCursorSpelling(CXCursor C) { return createCXString(getCursorContext(C).getTypeDeclType(Type). getAsString()); } + case CXCursor_TemplateRef: { + TemplateDecl *Template = getCursorTemplateRef(C).first; + assert(Template && "Missing template decl"); + + return createCXString(Template->getNameAsString()); + } + + case CXCursor_NamespaceRef: { + NamedDecl *NS = getCursorNamespaceRef(C).first; + assert(NS && "Missing namespace decl"); + + return createCXString(NS->getNameAsString()); + } default: return createCXString("<not implemented>"); @@ -1715,6 +2504,10 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("ObjCClassRef"); case CXCursor_TypeRef: return createCXString("TypeRef"); + case CXCursor_TemplateRef: + return createCXString("TemplateRef"); + case CXCursor_NamespaceRef: + return createCXString("NamespaceRef"); case CXCursor_UnexposedExpr: return createCXString("UnexposedExpr"); case CXCursor_BlockExpr: @@ -1757,6 +2550,32 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("Namespace"); case CXCursor_LinkageSpec: return createCXString("LinkageSpec"); + case CXCursor_CXXBaseSpecifier: + return createCXString("C++ base class specifier"); + case CXCursor_Constructor: + return createCXString("CXXConstructor"); + case CXCursor_Destructor: + return createCXString("CXXDestructor"); + case CXCursor_ConversionFunction: + return createCXString("CXXConversion"); + case CXCursor_TemplateTypeParameter: + return createCXString("TemplateTypeParameter"); + case CXCursor_NonTypeTemplateParameter: + return createCXString("NonTypeTemplateParameter"); + case CXCursor_TemplateTemplateParameter: + return createCXString("TemplateTemplateParameter"); + case CXCursor_FunctionTemplate: + return createCXString("FunctionTemplate"); + case CXCursor_ClassTemplate: + return createCXString("ClassTemplate"); + case CXCursor_ClassTemplatePartialSpecialization: + return createCXString("ClassTemplatePartialSpecialization"); + case CXCursor_NamespaceAlias: + return createCXString("NamespaceAlias"); + case CXCursor_UsingDirective: + return createCXString("UsingDirective"); + case CXCursor_UsingDeclaration: + return createCXString("UsingDeclaration"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -1776,20 +2595,28 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { return clang_getNullCursor(); ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); - ASTUnit::ConcurrencyCheck Check(*CXXUnit); + // Translate the given source location to make it point at the beginning of + // the token under the cursor. SourceLocation SLoc = cxloc::translateSourceLocation(Loc); + + // Guard against an invalid SourceLocation, or we may assert in one + // of the following calls. + if (SLoc.isInvalid()) + return clang_getNullCursor(); + + SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(), + CXXUnit->getASTContext().getLangOptions()); + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); if (SLoc.isValid()) { - SourceRange RegionOfInterest(SLoc, SLoc.getFileLocWithOffset(1)); - // FIXME: Would be great to have a "hint" cursor, then walk from that // hint cursor upward until we find a cursor whose source range encloses // the region of interest, rather than starting from the translation unit. CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, - Decl::MaxPCHLevel, RegionOfInterest); + Decl::MaxPCHLevel, SourceLocation(SLoc)); CursorVis.VisitChildren(Parent); } return Result; @@ -1873,6 +2700,21 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } + case CXCursor_TemplateRef: { + std::pair<TemplateDecl *, SourceLocation> P = getCursorTemplateRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_NamespaceRef: { + std::pair<NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_CXXBaseSpecifier: { + // FIXME: Figure out what location to return for a CXXBaseSpecifier. + return clang_getNullLocation(); + } + default: // FIXME: Need a way to enumerate all non-reference cases. llvm_unreachable("Missed a reference kind"); @@ -1909,67 +2751,68 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), Loc); } -CXSourceRange clang_getCursorExtent(CXCursor C) { +} // end extern "C" + +static SourceRange getRawCursorExtent(CXCursor C) { if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCSuperClassRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_ObjCSuperClassRef: + return getCursorObjCSuperClassRef(C).second; - case CXCursor_ObjCProtocolRef: { - std::pair<ObjCProtocolDecl *, SourceLocation> P - = getCursorObjCProtocolRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_ObjCProtocolRef: + return getCursorObjCProtocolRef(C).second; - case CXCursor_ObjCClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCClassRef(C); + case CXCursor_ObjCClassRef: + return getCursorObjCClassRef(C).second; - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_TypeRef: + return getCursorTypeRef(C).second; - case CXCursor_TypeRef: { - std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_TemplateRef: + return getCursorTemplateRef(C).second; + + case CXCursor_NamespaceRef: + return getCursorNamespaceRef(C).second; + + case CXCursor_CXXBaseSpecifier: + // FIXME: Figure out what source range to use for a CXBaseSpecifier. + return SourceRange(); - default: - // FIXME: Need a way to enumerate all non-reference cases. - llvm_unreachable("Missed a reference kind"); + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); } } if (clang_isExpression(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), - getCursorExpr(C)->getSourceRange()); + return getCursorExpr(C)->getSourceRange(); if (clang_isStatement(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), - getCursorStmt(C)->getSourceRange()); + return getCursorStmt(C)->getSourceRange(); - if (C.kind == CXCursor_PreprocessingDirective) { - SourceRange R = cxcursor::getCursorPreprocessingDirective(C); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_PreprocessingDirective) + return cxcursor::getCursorPreprocessingDirective(C); - if (C.kind == CXCursor_MacroInstantiation) { - SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_MacroInstantiation) + return cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); - if (C.kind == CXCursor_MacroDefinition) { - SourceRange R = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_MacroDefinition) + return cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) + if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) + return getCursorDecl(C)->getSourceRange(); + + return SourceRange(); +} + +extern "C" { + +CXSourceRange clang_getCursorExtent(CXCursor C) { + SourceRange R = getRawCursorExtent(C); + if (R.isInvalid()) return clang_getNullRange(); - Decl *D = getCursorDecl(C); - return cxloc::translateSourceRange(getCursorContext(C), D->getSourceRange()); + return cxloc::translateSourceRange(getCursorContext(C), R); } CXCursor clang_getCursorReferenced(CXCursor C) { @@ -2008,6 +2851,18 @@ CXCursor clang_getCursorReferenced(CXCursor C) { case CXCursor_TypeRef: return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit); + case CXCursor_TemplateRef: + return MakeCXCursor(getCursorTemplateRef(C).first, CXXUnit); + + case CXCursor_NamespaceRef: + return MakeCXCursor(getCursorNamespaceRef(C).first, CXXUnit); + + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C); + return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(), + CXXUnit)); + } + default: // We would prefer to enumerate all non-reference cursor kinds here. llvm_unreachable("Unhandled reference cursor kind"); @@ -2118,8 +2973,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::ClassTemplate: { if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl() ->getDefinition()) - return MakeCXCursor( - cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), + return MakeCXCursor(cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), CXXUnit); return clang_getNullCursor(); } @@ -2530,8 +3384,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { return CXChildVisit_Recurse; } - CXSourceRange cursorExtent = clang_getCursorExtent(cursor); - SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent); + SourceRange cursorRange = getRawCursorExtent(cursor); if (cursorRange.isInvalid()) return CXChildVisit_Continue; @@ -2559,11 +3412,27 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { } } + // If the location of the cursor occurs within a macro instantiation, record + // the spelling location of the cursor in our annotation map. We can then + // paper over the token labelings during a post-processing step to try and + // get cursor mappings for tokens that are the *arguments* of a macro + // instantiation. + if (L.isMacroID()) { + unsigned rawEncoding = SrcMgr.getSpellingLoc(L).getRawEncoding(); + // Only invalidate the old annotation if it isn't part of a preprocessing + // directive. Here we assume that the default construction of CXCursor + // results in CXCursor.kind being an initialized value (i.e., 0). If + // this isn't the case, we can fix by doing lookup + insertion. + + CXCursor &oldC = Annotated[rawEncoding]; + if (!clang_isPreprocessing(oldC.kind)) + oldC = cursor; + } + const enum CXCursorKind K = clang_getCursorKind(parent); const CXCursor updateC = - (clang_isInvalid(K) || K == CXCursor_TranslationUnit || - L.isMacroID()) - ? clang_getNullCursor() : parent; + (clang_isInvalid(K) || K == CXCursor_TranslationUnit) + ? clang_getNullCursor() : parent; while (MoreTokens()) { const unsigned I = NextToken(); @@ -2574,7 +3443,6 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { AdvanceToken(); continue; case RangeAfter: - return CXChildVisit_Continue; case RangeOverlap: break; } @@ -2658,11 +3526,9 @@ void clang_annotateTokens(CXTranslationUnit TU, SourceRange RegionOfInterest; RegionOfInterest.setBegin(cxloc::translateSourceLocation( clang_getTokenLocation(TU, Tokens[0]))); - - SourceLocation End - = cxloc::translateSourceLocation(clang_getTokenLocation(TU, - Tokens[NumTokens - 1])); - RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End)); + RegionOfInterest.setEnd(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, + Tokens[NumTokens - 1]))); // A mapping from the source locations found when re-lexing or traversing the // region of interest to the corresponding cursors. @@ -2811,6 +3677,21 @@ static CXLanguageKind getDeclLanguage(const Decl *D) { } extern "C" { + +enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) + if (Decl *D = cxcursor::getCursorDecl(cursor)) { + if (D->hasAttr<UnavailableAttr>() || + (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())) + return CXAvailability_Available; + + if (D->hasAttr<DeprecatedAttr>()) + return CXAvailability_Deprecated; + } + + return CXAvailability_Available; +} + CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { if (clang_isDeclaration(cursor.kind)) return getDeclLanguage(cxcursor::getCursorDecl(cursor)); @@ -2828,13 +3709,35 @@ extern "C" { unsigned clang_CXXMethod_isStatic(CXCursor C) { if (!clang_isDeclaration(C.kind)) return 0; - CXXMethodDecl *D = dyn_cast<CXXMethodDecl>(cxcursor::getCursorDecl(C)); - return (D && D->isStatic()) ? 1 : 0; + + CXXMethodDecl *Method = 0; + Decl *D = cxcursor::getCursorDecl(C); + if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + else + Method = dyn_cast_or_null<CXXMethodDecl>(D); + return (Method && Method->isStatic()) ? 1 : 0; } } // end: extern "C" //===----------------------------------------------------------------------===// +// Attribute introspection. +//===----------------------------------------------------------------------===// + +extern "C" { +CXType clang_getIBOutletCollectionType(CXCursor C) { + if (C.kind != CXCursor_IBOutletCollectionAttr) + return cxtype::MakeCXType(QualType(), cxcursor::getCursorASTUnit(C)); + + IBOutletCollectionAttr *A = + cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C)); + + return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorASTUnit(C)); +} +} // end: extern "C" + +//===----------------------------------------------------------------------===// // CXString Operations. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp new file mode 100644 index 0000000..3ade519 --- /dev/null +++ b/tools/libclang/CIndexCXX.cpp @@ -0,0 +1,124 @@ +//===- CIndexCXX.cpp - Clang-C Source Indexing Library --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the libclang support for C++ cursors. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXType.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +using namespace clang; +using namespace clang::cxstring; +using namespace clang::cxcursor; + +extern "C" { + +unsigned clang_isVirtualBase(CXCursor C) { + if (C.kind != CXCursor_CXXBaseSpecifier) + return 0; + + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return B->isVirtual(); +} + +enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) { + if (C.kind != CXCursor_CXXBaseSpecifier) + return CX_CXXInvalidAccessSpecifier; + + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + switch (B->getAccessSpecifier()) { + case AS_public: return CX_CXXPublic; + case AS_protected: return CX_CXXProtected; + case AS_private: return CX_CXXPrivate; + case AS_none: return CX_CXXInvalidAccessSpecifier; + } + + // FIXME: Clang currently thinks this is reachable. + return CX_CXXInvalidAccessSpecifier; +} + +enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) { + using namespace clang::cxcursor; + + switch (C.kind) { + case CXCursor_ClassTemplate: + case CXCursor_FunctionTemplate: + if (TemplateDecl *Template + = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C))) + return MakeCXCursor(Template->getTemplatedDecl(), + getCursorASTUnit(C)).kind; + break; + + case CXCursor_ClassTemplatePartialSpecialization: + if (ClassTemplateSpecializationDecl *PartialSpec + = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>( + getCursorDecl(C))) { + switch (PartialSpec->getTagKind()) { + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_NoDeclFound; + } + } + break; + + default: + break; + } + + return CXCursor_NoDeclFound; +} + +CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + Decl *Template = 0; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) + Template = PartialSpec->getSpecializedTemplate(); + else if (ClassTemplateSpecializationDecl *ClassSpec + = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> Result + = ClassSpec->getSpecializedTemplateOrPartial(); + if (Result.is<ClassTemplateDecl *>()) + Template = Result.get<ClassTemplateDecl *>(); + else + Template = Result.get<ClassTemplatePartialSpecializationDecl *>(); + + } else + Template = CXXRecord->getInstantiatedFromMemberClass(); + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + Template = Function->getPrimaryTemplate(); + if (!Template) + Template = Function->getInstantiatedFromMemberFunction(); + } else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->isStaticDataMember()) + Template = Var->getInstantiatedFromStaticDataMember(); + } else if (RedeclarableTemplateDecl *Tmpl + = dyn_cast<RedeclarableTemplateDecl>(D)) + Template = Tmpl->getInstantiatedFromMemberTemplate(); + + if (!Template) + return clang_getNullCursor(); + + return MakeCXCursor(Template, getCursorASTUnit(C)); +} + +} // end extern "C" diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 277fadf..d591c5d 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -16,18 +16,23 @@ #include "CIndexDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Program.h" +#include <cstdlib> +#include <cstdio> + #ifdef UDP_CODE_COMPLETION_LOGGER #include "clang/Basic/Version.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" #include <arpa/inet.h> #include <sys/socket.h> #include <sys/types.h> @@ -43,11 +48,15 @@ namespace { /// This is the representation behind a CXCompletionString. class CXStoredCodeCompletionString : public CodeCompletionString { unsigned Priority; + CXAvailabilityKind Availability; public: - CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } + CXStoredCodeCompletionString(unsigned Priority, + CXAvailabilityKind Availability) + : Priority(Priority), Availability(Availability) { } unsigned getPriority() const { return Priority; } + CXAvailabilityKind getAvailability() const { return Availability; } }; } @@ -205,6 +214,13 @@ unsigned clang_getCompletionPriority(CXCompletionString completion_string) { return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); } +enum CXAvailabilityKind +clang_getCompletionAvailability(CXCompletionString completion_string) { + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; + return CCStr? CCStr->getAvailability() : CXAvailability_Available; +} + static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, unsigned &Value) { if (Memory + sizeof(unsigned) > MemoryEnd) @@ -221,15 +237,11 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { AllocatedCXCodeCompleteResults(); ~AllocatedCXCodeCompleteResults(); - /// \brief The memory buffer from which we parsed the results. We - /// retain this buffer because the completion strings point into it. - llvm::MemoryBuffer *Buffer; - /// \brief Diagnostics produced while performing code completion. llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; /// \brief Diag object - Diagnostic Diag; + llvm::IntrusiveRefCntPtr<Diagnostic> Diag; /// \brief Language options used to adjust source locations. LangOptions LangOpts; @@ -243,25 +255,29 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Temporary files that should be removed once we have finished /// with the code-completion results. std::vector<llvm::sys::Path> TemporaryFiles; + + /// \brief Temporary buffers that will be deleted once we have finished with the code-completion results. + llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; }; AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() - : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { } + : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { } AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { for (unsigned I = 0, N = NumResults; I != N; ++I) delete (CXStoredCodeCompletionString *)Results[I].CompletionString; delete [] Results; - delete Buffer; for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) TemporaryFiles[I].eraseFromDisk(); + for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) + delete TemporaryBuffers[I]; } CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args, + const char * const *command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files, const char *complete_filename, @@ -273,6 +289,17 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, #endif #endif + bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; + + llvm::OwningPtr<llvm::NamedRegionTimer> CCTimer; + if (getenv("LIBCLANG_TIMING")) { + llvm::SmallString<128> TimerName; + llvm::raw_svector_ostream TimerNameOut(TimerName); + TimerNameOut << "Code completion (out-of-process) @ " << complete_filename + << ":" << complete_line << ":" << complete_column; + CCTimer.reset(new llvm::NamedRegionTimer(TimerNameOut.str())); + } + // The indexer, which is mainly used to determine where diagnostics go. CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); @@ -348,6 +375,15 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, argv.push_back(arg); } + if (EnableLogging) { + std::string Log = ClangPath.str(); + for (unsigned I = 0, N = argv.size(); I != N; ++I) { + Log += ' '; + Log += argv[I]; + } + fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str()); + } + // Add the null terminator. argv.push_back(NULL); @@ -363,6 +399,8 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, llvm::sys::Path DiagnosticsFile(tmpResultsFileName); TemporaryFiles.push_back(DiagnosticsFile); + + // Invoke 'clang'. llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null // on Unix or NUL (Windows). @@ -392,7 +430,6 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; Results->Results = 0; Results->NumResults = 0; - Results->Buffer = 0; // FIXME: Set Results->LangOpts! if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { llvm::SmallVector<CXCompletionResult, 4> CompletionResults; @@ -407,8 +444,13 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, if (ReadUnsigned(Str, StrEnd, Priority)) break; + unsigned Availability; + if (ReadUnsigned(Str, StrEnd, Availability)) + break; + CXStoredCodeCompletionString *CCStr - = new CXStoredCodeCompletionString(Priority); + = new CXStoredCodeCompletionString(Priority, + (CXAvailabilityKind)Availability); if (!CCStr->Deserialize(Str, StrEnd)) { delete CCStr; continue; @@ -428,7 +470,7 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, Results->NumResults = CompletionResults.size(); memcpy(Results->Results, CompletionResults.data(), CompletionResults.size() * sizeof(CXCompletionResult)); - Results->Buffer = F; + Results->TemporaryBuffers.push_back(F); } LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, @@ -511,9 +553,208 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, } #endif #endif + clang_sortCodeCompletionResults(Results->Results, Results->NumResults); return Results; } +} // end extern "C" + +namespace { + class CaptureCompletionResults : public CodeCompleteConsumer { + AllocatedCXCodeCompleteResults &AllocatedResults; + + public: + explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) + : CodeCompleteConsumer(true, false, true, false), + AllocatedResults(Results) { } + + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { + AllocatedResults.Results = new CXCompletionResult [NumResults]; + AllocatedResults.NumResults = NumResults; + for (unsigned I = 0; I != NumResults; ++I) { + CXStoredCodeCompletionString *StoredCompletion + = new CXStoredCodeCompletionString(Results[I].Priority, + Results[I].Availability); + (void)Results[I].CreateCodeCompletionString(S, StoredCompletion); + AllocatedResults.Results[I].CursorKind = Results[I].CursorKind; + AllocatedResults.Results[I].CompletionString = StoredCompletion; + } + } + + // FIXME: Add ProcessOverloadCandidates? + }; +} + +extern "C" { +struct CodeCompleteAtInfo { + CXTranslationUnit TU; + const char *complete_filename; + unsigned complete_line; + unsigned complete_column; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + unsigned options; + CXCodeCompleteResults *result; +}; +void clang_codeCompleteAt_Impl(void *UserData) { + CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData); + CXTranslationUnit TU = CCAI->TU; + const char *complete_filename = CCAI->complete_filename; + unsigned complete_line = CCAI->complete_line; + unsigned complete_column = CCAI->complete_column; + struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files; + unsigned num_unsaved_files = CCAI->num_unsaved_files; + unsigned options = CCAI->options; + CCAI->result = 0; + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); +#endif +#endif + + bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; + + ASTUnit *AST = static_cast<ASTUnit *>(TU); + if (!AST) + return; + + // Perform the remapping of source files. + llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + + if (EnableLogging) { + // FIXME: Add logging. + } + + // Parse the resulting source file to find code-completion results. + AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; + Results->Results = 0; + Results->NumResults = 0; + + // Create a code-completion consumer to capture the results. + CaptureCompletionResults Capture(*Results); + + // Perform completion. + AST->CodeComplete(complete_filename, complete_line, complete_column, + RemappedFiles.data(), RemappedFiles.size(), + (options & CXCodeComplete_IncludeMacros), + (options & CXCodeComplete_IncludeCodePatterns), + Capture, + *Results->Diag, Results->LangOpts, Results->SourceMgr, + Results->FileMgr, Results->Diagnostics, + Results->TemporaryBuffers); + + + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); + llvm::SmallString<256> LogResult; + llvm::raw_svector_ostream os(LogResult); + + // Figure out the language and whether or not it uses PCH. + const char *lang = 0; + bool usesPCH = false; + + for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); + I != E; ++I) { + if (*I == 0) + continue; + if (strcmp(*I, "-x") == 0) { + if (I + 1 != E) { + lang = *(++I); + continue; + } + } + else if (strcmp(*I, "-include") == 0) { + if (I+1 != E) { + const char *arg = *(++I); + llvm::SmallString<512> pchName; + { + llvm::raw_svector_ostream os(pchName); + os << arg << ".pth"; + } + pchName.push_back('\0'); + struct stat stat_results; + if (stat(pchName.data(), &stat_results) == 0) + usesPCH = true; + continue; + } + } + } + + os << "{ "; + os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); + os << ", \"numRes\": " << Results->NumResults; + os << ", \"diags\": " << Results->Diagnostics.size(); + os << ", \"pch\": " << (usesPCH ? "true" : "false"); + os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; + const char *name = getlogin(); + os << ", \"user\": \"" << (name ? name : "unknown") << '"'; + os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; + os << " }"; + + llvm::StringRef res = os.str(); + if (res.size() > 0) { + do { + // Setup the UDP socket. + struct sockaddr_in servaddr; + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); + if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, + &servaddr.sin_addr) <= 0) + break; + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + break; + + sendto(sockfd, res.data(), res.size(), 0, + (struct sockaddr *)&servaddr, sizeof(servaddr)); + close(sockfd); + } + while (false); + } +#endif +#endif + CCAI->result = Results; +} +CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, + const char *complete_filename, + unsigned complete_line, + unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + CodeCompleteAtInfo CCAI = { TU, complete_filename, complete_line, + complete_column, unsaved_files, num_unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!CRC.RunSafely(clang_codeCompleteAt_Impl, &CCAI)) { + fprintf(stderr, "libclang: crash detected in code completion\n"); + static_cast<ASTUnit *>(TU)->setUnsafeToFree(true); + return 0; + } + + return CCAI.result; +} + +unsigned clang_defaultCodeCompleteOptions(void) { + return CXCodeComplete_IncludeMacros; +} + void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { if (!ResultsIn) return; @@ -522,7 +763,7 @@ void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); delete Results; } - + unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { AllocatedCXCodeCompleteResults *Results @@ -546,3 +787,36 @@ clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, } // end extern "C" + +namespace { + struct OrderCompletionResults { + bool operator()(const CXCompletionResult &XR, + const CXCompletionResult &YR) const { + CXStoredCodeCompletionString *X + = (CXStoredCodeCompletionString *)XR.CompletionString; + CXStoredCodeCompletionString *Y + = (CXStoredCodeCompletionString *)YR.CompletionString; + + const char *XText = X->getTypedText(); + const char *YText = Y->getTypedText(); + if (!XText || !YText) + return XText != 0; + + int result = llvm::StringRef(XText).compare_lower(YText); + if (result < 0) + return true; + if (result > 0) + return false; + + result = llvm::StringRef(XText).compare(YText); + return result; + } + }; +} + +extern "C" { + void clang_sortCodeCompletionResults(CXCompletionResult *Results, + unsigned NumResults) { + std::stable_sort(Results, Results + NumResults, OrderCompletionResults()); + } +} diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp index 3db37b9..531992e 100644 --- a/tools/libclang/CIndexDiagnostic.cpp +++ b/tools/libclang/CIndexDiagnostic.cpp @@ -204,26 +204,13 @@ CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; if (ReplacementRange) { - if (Hint.RemoveRange.isInvalid()) { - // Create an empty range that refers to a single source - // location (which is the insertion point). - CXSourceRange Range = { - { (void *)&StoredDiag->Diag.getLocation().getManager(), - (void *)&StoredDiag->LangOpts }, - Hint.InsertionLoc.getRawEncoding(), - Hint.InsertionLoc.getRawEncoding() - }; - - *ReplacementRange = Range; - } else { - // Create a range that covers the entire replacement (or - // removal) range, adjusting the end of the range to point to - // the end of the token. - *ReplacementRange - = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), - StoredDiag->LangOpts, - Hint.RemoveRange); - } + // Create a range that covers the entire replacement (or + // removal) range, adjusting the end of the range to point to + // the end of the token. + *ReplacementRange + = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), + StoredDiag->LangOpts, + Hint.RemoveRange); } return createCXString(Hint.CodeToInsert); diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index e98fd26..8f3dacf 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -13,6 +13,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Lex/PreprocessingRecord.h" @@ -64,6 +65,9 @@ public: void VisitFunctionDecl(FunctionDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitObjCClassDecl(ObjCClassDecl *CD); void VisitObjCContainerDecl(ObjCContainerDecl *CD); void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P); @@ -72,12 +76,26 @@ public: void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitVarDecl(VarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D) { IgnoreResults = true; - return; } - + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + IgnoreResults = true; + } + void VisitUsingDecl(UsingDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + IgnoreResults = true; + } + /// Generate the string component containing the location of the /// declaration. bool GenLoc(const Decl *D); @@ -104,7 +122,10 @@ public: void GenObjCProtocol(llvm::StringRef prot); void VisitType(QualType T); - + void VisitTemplateParameterList(const TemplateParameterList *Params); + void VisitTemplateName(TemplateName Name); + void VisitTemplateArgument(const TemplateArgument &Arg); + /// Emit a Decl's name using NamedDecl::printName() and return true if /// the decl had no name. bool EmitDeclName(const NamedDecl *D); @@ -155,7 +176,11 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { return; VisitDeclContext(D->getDeclContext()); - Out << "@F@"; + if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { + Out << "@FT@"; + VisitTemplateParameterList(FunTmpl->getTemplateParameters()); + } else + Out << "@F@"; D->printName(Out); ASTContext &Ctx = AU->getASTContext(); @@ -207,7 +232,7 @@ void USRGenerator::VisitVarDecl(VarDecl *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 *); + // void (*f)(void *); // In this case, don't generate a USR. if (s.empty()) IgnoreResults = true; @@ -215,6 +240,16 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { Out << '@' << s; } +void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + GenLoc(D); + return; +} + void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { if (D->isAnonymousNamespace()) { Out << "@aN"; @@ -226,8 +261,35 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { Out << "@N@" << D->getName(); } +void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + VisitFunctionDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + VisitTagDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@NA@" << D->getName(); +} + void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { - Visit(cast<Decl>(D->getDeclContext())); + Decl *container = cast<Decl>(D->getDeclContext()); + + // The USR for a method declared in a class extension is based on + // the ObjCInterfaceDecl, not the ObjCCategoryDecl. + do { + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(container)) + if (CD->IsClassExtension()) { + Visit(CD->getClassInterface()); + break; + } + Visit(cast<Decl>(D->getDeclContext())); + } + while (false); + // 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(). @@ -267,7 +329,15 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { IgnoreResults = true; return; } - GenObjCCategory(ID->getName(), CD->getName()); + // Specially handle class extensions, which are anonymous categories. + // We want to mangle in the location to uniquely distinguish them. + if (CD->IsClassExtension()) { + Out << "objc(ext)" << ID->getName() << '@'; + GenLoc(CD); + } + else + GenObjCCategory(ID->getName(), CD->getName()); + break; } case Decl::ObjCCategoryImpl: { @@ -313,13 +383,41 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { D = D->getCanonicalDecl(); VisitDeclContext(D->getDeclContext()); - 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; + bool AlreadyStarted = false; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Struct: Out << "@ST"; break; + case TTK_Class: Out << "@CT"; break; + case TTK_Union: Out << "@UT"; break; + case TTK_Enum: llvm_unreachable("enum template"); break; + } + VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); + } else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Struct: Out << "@SP"; break; + case TTK_Class: Out << "@CP"; break; + case TTK_Union: Out << "@UP"; break; + case TTK_Enum: llvm_unreachable("enum partial specialization"); break; + } + VisitTemplateParameterList(PartialSpec->getTemplateParameters()); + } } - + + if (!AlreadyStarted) { + 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; + } + } + Out << '@'; Out.flush(); assert(Buf.size() > 0); @@ -333,6 +431,17 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { else Buf[off] = 'a'; } + + // For a class template specialization, mangle the template arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); + Out << '>'; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(Args.get(I)); + } + } } void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { @@ -345,6 +454,11 @@ void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { Out << D->getName(); } +void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + GenLoc(D); + return; +} + bool USRGenerator::GenLoc(const Decl *D) { if (generatedLoc) return IgnoreResults; @@ -368,10 +482,10 @@ bool USRGenerator::GenLoc(const Decl *D) { IgnoreResults = true; return true; } - Out << '@' - << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':' - << SM.getColumnNumber(Decomposed.first, Decomposed.second); - + // Use the offest into the FileID to represent the location. Using + // a line/column can cause us to look back at the original source file, + // which is expensive. + Out << '@' << Decomposed.second; return IgnoreResults; } @@ -494,13 +608,100 @@ void USRGenerator::VisitType(QualType T) { VisitTagDecl(TT->getDecl()); return; } - + if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + if (const TemplateSpecializationType *Spec + = T->getAs<TemplateSpecializationType>()) { + Out << '>'; + VisitTemplateName(Spec->getTemplateName()); + Out << Spec->getNumArgs(); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + VisitTemplateArgument(Spec->getArg(I)); + return; + } + // Unhandled type. Out << ' '; break; } while (true); } +void USRGenerator::VisitTemplateParameterList( + const TemplateParameterList *Params) { + if (!Params) + return; + Out << '>' << Params->size(); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Out << '#'; + if (isa<TemplateTypeParmDecl>(*P)) { + Out << 'T'; + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + Out << 'N'; + VisitType(NTTP->getType()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + Out << 't'; + VisitTemplateParameterList(TTP->getTemplateParameters()); + } +} + +void USRGenerator::VisitTemplateName(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + + Visit(Template); + return; + } + + // FIXME: Visit dependent template names. +} + +void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Declaration: + Visit(Arg.getAsDecl()); + break; + + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplate()); + break; + + case TemplateArgument::Expression: + // FIXME: Visit expressions. + break; + + case TemplateArgument::Pack: + // FIXME: Variadic templates + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Integral: + Out << 'V'; + VisitType(Arg.getIntegralType()); + Out << *Arg.getAsIntegral(); + break; + } +} + //===----------------------------------------------------------------------===// // General purpose USR generation methods. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index ab4acca..29ef574 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -5,10 +5,11 @@ set(LLVM_NO_RTTI 1) set(LLVM_USED_LIBS clangFrontend clangDriver + clangSerialization + clangParse clangSema clangAnalysis clangAST - clangParse clangLex clangBasic) @@ -20,28 +21,34 @@ set( LLVM_LINK_COMPONENTS add_clang_library(libclang CIndex.cpp + CIndexCXX.cpp CIndexCodeCompletion.cpp CIndexDiagnostic.cpp CIndexInclusionStack.cpp CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp - CXTypes.cpp + CXType.cpp ../../include/clang-c/Index.h ) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - # FIXME: Deal with LLVM_SUBMIT_VERSION? + # dylib versioning information + # FIXME: Is there a more CMake-ish way to handle this? + set(LIBCLANG_VERSION 1 + CACHE STRING "Version number of the libclang library") + set(LIBCLANG_SUBVERSION 0 + CACHE STRING "Minor version number of the libclang library") + set(LIBCLANG_LINK_FLAGS + "-Wl,-current_version -Wl,${LIBCLANG_VERSION}.${LIBCLANG_SUBVERSION} -Wl,-compatibility_version -Wl,1") + + set(LIBCLANG_LINK_FLAGS + "${LIBCLANG_LINK_FLAGS} -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000") - # FIXME: This uses a special darwin-specific exports file in order to - # get underscore-prefixed names. It would be better to have build rules - # which know how to produce a darwin-suitable exports file from the - # regular exports file. set_target_properties(libclang PROPERTIES - LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/libclang.darwin.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000" - INSTALL_NAME_DIR "@executable_path/../lib" - ) + LINK_FLAGS "${LIBCLANG_LINK_FLAGS}" + INSTALL_NAME_DIR "@executable_path/../lib") endif() if(MSVC) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index be3623f..a8fd049 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -16,6 +16,7 @@ #include "CXCursor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "llvm/Support/ErrorHandling.h" @@ -28,52 +29,6 @@ CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) { return C; } -static CXCursorKind GetCursorKind(Decl *D) { - assert(D && "Invalid arguments!"); - switch (D->getKind()) { - case Decl::Enum: return CXCursor_EnumDecl; - case Decl::EnumConstant: return CXCursor_EnumConstantDecl; - case Decl::Field: return CXCursor_FieldDecl; - case Decl::Function: - return CXCursor_FunctionDecl; - case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; - case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; - case Decl::ObjCClass: - // FIXME - return CXCursor_UnexposedDecl; - case Decl::ObjCForwardProtocol: - // FIXME - return CXCursor_UnexposedDecl; - case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; - case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; - case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; - case Decl::ObjCMethod: - return cast<ObjCMethodDecl>(D)->isInstanceMethod() - ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; - case Decl::CXXMethod: return CXCursor_CXXMethod; - case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl; - case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; - case Decl::ParmVar: return CXCursor_ParmDecl; - case Decl::Typedef: return CXCursor_TypedefDecl; - case Decl::Var: return CXCursor_VarDecl; - case Decl::Namespace: return CXCursor_Namespace; - default: - if (TagDecl *TD = dyn_cast<TagDecl>(D)) { - switch (TD->getTagKind()) { - case TTK_Struct: return CXCursor_StructDecl; - case TTK_Class: return CXCursor_ClassDecl; - case TTK_Union: return CXCursor_UnionDecl; - case TTK_Enum: return CXCursor_EnumDecl; - } - } - - return CXCursor_UnexposedDecl; - } - - llvm_unreachable("Invalid Decl"); - return CXCursor_NotImplemented; -} - static CXCursorKind GetCursorKind(const Attr *A) { assert(A && "Invalid arguments!"); switch (A->getKind()) { @@ -94,7 +49,7 @@ CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent, ASTUnit *TU) { CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) { assert(D && TU && "Invalid arguments!"); - CXCursor C = { GetCursorKind(D), { D, 0, TU } }; + CXCursor C = { getCursorKindForDecl(D), { D, 0, TU } }; return C; } @@ -182,7 +137,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) { case Stmt::UnaryTypeTraitExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::CXXBindTemporaryExprClass: - case Stmt::CXXBindReferenceExprClass: case Stmt::CXXExprWithTemporariesClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::CXXDependentScopeMemberExprClass: @@ -302,6 +256,50 @@ cxcursor::getCursorTypeRef(CXCursor C) { reinterpret_cast<uintptr_t>(C.data[1]))); } +CXCursor cxcursor::MakeCursorTemplateRef(TemplateDecl *Template, + SourceLocation Loc, ASTUnit *TU) { + assert(Template && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_TemplateRef, { Template, RawLoc, TU } }; + return C; +} + +std::pair<TemplateDecl *, SourceLocation> +cxcursor::getCursorTemplateRef(CXCursor C) { + assert(C.kind == CXCursor_TemplateRef); + return std::make_pair(static_cast<TemplateDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc, + ASTUnit *TU) { + + assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU && + "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_NamespaceRef, { NS, RawLoc, TU } }; + return C; +} + +std::pair<NamedDecl *, SourceLocation> +cxcursor::getCursorNamespaceRef(CXCursor C) { + assert(C.kind == CXCursor_NamespaceRef); + return std::make_pair(static_cast<NamedDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU){ + CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } }; + return C; +} + +CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) { + assert(C.kind == CXCursor_CXXBaseSpecifier); + return static_cast<CXXBaseSpecifier*>(C.data[0]); +} + CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU) { CXCursor C = { CXCursor_PreprocessingDirective, @@ -358,6 +356,10 @@ Stmt *cxcursor::getCursorStmt(CXCursor Cursor) { return (Stmt *)Cursor.data[1]; } +Attr *cxcursor::getCursorAttr(CXCursor Cursor) { + return (Attr *)Cursor.data[1]; +} + ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { return getCursorASTUnit(Cursor)->getASTContext(); } diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h index 1664f5a..a5f111e 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -23,6 +23,7 @@ namespace clang { class ASTContext; class ASTUnit; class Attr; +class CXXBaseSpecifier; class Decl; class Expr; class MacroDefinition; @@ -31,6 +32,7 @@ class NamedDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; class Stmt; +class TemplateDecl; class TypeDecl; namespace cxcursor { @@ -70,11 +72,33 @@ std::pair<ObjCInterfaceDecl *, SourceLocation> /// \brief Create a type reference at the given location. CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU); - + /// \brief Unpack a TypeRef cursor into the class it references /// and optionally the location where the reference occurred. std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); +/// \brief Create a reference to a template at the given location. +CXCursor MakeCursorTemplateRef(TemplateDecl *Template, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack a TemplateRef cursor into the template it references and +/// the location where the reference occurred. +std::pair<TemplateDecl *, SourceLocation> getCursorTemplateRef(CXCursor C); + +/// \brief Create a reference to a namespace or namespace alias at the given +/// location. +CXCursor MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc, ASTUnit *TU); + +/// \brief Unpack a NamespaceRef cursor into the namespace or namespace alias +/// it references and the location where the reference occurred. +std::pair<NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C); + +/// \brief Create a CXX base specifier cursor. +CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU); + +/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier. +CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C); + /// \brief Create a preprocessing directive cursor. CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU); @@ -98,6 +122,8 @@ MacroInstantiation *getCursorMacroInstantiation(CXCursor C); Decl *getCursorDecl(CXCursor Cursor); Expr *getCursorExpr(CXCursor Cursor); Stmt *getCursorStmt(CXCursor Cursor); +Attr *getCursorAttr(CXCursor Cursor); + ASTContext &getCursorContext(CXCursor Cursor); ASTUnit *getCursorASTUnit(CXCursor Cursor); diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXType.cpp index d5c9f45..aa173ca 100644 --- a/tools/libclang/CXTypes.cpp +++ b/tools/libclang/CXType.cpp @@ -13,6 +13,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "CXType.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/AST/Decl.h" @@ -85,12 +86,15 @@ static CXTypeKind GetTypeKind(QualType T) { #undef TKCASE } -static CXType MakeCXType(QualType T, ASTUnit *TU) { + +CXType cxtype::MakeCXType(QualType T, ASTUnit *TU) { CXTypeKind TK = GetTypeKind(T); CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; return CT; } +using cxtype::MakeCXType; + static inline QualType GetQualType(CXType CT) { return QualType::getFromOpaquePtr(CT.data[0]); } @@ -283,4 +287,11 @@ CXType clang_getCursorResultType(CXCursor C) { return MakeCXType(QualType(), cxcursor::getCursorASTUnit(C)); } +unsigned clang_isPODType(CXType X) { + QualType T = GetQualType(X); + if (!T.getTypePtr()) + return 0; + return T->isPODType() ? 1 : 0; +} + } // end: extern "C" diff --git a/tools/libclang/CXType.h b/tools/libclang/CXType.h new file mode 100644 index 0000000..94151ed --- /dev/null +++ b/tools/libclang/CXType.h @@ -0,0 +1,29 @@ +//===- CXTypes.h - Routines for manipulating CXTypes ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXTYPES_H +#define LLVM_CLANG_CXTYPES_H + +#include "clang-c/Index.h" +#include "clang/AST/Type.h" + +namespace clang { + +class ASTUnit; + +namespace cxtype { + +CXType MakeCXType(QualType T, ASTUnit *TU); + +}} // end namespace clang::cxtype +#endif diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index 253ea38..6d2a13c 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -16,8 +16,8 @@ LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 LINK_COMPONENTS := bitreader mc core -USEDLIBS = clangFrontend.a clangDriver.a clangSema.a \ - clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a +USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ + clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile @@ -26,23 +26,21 @@ include $(CLANG_LEVEL)/Makefile ##===----------------------------------------------------------------------===## ifeq ($(HOST_OS),Darwin) - # set dylib internal version number to llvmCore submission number + LLVMLibsOptions += -Wl,-compatibility_version,1 + + # Set dylib internal version number to submission number. ifdef LLVM_SUBMIT_VERSION - LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \ - -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ - -Wl,-compatibility_version -Wl,1 + LLVMLibsOptions += -Wl,-current_version \ + -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) endif - # extra options to override libtool defaults - LLVMLibsOptions := $(LLVMLibsOptions) \ - -avoid-version \ - -Wl,-dead_strip \ - -Wl,-seg1addr -Wl,0xE0000000 + + # Extra options to override libtool defaults. + LLVMLibsOptions += -Wl,-dead_strip -Wl,-seg1addr,0xE0000000 # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') ifneq ($(DARWIN_VERS),8) - LLVMLibsOptions := $(LLVMLibsOptions) \ - -no-undefined -Wl,-install_name \ - -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" + LLVMLibsOptions += -Wl,-install_name \ + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index f21fec6..d1b45a2 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -1,6 +1,7 @@ _clang_CXXMethod_isStatic _clang_annotateTokens _clang_codeComplete +_clang_codeCompleteAt _clang_codeCompleteGetDiagnostic _clang_codeCompleteGetNumDiagnostics _clang_constructUSR_ObjCCategory @@ -12,7 +13,11 @@ _clang_constructUSR_ObjCProtocol _clang_createIndex _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile +_clang_defaultCodeCompleteOptions _clang_defaultDiagnosticDisplayOptions +_clang_defaultEditingTranslationUnitOptions +_clang_defaultReparseOptions +_clang_defaultSaveOptions _clang_disposeCodeCompleteResults _clang_disposeDiagnostic _clang_disposeIndex @@ -25,13 +30,16 @@ _clang_equalLocations _clang_equalTypes _clang_formatDiagnostic _clang_getCString +_clang_getCXXAccessSpecifier _clang_getCanonicalType _clang_getClangVersion +_clang_getCompletionAvailability _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText _clang_getCompletionPriority _clang_getCursor +_clang_getCursorAvailability _clang_getCursorDefinition _clang_getCursorExtent _clang_getCursorKind @@ -40,8 +48,8 @@ _clang_getCursorLanguage _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced -_clang_getCursorSpelling _clang_getCursorResultType +_clang_getCursorSpelling _clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent @@ -56,6 +64,7 @@ _clang_getDiagnosticSpelling _clang_getFile _clang_getFileName _clang_getFileTime +_clang_getIBOutletCollectionType _clang_getInclusions _clang_getInstantiationLocation _clang_getLocation @@ -69,6 +78,8 @@ _clang_getRange _clang_getRangeEnd _clang_getRangeStart _clang_getResultType +_clang_getSpecializedCursorTemplate +_clang_getTemplateCursorKind _clang_getTokenExtent _clang_getTokenKind _clang_getTokenLocation @@ -81,11 +92,17 @@ _clang_isCursorDefinition _clang_isDeclaration _clang_isExpression _clang_isInvalid +_clang_isPODType _clang_isPreprocessing _clang_isReference _clang_isStatement _clang_isTranslationUnit _clang_isUnexposed +_clang_isVirtualBase +_clang_parseTranslationUnit +_clang_reparseTranslationUnit +_clang_saveTranslationUnit _clang_setUseExternalASTGeneration +_clang_sortCodeCompletionResults _clang_tokenize _clang_visitChildren diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index dcb40d4..0ea6993 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -1,6 +1,7 @@ clang_CXXMethod_isStatic clang_annotateTokens clang_codeComplete +clang_codeCompleteAt clang_codeCompleteGetDiagnostic clang_codeCompleteGetNumDiagnostics clang_constructUSR_ObjCCategory @@ -12,7 +13,11 @@ clang_constructUSR_ObjCProtocol clang_createIndex clang_createTranslationUnit clang_createTranslationUnitFromSourceFile +clang_defaultCodeCompleteOptions clang_defaultDiagnosticDisplayOptions +clang_defaultEditingTranslationUnitOptions +clang_defaultReparseOptions +clang_defaultSaveOptions clang_disposeCodeCompleteResults clang_disposeDiagnostic clang_disposeIndex @@ -25,13 +30,16 @@ clang_equalLocations clang_equalTypes clang_formatDiagnostic clang_getCString +clang_getCXXAccessSpecifier clang_getCanonicalType clang_getClangVersion +clang_getCompletionAvailability clang_getCompletionChunkCompletionString clang_getCompletionChunkKind clang_getCompletionChunkText clang_getCompletionPriority clang_getCursor +clang_getCursorAvailability clang_getCursorDefinition clang_getCursorExtent clang_getCursorKind @@ -40,8 +48,8 @@ clang_getCursorLanguage clang_getCursorLinkage clang_getCursorLocation clang_getCursorReferenced -clang_getCursorSpelling clang_getCursorResultType +clang_getCursorSpelling clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent @@ -56,6 +64,7 @@ clang_getDiagnosticSpelling clang_getFile clang_getFileName clang_getFileTime +clang_getIBOutletCollectionType clang_getInclusions clang_getInstantiationLocation clang_getLocation @@ -69,6 +78,8 @@ clang_getRange clang_getRangeEnd clang_getRangeStart clang_getResultType +clang_getSpecializedCursorTemplate +clang_getTemplateCursorKind clang_getTokenExtent clang_getTokenKind clang_getTokenLocation @@ -81,11 +92,17 @@ clang_isCursorDefinition clang_isDeclaration clang_isExpression clang_isInvalid +clang_isPODType clang_isPreprocessing clang_isReference clang_isStatement clang_isTranslationUnit clang_isUnexposed +clang_isVirtualBase +clang_parseTranslationUnit +clang_reparseTranslationUnit +clang_saveTranslationUnit clang_setUseExternalASTGeneration +clang_sortCodeCompletionResults clang_tokenize clang_visitChildren |