summaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h')
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h44
1 files changed, 41 insertions, 3 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index a4ff133..d4f014d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -224,13 +224,39 @@ public:
}
/// \brief Generate a sink node. Generating a sink stops exploration of the
- /// given path.
- ExplodedNode *generateSink(ProgramStateRef State = nullptr,
- ExplodedNode *Pred = nullptr,
+ /// given path. To create a sink node for the purpose of reporting an error,
+ /// checkers should use generateErrorNode() instead.
+ ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
const ProgramPointTag *Tag = nullptr) {
return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
}
+ /// \brief Generate a transition to a node that will be used to report
+ /// an error. This node will be a sink. That is, it will stop exploration of
+ /// the given path.
+ ///
+ /// @param State The state of the generated node.
+ /// @param Tag The tag to uniquely identify the creation site. If null,
+ /// the default tag for the checker will be used.
+ ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr,
+ const ProgramPointTag *Tag = nullptr) {
+ return generateSink(State, Pred,
+ (Tag ? Tag : Location.getTag()));
+ }
+
+ /// \brief Generate a transition to a node that will be used to report
+ /// an error. This node will not be a sink. That is, exploration will
+ /// continue along this path.
+ ///
+ /// @param State The state of the generated node.
+ /// @param Tag The tag to uniquely identify the creation site. If null,
+ /// the default tag for the checker will be used.
+ ExplodedNode *
+ generateNonFatalErrorNode(ProgramStateRef State = nullptr,
+ const ProgramPointTag *Tag = nullptr) {
+ return addTransition(State, (Tag ? Tag : Location.getTag()));
+ }
+
/// \brief Emit the diagnostics report.
void emitReport(std::unique_ptr<BugReport> R) {
Changed = true;
@@ -287,6 +313,18 @@ private:
bool MarkAsSink,
ExplodedNode *P = nullptr,
const ProgramPointTag *Tag = nullptr) {
+ // The analyzer may stop exploring if it sees a state it has previously
+ // visited ("cache out"). The early return here is a defensive check to
+ // prevent accidental caching out by checker API clients. Unless there is a
+ // tag or the client checker has requested that the generated node be
+ // marked as a sink, we assume that a client requesting a transition to a
+ // state that is the same as the predecessor state has made a mistake. We
+ // return the predecessor rather than cache out.
+ //
+ // TODO: We could potentially change the return to an assertion to alert
+ // clients to their mistake, but several checkers (including
+ // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation)
+ // rely upon the defensive behavior and would need to be updated.
if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
return Pred;
OpenPOWER on IntegriCloud