152 lines · cpp
1//===- unittests/Analysis/FlowSensitive/ASTOpsTest.cpp --------------------===//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/Analysis/FlowSensitive/ASTOps.h"10#include "TestingSupport.h"11#include "clang/AST/Decl.h"12#include "clang/AST/DeclCXX.h"13#include "clang/ASTMatchers/ASTMatchers.h"14#include "clang/Basic/LLVM.h"15#include "clang/Frontend/ASTUnit.h"16#include "clang/Tooling/Tooling.h"17#include "gmock/gmock.h"18#include "gtest/gtest.h"19#include <memory>20#include <string>21 22namespace {23 24using namespace clang;25using namespace dataflow;26 27using ast_matchers::cxxMethodDecl;28using ast_matchers::cxxRecordDecl;29using ast_matchers::hasName;30using ast_matchers::hasType;31using ast_matchers::initListExpr;32using ast_matchers::match;33using ast_matchers::selectFirst;34using test::findValueDecl;35using testing::IsEmpty;36using testing::UnorderedElementsAre;37 38TEST(ASTOpsTest, RecordInitListHelperOnEmptyUnionInitList) {39 // This is a regression test: The `RecordInitListHelper` used to assert-fail40 // when called for the `InitListExpr` of an empty union.41 std::string Code = R"cc(42 struct S {43 S() : UField{} {};44 45 union U {} UField;46 };47 )cc";48 std::unique_ptr<ASTUnit> Unit =49 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});50 auto &ASTCtx = Unit->getASTContext();51 52 ASSERT_EQ(ASTCtx.getDiagnostics().getClient()->getNumErrors(), 0U);53 54 auto *InitList = selectFirst<InitListExpr>(55 "init",56 match(initListExpr(hasType(cxxRecordDecl(hasName("U")))).bind("init"),57 ASTCtx));58 ASSERT_NE(InitList, nullptr);59 60 RecordInitListHelper Helper(InitList);61 EXPECT_THAT(Helper.base_inits(), IsEmpty());62 EXPECT_THAT(Helper.field_inits(), IsEmpty());63}64 65TEST(ASTOpsTest, ReferencedDeclsOnUnionInitList) {66 // This is a regression test: `getReferencedDecls()` used to return a null67 // `FieldDecl` in this case (in addition to the correct non-null `FieldDecl`)68 // because `getInitializedFieldInUnion()` returns null for the syntactic form69 // of the `InitListExpr`.70 std::string Code = R"cc(71 struct S {72 S() : UField{0} {};73 74 union U {75 int I;76 } UField;77 };78 )cc";79 std::unique_ptr<ASTUnit> Unit =80 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});81 auto &ASTCtx = Unit->getASTContext();82 83 ASSERT_EQ(ASTCtx.getDiagnostics().getClient()->getNumErrors(), 0U);84 85 auto *InitList = selectFirst<InitListExpr>(86 "init",87 match(initListExpr(hasType(cxxRecordDecl(hasName("U")))).bind("init"),88 ASTCtx));89 ASSERT_NE(InitList, nullptr);90 auto *IDecl = cast<FieldDecl>(findValueDecl(ASTCtx, "I"));91 92 EXPECT_THAT(getReferencedDecls(*InitList).Fields,93 UnorderedElementsAre(IDecl));94}95 96TEST(ASTOpsTest, ReferencedDeclsLocalsNotParamsOrStatics) {97 std::string Code = R"cc(98 void func(int Param) {99 static int Static = 0;100 int Local = Param;101 Local = Static;102 }103 )cc";104 std::unique_ptr<ASTUnit> Unit =105 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});106 auto &ASTCtx = Unit->getASTContext();107 108 ASSERT_EQ(ASTCtx.getDiagnostics().getClient()->getNumErrors(), 0U);109 110 auto *Func = cast<FunctionDecl>(findValueDecl(ASTCtx, "func"));111 ASSERT_NE(Func, nullptr);112 auto *LocalDecl = cast<VarDecl>(findValueDecl(ASTCtx, "Local"));113 114 EXPECT_THAT(getReferencedDecls(*Func).Locals,115 UnorderedElementsAre(LocalDecl));116}117 118TEST(ASTOpsTest, LambdaCaptures) {119 std::string Code = R"cc(120 void func(int CapturedByRef, int CapturedByValue, int NotCaptured) {121 int Local;122 auto Lambda = [&CapturedByRef, CapturedByValue, &Local](int LambdaParam) {123 };124 }125 )cc";126 std::unique_ptr<ASTUnit> Unit =127 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});128 auto &ASTCtx = Unit->getASTContext();129 130 ASSERT_EQ(ASTCtx.getDiagnostics().getClient()->getNumErrors(), 0U);131 132 auto *LambdaCallOp = selectFirst<CXXMethodDecl>(133 "l", match(cxxMethodDecl(hasName("operator()")).bind("l"), ASTCtx));134 ASSERT_NE(LambdaCallOp, nullptr);135 auto *Func = cast<FunctionDecl>(findValueDecl(ASTCtx, "func"));136 ASSERT_NE(Func, nullptr);137 auto *CapturedByRefDecl = Func->getParamDecl(0);138 ASSERT_NE(CapturedByRefDecl, nullptr);139 auto *CapturedByValueDecl = Func->getParamDecl(1);140 ASSERT_NE(CapturedByValueDecl, nullptr);141 142 EXPECT_THAT(getReferencedDecls(*Func).LambdaCapturedParams, IsEmpty());143 ReferencedDecls ForLambda = getReferencedDecls(*LambdaCallOp);144 EXPECT_THAT(ForLambda.LambdaCapturedParams,145 UnorderedElementsAre(CapturedByRefDecl, CapturedByValueDecl));146 // Captured locals must be seen in the body for them to appear in147 // ReferencedDecls.148 EXPECT_THAT(ForLambda.Locals, IsEmpty());149}150 151} // namespace152