zeek/src/script_opt/GenIDDefs.h

113 lines
4.5 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
// Class for generating identifier definition information by traversing
// a function body's AST.
#pragma once
#include "zeek/script_opt/IDOptInfo.h"
#include "zeek/script_opt/ProfileFunc.h"
namespace zeek::detail {
class GenIDDefs : public TraversalCallback {
public:
GenIDDefs(std::shared_ptr<ProfileFunc> _pf, const FuncPtr& f, ScopePtr scope, StmtPtr body);
private:
// Traverses the given function body, using the first two
// arguments for context.
void TraverseFunction(const FuncPtr& f, ScopePtr scope, StmtPtr body);
TraversalCode PreStmt(const Stmt*) override;
void AnalyzeSwitch(const SwitchStmt* sw);
TraversalCode PostStmt(const Stmt*) override;
TraversalCode PreExpr(const Expr*) override;
TraversalCode PostExpr(const Expr*) override;
// Analyzes the target of an assignment. Returns true if the LHS
// was an expression for which we can track it as a definition
// (e.g., assignments to variables, but not to elements of
// aggregates). "rhs" gives the expression used for simple direct
// assignments.
bool CheckLHS(const ExprPtr& lhs, const ExprPtr& rhs = nullptr);
// True if the given expression directly represents an aggregate.
bool IsAggr(const ExprPtr& e) const { return IsAggr(e.get()); }
bool IsAggr(const Expr* e) const;
// If -u is active, checks for whether the given identifier present
// in the given expression is undefined at that point.
void CheckVarUsage(const Expr* e, const IDPtr& id);
// Begin a new confluence block with the given statement.
void StartConfluenceBlock(const Stmt* s);
// Finish up the current confluence block. If no_orig_flow is true,
// then there's no control flow from the origin (the statement that
// starts the block).
void EndConfluenceBlock(bool no_orig_flow = false);
// Note branches from the given "from" statement back up to the
// beginning of, or just past, the "to" statement. If "close_all"
// is true then the nature of the branch is that it terminates
// all pending confluence blocks.
void BranchBackTo(const Stmt* from, const Stmt* to, bool close_all);
void BranchBeyond(const Stmt* from, const Stmt* to, bool close_all);
// These search back through the active confluence blocks looking
// for either the innermost loop, or the innermost block for which
// a "break" would target going beyond that block.
const Stmt* FindLoop();
const Stmt* FindBreakTarget();
// Note that the given statement executes a "return" (which could
// instead be an outer "break" for a hook).
void ReturnAt(const Stmt* s);
// Tracks that the given identifier is defined at the current
// statement in the current confluence block. 'e' is the
// expression used to define the identifier, for simple direct
// assignments.
void TrackID(const IDPtr& id, const ExprPtr& e = nullptr);
// Profile for the function. Currently, all we actually need from
// this is the list of globals and locals.
std::shared_ptr<ProfileFunc> pf;
// Whether the Func is an event/hook/function. We currently only
// need to know whether it's a hook, so we correctly interpret an
// outer "break" in that context.
FunctionFlavor func_flavor;
// The most recently traversed statement.
const Stmt* last_stmt_traversed = nullptr;
// Used to number Stmt objects found during AST traversal.
int stmt_num;
// A stack of confluence blocks, with the innermost at the top/back.
std::vector<const Stmt*> confluence_blocks;
// Stack of confluence blocks corresponding to activate catch-return
// statements. We used to stop identifier definitions at these
// boundaries, but given there's limited confluence (i.e., the body of
// the catch-return *will* execute, up through its first return), we
// can do broader optimization if we don't treat them as their own
// (new) confluence blocks.
std::vector<zeek_uint_t> cr_active;
// The following is parallel to confluence_blocks except
// the front entry tracks identifiers at the outermost
// (non-confluence) scope. Thus, to index it for a given
// confluence block i, we need to use i+1.
std::vector<IDSet> modified_IDs;
// If non-zero, indicates we should suspend any generation
// of usage errors. A counter rather than a boolean because
// such situations might nest.
int suppress_usage = 0;
};
} // namespace zeek::detail