Author: DonĂ¡t Nagy Date: 2026-05-05T12:53:03+02:00 New Revision: b2e063bf37f4ea3625c06ffdbfdc4cb951bb5be0
URL: https://github.com/llvm/llvm-project/commit/b2e063bf37f4ea3625c06ffdbfdc4cb951bb5be0 DIFF: https://github.com/llvm/llvm-project/commit/b2e063bf37f4ea3625c06ffdbfdc4cb951bb5be0.diff LOG: [NFC][analyzer] Introduce specialized variants of makeNode (#194459) This commit introduces new methods `makePostStmtNode` and `makeNodeWithBinding` of `CoreEngine`, which will be used instead of the 5-parameter overloads of `NodeBuilder::generateNode` and `NodeBuilder::generateSink` (which were originally methods of the class `StmtNodeBuilder` that was deleted in commit fb46677a858697afa116c4252e84050a07bc6a70). This commit applies the newly introduced methods in a few places (as examples), but there are 80+ call sites that use the 5-parameter `NodeBuilder::generateNode` or `generateSink`, so this transition will be completed in multiple follow-up commits. I decided to introduce these methods because after the transition there will be 20+ calls to `makePostStmtNode` and 30+ calls to `makeNodeWithBinding` and it would be cumbersome to use plain `makeNode` instead of these specialized variants. (On the other hand these new methods don't support specifying a `tag` because only a few call sites would use that feature of the 5-parameter `generateNode`.) Added: Modified: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h clang/lib/StaticAnalyzer/Core/ExprEngine.cpp Removed: ################################################################################ diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 57b0947093b78..1068cb2353f90 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -170,6 +170,29 @@ class CoreEngine { ExplodedNode *makeNode(const ProgramPoint &Loc, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink = false) const; + ExplodedNode *makePostStmtNode(const Stmt *S, ProgramStateRef State, + ExplodedNode *Pred, + bool MarkAsSink = false) const { + PostStmt Loc(S, Pred->getLocationContext(), /*tag=*/nullptr); + return makeNode(Loc, State, Pred, MarkAsSink); + } + + ExplodedNode * + makeNodeWithBinding(ExplodedNode *Pred, const Expr *E, SVal V, + ProgramStateRef State, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind) const { + const LocationContext *LC = Pred->getLocationContext(); + State = State->BindExpr(E, LC, V); + const auto &L = ProgramPoint::getProgramPoint(E, K, LC, /*tag=*/nullptr); + return makeNode(L, State, Pred); + } + + ExplodedNode * + makeNodeWithBinding(ExplodedNode *Pred, const Expr *E, SVal V, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind) const { + return makeNodeWithBinding(Pred, E, V, Pred->getState(), K); + } + /// Enqueue the given set of nodes onto the work list. void enqueue(ExplodedNodeSet &Set); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4ebc5912f2597..1efe7e6f84b23 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1557,13 +1557,11 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, const LocationContext *LC = Pred->getLocationContext(); const MemRegion *MR = nullptr; - if (std::optional<SVal> V = getObjectUnderConstruction( - State, D.getBindTemporaryExpr(), Pred->getLocationContext())) { + if (std::optional<SVal> V = getObjectUnderConstruction(State, BTE, LC)) { // FIXME: Currently we insert temporary destructors for default parameters, // but we don't insert the constructors, so the entry in // ObjectsUnderConstruction may be missing. - State = finishObjectConstruction(State, D.getBindTemporaryExpr(), - Pred->getLocationContext()); + State = finishObjectConstruction(State, BTE, LC); MR = V->getAsRegion(); } @@ -1571,24 +1569,21 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, // destructor was elided, we need to skip the destructor as well. if (isDestructorElided(State, BTE, LC)) { State = cleanupElidedDestructor(State, BTE, LC); - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - PostImplicitCall PP(D.getDestructorDecl(getContext()), - D.getBindTemporaryExpr()->getBeginLoc(), - Pred->getLocationContext(), getCFGElementRef()); - Bldr.generateNode(PP, State, Pred); + PostImplicitCall PP(D.getDestructorDecl(getContext()), BTE->getBeginLoc(), + LC, getCFGElementRef()); + Dst.insert(Engine.makeNode(PP, State, Pred)); return; } - ExplodedNodeSet CleanDtorState; - NodeBuilder Builder(Pred, CleanDtorState, *currBldrCtx); - Builder.generateNode(D.getBindTemporaryExpr(), Pred, State); + ExplodedNode *CleanPred = Engine.makePostStmtNode(BTE, State, Pred); + if (!CleanPred || CleanPred->isSink()) { + // FIXME: We can get a null node here due to temporaries being + // bound to default parameters. + // Sink check is just PosteriorlyOverconstrained paranoia. + CleanPred = Pred; + } - QualType T = D.getBindTemporaryExpr()->getSubExpr()->getType(); - // FIXME: Currently CleanDtorState can be empty here due to temporaries being - // bound to default parameters. - assert(CleanDtorState.size() <= 1); - ExplodedNode *CleanPred = - CleanDtorState.empty() ? Pred : *CleanDtorState.begin(); + QualType T = BTE->getSubExpr()->getType(); EvalCallOptions CallOpts; CallOpts.IsTemporaryCtorOrDtor = true; @@ -1621,7 +1616,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, // but for now we don't have the respective construction contexts, // so MR would always be null in this case. Do nothing for now. } - VisitCXXDestructor(T, MR, D.getBindTemporaryExpr(), + VisitCXXDestructor(T, MR, BTE, /*IsBase=*/false, CleanPred, Dst, CallOpts); } @@ -3189,8 +3184,6 @@ void ExprEngine::processSwitch(const SwitchStmt *Switch, ExplodedNode *Pred, void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); @@ -3223,12 +3216,11 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, // C permits "extern void v", and if you cast the address to a valid type, // you can even do things with it. We simply pretend assert(Ex->isGLValue() || VD->getType()->isVoidType()); - const LocationContext *LocCtxt = Pred->getLocationContext(); std::optional<std::pair<SVal, QualType>> VInfo = resolveAsLambdaCapturedVar(VD); if (!VInfo) - VInfo = std::make_pair(state->getLValue(VD, LocCtxt), VD->getType()); + VInfo = std::make_pair(state->getLValue(VD, LCtx), VD->getType()); SVal V = VInfo->first; bool IsReference = VInfo->second->isReferenceType(); @@ -3242,25 +3234,26 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + Dst.insert( + Engine.makeNodeWithBinding(Pred, Ex, V, ProgramPoint::PostLValueKind)); return; } if (const auto *ED = dyn_cast<EnumConstantDecl>(D)) { assert(!Ex->isGLValue()); SVal V = svalBuilder.makeIntVal(ED->getInitVal()); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V)); + Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V)); return; } if (const auto *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + Dst.insert( + Engine.makeNodeWithBinding(Pred, Ex, V, ProgramPoint::PostLValueKind)); return; } if (isa<FieldDecl, IndirectFieldDecl>(D)) { // Delegate all work related to pointer to members to the surrounding // operator&. + Dst.insert(Pred); return; } if (const auto *BD = dyn_cast<BindingDecl>(D)) { @@ -3276,8 +3269,8 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V, + ProgramPoint::PostLValueKind)); return; } @@ -3331,15 +3324,15 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); - + Dst.insert( + Engine.makeNodeWithBinding(Pred, Ex, V, ProgramPoint::PostLValueKind)); return; } if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) { // FIXME: We should meaningfully implement this. (void)TPO; + Dst.insert(Pred); return; } @@ -3455,7 +3448,6 @@ void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this); ExplodedNodeSet EvalSet; - NodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); bool IsVectorType = A->getBase()->getType()->isVectorType(); @@ -3481,11 +3473,11 @@ void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, SVal V = state->getLValue(T, state->getSVal(Idx, LCtx), state->getSVal(Base, LCtx)); - Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + EvalSet.insert( + Engine.makeNodeWithBinding(Node, A, V, ProgramPoint::PostLValueKind)); } else if (IsVectorType) { // FIXME: non-glvalue vector reads are not modelled. - Bldr.generateNode(A, Node, state, nullptr); + EvalSet.insert(Engine.makePostStmtNode(A, state, Node)); } else { llvm_unreachable("Array subscript should be an lValue when not \ a vector and not a forbidden lvalue type"); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
