Previously, we hard-coded the cap on block visits inside the framework.
This
patch enables the caller to specify the cap in the APIs for running an
analysis.
Synthetic fields are intended to model the internal state of a class
(e.g. the value stored in a `std::optional`) without having to depend on
that class's implementation details.
Today, this is typically done with properties on `RecordValue`s, but
these have several drawbacks:
* Care must be taken to call `refreshRecordValue()` before modifying a
property so that the modified property values aren’t seen by other
environments that may have access to the same `RecordValue`.
* Properties aren’t associated with a storage location. If an analysis
needs to associate a location with the value stored in a property (e.g.
to model the reference returned by `std::optional::value()`), it needs
to manually add an indirection using a `PointerValue`. (See for example
the way this is done in UncheckedOptionalAccessModel.cpp, specifically
in `maybeInitializeOptionalValueMember()`.)
* Properties don’t participate in the builtin compare, join, and widen
operations. If an analysis needs to apply these operations to
properties, it needs to override the corresponding methods of
`ValueModel`.
* Longer-term, we plan to eliminate `RecordValue`, as by-value
operations on records aren’t really “a thing” in C++ (see
https://discourse.llvm.org/t/70086#changed-structvalue-api-14). This
would obviously eliminate the ability to set properties on
`RecordValue`s.
To demonstrate the advantages of synthetic fields, this patch converts
UncheckedOptionalAccessModel.cpp to synthetic fields. This greatly
simplifies the implementation of the check.
This PR is pretty big; to make it easier to review, I have broken it
down into a stack of three commits, each of which contains a set of
logically related changes. I considered submitting each of these as a
separate PR, but the commits only really make sense when taken together.
To review, I suggest first looking at the changes in
UncheckedOptionalAccessModel.cpp. This gives a flavor for how the
various API changes work together in the context of an analysis. Then,
review the rest of the changes.
It turns out this didn't need to be a template at all.
Likewise, change callers to they're non-template functions.
Also, correct / clarify some comments in RecordOps.h.
This is in response to post-commit comments on https://reviews.llvm.org/D153006.
Reviewed By: gribozavr2
Differential Revision: https://reviews.llvm.org/D154339
In unit tests for concrete dataflow analyses we typically use the
testonly `checkDataflow()` helper to analyse a free function called
"target". This pattern allows our tests to be uniform and focused on
specific statement- or expression-level C++ features.
As we expand our feature coverage, we want to analyze functions whose
names we don't fully control, like constructors, destructors, operators
etc. In such tests it is often convenient to analyze all functions
defined in the input code, to avoid having to carefully craft an AST
matcher that finds the exact function we're interested in. That can be
easily done by providing `checkDataflow()` with a catch-all matcher like
`functionDecl()`.
It is also often convenient to define multiple special member functions
in a single unit test, for example, multiple constructors, and share the
rest of the class definition code between constructors. As a result, it
makes sense to analyze multiple functions in one unit test.
This change allows `checkDataflow()` to correctly handle AST matchers
that match more than one function. Previously, it would only ever
analyze the first matched function, and silently ignore the rest. Now it
runs dataflow analysis in a loop, and calls `VerifyResults` for each
function that was found in the input and analyzed.
Reviewed By: ymandel, sgatev
Differential Revision: https://reviews.llvm.org/D140859
The Annotations helper class does not have a gtest or gmock dependency, but because it's bundled with the rest of TestingSupport, it gets one. By splitting it out, a target can use it without being forced to use LLVM's copy of gtest.
Reviewed By: GMNGeoffrey, sammccall, gribozavr2
Differential Revision: https://reviews.llvm.org/D141175
Moves the work required for retrieving annotation states into the `SetupTest` and `PostVisitCFG` callback to avoid having to run a separate pass over the CFG after analysis has completed.
Reviewed By: gribozavr2, sgatev, ymandel
Differential Revision: https://reviews.llvm.org/D132377
- Add `AnalysisInputs` struct as the parameters for `checkDataflow`, and renamed `AnalysisData` struct to `AnalysisOutputs` which contains the data structures generated from a dataflow analysis run.
- Remove compulsory binding from statement to annotations. Instead, `checkDataflow` in the most general form takes a `VerifyResults` callback which takes as input an `AnalysisOutputs` struct. This struct contains the data structures generated by the analysis that can then be tested. We then introduce two overloads/wrappers of `checkDataflow` for different mechanisms of testing - one which exposes annotation line numbers and is not restricted to statements, and the other which exposes states computed after annotated statements. In the future, we should look at retrieving the analysis states for constructs other than statements.
Reviewed By: gribozavr2, sgatev
Differential Revision: https://reviews.llvm.org/D132147
This enables tests out of clang/unittests/Analysis/FlowSensitive to
use the testing support utilities.
Reviewed-by: ymandel, gribozavr2
Differential Revision: https://reviews.llvm.org/D121285
Adds a dataflow analysis that detects unsafe accesses to values of type
`std::optional`, `absl::optional`, or `base::Optional`.
Reviewed-by: ymandel, xazax.hun
Differential Revision: https://reviews.llvm.org/D121197
Make specializations of `DataflowAnalysis` extendable with domain-specific
logic for merging distinct values when joining environments. This could be
a strict lattice join or a more general widening operation.
This is part of the implementation of the dataflow analysis framework.
See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev.
Reviewed-by: xazax.hun
Differential Revision: https://reviews.llvm.org/D118038
Users outside of the clang repo may use different googletest versions. So, it's
better not to depend on llvm's googletest. This patch removes the dependency by
having `checkDataflow` return an `llvm::Error` instead of calling googletest's
`FAIL` or `ASSERT...` macros.
Differential Revision: https://reviews.llvm.org/D117304
This is part of the implementation of the dataflow analysis framework.
See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev.
Reviewed By: xazax.hun, gribozavr2
Differential Revision: https://reviews.llvm.org/D116022