xref: /llvm-project/clang/unittests/AST/AttrTest.cpp (revision 874217f99b99ab3c9026dc3b7bd84cd2beebde6e)
118f9e25cSSam McCall //===- unittests/AST/AttrTests.cpp --- Attribute tests --------------------===//
218f9e25cSSam McCall //
318f9e25cSSam McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
418f9e25cSSam McCall // See https://llvm.org/LICENSE.txt for license information.
518f9e25cSSam McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618f9e25cSSam McCall //
718f9e25cSSam McCall //===----------------------------------------------------------------------===//
818f9e25cSSam McCall 
918f9e25cSSam McCall #include "clang/AST/Attr.h"
10665da187SMartin Boehme #include "clang/ASTMatchers/ASTMatchFinder.h"
11665da187SMartin Boehme #include "clang/ASTMatchers/ASTMatchers.h"
1218f9e25cSSam McCall #include "clang/Basic/AttrKinds.h"
13665da187SMartin Boehme #include "clang/Tooling/Tooling.h"
1418f9e25cSSam McCall #include "gmock/gmock.h"
1518f9e25cSSam McCall #include "gtest/gtest.h"
1618f9e25cSSam McCall 
1718f9e25cSSam McCall using namespace clang;
1818f9e25cSSam McCall 
1918f9e25cSSam McCall namespace {
2018f9e25cSSam McCall 
21665da187SMartin Boehme using clang::ast_matchers::constantExpr;
22665da187SMartin Boehme using clang::ast_matchers::equals;
23665da187SMartin Boehme using clang::ast_matchers::functionDecl;
24665da187SMartin Boehme using clang::ast_matchers::has;
25665da187SMartin Boehme using clang::ast_matchers::hasDescendant;
26665da187SMartin Boehme using clang::ast_matchers::hasName;
27665da187SMartin Boehme using clang::ast_matchers::integerLiteral;
28665da187SMartin Boehme using clang::ast_matchers::match;
29665da187SMartin Boehme using clang::ast_matchers::selectFirst;
30665da187SMartin Boehme using clang::ast_matchers::stringLiteral;
31665da187SMartin Boehme using clang::ast_matchers::varDecl;
32665da187SMartin Boehme using clang::tooling::buildASTFromCode;
33665da187SMartin Boehme using clang::tooling::buildASTFromCodeWithArgs;
34665da187SMartin Boehme 
TEST(Attr,Doc)3518f9e25cSSam McCall TEST(Attr, Doc) {
3618f9e25cSSam McCall   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
3718f9e25cSSam McCall               testing::HasSubstr("The compiler must emit the definition even "
3818f9e25cSSam McCall                                  "if it appears to be unused"));
3918f9e25cSSam McCall }
4018f9e25cSSam McCall 
getFunctionNode(ASTUnit * AST,const std::string & Name)41665da187SMartin Boehme const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
42665da187SMartin Boehme   auto Result =
43665da187SMartin Boehme       match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
44665da187SMartin Boehme   EXPECT_EQ(Result.size(), 1u);
45665da187SMartin Boehme   return Result[0].getNodeAs<FunctionDecl>("fn");
46665da187SMartin Boehme }
47665da187SMartin Boehme 
getVariableNode(ASTUnit * AST,const std::string & Name)48665da187SMartin Boehme const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
49665da187SMartin Boehme   auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
50665da187SMartin Boehme   EXPECT_EQ(Result.size(), 1u);
51665da187SMartin Boehme   return Result[0].getNodeAs<VarDecl>("var");
52665da187SMartin Boehme }
53665da187SMartin Boehme 
54665da187SMartin Boehme template <class ModifiedTypeLoc>
AssertAnnotatedAs(TypeLoc TL,llvm::StringRef annotation,ModifiedTypeLoc & ModifiedTL,const AnnotateTypeAttr ** AnnotateOut=nullptr)55665da187SMartin Boehme void AssertAnnotatedAs(TypeLoc TL, llvm::StringRef annotation,
56665da187SMartin Boehme                        ModifiedTypeLoc &ModifiedTL,
57665da187SMartin Boehme                        const AnnotateTypeAttr **AnnotateOut = nullptr) {
58665da187SMartin Boehme   const auto AttributedTL = TL.getAs<AttributedTypeLoc>();
59665da187SMartin Boehme   ASSERT_FALSE(AttributedTL.isNull());
60665da187SMartin Boehme   ModifiedTL = AttributedTL.getModifiedLoc().getAs<ModifiedTypeLoc>();
61665da187SMartin Boehme   ASSERT_TRUE(ModifiedTL);
62665da187SMartin Boehme 
63665da187SMartin Boehme   ASSERT_NE(AttributedTL.getAttr(), nullptr);
64665da187SMartin Boehme   const auto *Annotate = dyn_cast<AnnotateTypeAttr>(AttributedTL.getAttr());
65665da187SMartin Boehme   ASSERT_NE(Annotate, nullptr);
66665da187SMartin Boehme   EXPECT_EQ(Annotate->getAnnotation(), annotation);
67665da187SMartin Boehme   if (AnnotateOut) {
68665da187SMartin Boehme     *AnnotateOut = Annotate;
69665da187SMartin Boehme   }
70665da187SMartin Boehme }
71665da187SMartin Boehme 
TEST(Attr,AnnotateType)72665da187SMartin Boehme TEST(Attr, AnnotateType) {
73665da187SMartin Boehme 
74665da187SMartin Boehme   // Test that the AnnotateType attribute shows up in the right places and that
75665da187SMartin Boehme   // it stores its arguments correctly.
76665da187SMartin Boehme 
77665da187SMartin Boehme   auto AST = buildASTFromCode(R"cpp(
78665da187SMartin Boehme     void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
79665da187SMartin Boehme            int [[clang::annotate_type("bar")]]);
80665da187SMartin Boehme 
81665da187SMartin Boehme     int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
82665da187SMartin Boehme       array[10] [[clang::annotate_type("arr")]];
83665da187SMartin Boehme 
84665da187SMartin Boehme     void (* [[clang::annotate_type("funcptr")]] fp)(void);
85665da187SMartin Boehme 
86665da187SMartin Boehme     struct S { int mem; };
87665da187SMartin Boehme     int [[clang::annotate_type("int")]]
88665da187SMartin Boehme     S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
89665da187SMartin Boehme   )cpp");
90665da187SMartin Boehme 
91665da187SMartin Boehme   {
92665da187SMartin Boehme     const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
93665da187SMartin Boehme 
94665da187SMartin Boehme     // First parameter.
95665da187SMartin Boehme     const auto PointerTL = Func->getParamDecl(0)
96665da187SMartin Boehme                                ->getTypeSourceInfo()
97665da187SMartin Boehme                                ->getTypeLoc()
98665da187SMartin Boehme                                .getAs<PointerTypeLoc>();
99665da187SMartin Boehme     ASSERT_FALSE(PointerTL.isNull());
100665da187SMartin Boehme     PointerTypeLoc PointerPointerTL;
101665da187SMartin Boehme     const AnnotateTypeAttr *Annotate;
102665da187SMartin Boehme     AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
103665da187SMartin Boehme                       &Annotate);
104665da187SMartin Boehme 
1051784fe7bSMartin Boehme     EXPECT_EQ(Annotate->args_size(), 2u);
106665da187SMartin Boehme     const auto *StringLit = selectFirst<StringLiteral>(
107665da187SMartin Boehme         "str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
108665da187SMartin Boehme                      *Annotate->args_begin()[0], AST->getASTContext()));
109665da187SMartin Boehme     ASSERT_NE(StringLit, nullptr);
110665da187SMartin Boehme     EXPECT_EQ(StringLit->getString(), "arg1");
1111784fe7bSMartin Boehme     EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2u)).bind("int"))),
112665da187SMartin Boehme                     *Annotate->args_begin()[1], AST->getASTContext())
113665da187SMartin Boehme                   .size(),
11443e7ba64SSimon Pilgrim               1u);
115665da187SMartin Boehme 
116665da187SMartin Boehme     // Second parameter.
117665da187SMartin Boehme     BuiltinTypeLoc IntTL;
118665da187SMartin Boehme     AssertAnnotatedAs(Func->getParamDecl(1)->getTypeSourceInfo()->getTypeLoc(),
119665da187SMartin Boehme                       "bar", IntTL);
120665da187SMartin Boehme     EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
121665da187SMartin Boehme   }
122665da187SMartin Boehme 
123665da187SMartin Boehme   {
124665da187SMartin Boehme     const VarDecl *Var = getVariableNode(AST.get(), "array");
125665da187SMartin Boehme 
126665da187SMartin Boehme     ArrayTypeLoc ArrayTL;
127665da187SMartin Boehme     AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "arr", ArrayTL);
128665da187SMartin Boehme     PointerTypeLoc PointerTL;
129665da187SMartin Boehme     AssertAnnotatedAs(ArrayTL.getElementLoc(), "ptr", PointerTL);
130665da187SMartin Boehme     BuiltinTypeLoc IntTL;
131665da187SMartin Boehme     AssertAnnotatedAs(PointerTL.getPointeeLoc(), "int", IntTL);
132665da187SMartin Boehme     EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
133665da187SMartin Boehme   }
134665da187SMartin Boehme 
135665da187SMartin Boehme   {
136665da187SMartin Boehme     const VarDecl *Var = getVariableNode(AST.get(), "fp");
137665da187SMartin Boehme 
138665da187SMartin Boehme     PointerTypeLoc PointerTL;
139665da187SMartin Boehme     AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "funcptr",
140665da187SMartin Boehme                       PointerTL);
141665da187SMartin Boehme     ASSERT_TRUE(
142665da187SMartin Boehme         PointerTL.getPointeeLoc().IgnoreParens().getAs<FunctionTypeLoc>());
143665da187SMartin Boehme   }
144665da187SMartin Boehme 
145665da187SMartin Boehme   {
146665da187SMartin Boehme     const VarDecl *Var = getVariableNode(AST.get(), "ptr_to_member");
147665da187SMartin Boehme 
148665da187SMartin Boehme     MemberPointerTypeLoc MemberPointerTL;
149665da187SMartin Boehme     AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "ptr_to_mem",
150665da187SMartin Boehme                       MemberPointerTL);
151665da187SMartin Boehme     BuiltinTypeLoc IntTL;
152665da187SMartin Boehme     AssertAnnotatedAs(MemberPointerTL.getPointeeLoc(), "int", IntTL);
153665da187SMartin Boehme     EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
154665da187SMartin Boehme   }
155665da187SMartin Boehme 
156665da187SMartin Boehme   // Test type annotation on an `__auto_type` type in C mode.
157665da187SMartin Boehme   AST = buildASTFromCodeWithArgs(R"c(
158665da187SMartin Boehme     __auto_type [[clang::annotate_type("auto")]] auto_var = 1;
159665da187SMartin Boehme   )c",
160*874217f9SNikolas Klauser                                  {},
161665da187SMartin Boehme                                  "input.c");
162665da187SMartin Boehme 
163665da187SMartin Boehme   {
164665da187SMartin Boehme     const VarDecl *Var = getVariableNode(AST.get(), "auto_var");
165665da187SMartin Boehme 
166665da187SMartin Boehme     AutoTypeLoc AutoTL;
167665da187SMartin Boehme     AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "auto", AutoTL);
168665da187SMartin Boehme   }
169665da187SMartin Boehme }
170665da187SMartin Boehme 
TEST(Attr,RegularKeywordAttribute)171301eb6b6SRichard Sandiford TEST(Attr, RegularKeywordAttribute) {
172301eb6b6SRichard Sandiford   auto AST = clang::tooling::buildASTFromCode("");
173301eb6b6SRichard Sandiford   auto &Ctx = AST->getASTContext();
174301eb6b6SRichard Sandiford   auto Funcref = clang::WebAssemblyFuncrefAttr::CreateImplicit(Ctx);
175301eb6b6SRichard Sandiford   EXPECT_EQ(Funcref->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
176301eb6b6SRichard Sandiford   ASSERT_FALSE(Funcref->isRegularKeywordAttribute());
177301eb6b6SRichard Sandiford 
178301eb6b6SRichard Sandiford   auto Streaming = clang::ArmStreamingAttr::CreateImplicit(Ctx);
179301eb6b6SRichard Sandiford   EXPECT_EQ(Streaming->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
180301eb6b6SRichard Sandiford   ASSERT_TRUE(Streaming->isRegularKeywordAttribute());
181301eb6b6SRichard Sandiford }
182301eb6b6SRichard Sandiford 
18318f9e25cSSam McCall } // namespace
184