Skip to content

Commit 5aa06b1

Browse files
fridtjofAaronBallman
authored andcommitted
[libclang] Expose arguments of clang::annotate
This enables easy consumption of arbitrary data added to this annotation in addition to the annotation category, which was already exposed. Differential Revision: https://reviews.llvm.org/D151373
1 parent 2df9328 commit 5aa06b1

File tree

4 files changed

+114
-4
lines changed

4 files changed

+114
-4
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ clang-format
245245
libclang
246246
--------
247247

248+
- Exposed arguments of ``clang::annotate``.
249+
248250
Static Analyzer
249251
---------------
250252

clang/tools/libclang/CIndex.cpp

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "CursorVisitor.h"
2424
#include "clang-c/FatalErrorHandler.h"
2525
#include "clang/AST/Attr.h"
26+
#include "clang/AST/AttrVisitor.h"
2627
#include "clang/AST/DeclObjCCommon.h"
2728
#include "clang/AST/Expr.h"
2829
#include "clang/AST/ExprCXX.h"
@@ -575,6 +576,13 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
575576
A->getInterfaceLoc()->getTypeLoc().getBeginLoc(), TU));
576577
}
577578

579+
if (clang_isAttribute(Cursor.kind)) {
580+
if (const Attr *A = getCursorAttr(Cursor))
581+
return Visit(A);
582+
583+
return false;
584+
}
585+
578586
// If pointing inside a macro definition, check if the token is an identifier
579587
// that was ever defined as a macro. In such a case, create a "pseudo" macro
580588
// expansion cursor for that token.
@@ -2089,7 +2097,8 @@ class MemberRefVisit : public VisitorJob {
20892097
(SourceLocation::UIntTy)(uintptr_t)data[1]);
20902098
}
20912099
};
2092-
class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> {
2100+
class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
2101+
public ConstAttrVisitor<EnqueueVisitor, void> {
20932102
friend class OMPClauseEnqueue;
20942103
VisitorWorkList &WL;
20952104
CXCursor Parent;
@@ -2231,6 +2240,9 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> {
22312240
void VisitOMPTargetTeamsDistributeSimdDirective(
22322241
const OMPTargetTeamsDistributeSimdDirective *D);
22332242

2243+
// Attributes
2244+
void VisitAnnotateAttr(const AnnotateAttr *A);
2245+
22342246
private:
22352247
void AddDeclarationNameInfo(const Stmt *S);
22362248
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
@@ -2242,6 +2254,7 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> {
22422254
void AddTypeLoc(TypeSourceInfo *TI);
22432255
void EnqueueChildren(const Stmt *S);
22442256
void EnqueueChildren(const OMPClause *S);
2257+
void EnqueueChildren(const AnnotateAttr *A);
22452258
};
22462259
} // namespace
22472260

@@ -2736,6 +2749,20 @@ void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {
27362749
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
27372750
std::reverse(I, E);
27382751
}
2752+
2753+
void EnqueueVisitor::EnqueueChildren(const AnnotateAttr *A) {
2754+
unsigned size = WL.size();
2755+
for (const Expr *Arg : A->args()) {
2756+
VisitStmt(Arg);
2757+
}
2758+
if (size == WL.size())
2759+
return;
2760+
// Now reverse the entries we just added. This will match the DFS
2761+
// ordering performed by the worklist.
2762+
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
2763+
std::reverse(I, E);
2764+
}
2765+
27392766
void EnqueueVisitor::VisitAddrLabelExpr(const AddrLabelExpr *E) {
27402767
WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent));
27412768
}
@@ -3008,7 +3035,7 @@ void EnqueueVisitor::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
30083035
// If the opaque value has a source expression, just transparently
30093036
// visit that. This is useful for (e.g.) pseudo-object expressions.
30103037
if (Expr *SourceExpr = E->getSourceExpr())
3011-
return Visit(SourceExpr);
3038+
return ConstStmtVisitor::Visit(SourceExpr);
30123039
}
30133040
void EnqueueVisitor::VisitLambdaExpr(const LambdaExpr *E) {
30143041
AddStmt(E->getBody());
@@ -3028,7 +3055,7 @@ void EnqueueVisitor::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E) {
30283055
}
30293056
void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
30303057
// Treat the expression like its syntactic form.
3031-
Visit(E->getSyntacticForm());
3058+
ConstStmtVisitor::Visit(E->getSyntacticForm());
30323059
}
30333060

30343061
void EnqueueVisitor::VisitOMPExecutableDirective(
@@ -3338,9 +3365,28 @@ void EnqueueVisitor::VisitOMPTargetTeamsDistributeSimdDirective(
33383365
VisitOMPLoopDirective(D);
33393366
}
33403367

3368+
void EnqueueVisitor::VisitAnnotateAttr(const AnnotateAttr *A) {
3369+
EnqueueChildren(A);
3370+
}
3371+
33413372
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
33423373
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU, RegionOfInterest))
3343-
.Visit(S);
3374+
.ConstStmtVisitor::Visit(S);
3375+
}
3376+
3377+
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Attr *A) {
3378+
// Parent is the attribute itself when this is indirectly called from
3379+
// VisitChildren. Because we need to make a CXCursor for A, we need *its*
3380+
// parent.
3381+
auto AttrCursor = Parent;
3382+
3383+
// Get the attribute's parent as stored in
3384+
// cxcursor::MakeCXCursor(const Attr *A, const Decl *Parent, CXTranslationUnit
3385+
// TU)
3386+
const Decl *AttrParent = static_cast<const Decl *>(AttrCursor.data[1]);
3387+
3388+
EnqueueVisitor(WL, MakeCXCursor(A, AttrParent, TU))
3389+
.ConstAttrVisitor::Visit(A);
33443390
}
33453391

33463392
bool CursorVisitor::IsInRegionOfInterest(CXCursor C) {
@@ -3605,6 +3651,22 @@ bool CursorVisitor::Visit(const Stmt *S) {
36053651
return result;
36063652
}
36073653

3654+
bool CursorVisitor::Visit(const Attr *A) {
3655+
VisitorWorkList *WL = nullptr;
3656+
if (!WorkListFreeList.empty()) {
3657+
WL = WorkListFreeList.back();
3658+
WL->clear();
3659+
WorkListFreeList.pop_back();
3660+
} else {
3661+
WL = new VisitorWorkList();
3662+
WorkListCache.push_back(WL);
3663+
}
3664+
EnqueueWorkList(*WL, A);
3665+
bool result = RunVisitorWorkList(*WL);
3666+
WorkListFreeList.push_back(WL);
3667+
return result;
3668+
}
3669+
36083670
namespace {
36093671
typedef SmallVector<SourceRange, 4> RefNamePieces;
36103672
RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,

clang/tools/libclang/CursorVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,9 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
276276
bool IsInRegionOfInterest(CXCursor C);
277277
bool RunVisitorWorkList(VisitorWorkList &WL);
278278
void EnqueueWorkList(VisitorWorkList &WL, const Stmt *S);
279+
void EnqueueWorkList(VisitorWorkList &WL, const Attr *A);
279280
LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S);
281+
LLVM_ATTRIBUTE_NOINLINE bool Visit(const Attr *A);
280282

281283
private:
282284
std::optional<bool> handleDeclForVisitation(const Decl *D);

clang/unittests/libclang/LibclangTest.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,50 @@ static_assert(true, message);
12461246
EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");
12471247
}
12481248

1249+
TEST_F(LibclangParseTest, ExposesAnnotateArgs) {
1250+
const char testSource[] = R"cpp(
1251+
[[clang::annotate("category", 42)]]
1252+
void func() {}
1253+
)cpp";
1254+
std::string fileName = "main.cpp";
1255+
WriteFile(fileName, testSource);
1256+
1257+
const char *Args[] = {"-xc++"};
1258+
ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,
1259+
nullptr, 0, TUFlags);
1260+
1261+
int attrCount = 0;
1262+
1263+
Traverse(
1264+
[&attrCount](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
1265+
if (cursor.kind == CXCursor_AnnotateAttr) {
1266+
int childCount = 0;
1267+
clang_visitChildren(
1268+
cursor,
1269+
[](CXCursor child, CXCursor,
1270+
CXClientData data) -> CXChildVisitResult {
1271+
int *pcount = static_cast<int *>(data);
1272+
1273+
// we only expect one argument here, so bail otherwise
1274+
EXPECT_EQ(*pcount, 0);
1275+
1276+
auto *result = clang_Cursor_Evaluate(child);
1277+
EXPECT_NE(result, nullptr);
1278+
EXPECT_EQ(clang_EvalResult_getAsInt(result), 42);
1279+
++*pcount;
1280+
1281+
return CXChildVisit_Recurse;
1282+
},
1283+
&childCount);
1284+
attrCount++;
1285+
return CXChildVisit_Continue;
1286+
}
1287+
return CXChildVisit_Recurse;
1288+
});
1289+
1290+
EXPECT_EQ(attrCount, 1);
1291+
}
1292+
12491293
class LibclangRewriteTest : public LibclangParseTest {
12501294
public:
12511295
CXRewriter Rew = nullptr;

0 commit comments

Comments
 (0)