1 //===- unittests/StaticAnalyzer/Reusables.h -------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H
10 #define LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/CrossTU/CrossTranslationUnit.h"
14 #include "clang/Frontend/CompilerInstance.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
16 #include "gtest/gtest.h"
21 // Find a node in the current AST that matches a matcher.
22 template <typename T
, typename MatcherT
>
23 const T
*findNode(const Decl
*Where
, MatcherT What
) {
24 using namespace ast_matchers
;
25 auto Matches
= match(decl(hasDescendant(What
.bind("root"))),
26 *Where
, Where
->getASTContext());
27 assert(Matches
.size() <= 1 && "Ambiguous match!");
28 assert(Matches
.size() >= 1 && "Match not found!");
29 const T
*Node
= selectFirst
<T
>("root", Matches
);
30 assert(Node
&& "Type mismatch!");
34 // Find a declaration in the current AST by name.
36 const T
*findDeclByName(const Decl
*Where
, StringRef Name
) {
37 using namespace ast_matchers
;
38 return findNode
<T
>(Where
, namedDecl(hasName(Name
)));
41 // A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
42 class ExprEngineConsumer
: public ASTConsumer
{
47 // We need to construct all of these in order to construct ExprEngine.
48 CheckerManager ChkMgr
;
49 cross_tu::CrossTranslationUnitContext CTU
;
50 PathDiagnosticConsumers Consumers
;
52 SetOfConstDecls VisitedCallees
;
53 FunctionSummariesTy FS
;
59 ExprEngineConsumer(CompilerInstance
&C
)
61 ChkMgr(C
.getASTContext(), C
.getAnalyzerOpts(), C
.getPreprocessor()),
63 AMgr(C
.getASTContext(), C
.getPreprocessor(), Consumers
,
64 CreateRegionStoreManager
, CreateRangeConstraintManager
, &ChkMgr
,
66 VisitedCallees(), FS(),
67 Eng(CTU
, AMgr
, &VisitedCallees
, &FS
, ExprEngine::Inline_Regular
) {}
70 struct ExpectedLocationTy
{
74 void testEquality(SourceLocation L
, SourceManager
&SM
) const {
75 EXPECT_EQ(SM
.getSpellingLineNumber(L
), Line
);
76 EXPECT_EQ(SM
.getSpellingColumnNumber(L
), Column
);
80 struct ExpectedRangeTy
{
81 ExpectedLocationTy Begin
;
82 ExpectedLocationTy End
;
84 void testEquality(SourceRange R
, SourceManager
&SM
) const {
85 Begin
.testEquality(R
.getBegin(), SM
);
86 End
.testEquality(R
.getEnd(), SM
);
90 struct ExpectedPieceTy
{
91 ExpectedLocationTy Loc
;
93 std::vector
<ExpectedRangeTy
> Ranges
;
95 void testEquality(const PathDiagnosticPiece
&Piece
, SourceManager
&SM
) {
96 Loc
.testEquality(Piece
.getLocation().asLocation(), SM
);
97 EXPECT_EQ(Piece
.getString(), Text
);
98 EXPECT_EQ(Ranges
.size(), Piece
.getRanges().size());
99 for (const auto &RangeItem
: llvm::enumerate(Piece
.getRanges()))
100 Ranges
[RangeItem
.index()].testEquality(RangeItem
.value(), SM
);
104 struct ExpectedDiagTy
{
105 ExpectedLocationTy Loc
;
106 std::string VerboseDescription
;
107 std::string ShortDescription
;
108 std::string CheckerName
;
110 std::string Category
;
111 std::vector
<ExpectedPieceTy
> Path
;
113 void testEquality(const PathDiagnostic
&Diag
, SourceManager
&SM
) {
114 Loc
.testEquality(Diag
.getLocation().asLocation(), SM
);
115 EXPECT_EQ(Diag
.getVerboseDescription(), VerboseDescription
);
116 EXPECT_EQ(Diag
.getShortDescription(), ShortDescription
);
117 EXPECT_EQ(Diag
.getCheckerName(), CheckerName
);
118 EXPECT_EQ(Diag
.getBugType(), BugType
);
119 EXPECT_EQ(Diag
.getCategory(), Category
);
121 EXPECT_EQ(Path
.size(), Diag
.path
.size());
122 for (const auto &PieceItem
: llvm::enumerate(Diag
.path
)) {
123 if (PieceItem
.index() < Path
.size())
124 Path
[PieceItem
.index()].testEquality(*PieceItem
.value(), SM
);
129 using ExpectedDiagsTy
= std::vector
<ExpectedDiagTy
>;
131 // A consumer to verify the generated diagnostics.
132 class VerifyPathDiagnosticConsumer
: public PathDiagnosticConsumer
{
133 ExpectedDiagsTy ExpectedDiags
;
137 VerifyPathDiagnosticConsumer(ExpectedDiagsTy
&&ExpectedDiags
,
139 : ExpectedDiags(ExpectedDiags
), SM(SM
) {}
141 StringRef
getName() const override
{ return "verify test diagnostics"; }
143 void FlushDiagnosticsImpl(std::vector
<const PathDiagnostic
*> &Diags
,
144 FilesMade
*filesMade
) override
{
145 EXPECT_EQ(Diags
.size(), ExpectedDiags
.size());
146 for (const auto &Item
: llvm::enumerate(Diags
))
147 if (Item
.index() < ExpectedDiags
.size())
148 ExpectedDiags
[Item
.index()].testEquality(*Item
.value(), SM
);