155 lines · c
1//===- unittests/StaticAnalyzer/Reusables.h -------------------------------===//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#ifndef LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H10#define LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H11 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"17 18namespace clang {19namespace ento {20 21// Find a node in the current AST that matches a matcher.22template <typename T, typename MatcherT>23const 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!");31 return Node;32}33 34// Find a declaration in the current AST by name.35template <typename T>36const T *findDeclByName(const Decl *Where, StringRef Name) {37 using namespace ast_matchers;38 return findNode<T>(Where, namedDecl(hasName(Name)));39}40 41// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.42class ExprEngineConsumer : public ASTConsumer {43protected:44 CompilerInstance &C;45 46private:47 // We need to construct all of these in order to construct ExprEngine.48 CheckerManager ChkMgr;49 cross_tu::CrossTranslationUnitContext CTU;50 PathDiagnosticConsumers Consumers;51 AnalysisManager AMgr;52 SetOfConstDecls VisitedCallees;53 FunctionSummariesTy FS;54 55protected:56 ExprEngine Eng;57 58public:59 ExprEngineConsumer(CompilerInstance &C)60 : C(C),61 ChkMgr(C.getASTContext(), C.getAnalyzerOpts(), C.getPreprocessor()),62 CTU(C), AMgr(C.getASTContext(), C.getPreprocessor(), {},63 CreateRegionStoreManager, CreateRangeConstraintManager,64 &ChkMgr, C.getAnalyzerOpts()),65 VisitedCallees(), FS(),66 Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}67};68 69struct ExpectedLocationTy {70 unsigned Line;71 unsigned Column;72 73 void testEquality(SourceLocation L, SourceManager &SM) const {74 EXPECT_EQ(SM.getSpellingLineNumber(L), Line);75 EXPECT_EQ(SM.getSpellingColumnNumber(L), Column);76 }77};78 79struct ExpectedRangeTy {80 ExpectedLocationTy Begin;81 ExpectedLocationTy End;82 83 void testEquality(SourceRange R, SourceManager &SM) const {84 Begin.testEquality(R.getBegin(), SM);85 End.testEquality(R.getEnd(), SM);86 }87};88 89struct ExpectedPieceTy {90 ExpectedLocationTy Loc;91 std::string Text;92 std::vector<ExpectedRangeTy> Ranges;93 94 void testEquality(const PathDiagnosticPiece &Piece, SourceManager &SM) {95 Loc.testEquality(Piece.getLocation().asLocation(), SM);96 EXPECT_EQ(Piece.getString(), Text);97 EXPECT_EQ(Ranges.size(), Piece.getRanges().size());98 for (const auto &RangeItem : llvm::enumerate(Piece.getRanges()))99 Ranges[RangeItem.index()].testEquality(RangeItem.value(), SM);100 }101};102 103struct ExpectedDiagTy {104 ExpectedLocationTy Loc;105 std::string VerboseDescription;106 std::string ShortDescription;107 std::string CheckerName;108 std::string BugType;109 std::string Category;110 std::vector<ExpectedPieceTy> Path;111 112 void testEquality(const PathDiagnostic &Diag, SourceManager &SM) {113 Loc.testEquality(Diag.getLocation().asLocation(), SM);114 EXPECT_EQ(Diag.getVerboseDescription(), VerboseDescription);115 EXPECT_EQ(Diag.getShortDescription(), ShortDescription);116 EXPECT_EQ(Diag.getCheckerName(), CheckerName);117 EXPECT_EQ(Diag.getBugType(), BugType);118 EXPECT_EQ(Diag.getCategory(), Category);119 120 EXPECT_EQ(Path.size(), Diag.path.size());121 for (const auto &PieceItem : llvm::enumerate(Diag.path)) {122 if (PieceItem.index() < Path.size())123 Path[PieceItem.index()].testEquality(*PieceItem.value(), SM);124 }125 }126};127 128using ExpectedDiagsTy = std::vector<ExpectedDiagTy>;129 130// A consumer to verify the generated diagnostics.131class VerifyPathDiagnosticConsumer : public PathDiagnosticConsumer {132 ExpectedDiagsTy ExpectedDiags;133 SourceManager &SM;134 135public:136 VerifyPathDiagnosticConsumer(ExpectedDiagsTy &&ExpectedDiags,137 SourceManager &SM)138 : ExpectedDiags(ExpectedDiags), SM(SM) {}139 140 StringRef getName() const override { return "verify test diagnostics"; }141 142 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,143 FilesMade *filesMade) override {144 EXPECT_EQ(Diags.size(), ExpectedDiags.size());145 for (const auto &Item : llvm::enumerate(Diags))146 if (Item.index() < ExpectedDiags.size())147 ExpectedDiags[Item.index()].testEquality(*Item.value(), SM);148 }149};150 151} // namespace ento152} // namespace clang153 154#endif155