Clang Project

clang_source_code/unittests/StaticAnalyzer/SymbolReaperTest.cpp
1//===- unittests/StaticAnalyzer/SymbolReaperTest.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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/ASTMatchers/ASTMatchFinder.h"
10#include "clang/Frontend/CompilerInstance.h"
11#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
12#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
13#include "clang/CrossTU/CrossTranslationUnit.h"
14#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
15#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
16#include "clang/Tooling/Tooling.h"
17#include "gtest/gtest.h"
18
19namespace clang {
20namespace ento {
21namespace {
22
23using namespace ast_matchers;
24
25// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
26// TODO: Actually re-use it when we write our second test.
27class ExprEngineConsumer : public ASTConsumer {
28protected:
29  CompilerInstance &C;
30
31private:
32  // We need to construct all of these in order to construct ExprEngine.
33  CheckerManager ChkMgr;
34  cross_tu::CrossTranslationUnitContext CTU;
35  PathDiagnosticConsumers Consumers;
36  AnalysisManager AMgr;
37  SetOfConstDecls VisitedCallees;
38  FunctionSummariesTy FS;
39
40protected:
41  ExprEngine Eng;
42
43  // Find a declaration in the current AST by name. This has nothing to do
44  // with ExprEngine but turns out to be handy.
45  // TODO: There's probably a better place for it.
46  template <typename T>
47  const T *findDeclByName(const Decl *WhereStringRef Name) {
48    auto Matcher = decl(hasDescendant(namedDecl(hasName(Name)).bind("d")));
49    auto Matches = match(Matcher, *Where, Eng.getContext());
50     (0) . __assert_fail ("Matches.size() == 1 && \"Ambiguous name!\"", "/home/seafit/code_projects/clang_source/clang/unittests/StaticAnalyzer/SymbolReaperTest.cpp", 50, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Matches.size() == 1 && "Ambiguous name!");
51    const T *Node = selectFirst<T>("d", Matches);
52     (0) . __assert_fail ("Node && \"Name not found!\"", "/home/seafit/code_projects/clang_source/clang/unittests/StaticAnalyzer/SymbolReaperTest.cpp", 52, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Node && "Name not found!");
53    return Node;
54  }
55
56public:
57  ExprEngineConsumer(CompilerInstance &C)
58      : C(C), ChkMgr(C.getASTContext(), *C.getAnalyzerOpts()), CTU(C),
59        Consumers(),
60        AMgr(C.getASTContext(), C.getDiagnostics(), Consumers,
61             CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
62             *C.getAnalyzerOpts()),
63        VisitedCallees(), FS(),
64        Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
65};
66
67class SuperRegionLivenessConsumer : public ExprEngineConsumer {
68  void performTest(const Decl *D) {
69    const auto *FD = findDeclByName<FieldDecl>(D"x");
70    const auto *VD = findDeclByName<VarDecl>(D"s");
71    assert(FD && VD);
72
73    // The variable must belong to a stack frame,
74    // otherwise SymbolReaper would think it's a global.
75    const StackFrameContext *SFC =
76        Eng.getAnalysisDeclContextManager().getStackFrame(D);
77
78    // Create regions for 's' and 's.x'.
79    const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC);
80    const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR);
81
82    // Pass a null location context to the SymbolReaper so that
83    // it was thinking that the variable is dead.
84    SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr,
85                           Eng.getSymbolManager(), Eng.getStoreManager());
86
87    SymReaper.markLive(FR);
88    EXPECT_TRUE(SymReaper.isLiveRegion(VR));
89  }
90
91public:
92  SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
93  ~SuperRegionLivenessConsumer() override {}
94
95  bool HandleTopLevelDecl(DeclGroupRef DG) override {
96    for (const auto *D : DG)
97      performTest(D);
98    return true;
99  }
100};
101
102class SuperRegionLivenessActionpublic ASTFrontendAction {
103public:
104  SuperRegionLivenessAction() {}
105  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
106                                                 StringRef File) override {
107    return llvm::make_unique<SuperRegionLivenessConsumer>(Compiler);
108  }
109};
110
111// Test that marking s.x as live would also make s live.
112TEST(SymbolReaper, SuperRegionLiveness) {
113  EXPECT_TRUE(tooling::runToolOnCode(new SuperRegionLivenessAction,
114                                     "void foo() { struct S { int x; } s; }"));
115}
116
117// namespace
118// namespace ento
119// namespace clang
120