253 lines · cpp
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-exception6//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(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());44 EXPECT_EQ(Result.size(), 1u);45 return Result[0].getNodeAs<FunctionDecl>("fn");46}47 48const 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");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 that75 // it stores its arguments correctly.76 77 auto AST = buildASTFromCode(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 Attributes91 __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_RETURN100 (101 __attribute__((warn_unused_result))102 (f_w_paren_and_attr)103 )104 ) ();105 )cpp");106 107 {108 const FunctionDecl *Func = getFunctionNode(AST.get(), "f");109 110 // First parameter.111 const auto PointerTL = Func->getParamDecl(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("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(1)->getTypeSourceInfo()->getTypeLoc(),135 "bar", IntTL);136 EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);137 }138 139 {140 const VarDecl *Var = getVariableNode(AST.get(), "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.get(), "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.get(), "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.get(), "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.get(), should_have_func_type_loc);189 190 EXPECT_TRUE(Func->getFunctionTypeLoc());191 }192 }193 194 // The following test verifies getFunctionTypeLoc returns a type195 // which takes into account the attribute (instead of only the nake196 // type).197 //198 // This is hard to do with C/C++ because it seems using a function199 // type attribute with a C/C++ function declaration only results200 // with either:201 //202 // 1. It does NOT produce any AttributedType (for example it only203 // sets one flag of the FunctionType's ExtInfo, e.g. NoReturn).204 // 2. It produces an AttributedType with modified type and205 // equivalent type that are equal (for example, that's what206 // happens with Calling Convention attributes).207 //208 // Fortunately, ObjC has one specific function type attribute that209 // creates an AttributedType with different modified type and210 // equivalent type.211 auto AST_ObjC = buildASTFromCodeWithArgs(212 R"objc(213 __attribute__((ns_returns_retained)) id f();214 )objc",215 {"-fobjc-arc", "-fsyntax-only", "-fobjc-runtime=macosx-10.7"},216 "input.mm");217 {218 const FunctionDecl *f = getFunctionNode(AST_ObjC.get(), "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(R"c(227 __auto_type [[clang::annotate_type("auto")]] auto_var = 1;228 )c",229 {},230 "input.c");231 232 {233 const VarDecl *Var = getVariableNode(AST.get(), "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("");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} // namespace253