Author: DonĂ¡t Nagy
Date: 2026-06-30T16:35:44+02:00
New Revision: 84e496da5f0e3e5dde1e405bf6a011347ad4c460

URL: 
https://github.com/llvm/llvm-project/commit/84e496da5f0e3e5dde1e405bf6a011347ad4c460
DIFF: 
https://github.com/llvm/llvm-project/commit/84e496da5f0e3e5dde1e405bf6a011347ad4c460.diff

LOG: [NFC][analyzer] Improve code quality in VisitBinaryOperator (#205151)

I started out to remove the `NodeBuilder` in
`ExprEngine::VisitBinaryOperator` (as a part of my commit series that
removes `NodeBuilder`s), but I noticed that this method is full of
technical debt, so I decided to do a through clean-up (which includes
the removal of the trivial `NodeBuilder`).

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index f2682b25630e1..33c31fe10782a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -20,27 +20,10 @@ using namespace clang;
 using namespace ento;
 using llvm::APSInt;
 
-/// Optionally conjure and return a symbol for offset when processing
-/// \p Elem.
-/// If \p Other is a location, conjure a symbol for \p Symbol
-/// (offset) if it is unknown so that memory arithmetic always
-/// results in an ElementRegion.
-/// \p Count The number of times the current basic block was visited.
-static SVal conjureOffsetSymbolOnLocation(SVal Symbol, SVal Other,
-                                          ConstCFGElementRef Elem, QualType Ty,
-                                          SValBuilder &svalBuilder,
-                                          unsigned Count,
-                                          const StackFrame *SF) {
-  if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() &&
-      Symbol.isUnknown()) {
-    return svalBuilder.conjureSymbolVal(Elem, SF, Ty, Count);
-  }
-  return Symbol;
-}
-
 void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
                                      ExplodedNode *Pred,
                                      ExplodedNodeSet &Dst) {
+  const StackFrame *SF = Pred->getStackFrame();
 
   Expr *LHS = B->getLHS()->IgnoreParens();
   Expr *RHS = B->getRHS()->IgnoreParens();
@@ -51,19 +34,14 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* 
B,
   getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this);
 
   // With both the LHS and RHS evaluated, process the operation itself.
-  for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
-         it != ei; ++it) {
-
-    ProgramStateRef state = (*it)->getState();
-    const StackFrame *SF = (*it)->getStackFrame();
-    SVal LeftV = state->getSVal(LHS, SF);
-    SVal RightV = state->getSVal(RHS, SF);
+  for (ExplodedNode *N : CheckedSet) {
+    ProgramStateRef State = N->getState();
+    SVal LeftV = State->getSVal(LHS, SF);
+    SVal RightV = State->getSVal(RHS, SF);
 
     BinaryOperator::Opcode Op = B->getOpcode();
 
     if (Op == BO_Assign) {
-      // EXPERIMENTAL: "Conjured" symbols.
-      // FIXME: Handle structs.
       if (RightV.isUnknown()) {
         unsigned Count = getNumVisitedCurrent();
         RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), SF,
@@ -72,44 +50,45 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* 
B,
       // Simulate the effects of a "store":  bind the value of the RHS
       // to the L-Value represented by the LHS.
       SVal ExprVal = B->isGLValue() ? LeftV : RightV;
-      evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, SF, ExprVal), LeftV,
+      evalStore(Tmp2, B, LHS, N, State->BindExpr(B, SF, ExprVal), LeftV,
                 RightV);
       continue;
     }
 
     if (!B->isAssignmentOp()) {
-      NodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
-
       if (B->isAdditiveOp()) {
-        // TODO: This can be removed after we enable history tracking with
-        // SymSymExpr.
-        unsigned Count = getNumVisitedCurrent();
-        RightV = conjureOffsetSymbolOnLocation(
-            RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder,
-            Count, SF);
-        LeftV = conjureOffsetSymbolOnLocation(LeftV, RightV, 
getCFGElementRef(),
-                                              LHS->getType(), svalBuilder,
-                                              Count, SF);
+        // Ensure that if `p` is a pointer and `i` is an integer with Unknown
+        // value, then `p+i`, `i+p` and `p-i` are evaluated to element regions
+        // (with a symbolic offset) instead of Unknown.
+        auto ConjureIfNeeded = [this, SF](SVal &V, SVal Other, QualType VTy) {
+          if (isa<Loc>(Other) && VTy->isIntegralOrEnumerationType() &&
+              V.isUnknown()) {
+            V = svalBuilder.conjureSymbolVal(getCFGElementRef(), SF, VTy,
+                                             getNumVisitedCurrent());
+          }
+        };
+        ConjureIfNeeded(RightV, LeftV, RHS->getType());
+        ConjureIfNeeded(LeftV, RightV, LHS->getType());
       }
 
       // Although we don't yet model pointers-to-members, we do need to make
       // sure that the members of temporaries have a valid 'this' pointer for
       // other checks.
       if (B->getOpcode() == BO_PtrMemD)
-        state = createTemporaryRegionIfNeeded(state, SF, LHS);
+        State = createTemporaryRegionIfNeeded(State, SF, LHS);
 
       // Process non-assignments except commas or short-circuited
       // logical expressions (LAnd and LOr).
-      SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
+      SVal Result = evalBinOp(State, Op, LeftV, RightV, B->getType());
       if (!Result.isUnknown()) {
-        state = state->BindExpr(B, SF, Result);
+        State = State->BindExpr(B, SF, Result);
       } else {
         // If we cannot evaluate the operation escape the operands.
-        state = escapeValues(state, LeftV, PSK_EscapeOther);
-        state = escapeValues(state, RightV, PSK_EscapeOther);
+        State = escapeValues(State, LeftV, PSK_EscapeOther);
+        State = escapeValues(State, RightV, PSK_EscapeOther);
       }
 
-      Bldr.generateNode(B, *it, state);
+      Tmp2.insert(Engine.makePostStmtNode(B, State, N));
       continue;
     }
 
@@ -133,60 +112,51 @@ void ExprEngine::VisitBinaryOperator(const 
BinaryOperator* B,
     // Perform a load (the LHS).  This performs the checks for
     // null dereferences, and so on.
     ExplodedNodeSet Tmp;
-    SVal location = LeftV;
-    evalLoad(Tmp, B, LHS, *it, state, location);
+    evalLoad(Tmp, B, LHS, N, State, LeftV);
 
     for (ExplodedNode *N : Tmp) {
-      state = N->getState();
-      const StackFrame *SF = N->getStackFrame();
-      SVal V = state->getSVal(LHS, SF);
-
-      // Get the computation type.
-      QualType CTy =
-        cast<CompoundAssignOperator>(B)->getComputationResultType();
-      CTy = getContext().getCanonicalType(CTy);
+      State = N->getState();
+      SVal V = State->getSVal(LHS, SF);
 
-      QualType CLHSTy =
-        cast<CompoundAssignOperator>(B)->getComputationLHSType();
-      CLHSTy = getContext().getCanonicalType(CLHSTy);
-
-      QualType LTy = getContext().getCanonicalType(LHS->getType());
+      // Determine the relevant types.
+      const ASTContext &ACtx = getContext();
+      const auto *CAOpB = cast<CompoundAssignOperator>(B);
+      QualType CTy = ACtx.getCanonicalType(CAOpB->getComputationResultType());
+      QualType CLHSTy = ACtx.getCanonicalType(CAOpB->getComputationLHSType());
+      QualType LTy = ACtx.getCanonicalType(LHS->getType());
 
       // Promote LHS.
       V = svalBuilder.evalCast(V, CLHSTy, LTy);
 
       // Compute the result of the operation.
-      SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
+      SVal Result = svalBuilder.evalCast(evalBinOp(State, Op, V, RightV, CTy),
                                          B->getType(), CTy);
 
-      // EXPERIMENTAL: "Conjured" symbols.
-      // FIXME: Handle structs.
-
-      SVal LHSVal;
+      SVal StoredInLeftV;
 
       if (Result.isUnknown()) {
         // The symbolic value is actually for the type of the left-hand side
         // expression, not the computation type, as this is the value the
         // LValue on the LHS will bind to.
-        LHSVal = svalBuilder.conjureSymbolVal(/*symbolTag=*/nullptr,
-                                              getCFGElementRef(), SF, LTy,
-                                              getNumVisitedCurrent());
+        StoredInLeftV = svalBuilder.conjureSymbolVal(
+            /*symbolTag=*/nullptr, getCFGElementRef(), SF, LTy,
+            getNumVisitedCurrent());
         // However, we need to convert the symbol to the computation type.
-        Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
+        Result = svalBuilder.evalCast(StoredInLeftV, CTy, LTy);
       } else {
         // The left-hand side may bind to a 
diff erent value then the
         // computation type.
-        LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
+        StoredInLeftV = svalBuilder.evalCast(Result, LTy, CTy);
       }
 
       // In C++, assignment and compound assignment operators return an
       // lvalue.
       if (B->isGLValue())
-        state = state->BindExpr(B, SF, location);
+        State = State->BindExpr(B, SF, LeftV);
       else
-        state = state->BindExpr(B, SF, Result);
+        State = State->BindExpr(B, SF, Result);
 
-      evalStore(Tmp2, B, LHS, N, state, location, LHSVal);
+      evalStore(Tmp2, B, LHS, N, State, LeftV, StoredInLeftV);
     }
   }
 


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to