Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -22,6 +22,7 @@ #include "CursorVisitor.h" #include "clang-c/FatalErrorHandler.h" #include "clang/AST/Attr.h" +#include "clang/AST/AttrVisitor.h" #include "clang/AST/DeclObjCCommon.h" #include "clang/AST/Mangle.h" #include "clang/AST/OpenMPClause.h" @@ -523,6 +524,13 @@ return false; } + if (clang_isAttribute(Cursor.kind)) { + if (const Attr *A = getCursorAttr(Cursor)) + return Visit(A); + + return false; + } + if (clang_isTranslationUnit(Cursor.kind)) { CXTranslationUnit TU = getCursorTU(Cursor); ASTUnit *CXXUnit = cxtu::getASTUnit(TU); @@ -2085,7 +2093,8 @@ (SourceLocation::UIntTy)(uintptr_t)data[1]); } }; -class EnqueueVisitor : public ConstStmtVisitor { +class EnqueueVisitor : public ConstStmtVisitor, + public ConstAttrVisitor { friend class OMPClauseEnqueue; VisitorWorkList &WL; CXCursor Parent; @@ -2227,6 +2236,10 @@ void VisitOMPTargetTeamsDistributeSimdDirective( const OMPTargetTeamsDistributeSimdDirective *D); + // Attributes + void VisitAnnotateAttr(const AnnotateAttr *A); + void VisitAnnotateTypeAttr(const AnnotateTypeAttr *A); + private: void AddDeclarationNameInfo(const Stmt *S); void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier); @@ -2238,6 +2251,8 @@ void AddTypeLoc(TypeSourceInfo *TI); void EnqueueChildren(const Stmt *S); void EnqueueChildren(const OMPClause *S); + void EnqueueChildren(const AnnotateAttr *A); + void EnqueueChildren(const AnnotateTypeAttr *A); }; } // namespace @@ -2727,6 +2742,31 @@ VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); std::reverse(I, E); } +// TODO these two methods are exactly the same. Can this be expressed better? +void EnqueueVisitor::EnqueueChildren(const AnnotateAttr *A) { + unsigned size = WL.size(); + for (const Expr *Arg : A->args()) { + VisitStmt(Arg); + } + if (size == WL.size()) + return; + // Now reverse the entries we just added. This will match the DFS + // ordering performed by the worklist. + VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); + std::reverse(I, E); +} +void EnqueueVisitor::EnqueueChildren(const AnnotateTypeAttr *A) { + unsigned size = WL.size(); + for (const Expr *Arg : A->args()) { + AddStmt(Arg); + } + if (size == WL.size()) + return; + // Now reverse the entries we just added. This will match the DFS + // ordering performed by the worklist. + VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); + std::reverse(I, E); +} void EnqueueVisitor::VisitAddrLabelExpr(const AddrLabelExpr *E) { WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent)); } @@ -2999,7 +3039,7 @@ // If the opaque value has a source expression, just transparently // visit that. This is useful for (e.g.) pseudo-object expressions. if (Expr *SourceExpr = E->getSourceExpr()) - return Visit(SourceExpr); + return ConstStmtVisitor::Visit(SourceExpr); } void EnqueueVisitor::VisitLambdaExpr(const LambdaExpr *E) { AddStmt(E->getBody()); @@ -3019,7 +3059,7 @@ } void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) { // Treat the expression like its syntactic form. - Visit(E->getSyntacticForm()); + ConstStmtVisitor::Visit(E->getSyntacticForm()); } void EnqueueVisitor::VisitOMPExecutableDirective( @@ -3329,9 +3369,32 @@ VisitOMPLoopDirective(D); } +void EnqueueVisitor::VisitAnnotateAttr(const AnnotateAttr *A) { + EnqueueChildren(A); +} + +void EnqueueVisitor::VisitAnnotateTypeAttr(const AnnotateTypeAttr *A) { + EnqueueChildren(A); +} + void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU, RegionOfInterest)) - .Visit(S); + .ConstStmtVisitor::Visit(S); +} + +void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Attr *A) { + // Parent is the attribute itself when this is indirectly called from + // VisitChildren. Because we need to make a CXCursor for A, we need *its* + // parent. + auto AttrCursor = Parent; + + // Get the attribute's parent as stored in + // cxcursor::MakeCXCursor(const Attr *A, const Decl *Parent, CXTranslationUnit + // TU) + const Decl *AttrParent = static_cast(AttrCursor.data[1]); + + EnqueueVisitor(WL, MakeCXCursor(A, AttrParent, TU)) + .ConstAttrVisitor::Visit(A); } bool CursorVisitor::IsInRegionOfInterest(CXCursor C) { @@ -3596,6 +3659,22 @@ return result; } +bool CursorVisitor::Visit(const Attr *A) { + VisitorWorkList *WL = nullptr; + if (!WorkListFreeList.empty()) { + WL = WorkListFreeList.back(); + WL->clear(); + WorkListFreeList.pop_back(); + } else { + WL = new VisitorWorkList(); + WorkListCache.push_back(WL); + } + EnqueueWorkList(*WL, A); + bool result = RunVisitorWorkList(*WL); + WorkListFreeList.push_back(WL); + return result; +} + namespace { typedef SmallVector RefNamePieces; RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, Index: clang/tools/libclang/CursorVisitor.h =================================================================== --- clang/tools/libclang/CursorVisitor.h +++ clang/tools/libclang/CursorVisitor.h @@ -276,7 +276,9 @@ bool IsInRegionOfInterest(CXCursor C); bool RunVisitorWorkList(VisitorWorkList &WL); void EnqueueWorkList(VisitorWorkList &WL, const Stmt *S); + void EnqueueWorkList(VisitorWorkList &WL, const Attr *A); LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S); + LLVM_ATTRIBUTE_NOINLINE bool Visit(const Attr *A); private: std::optional handleDeclForVisitation(const Decl *D);