brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · c4c6e7a Raw
152 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Analysis/PathDiagnostic.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/StaticAnalyzer/Core/Checker.h"14#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"15#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"16#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"17#include "clang/Tooling/Tooling.h"18#include "gtest/gtest.h"19 20namespace clang {21namespace ento {22 23class OnlyWarningsDiagConsumer : public PathDiagnosticConsumer {24  llvm::raw_ostream &Output;25 26public:27  OnlyWarningsDiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}28  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,29                            FilesMade *filesMade) override {30    for (const auto *PD : Diags) {31      Output << PD->getCheckerName() << ": ";32      Output << PD->getShortDescription() << '\n';33    }34  }35 36  StringRef getName() const override { return "Test"; }37};38 39class PathDiagConsumer : public PathDiagnosticConsumer {40  llvm::raw_ostream &Output;41 42public:43  PathDiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}44  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,45                            FilesMade *filesMade) override {46    for (const auto *PD : Diags) {47      Output << PD->getCheckerName() << ": ";48 49      for (PathDiagnosticPieceRef Piece :50           PD->path.flatten(/*ShouldFlattenMacros*/ true)) {51        if (Piece->getKind() != PathDiagnosticPiece::Event)52          continue;53        if (Piece->getString().empty())54          continue;55        // The last event is usually the same as the warning message, skip.56        if (Piece->getString() == PD->getShortDescription())57          continue;58 59        Output << Piece->getString() << " | ";60      }61      Output << PD->getShortDescription() << '\n';62    }63  }64 65  StringRef getName() const override { return "Test"; }66};67 68using AddCheckerFn = void(AnalysisASTConsumer &AnalysisConsumer,69                          AnalyzerOptions &AnOpts);70 71template <AddCheckerFn Fn1, AddCheckerFn Fn2, AddCheckerFn... Fns>72void addChecker(AnalysisASTConsumer &AnalysisConsumer,73                AnalyzerOptions &AnOpts) {74  Fn1(AnalysisConsumer, AnOpts);75  addChecker<Fn2, Fns...>(AnalysisConsumer, AnOpts);76}77 78template <AddCheckerFn Fn1>79void addChecker(AnalysisASTConsumer &AnalysisConsumer,80                AnalyzerOptions &AnOpts) {81  Fn1(AnalysisConsumer, AnOpts);82}83 84template <AddCheckerFn... Fns> class TestAction : public ASTFrontendAction {85  llvm::raw_ostream &DiagsOutput;86  bool OnlyEmitWarnings;87 88public:89  TestAction(llvm::raw_ostream &DiagsOutput, bool OnlyEmitWarnings)90      : DiagsOutput(DiagsOutput), OnlyEmitWarnings(OnlyEmitWarnings) {}91 92  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,93                                                 StringRef File) override {94    std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =95        CreateAnalysisConsumer(Compiler);96    if (OnlyEmitWarnings)97      AnalysisConsumer->AddDiagnosticConsumer(98          std::make_unique<OnlyWarningsDiagConsumer>(DiagsOutput));99    else100      AnalysisConsumer->AddDiagnosticConsumer(101          std::make_unique<PathDiagConsumer>(DiagsOutput));102    addChecker<Fns...>(*AnalysisConsumer, Compiler.getAnalyzerOpts());103    return std::move(AnalysisConsumer);104  }105};106 107inline SmallString<80> getCurrentTestNameAsFileName() {108  const ::testing::TestInfo *Info =109      ::testing::UnitTest::GetInstance()->current_test_info();110 111  SmallString<80> FileName;112  (Twine{Info->name()} + ".cc").toVector(FileName);113  return FileName;114}115 116template <AddCheckerFn... Fns>117bool runCheckerOnCode(const std::string &Code, std::string &Diags,118                      bool OnlyEmitWarnings = false) {119  const SmallVectorImpl<char> &FileName = getCurrentTestNameAsFileName();120  llvm::raw_string_ostream OS(Diags);121  return tooling::runToolOnCode(122      std::make_unique<TestAction<Fns...>>(OS, OnlyEmitWarnings), Code,123      FileName);124}125 126template <AddCheckerFn... Fns> bool runCheckerOnCode(const std::string &Code) {127  std::string Diags;128  return runCheckerOnCode<Fns...>(Code, Diags);129}130 131template <AddCheckerFn... Fns>132bool runCheckerOnCodeWithArgs(const std::string &Code,133                              const std::vector<std::string> &Args,134                              std::string &Diags,135                              bool OnlyEmitWarnings = false) {136  const SmallVectorImpl<char> &FileName = getCurrentTestNameAsFileName();137  llvm::raw_string_ostream OS(Diags);138  return tooling::runToolOnCodeWithArgs(139      std::make_unique<TestAction<Fns...>>(OS, OnlyEmitWarnings), Code, Args,140      FileName);141}142 143template <AddCheckerFn... Fns>144bool runCheckerOnCodeWithArgs(const std::string &Code,145                              const std::vector<std::string> &Args) {146  std::string Diags;147  return runCheckerOnCodeWithArgs<Fns...>(Code, Args, Diags);148}149 150} // namespace ento151} // namespace clang152