RegisterCustomCheckersTest.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. #include "clang/Frontend/CompilerInstance.h"
  9. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  10. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  11. #include "clang/StaticAnalyzer/Core/Checker.h"
  12. #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
  13. #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
  14. #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
  15. #include "clang/Tooling/Tooling.h"
  16. #include "gtest/gtest.h"
  17. namespace clang {
  18. namespace ento {
  19. namespace {
  20. template <typename CheckerT>
  21. class TestAction : public ASTFrontendAction {
  22. class DiagConsumer : public PathDiagnosticConsumer {
  23. llvm::raw_ostream &Output;
  24. public:
  25. DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}
  26. void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
  27. FilesMade *filesMade) override {
  28. for (const auto *PD : Diags)
  29. Output << PD->getCheckName() << ":" << PD->getShortDescription();
  30. }
  31. StringRef getName() const override { return "Test"; }
  32. };
  33. llvm::raw_ostream &DiagsOutput;
  34. public:
  35. TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {}
  36. std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
  37. StringRef File) override {
  38. std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
  39. CreateAnalysisConsumer(Compiler);
  40. AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
  41. Compiler.getAnalyzerOpts()->CheckersAndPackages = {
  42. {"custom.CustomChecker", true}};
  43. AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
  44. Registry.addChecker<CheckerT>("custom.CustomChecker", "Description", "");
  45. });
  46. return std::move(AnalysisConsumer);
  47. }
  48. };
  49. template <typename CheckerT>
  50. bool runCheckerOnCode(const std::string &Code, std::string &Diags) {
  51. llvm::raw_string_ostream OS(Diags);
  52. return tooling::runToolOnCode(std::make_unique<TestAction<CheckerT>>(OS),
  53. Code);
  54. }
  55. template <typename CheckerT>
  56. bool runCheckerOnCode(const std::string &Code) {
  57. std::string Diags;
  58. return runCheckerOnCode<CheckerT>(Code, Diags);
  59. }
  60. class CustomChecker : public Checker<check::ASTCodeBody> {
  61. public:
  62. void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
  63. BugReporter &BR) const {
  64. BR.EmitBasicReport(D, this, "Custom diagnostic", categories::LogicError,
  65. "Custom diagnostic description",
  66. PathDiagnosticLocation(D, Mgr.getSourceManager()), {});
  67. }
  68. };
  69. TEST(RegisterCustomCheckers, RegisterChecker) {
  70. std::string Diags;
  71. EXPECT_TRUE(runCheckerOnCode<CustomChecker>("void f() {;}", Diags));
  72. EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description");
  73. }
  74. class LocIncDecChecker : public Checker<check::Location> {
  75. public:
  76. void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
  77. CheckerContext &C) const {
  78. auto UnaryOp = dyn_cast<UnaryOperator>(S);
  79. if (UnaryOp && !IsLoad) {
  80. EXPECT_FALSE(UnaryOp->isIncrementOp());
  81. }
  82. }
  83. };
  84. TEST(RegisterCustomCheckers, CheckLocationIncDec) {
  85. EXPECT_TRUE(
  86. runCheckerOnCode<LocIncDecChecker>("void f() { int *p; (*p)++; }"));
  87. }
  88. }
  89. }
  90. }