1 //===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
24 template <typename CheckerT>
25 class TestAction : public ASTFrontendAction {
26 class DiagConsumer : public PathDiagnosticConsumer {
27 llvm::raw_ostream &Output;
30 DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}
31 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
32 FilesMade *filesMade) override {
33 for (const auto *PD : Diags)
34 Output << PD->getCheckName() << ":" << PD->getShortDescription();
37 StringRef getName() const override { return "Test"; }
40 llvm::raw_ostream &DiagsOutput;
43 TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {}
45 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
46 StringRef File) override {
47 std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
48 CreateAnalysisConsumer(Compiler);
49 AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
50 Compiler.getAnalyzerOpts()->CheckersControlList = {
51 {"custom.CustomChecker", true}};
52 AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
53 Registry.addChecker<CheckerT>("custom.CustomChecker", "Description", "");
55 return std::move(AnalysisConsumer);
59 template <typename CheckerT>
60 bool runCheckerOnCode(const std::string &Code, std::string &Diags) {
61 llvm::raw_string_ostream OS(Diags);
62 return tooling::runToolOnCode(new TestAction<CheckerT>(OS), Code);
64 template <typename CheckerT>
65 bool runCheckerOnCode(const std::string &Code) {
67 return runCheckerOnCode<CheckerT>(Code, Diags);
71 class CustomChecker : public Checker<check::ASTCodeBody> {
73 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
74 BugReporter &BR) const {
75 BR.EmitBasicReport(D, this, "Custom diagnostic", categories::LogicError,
76 "Custom diagnostic description",
77 PathDiagnosticLocation(D, Mgr.getSourceManager()), {});
81 TEST(RegisterCustomCheckers, RegisterChecker) {
83 EXPECT_TRUE(runCheckerOnCode<CustomChecker>("void f() {;}", Diags));
84 EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description");
87 class LocIncDecChecker : public Checker<check::Location> {
89 void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
90 CheckerContext &C) const {
91 auto UnaryOp = dyn_cast<UnaryOperator>(S);
92 if (UnaryOp && !IsLoad)
93 EXPECT_FALSE(UnaryOp->isIncrementOp());
97 TEST(RegisterCustomCheckers, CheckLocationIncDec) {
99 runCheckerOnCode<LocIncDecChecker>("void f() { int *p; (*p)++; }"));