# Wolf Analysis

The code in this directory is __experimental__ and not yet ready for public
consumption. This file briefly describes its design and intended use.

## Intention

Wolf analysis is intended as a broader, more extensible version of flow analysis
for use in the analyzer package and the linter. If it proves useful, we may
expand it to be usable by clients of the analyzer such as code generators.

The reason for making a new type of analysis, rather than extending flow
analysis, is because the design of flow analysis is heavily constrained in ways
that make it expensive to modify, maintain, and extend:

- It has to operate in parallel with type inference. This means that it can only
  make a single pass through the source code, and any time it "looks ahead", the
  code it is looking at doesn't yet have types. This forces it to make some
  conservative assumptions when analyzing loops and closures--for example, on
  entry to a loop, flow analysis knows which variables are written inside the
  loop body, but it doesn't know the types of the values that are written to
  those variables; so it has to discard type promotions for all of them. If
  later analysis shows that the values that were written are compatible with the
  promoted type, it's too late to go back and update the analysis.

- It can't be improved without bumping the language version (or it will break
  existing programs).

- All of its analyses must be 100% sound, because they are relied on by later
  compilation stages. This severly limits its ability to account for human
  intent, which we would sometimes like to do in lints.

- It has to be shared between the analyzer and the common front end, which means
  that all of the data structures it acts on must be abstract.

Additionally, flow analysis doesn't understand special behavioral guarantees of
methods and types declared outside the SDK, and it never looks outside of a
single method body.

## Design

The design consists of multiple analysis stages:

- AST-to-IR. The analyzer's AST is converted to a stack-based IR (intermediate
  representation). The proposed IR and the approach for converting to it are
  described in https://flutter.dev/go/dart-static-analysis-ir.

- Scope analysis. A pass is made through the IR, identifying all the state
  variables of interest. This includes local variables as well as any other
  pieces of state that are needed for whatever lints are enabled. This stage
  records the set of state variables that could potentially be changed inside
  each loop, block, closure, etc., for use in later analysis stages.

- SSA (single static assignment) analysis. A pass is made through the IR to
  assign SSA node ids to each state variable and stack value. Queries are
  generated at points that are of interest to whatever lints are enabled (e.g. a
  lint that verifies that certain kinds of values are never null will generate
  queries that ask "is the value represented by this SSA node null?").

- Query solver. Each query generated by SSA analysis is resolved by working
  backwards through the IR, rewriting it in terms of previous SSA nodes, until a
  point in the code is reached where the query either can or can't be
  definitively answered. The mechanism for rewriting queries is inspired by
  Prolog. Depending on the result of the query, a lint output might be
  generated.

Other analysis stages might be added in the future. For example, if we find that
some lints can't be easily expressed in terms of queries, but can still benefit
from the SSA representation, we may add other analysis stages after SSA
analysis, to support those lints.

## Support structure

In addition to the pieces above, there is a simple interpreter that executes the
IR. The interpreter is not intended for production use; it is just sophisticated
enough to serve as the basis for unit testing the other stages. For example, we
use it in the unit tests of the AST-to-IR conversion stage, to make sure that
the output of this stage properly reflects Dart semantics. (If, instead, our
unit tests simply compared the output of AST-to-IR conversion to an expected
sequence of instructions, the unit tests would be much more brittle, and there
would be a much greater risk of human error in reviewing them.)
