brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.5 KiB · 4331ffc Raw
103 lines · cpp
1//===- unittests/StaticAnalyzer/SValSimplifyerTest.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 "CheckerRegistration.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/CallDescription.h"14#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"15#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"16#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"17#include "llvm/ADT/Twine.h"18#include "llvm/Support/raw_ostream.h"19#include "gtest/gtest.h"20 21using namespace clang;22using namespace ento;23 24static std::string toString(SVal V) {25  std::string Result;26  llvm::raw_string_ostream Stream(Result);27  V.dumpToStream(Stream);28  return Result;29}30 31static void replace(std::string &Content, StringRef Substr,32                    StringRef Replacement) {33  std::size_t Pos = 0;34  while ((Pos = Content.find(Substr, Pos)) != std::string::npos) {35    Content.replace(Pos, Substr.size(), Replacement);36    Pos += Replacement.size();37  }38}39 40namespace {41 42class SimplifyChecker : public Checker<check::PreCall> {43  const BugType Bug{this, "SimplifyChecker"};44  const CallDescription SimplifyCall{CDM::SimpleFunc, {"simplify"}, 1};45 46  void report(CheckerContext &C, const Expr *E, StringRef Description) const {47    PathDiagnosticLocation Loc(E->getExprLoc(), C.getSourceManager());48    auto Report = std::make_unique<BasicBugReport>(Bug, Description, Loc);49    C.emitReport(std::move(Report));50  }51 52public:53  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {54    if (!SimplifyCall.matches(Call))55      return;56    const Expr *Arg = Call.getArgExpr(0);57    SVal Val = C.getSVal(Arg);58    SVal SimplifiedVal = C.getSValBuilder().simplifySVal(C.getState(), Val);59    std::string Subject = toString(Val);60    std::string Simplified = toString(SimplifiedVal);61    std::string Message = (llvm::Twine{Subject} + " -> " + Simplified).str();62    report(C, Arg, Message);63  }64};65} // namespace66 67static void addSimplifyChecker(AnalysisASTConsumer &AnalysisConsumer,68                               AnalyzerOptions &AnOpts) {69  AnOpts.CheckersAndPackages = {{"SimplifyChecker", true}};70  AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {71    Registry.addChecker<SimplifyChecker>("SimplifyChecker", "MockDescription");72  });73}74 75static void runThisCheckerOnCode(const std::string &Code, std::string &Diags) {76  ASSERT_TRUE(runCheckerOnCode<addSimplifyChecker>(Code, Diags,77                                                   /*OnlyEmitWarnings=*/true));78  ASSERT_FALSE(Diags.empty());79  ASSERT_EQ(Diags.back(), '\n');80  Diags.pop_back();81}82 83namespace {84 85TEST(SValSimplifyerTest, LHSConstrainedNullPtrDiff) {86  constexpr auto Code = R"cpp(87template <class T> void simplify(T);88void LHSConstrainedNullPtrDiff(char *p, char *q) {89  int diff = p - q;90  if (!p)91    simplify(diff);92})cpp";93 94  std::string Diags;95  runThisCheckerOnCode(Code, Diags);96  replace(Diags, "(reg_$0<char * p>)", "reg_p");97  replace(Diags, "(reg_$1<char * q>)", "reg_q");98  // This should not be simplified to "Unknown".99  EXPECT_EQ(Diags, "SimplifyChecker: reg_p - reg_q -> 0U - reg_q");100}101 102} // namespace103