Clang Project

clang_source_code/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
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
19namespace clang {
20namespace ento {
21namespace {
22
23template <typename CheckerT>
24class TestAction : public ASTFrontendAction {
25  class DiagConsumer : public PathDiagnosticConsumer {
26    llvm::raw_ostream &Output;
27
28  public:
29    DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}
30    void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
31                              FilesMade *filesMade) override {
32      for (const auto *PD : Diags)
33        Output << PD->getCheckName() << ":" << PD->getShortDescription();
34    }
35
36    StringRef getName() const override { return "Test"; }
37  };
38
39  llvm::raw_ostream &DiagsOutput;
40
41public:
42  TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {}
43
44  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
45                                                 StringRef File) override {
46    std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
47        CreateAnalysisConsumer(Compiler);
48    AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
49    Compiler.getAnalyzerOpts()->CheckersControlList = {
50        {"custom.CustomChecker"true}};
51    AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
52      Registry.addChecker<CheckerT>("custom.CustomChecker""Description""");
53    });
54    return std::move(AnalysisConsumer);
55  }
56};
57
58template <typename CheckerT>
59bool runCheckerOnCode(const std::string &Codestd::string &Diags) {
60  llvm::raw_string_ostream OS(Diags);
61  return tooling::runToolOnCode(new TestAction<CheckerT>(OS), Code);
62}
63template <typename CheckerT>
64bool runCheckerOnCode(const std::string &Code) {
65  std::string Diags;
66  return runCheckerOnCode<CheckerT>(CodeDiags);
67}
68
69
70class CustomChecker : public Checker<check::ASTCodeBody> {
71public:
72  void checkASTCodeBody(const Decl *DAnalysisManager &Mgr,
73                        BugReporter &BRconst {
74    BR.EmitBasicReport(Dthis"Custom diagnostic"categories::LogicError,
75                       "Custom diagnostic description",
76                       PathDiagnosticLocation(DMgr.getSourceManager()), {});
77  }
78};
79
80TEST(RegisterCustomCheckers, RegisterChecker) {
81  std::string Diags;
82  EXPECT_TRUE(runCheckerOnCode<CustomChecker>("void f() {;}"Diags));
83  EXPECT_EQ(Diags"custom.CustomChecker:Custom diagnostic description");
84}
85
86class LocIncDecChecker : public Checker<check::Location> {
87public:
88  void checkLocation(SVal Locbool IsLoadconst Stmt *S,
89                     CheckerContext &Cconst {
90    auto UnaryOp = dyn_cast<UnaryOperator>(S);
91    if (UnaryOp && !IsLoad) {
92      EXPECT_FALSE(UnaryOp->isIncrementOp());
93    }
94  }
95};
96
97TEST(RegisterCustomCheckers, CheckLocationIncDec) {
98  EXPECT_TRUE(
99      runCheckerOnCode<LocIncDecChecker>("void f() { int *p; (*p)++; }"));
100}
101
102}
103}
104}
105