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
90 // Function Type Attributes
91 __attribute__((noreturn)) int f_noreturn();
92
93 #define NO_RETURN __attribute__((noreturn))
94 NO_RETURN int f_macro_attribue();
95
96 int (__attribute__((noreturn)) f_paren_attribute)();
97
98 int (
99 NO_RETURN
100 (
101 __attribute__((warn_unused_result))
102 (f_w_paren_and_attr)
103 )
104 ) ();
105 )cpp");
106
107 {
108 const FunctionDecl *Func = getFunctionNode(AST: AST.get(), Name: "f");
109
110 // First parameter.
111 const auto PointerTL = Func->getParamDecl(i: 0)
112 ->getTypeSourceInfo()
113 ->getTypeLoc()
114 .getAs<PointerTypeLoc>();
115 ASSERT_FALSE(PointerTL.isNull());
116 PointerTypeLoc PointerPointerTL;
117 const AnnotateTypeAttr *Annotate;
118 AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
119 &Annotate);
120
121 EXPECT_EQ(Annotate->args_size(), 2u);
122 const auto *StringLit = selectFirst<StringLiteral>(
123 "str", match(constantExpr(hasDescendant(stringLiteral().bind(ID: "str"))),
124 *Annotate->args_begin()[0], AST->getASTContext()));
125 ASSERT_NE(StringLit, nullptr);
126 EXPECT_EQ(StringLit->getString(), "arg1");
127 EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2u)).bind("int"))),
128 *Annotate->args_begin()[1], AST->getASTContext())
129 .size(),
130 1u);
131
132 // Second parameter.
133 BuiltinTypeLoc IntTL;
134 AssertAnnotatedAs(Func->getParamDecl(i: 1)->getTypeSourceInfo()->getTypeLoc(),
135 "bar", IntTL);
136 EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
137 }
138
139 {
140 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "array");
141
142 ArrayTypeLoc ArrayTL;
143 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "arr", ArrayTL);
144 PointerTypeLoc PointerTL;
145 AssertAnnotatedAs(ArrayTL.getElementLoc(), "ptr", PointerTL);
146 BuiltinTypeLoc IntTL;
147 AssertAnnotatedAs(PointerTL.getPointeeLoc(), "int", IntTL);
148 EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
149 }
150
151 {
152 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "fp");
153
154 PointerTypeLoc PointerTL;
155 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "funcptr",
156 PointerTL);
157 ASSERT_TRUE(
158 PointerTL.getPointeeLoc().IgnoreParens().getAs<FunctionTypeLoc>());
159 }
160
161 {
162 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "ptr_to_member");
163
164 MemberPointerTypeLoc MemberPointerTL;
165 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "ptr_to_mem",
166 MemberPointerTL);
167 BuiltinTypeLoc IntTL;
168 AssertAnnotatedAs(MemberPointerTL.getPointeeLoc(), "int", IntTL);
169 EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
170 }
171
172 {
173 const FunctionDecl *Func = getFunctionNode(AST: AST.get(), Name: "f_noreturn");
174 const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
175 const FunctionType *FT = FTL.getTypePtr();
176
177 EXPECT_TRUE(FT->getNoReturnAttr());
178 }
179
180 {
181 for (auto should_have_func_type_loc : {
182 "f_macro_attribue",
183 "f_paren_attribute",
184 "f_w_paren_and_attr",
185 }) {
186 llvm::errs() << "O: " << should_have_func_type_loc << "\n";
187 const FunctionDecl *Func =
188 getFunctionNode(AST: AST.get(), Name: should_have_func_type_loc);
189
190 EXPECT_TRUE(Func->getFunctionTypeLoc());
191 }
192 }
193
194 // The following test verifies getFunctionTypeLoc returns a type
195 // which takes into account the attribute (instead of only the nake
196 // type).
197 //
198 // This is hard to do with C/C++ because it seems using a function
199 // type attribute with a C/C++ function declaration only results
200 // with either:
201 //
202 // 1. It does NOT produce any AttributedType (for example it only
203 // sets one flag of the FunctionType's ExtInfo, e.g. NoReturn).
204 // 2. It produces an AttributedType with modified type and
205 // equivalent type that are equal (for example, that's what
206 // happens with Calling Convention attributes).
207 //
208 // Fortunately, ObjC has one specific function type attribute that
209 // creates an AttributedType with different modified type and
210 // equivalent type.
211 auto AST_ObjC = buildASTFromCodeWithArgs(
212 Code: R"objc(
213 __attribute__((ns_returns_retained)) id f();
214 )objc",
215 Args: {"-fobjc-arc", "-fsyntax-only", "-fobjc-runtime=macosx-10.7"},
216 FileName: "input.mm");
217 {
218 const FunctionDecl *f = getFunctionNode(AST: AST_ObjC.get(), Name: "f");
219 const FunctionTypeLoc FTL = f->getFunctionTypeLoc();
220
221 const FunctionType *FT = FTL.getTypePtr();
222 EXPECT_TRUE(FT->getExtInfo().getProducesResult());
223 }
224
225 // Test type annotation on an `__auto_type` type in C mode.
226 AST = buildASTFromCodeWithArgs(Code: R"c(
227 __auto_type [[clang::annotate_type("auto")]] auto_var = 1;
228 )c",
229 Args: {},
230 FileName: "input.c");
231
232 {
233 const VarDecl *Var = getVariableNode(AST: AST.get(), Name: "auto_var");
234
235 AutoTypeLoc AutoTL;
236 AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "auto", AutoTL);
237 }
238}
239
240TEST(Attr, RegularKeywordAttribute) {
241 auto AST = clang::tooling::buildASTFromCode(Code: "");
242 auto &Ctx = AST->getASTContext();
243 auto Funcref = clang::WebAssemblyFuncrefAttr::CreateImplicit(Ctx);
244 EXPECT_EQ(Funcref->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
245 ASSERT_FALSE(Funcref->isRegularKeywordAttribute());
246
247 auto Streaming = clang::ArmStreamingAttr::CreateImplicit(Ctx);
248 EXPECT_EQ(Streaming->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
249 ASSERT_TRUE(Streaming->isRegularKeywordAttribute());
250}
251
252} // namespace
253

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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