class NoStateChangeFuncVisitor
Declaration
class NoStateChangeFuncVisitor : public BugReporterVisitor { /* full declaration omitted */ };
Description
Put a diagnostic on return statement (or on } in its absence) of all inlined functions for which some property remained unchanged. Resulting diagnostics may read such as "Returning without writing to X". Descendants can define what a "state change is", like a change of value to a memory region, liveness, etc. For function calls where the state did not change as defined, a custom note may be constructed. For a minimal example, check out clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:639
Inherits from: BugReporterVisitor
Member Variables
- private llvm::SmallPtrSet<const StackFrameContext*, 32> FramesModifying
- Frames modifying the state as defined in \c wasModifiedBeforeCallExit. This visitor generates a note only if a function does *not* change the state that way. This information is not immediately available by looking at the node associated with the exit from the function (usually the return statement). To avoid recomputing the same information many times (going up the path for each node and checking whether the region was written into) we instead lazily compute the stack frames along the path.
- private llvm::SmallPtrSet<const StackFrameContext*, 32> FramesModifyingCalculated
- protected bugreporter::TrackingKind TKind
Method Overview
- public NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind)
- public clang::ento::PathDiagnosticPieceRef VisitNode(const clang::ento::ExplodedNode * N, clang::ento::BugReporterContext & BR, clang::ento::PathSensitiveBugReport & R)
- private void findModifyingFrames(const clang::ento::ExplodedNode *const CallExitBeginN)
- private bool isModifiedInFrame(const clang::ento::ExplodedNode * CallExitBeginN)
- private void markFrameAsModifying(const clang::StackFrameContext * SCtx)
- protected virtual clang::ento::PathDiagnosticPieceRef maybeEmitNoteForCXXThis(clang::ento::PathSensitiveBugReport & R, const clang::ento::CXXConstructorCall & Call, const clang::ento::ExplodedNode * N)
- protected virtual clang::ento::PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(clang::ento::PathSensitiveBugReport & R, const clang::ento::ObjCMethodCall & Call, const clang::ento::ExplodedNode * N)
- protected virtual clang::ento::PathDiagnosticPieceRef maybeEmitNoteForParameters(clang::ento::PathSensitiveBugReport & R, const clang::ento::CallEvent & Call, const clang::ento::ExplodedNode * N)
- protected virtual bool wasModifiedBeforeCallExit(const clang::ento::ExplodedNode * CurrN, const clang::ento::ExplodedNode * CallExitBeginN)
- protected virtual bool wasModifiedInFunction(const clang::ento::ExplodedNode * CallEnterN, const clang::ento::ExplodedNode * CallExitEndN)
Inherited from BugReporterVisitor:
Inherited from FoldingSetBase::Node:
Methods
¶NoStateChangeFuncVisitor(
bugreporter::TrackingKind TKind)
NoStateChangeFuncVisitor(
bugreporter::TrackingKind TKind)
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:730
Parameters
- bugreporter::TrackingKind TKind
¶clang::ento::PathDiagnosticPieceRef VisitNode(
const clang::ento::ExplodedNode* N,
clang::ento::BugReporterContext& BR,
clang::ento::PathSensitiveBugReport& R)
clang::ento::PathDiagnosticPieceRef VisitNode(
const clang::ento::ExplodedNode* N,
clang::ento::BugReporterContext& BR,
clang::ento::PathSensitiveBugReport& R)
Description
Return a diagnostic piece which should be associated with the given node. Note that this function does *not* get run on the very last node of the report, as the PathDiagnosticPiece associated with the last node should be unique. Use \ref getEndPath to customize the note associated with the report end instead. The last parameter can be used to register a new visitor with the given BugReport while processing a node.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:732
Parameters
- const clang::ento::ExplodedNode* N
- clang::ento::BugReporterContext& BR
- clang::ento::PathSensitiveBugReport& R
¶void findModifyingFrames(
const clang::ento::ExplodedNode* const
CallExitBeginN)
void findModifyingFrames(
const clang::ento::ExplodedNode* const
CallExitBeginN)
Description
Write to \c FramesModifying all stack frames along the path in the current stack frame which modifies the state.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:663
Parameters
- const clang::ento::ExplodedNode* const CallExitBeginN
¶bool isModifiedInFrame(
const clang::ento::ExplodedNode*
CallExitBeginN)
bool isModifiedInFrame(
const clang::ento::ExplodedNode*
CallExitBeginN)
Description
Check and lazily calculate whether the state is modified in the stack frame to which \p CallExitBeginN belongs. The calculation is cached in FramesModifying.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:657
Parameters
- const clang::ento::ExplodedNode* CallExitBeginN
¶void markFrameAsModifying(
const clang::StackFrameContext* SCtx)
void markFrameAsModifying(
const clang::StackFrameContext* SCtx)
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:659
Parameters
- const clang::StackFrameContext* SCtx
¶virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(
clang::ento::PathSensitiveBugReport& R,
const clang::ento::CXXConstructorCall& Call,
const clang::ento::ExplodedNode* N)
virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(
clang::ento::PathSensitiveBugReport& R,
const clang::ento::CXXConstructorCall& Call,
const clang::ento::ExplodedNode* N)
Description
Consume the information on the non-modifying stack frame in order to either emit a note or not. May suppress the report entirely.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:716
Parameters
- clang::ento::PathSensitiveBugReport& R
- const clang::ento::CXXConstructorCall& Call
- const clang::ento::ExplodedNode* N
Returns
Diagnostics piece for the unmodified state in the current function, if it decides to emit one. A good description might start with "Returning without...".
¶virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(
clang::ento::PathSensitiveBugReport& R,
const clang::ento::ObjCMethodCall& Call,
const clang::ento::ExplodedNode* N)
virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(
clang::ento::PathSensitiveBugReport& R,
const clang::ento::ObjCMethodCall& Call,
const clang::ento::ExplodedNode* N)
Description
Consume the information on the non-modifying stack frame in order to either emit a note or not. May suppress the report entirely.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:706
Parameters
- clang::ento::PathSensitiveBugReport& R
- const clang::ento::ObjCMethodCall& Call
- const clang::ento::ExplodedNode* N
Returns
Diagnostics piece for the unmodified state in the current function, if it decides to emit one. A good description might start with "Returning without...".
¶virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForParameters(
clang::ento::PathSensitiveBugReport& R,
const clang::ento::CallEvent& Call,
const clang::ento::ExplodedNode* N)
virtual clang::ento::PathDiagnosticPieceRef
maybeEmitNoteForParameters(
clang::ento::PathSensitiveBugReport& R,
const clang::ento::CallEvent& Call,
const clang::ento::ExplodedNode* N)
Description
Consume the information on the non-modifying stack frame in order to either emit a note or not. May suppress the report entirely.
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:726
Parameters
- clang::ento::PathSensitiveBugReport& R
- const clang::ento::CallEvent& Call
- const clang::ento::ExplodedNode* N
Returns
Diagnostics piece for the unmodified state in the current function, if it decides to emit one. A good description might start with "Returning without...".
¶virtual bool wasModifiedBeforeCallExit(
const clang::ento::ExplodedNode* CurrN,
const clang::ento::ExplodedNode*
CallExitBeginN)
virtual bool wasModifiedBeforeCallExit(
const clang::ento::ExplodedNode* CurrN,
const clang::ento::ExplodedNode*
CallExitBeginN)
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:677
Parameters
- const clang::ento::ExplodedNode* CurrN
- const clang::ento::ExplodedNode* CallExitBeginN
Returns
Whether the state was modified from the current node, \p CurrN, to the end of the stack frame, at \p CallExitBeginN. \p CurrN and\p CallExitBeginN are always in the same stack frame. Clients should override this callback when a state change is important not only on the entire function call, but inside of it as well. Example: we may want to leave a note about the lack of locking/unlocking on a particular mutex, but not if inside the function its state was changed, but also restored. wasModifiedInFunction() wouldn't know of this change.
¶virtual bool wasModifiedInFunction(
const clang::ento::ExplodedNode* CallEnterN,
const clang::ento::ExplodedNode* CallExitEndN)
virtual bool wasModifiedInFunction(
const clang::ento::ExplodedNode* CallEnterN,
const clang::ento::ExplodedNode* CallExitEndN)
Declared at: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:695
Parameters
- const clang::ento::ExplodedNode* CallEnterN
- const clang::ento::ExplodedNode* CallExitEndN
Returns
Whether the state was modified in the inlined function call in between \p CallEnterN and \p CallExitEndN. Mind that the stack frame retrieved from a CallEnterN and CallExitEndN is the *caller's* stack frame! The inlined function's stack should be retrieved from either the immediate successor to \p CallEnterN or immediate predecessor to\p CallExitEndN. Clients should override this function if a state changes local to the inlined function are not interesting, only the change occuring as a result of it. Example: we want to leave a not about a leaked resource object not being deallocated / its ownership changed inside a function, and we don't care if it was assigned to a local variable (its change in ownership is inconsequential).