1 //===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.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/Frontend/CompilerInstance.h"
10 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
11 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
12 #include "clang/StaticAnalyzer/Core/Checker.h"
13 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
14 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
15 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "gtest/gtest.h"
18
19 namespace clang {
20 namespace ento {
21
22 class DiagConsumer : public PathDiagnosticConsumer {
23 llvm::raw_ostream &Output;
24
25 public:
DiagConsumer(llvm::raw_ostream & Output)26 DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}
FlushDiagnosticsImpl(std::vector<const PathDiagnostic * > & Diags,FilesMade * filesMade)27 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
28 FilesMade *filesMade) override {
29 for (const auto *PD : Diags)
30 Output << PD->getCheckerName() << ":" << PD->getShortDescription() << '\n';
31 }
32
getName()33 StringRef getName() const override { return "Test"; }
34 };
35
36 using AddCheckerFn = void(AnalysisASTConsumer &AnalysisConsumer,
37 AnalyzerOptions &AnOpts);
38
39 template <AddCheckerFn Fn1, AddCheckerFn Fn2, AddCheckerFn... Fns>
addChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)40 void addChecker(AnalysisASTConsumer &AnalysisConsumer,
41 AnalyzerOptions &AnOpts) {
42 Fn1(AnalysisConsumer, AnOpts);
43 addChecker<Fn2, Fns...>(AnalysisConsumer, AnOpts);
44 }
45
46 template <AddCheckerFn Fn1>
addChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)47 void addChecker(AnalysisASTConsumer &AnalysisConsumer,
48 AnalyzerOptions &AnOpts) {
49 Fn1(AnalysisConsumer, AnOpts);
50 }
51
52 template <AddCheckerFn... Fns>
53 class TestAction : public ASTFrontendAction {
54 llvm::raw_ostream &DiagsOutput;
55
56 public:
TestAction(llvm::raw_ostream & DiagsOutput)57 TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {}
58
CreateASTConsumer(CompilerInstance & Compiler,StringRef File)59 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
60 StringRef File) override {
61 std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
62 CreateAnalysisConsumer(Compiler);
63 AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
64 addChecker<Fns...>(*AnalysisConsumer, *Compiler.getAnalyzerOpts());
65 return std::move(AnalysisConsumer);
66 }
67 };
68
getCurrentTestNameAsFileName()69 inline SmallString<80> getCurrentTestNameAsFileName() {
70 const ::testing::TestInfo *Info =
71 ::testing::UnitTest::GetInstance()->current_test_info();
72
73 SmallString<80> FileName;
74 (Twine{Info->name()} + ".cc").toVector(FileName);
75 return FileName;
76 }
77
78 template <AddCheckerFn... Fns>
runCheckerOnCode(const std::string & Code,std::string & Diags)79 bool runCheckerOnCode(const std::string &Code, std::string &Diags) {
80 const SmallVectorImpl<char> &FileName = getCurrentTestNameAsFileName();
81 llvm::raw_string_ostream OS(Diags);
82 return tooling::runToolOnCode(std::make_unique<TestAction<Fns...>>(OS), Code,
83 FileName);
84 }
85
86 template <AddCheckerFn... Fns>
runCheckerOnCode(const std::string & Code)87 bool runCheckerOnCode(const std::string &Code) {
88 std::string Diags;
89 return runCheckerOnCode<Fns...>(Code, Diags);
90 }
91
92 template <AddCheckerFn... Fns>
runCheckerOnCodeWithArgs(const std::string & Code,const std::vector<std::string> & Args,std::string & Diags)93 bool runCheckerOnCodeWithArgs(const std::string &Code,
94 const std::vector<std::string> &Args,
95 std::string &Diags) {
96 const SmallVectorImpl<char> &FileName = getCurrentTestNameAsFileName();
97 llvm::raw_string_ostream OS(Diags);
98 return tooling::runToolOnCodeWithArgs(
99 std::make_unique<TestAction<Fns...>>(OS), Code, Args, FileName);
100 }
101
102 template <AddCheckerFn... Fns>
runCheckerOnCodeWithArgs(const std::string & Code,const std::vector<std::string> & Args)103 bool runCheckerOnCodeWithArgs(const std::string &Code,
104 const std::vector<std::string> &Args) {
105 std::string Diags;
106 return runCheckerOnCodeWithArgs<Fns...>(Code, Args, Diags);
107 }
108
109 } // namespace ento
110 } // namespace clang
111