Index: include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h =================================================================== --- include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h +++ include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -371,11 +371,10 @@ : public BugReporterVisitorImpl { private: /// Holds the constraints in a given path - // TODO: should we use a set? - llvm::SmallVector Constraints; + ConstraintRangeTy Constraints; public: - FalsePositiveRefutationBRVisitor() = default; + FalsePositiveRefutationBRVisitor(); void Profile(llvm::FoldingSetNodeID &ID) const override; Index: lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -2357,8 +2357,7 @@ } static bool -areConstraintsUnfeasible(BugReporterContext &BRC, - const llvm::SmallVector &Cs) { +areConstraintsUnfeasible(BugReporterContext &BRC, ConstraintRangeTy &CRs) { // Create a refutation manager std::unique_ptr RefutationMgr = CreateZ3ConstraintManager( BRC.getStateManager(), BRC.getStateManager().getOwningEngine()); @@ -2367,21 +2366,86 @@ static_cast(RefutationMgr.get()); // Add constraints to the solver - for (const auto &C : Cs) - SMTRefutationMgr->addRangeConstraints(C); + SMTRefutationMgr->addRangeConstraints(CRs); // And check for satisfiability return SMTRefutationMgr->isModelFeasible().isConstrainedFalse(); } +static ConstraintRangeTy mergeConstraints(const ConstraintRangeTy &OldSet, + const ConstraintRangeTy &NewSet, + ConstraintRangeTy::Factory &CF, + RangeSet::Factory &RF, + BasicValueFactory &BV) { + // If the new set to be merged is empty, we can just return the old one + if (NewSet.isEmpty()) + return OldSet; + + ConstraintRangeTy Result = OldSet; + for (const auto &C : NewSet) { + const SymbolRef &NewSym = C.first; + const RangeSet &NewRanges = C.second; + + // Search if the new symbol is already in the old set + const RangeSet *OldRange = Result.lookup(NewSym); + + // If the old set does not contain the new symbol or if the range in the + // new set is empty, add the new range to the set + const RangeSet *OldRanges = Result.lookup(NewSym); + if (!OldRanges) { + Result = CF.add(Result, NewSym, NewRanges); + continue; + } + + // Don't try to merge ranges if they're equal + if(*OldRanges == NewRanges) + continue; + + // Otherwise, the old constraint set contains the new symbol, so merge + // both ranges + RangeSet ResultRange = *OldRange; + RangeSet R = *OldRange; + for (const auto &NewRange : NewRanges) { + // Get the intersection between the two ranges + R = R.Intersect(BV, RF, NewRange.From(), NewRange.To()); + + // If it's empty (there is no intersection between them), add the new + // range + if (R.isEmpty()) { + ResultRange = ResultRange.addRange( + RF, RangeSet(RF, NewRange.From(), NewRange.To())); + } else { + // Otherwise, replace the old range with the new one + ResultRange = R; + } + R = ResultRange; + } + + Result = CF.add(Result, NewSym, ResultRange); + } + return Result; +} + +FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor() + : Constraints(ConstraintRangeTy::Factory().getEmptyMap()) {} + std::shared_ptr FalsePositiveRefutationBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { - // Collect the constraint for the current state - const ConstraintRangeTy &CR = N->getState()->get(); - Constraints.push_back(CR); + // Get the current set of constraints + ConstraintRangeTy CR = N->getState()->get(); + + // Get the factories + ConstraintRangeTy::Factory &CF = + N->getState()->get_context(); + RangeSet::Factory &RF = static_cast( + BRC.getStateManager().getConstraintManager()).getRangeSetFactory(); + + // Merge the new set of constraints with the old one + Constraints = mergeConstraints(Constraints, CR, CF, RF, + BRC.getSValBuilder().getBasicValueFactory()); // If there are no predecessor, we reached the root node. In this point, // a new refutation manager will be created and the path will be checked