This revision was automatically updated to reflect the committed changes. Closed by commit rG37c1bf21d1da: [analyzer] Enable constructor support in evalCall event. (authored by vrnithinkumar, committed by Artem Dergachev <adergac...@apple.com>).
Changed prior to commit: https://reviews.llvm.org/D82256?vs=273162&id=273430#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D82256/new/ https://reviews.llvm.org/D82256 Files: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td clang/include/clang/StaticAnalyzer/Core/CheckerManager.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp clang/lib/StaticAnalyzer/Core/CallEvent.cpp clang/lib/StaticAnalyzer/Core/CheckerManager.cpp clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp clang/test/Analysis/analyzer-config.c clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp clang/test/Analysis/new-ctor-conservative.cpp
Index: clang/test/Analysis/new-ctor-conservative.cpp =================================================================== --- clang/test/Analysis/new-ctor-conservative.cpp +++ clang/test/Analysis/new-ctor-conservative.cpp @@ -27,6 +27,7 @@ S *s = new S[10]; // FIXME: Should be true once we inline array constructors. clang_analyzer_eval(s[0].x == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(s[1].x == 1); // expected-warning{{UNKNOWN}} } struct NullS { Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_analyze_cc1 %s \ +// RUN: -analyzer-checker=debug.AnalysisOrder \ +// RUN: -analyzer-config debug.AnalysisOrder:EvalCall=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PreCall=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PostCall=true \ +// RUN: 2>&1 | FileCheck %s + +// This test ensures that eval::Call event will be triggered for constructors. + +class C { +public: + C(){}; + C(int x){}; + C(int x, int y){}; +}; + +void foo() { + C C0; + C C1(42); + C *C2 = new C{2, 3}; +} + +// CHECK: PreCall (C::C) [CXXConstructorCall] +// CHECK-NEXT: EvalCall (C::C) {argno: 0} [CXXConstructorCall] +// CHECK-NEXT: PostCall (C::C) [CXXConstructorCall] +// CHECK-NEXT: PreCall (C::C) [CXXConstructorCall] +// CHECK-NEXT: EvalCall (C::C) {argno: 1} [CXXConstructorCall] +// CHECK-NEXT: PostCall (C::C) [CXXConstructorCall] +// CHECK-NEXT: PreCall (operator new) [CXXAllocatorCall] +// CHECK-NEXT: PostCall (operator new) [CXXAllocatorCall] +// CHECK-NEXT: PreCall (C::C) [CXXConstructorCall] +// CHECK-NEXT: EvalCall (C::C) {argno: 2} [CXXConstructorCall] +// CHECK-NEXT: PostCall (C::C) [CXXConstructorCall] Index: clang/test/Analysis/analyzer-config.c =================================================================== --- clang/test/Analysis/analyzer-config.c +++ clang/test/Analysis/analyzer-config.c @@ -50,6 +50,7 @@ // CHECK-NEXT: debug.AnalysisOrder:Bind = false // CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false +// CHECK-NEXT: debug.AnalysisOrder:EvalCall = false // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -584,7 +584,7 @@ // defaultEvalCall if all of them fail. ExplodedNodeSet dstCallEvaluated; getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit, - Call, *this); + Call, *this, EvalCallOptions()); // If there were other constructors called for object-type arguments // of this call, clean them up. @@ -717,7 +717,7 @@ ExprEngine::CallInlinePolicy ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, AnalyzerOptions &Opts, - const ExprEngine::EvalCallOptions &CallOpts) { + const EvalCallOptions &CallOpts) { const LocationContext *CurLC = Pred->getLocationContext(); const StackFrameContext *CallerSFC = CurLC->getStackFrame(); switch (Call.getKind()) { Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -615,7 +615,8 @@ } else { for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) - defaultEvalCall(Bldr, *I, *Call, CallOpts); + getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this, + CallOpts); } // If the CFG was constructed without elements for temporary destructors Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -653,7 +653,8 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, - ExprEngine &Eng) { + ExprEngine &Eng, + const EvalCallOptions &CallOpts) { for (auto *const Pred : Src) { bool anyEvaluated = false; @@ -665,10 +666,8 @@ // TODO: Support the situation when the call doesn't correspond // to any Expr. ProgramPoint L = ProgramPoint::getProgramPoint( - cast<CallExpr>(Call.getOriginExpr()), - ProgramPoint::PostStmtKind, - Pred->getLocationContext(), - EvalCallChecker.Checker); + Call.getOriginExpr(), ProgramPoint::PostStmtKind, + Pred->getLocationContext(), EvalCallChecker.Checker); bool evaluated = false; { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly @@ -690,7 +689,7 @@ // If none of the checkers evaluated the call, ask ExprEngine to handle it. if (!anyEvaluated) { NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); - Eng.defaultEvalCall(B, Pred, Call); + Eng.defaultEvalCall(B, Pred, Call, CallOpts); } } } Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -523,7 +523,7 @@ if (!CC) return None; - ExprEngine::EvalCallOptions CallOpts; + EvalCallOptions CallOpts; ExprEngine &Engine = getState()->getStateManager().getOwningEngine(); SVal RetVal = Engine.computeObjectUnderConstruction(getOriginExpr(), getState(), Index: clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp @@ -38,7 +38,7 @@ check::PostStmt<OffsetOfExpr>, check::PreCall, check::PostCall, check::EndFunction, check::EndAnalysis, check::NewAllocator, check::Bind, check::PointerEscape, check::RegionChanges, - check::LiveSymbols> { + check::LiveSymbols, eval::Call> { bool isCallbackEnabled(const AnalyzerOptions &Opts, StringRef CallbackName) const { @@ -122,6 +122,19 @@ llvm::errs() << "PostStmt<OffsetOfExpr>\n"; } + bool evalCall(const CallEvent &Call, CheckerContext &C) const { + if (isCallbackEnabled(C, "EvalCall")) { + llvm::errs() << "EvalCall"; + if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) + llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; + llvm::errs() << " {argno: " << Call.getNumArgs() << '}'; + llvm::errs() << " [" << Call.getKindAsString() << ']'; + llvm::errs() << '\n'; + return true; + } + return false; + } + void checkPreCall(const CallEvent &Call, CheckerContext &C) const { if (isCallbackEnabled(C, "PreCall")) { llvm::errs() << "PreCall"; Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -96,8 +96,37 @@ class SymbolManager; class SwitchNodeBuilder; +/// Hints for figuring out of a call should be inlined during evalCall(). +struct EvalCallOptions { + /// This call is a constructor or a destructor for which we do not currently + /// compute the this-region correctly. + bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false; + + /// This call is a constructor or a destructor for a single element within + /// an array, a part of array construction or destruction. + bool IsArrayCtorOrDtor = false; + + /// This call is a constructor or a destructor of a temporary value. + bool IsTemporaryCtorOrDtor = false; + + /// This call is a constructor for a temporary that is lifetime-extended + /// by binding it to a reference-type field within an aggregate, + /// for example 'A { const C &c; }; A a = { C() };' + bool IsTemporaryLifetimeExtendedViaAggregate = false; + + /// This call is a pre-C++17 elidable constructor that we failed to elide + /// because we failed to compute the target region into which + /// this constructor would have been ultimately elided. Analysis that + /// we perform in this case is still correct but it behaves differently, + /// as if copy elision is disabled. + bool IsElidableCtorThatHasNotBeenElided = false; + + EvalCallOptions() {} +}; + class ExprEngine { void anchor(); + public: /// The modes of inlining, which override the default analysis-wide settings. enum InliningModes { @@ -108,34 +137,6 @@ Inline_Minimal = 0x1 }; - /// Hints for figuring out of a call should be inlined during evalCall(). - struct EvalCallOptions { - /// This call is a constructor or a destructor for which we do not currently - /// compute the this-region correctly. - bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false; - - /// This call is a constructor or a destructor for a single element within - /// an array, a part of array construction or destruction. - bool IsArrayCtorOrDtor = false; - - /// This call is a constructor or a destructor of a temporary value. - bool IsTemporaryCtorOrDtor = false; - - /// This call is a constructor for a temporary that is lifetime-extended - /// by binding it to a reference-type field within an aggregate, - /// for example 'A { const C &c; }; A a = { C() };' - bool IsTemporaryLifetimeExtendedViaAggregate = false; - - /// This call is a pre-C++17 elidable constructor that we failed to elide - /// because we failed to compute the target region into which - /// this constructor would have been ultimately elided. Analysis that - /// we perform in this case is still correct but it behaves differently, - /// as if copy elision is disabled. - bool IsElidableCtorThatHasNotBeenElided = false; - - EvalCallOptions() {} - }; - private: cross_tu::CrossTranslationUnitContext &CTU; Index: clang/include/clang/StaticAnalyzer/Core/CheckerManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -47,6 +47,7 @@ class ExplodedNode; class ExplodedNodeSet; class ExprEngine; +struct EvalCallOptions; class MemRegion; struct NodeBuilderContext; class ObjCMethodCall; @@ -433,9 +434,9 @@ /// Run checkers for evaluating a call. /// /// Warning: Currently, the CallEvent MUST come from a CallExpr! - void runCheckersForEvalCall(ExplodedNodeSet &Dst, - const ExplodedNodeSet &Src, - const CallEvent &CE, ExprEngine &Eng); + void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const CallEvent &CE, ExprEngine &Eng, + const EvalCallOptions &CallOpts); /// Run checkers for the entire Translation Unit. void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1373,6 +1373,12 @@ Released, Hide>, CmdLineOption<Boolean, + "EvalCall", + "", + "false", + Released, + Hide>, + CmdLineOption<Boolean, "PreCall", "", "false",
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits