1 //===- unittests/AST/AttrTests.cpp --- Attribute tests --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "clang/AST/Attr.h"
10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "clang/ASTMatchers/ASTMatchers.h"
12 #include "clang/Basic/AttrKinds.h"
13 #include "clang/Tooling/Tooling.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
17 using namespace clang
;
21 using clang::ast_matchers::constantExpr
;
22 using clang::ast_matchers::equals
;
23 using clang::ast_matchers::functionDecl
;
24 using clang::ast_matchers::has
;
25 using clang::ast_matchers::hasDescendant
;
26 using clang::ast_matchers::hasName
;
27 using clang::ast_matchers::integerLiteral
;
28 using clang::ast_matchers::match
;
29 using clang::ast_matchers::selectFirst
;
30 using clang::ast_matchers::stringLiteral
;
31 using clang::ast_matchers::varDecl
;
32 using clang::tooling::buildASTFromCode
;
33 using clang::tooling::buildASTFromCodeWithArgs
;
36 EXPECT_THAT(Attr::getDocumentation(attr::Used
).str(),
37 testing::HasSubstr("The compiler must emit the definition even "
38 "if it appears to be unused"));
41 const FunctionDecl
*getFunctionNode(ASTUnit
*AST
, const std::string
&Name
) {
43 match(functionDecl(hasName(Name
)).bind("fn"), AST
->getASTContext());
44 EXPECT_EQ(Result
.size(), 1u);
45 return Result
[0].getNodeAs
<FunctionDecl
>("fn");
48 const VarDecl
*getVariableNode(ASTUnit
*AST
, const std::string
&Name
) {
49 auto Result
= match(varDecl(hasName(Name
)).bind("var"), AST
->getASTContext());
50 EXPECT_EQ(Result
.size(), 1u);
51 return Result
[0].getNodeAs
<VarDecl
>("var");
54 template <class ModifiedTypeLoc
>
55 void AssertAnnotatedAs(TypeLoc TL
, llvm::StringRef annotation
,
56 ModifiedTypeLoc
&ModifiedTL
,
57 const AnnotateTypeAttr
**AnnotateOut
= nullptr) {
58 const auto AttributedTL
= TL
.getAs
<AttributedTypeLoc
>();
59 ASSERT_FALSE(AttributedTL
.isNull());
60 ModifiedTL
= AttributedTL
.getModifiedLoc().getAs
<ModifiedTypeLoc
>();
61 ASSERT_TRUE(ModifiedTL
);
63 ASSERT_NE(AttributedTL
.getAttr(), nullptr);
64 const auto *Annotate
= dyn_cast
<AnnotateTypeAttr
>(AttributedTL
.getAttr());
65 ASSERT_NE(Annotate
, nullptr);
66 EXPECT_EQ(Annotate
->getAnnotation(), annotation
);
68 *AnnotateOut
= Annotate
;
72 TEST(Attr
, AnnotateType
) {
74 // Test that the AnnotateType attribute shows up in the right places and that
75 // it stores its arguments correctly.
77 auto AST
= buildASTFromCode(R
"cpp(
78 void f(int* [[clang::annotate_type("foo
", "arg1
", 2)]] *,
79 int [[clang::annotate_type("bar
")]]);
81 int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr
")]]
82 array[10] [[clang::annotate_type("arr
")]];
84 void (* [[clang::annotate_type("funcptr
")]] fp)(void);
86 struct S { int mem; };
87 int [[clang::annotate_type("int")]]
88 S::* [[clang::annotate_type("ptr_to_mem
")]] ptr_to_member = &S::mem;
92 const FunctionDecl
*Func
= getFunctionNode(AST
.get(), "f");
95 const auto PointerTL
= Func
->getParamDecl(0)
98 .getAs
<PointerTypeLoc
>();
99 ASSERT_FALSE(PointerTL
.isNull());
100 PointerTypeLoc PointerPointerTL
;
101 const AnnotateTypeAttr
*Annotate
;
102 AssertAnnotatedAs(PointerTL
.getPointeeLoc(), "foo", PointerPointerTL
,
105 EXPECT_EQ(Annotate
->args_size(), 2u);
106 const auto *StringLit
= selectFirst
<StringLiteral
>(
107 "str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
108 *Annotate
->args_begin()[0], AST
->getASTContext()));
109 ASSERT_NE(StringLit
, nullptr);
110 EXPECT_EQ(StringLit
->getString(), "arg1");
111 EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2u)).bind("int"))),
112 *Annotate
->args_begin()[1], AST
->getASTContext())
117 BuiltinTypeLoc IntTL
;
118 AssertAnnotatedAs(Func
->getParamDecl(1)->getTypeSourceInfo()->getTypeLoc(),
120 EXPECT_EQ(IntTL
.getType(), AST
->getASTContext().IntTy
);
124 const VarDecl
*Var
= getVariableNode(AST
.get(), "array");
126 ArrayTypeLoc ArrayTL
;
127 AssertAnnotatedAs(Var
->getTypeSourceInfo()->getTypeLoc(), "arr", ArrayTL
);
128 PointerTypeLoc PointerTL
;
129 AssertAnnotatedAs(ArrayTL
.getElementLoc(), "ptr", PointerTL
);
130 BuiltinTypeLoc IntTL
;
131 AssertAnnotatedAs(PointerTL
.getPointeeLoc(), "int", IntTL
);
132 EXPECT_EQ(IntTL
.getType(), AST
->getASTContext().IntTy
);
136 const VarDecl
*Var
= getVariableNode(AST
.get(), "fp");
138 PointerTypeLoc PointerTL
;
139 AssertAnnotatedAs(Var
->getTypeSourceInfo()->getTypeLoc(), "funcptr",
142 PointerTL
.getPointeeLoc().IgnoreParens().getAs
<FunctionTypeLoc
>());
146 const VarDecl
*Var
= getVariableNode(AST
.get(), "ptr_to_member");
148 MemberPointerTypeLoc MemberPointerTL
;
149 AssertAnnotatedAs(Var
->getTypeSourceInfo()->getTypeLoc(), "ptr_to_mem",
151 BuiltinTypeLoc IntTL
;
152 AssertAnnotatedAs(MemberPointerTL
.getPointeeLoc(), "int", IntTL
);
153 EXPECT_EQ(IntTL
.getType(), AST
->getASTContext().IntTy
);
156 // Test type annotation on an `__auto_type` type in C mode.
157 AST
= buildASTFromCodeWithArgs(R
"c(
158 __auto_type [[clang::annotate_type("auto")]] auto_var = 1;
164 const VarDecl
*Var
= getVariableNode(AST
.get(), "auto_var");
167 AssertAnnotatedAs(Var
->getTypeSourceInfo()->getTypeLoc(), "auto", AutoTL
);
171 TEST(Attr
, RegularKeywordAttribute
) {
172 auto AST
= clang::tooling::buildASTFromCode("");
173 auto &Ctx
= AST
->getASTContext();
174 auto Funcref
= clang::WebAssemblyFuncrefAttr::CreateImplicit(Ctx
);
175 EXPECT_EQ(Funcref
->getSyntax(), clang::AttributeCommonInfo::AS_Keyword
);
176 ASSERT_FALSE(Funcref
->isRegularKeywordAttribute());
178 auto Streaming
= clang::ArmStreamingAttr::CreateImplicit(Ctx
);
179 EXPECT_EQ(Streaming
->getSyntax(), clang::AttributeCommonInfo::AS_Keyword
);
180 ASSERT_TRUE(Streaming
->isRegularKeywordAttribute());