brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · bbf1c0f Raw
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