1//===- unittests/AST/AttrTests.cpp --- Attribute tests --------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
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"
16
17using namespace clang;
18
19namespace {
20
21using clang::ast_matchers::constantExpr;
22using clang::ast_matchers::equals;
23using clang::ast_matchers::functionDecl;
24using clang::ast_matchers::has;
25using clang::ast_matchers::hasDescendant;
26using clang::ast_matchers::hasName;
27using clang::ast_matchers::integerLiteral;
28using clang::ast_matchers::match;
29using clang::ast_matchers::selectFirst;
30using clang::ast_matchers::stringLiteral;
31using clang::ast_matchers::varDecl;
32using clang::tooling::buildASTFromCode;
33using clang::tooling::buildASTFromCodeWithArgs;
34
35TEST(Attr, Doc) {
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"));
39}
40
41const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
42 auto Result =
43 match(Matcher: functionDecl(hasName(Name)).bind(ID: "fn"), Context&: AST->getASTContext());
44 EXPECT_EQ(Result.size(), 1u);
45 return Result[0].getNodeAs<FunctionDecl>(ID: "fn");
46}
47
48const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
49 auto Result = match(Matcher: varDecl(hasName(Name)).bind(ID: "var"), Context&: AST->getASTContext());
50 EXPECT_EQ(Result.size(), 1u);
51 return Result[0].getNodeAs<VarDecl>(ID: "var");
52}
53
54template <class ModifiedTypeLoc>
55void 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);
62
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);
67 if (AnnotateOut) {
68 *AnnotateOut = Annotate;
69 }
70}
71
72TEST(Attr, AnnotateType) {
73
74 // Test that the AnnotateType attribute shows up in the right places and that
75 // it stores its arguments correctly.
76
77 auto AST = buildASTFromCode(Code: R"cpp(
78 void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
79 int [[clang::annotate_type("bar")]]);
80
81 int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
82 array[10] [[clang::annotate_type("arr")]];
83
84 void (* [[clang::annotate_type("funcptr")]] fp)(void);
85
86 struct S { int mem; };
87 int [[clang::annotate_type("int")]]
88 S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
89 )cpp");
90
91 {
92 const FunctionDecl *Func = getFunctionNode(AST: AST.get(), Name: "f");
93
94 // First parameter.
95 const auto PointerTL = Func->getParamDecl(i: 0)
96 ->getTypeSourceInfo()
97 ->getTypeLoc()
98 .getAs<PointerTypeLoc>();
99 ASSERT_FALSE(PointerTL.isNull());
100 PointerTypeLoc PointerPointerTL;
101 const AnnotateTypeAttr *Annotate;
102 AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
103 &Annotate);
104
105 EXPECT_EQ(Annotate->args_size(), 2u);
106 const auto *StringLit = selectFirst<StringLiteral>(
107 "str", match(constantExpr(hasDescendant(stringLiteral().bind(ID: "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())
113 .size(),
114 1u);
115
116 // Second parameter.
117 BuiltinTypeLoc IntTL;
118 AssertAnnotatedAs(Func->getParamDecl(i: 1)->getTypeSourceInfo()->getTypeLoc(),
119 "bar", IntTL);
120 EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
121 }
122
123 {
124 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "array");
125
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);
133 }
134
135 {
136 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "fp");
137
138 PointerTypeLoc PointerTL;
139 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "funcptr",
140 PointerTL);
141 ASSERT_TRUE(
142 PointerTL.getPointeeLoc().IgnoreParens().getAs<FunctionTypeLoc>());
143 }
144
145 {
146 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "ptr_to_member");
147
148 MemberPointerTypeLoc MemberPointerTL;
149 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "ptr_to_mem",
150 MemberPointerTL);
151 BuiltinTypeLoc IntTL;
152 AssertAnnotatedAs(MemberPointerTL.getPointeeLoc(), "int", IntTL);
153 EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
154 }
155
156 // Test type annotation on an `__auto_type` type in C mode.
157 AST = buildASTFromCodeWithArgs(Code: R"c(
158 __auto_type [[clang::annotate_type("auto")]] auto_var = 1;
159 )c",
160 Args: {},
161 FileName: "input.c");
162
163 {
164 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "auto_var");
165
166 AutoTypeLoc AutoTL;
167 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "auto", AutoTL);
168 }
169}
170
171TEST(Attr, RegularKeywordAttribute) {
172 auto AST = clang::tooling::buildASTFromCode(Code: "");
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());
177
178 auto Streaming = clang::ArmStreamingAttr::CreateImplicit(Ctx);
179 EXPECT_EQ(Streaming->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
180 ASSERT_TRUE(Streaming->isRegularKeywordAttribute());
181}
182
183} // namespace
184

source code of clang/unittests/AST/AttrTest.cpp