//===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInstance.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" namespace clang { namespace ento { class DiagConsumer : public PathDiagnosticConsumer { llvm::raw_ostream &Output; public: DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {} void FlushDiagnosticsImpl(std::vector &Diags, FilesMade *filesMade) override { for (const auto *PD : Diags) Output << PD->getCheckerName() << ":" << PD->getShortDescription() << '\n'; } StringRef getName() const override { return "Test"; } }; using AddCheckerFn = void(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts); template void addChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { Fn1(AnalysisConsumer, AnOpts); addChecker(AnalysisConsumer, AnOpts); } template void addChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { Fn1(AnalysisConsumer, AnOpts); } template class TestAction : public ASTFrontendAction { llvm::raw_ostream &DiagsOutput; public: TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {} std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, StringRef File) override { std::unique_ptr AnalysisConsumer = CreateAnalysisConsumer(Compiler); AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput)); addChecker(*AnalysisConsumer, *Compiler.getAnalyzerOpts()); return std::move(AnalysisConsumer); } }; inline SmallString<80> getCurrentTestNameAsFileName() { const ::testing::TestInfo *Info = ::testing::UnitTest::GetInstance()->current_test_info(); SmallString<80> FileName; (Twine{Info->name()} + ".cc").toVector(FileName); return FileName; } template bool runCheckerOnCode(const std::string &Code, std::string &Diags) { const SmallVectorImpl &FileName = getCurrentTestNameAsFileName(); llvm::raw_string_ostream OS(Diags); return tooling::runToolOnCode(std::make_unique>(OS), Code, FileName); } template bool runCheckerOnCode(const std::string &Code) { std::string Diags; return runCheckerOnCode(Code, Diags); } template bool runCheckerOnCodeWithArgs(const std::string &Code, const std::vector &Args, std::string &Diags) { const SmallVectorImpl &FileName = getCurrentTestNameAsFileName(); llvm::raw_string_ostream OS(Diags); return tooling::runToolOnCodeWithArgs( std::make_unique>(OS), Code, Args, FileName); } template bool runCheckerOnCodeWithArgs(const std::string &Code, const std::vector &Args) { std::string Diags; return runCheckerOnCodeWithArgs(Code, Args, Diags); } } // namespace ento } // namespace clang