Previously, if the migration tool encountered a Future expression with
a bad type (e.g. a Future<String?> where a Future<String> was needed),
it would "fix" the problem by introducing a cast. That is nearly
always the wrong thing to do; what we want to do is null check the
value that the future *completes* with.
This CL changes the migration tool so that it fixes this case by
appending `.then((value) => value!)` to the future expression.
Fixes#45472.
Bug: https://github.com/dart-lang/sdk/issues/45472
Change-Id: I7a35b54f673936e2e4b0f8f3a077ba8bf684b4eb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193700
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Well not quite all; migration_cli_test tests are a bit of a different
beast so I am going to tackle them separately. But this fixes over
1000 test failures, and should clean up test output for further
debugging of the flip CL.
Each test file needs to be in a package with a package config file
which spells out that it is _opted out_ of null safety.
Bug: https://github.com/dart-lang/sdk/issues/43883
Change-Id: I583f66119df57031fd80824111923e15e0f91782
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168900
Reviewed-by: Leaf Petersen <leafp@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
We produce a diagnostic under the following conditions:
- For compound assignments, if the type read from the LHS is nullable
(this is illegal after NNBD, and requires user intervention to fix).
- For compound assignments, if the type returned from the combiner is
not assignable to the LHS (this was required prior to NNBD, but it
is a stricter condition after migration, both because the LHS might
have a non-nullable type, and because implicit downcasts are not
allowed).
- For null-aware assignments, if the type read from the LHS is
non-nullable (this indicates that once strong mode is enabled, the
assignment will be dead code).
Bug: https://github.com/dart-lang/sdk/issues/38676
Change-Id: Icb242ba36437e38364ada069880831eb05e3a513
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/145664
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Previously, the spaces inserted by EditPlanner.addCommentPostfix
didn't carry the correct isInformative flag, so they would show up in
final migrated output.
Change-Id: I100ba88040ebff9ae5d406c49b242f6fb17ce7b8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/143887
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Previously we considered such code "dead", but it's not really dead
until Dart 3.0. Removing it changes weak mode semantics, and we don't
want to do that automatically.
Fixes#41231
Change-Id: I6a88f016b4f3fcba160dcb738558867219715cbb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/143941
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Previously, if we migrated a code snippet like this:
void f(int/*?*/ i) {
/*late*/ int j = i/*!*/;
}
the migration result would leave the hints and add the hinted text,
resulting in:
void f(int?/*?*/ i) {
/*late*/ late int j = i!/*!*/;
}
We now simply remove the `/*` and `*/` surrounding each hint (with
whitespace corrections as needed), to produce:
void f(int? i) {
late int j = i!;
}
Change-Id: Ic4e1216cb4693d73d71c9ab1a37d5cc15b8ef334
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/143460
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
There were two problems:
1. An info object isn't being properly passed to
NodeChangeForExpression, causing an assertion failure during the
FixAggregator stage. I've modified the assertion check so that it
happens earlier, during the FixBuilder, so that the exception is
caught by permissive mode logic and doesn't cause a hard crash.
I'll work on fixing the assertion in a follow-up CL.
2. The hack described in https://github.com/dart-lang/sdk/issues/40536
was causing a bogus assertion failure in
_PassThroughBuilderImpl._checkParenLogic. I've weakened the
assertion slightly so that for now, the hack won't cause trouble.
See the issue for more information about what's happening--this
should be cleaned up eventually but it's probably not high
priority.
Bug: https://github.com/dart-lang/sdk/issues/40533
Change-Id: Iee832fbd07e54b02d2c52f79a097ff9d973cda9a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134980
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
When adding a cast to a function expression like `() => null`, we need
to add parentheses, so that we produce `(() => null) as Type`, rather
than `() => null as Type`, which makes the cast appear to apply to the
function body expression.
Change-Id: Ib5ae93df5b840a832c10941e47fa092a4f764eea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134044
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
I realized that I can use the same "pass through" infrastructure for
these kinds of edits. This should help prepare for a future CL in
which we can aggregate together more complex changes, such as
introducing an "as" cast at the same time as changing `?.` into `.`.
Change-Id: Ie3af07a3563c44d62d4ed34d2a477eef6fae358f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133540
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Addresses a concern from code review
https://dart-review.googlesource.com/c/sdk/+/129302 that
EditPlanner.surround is difficult to use correctly, by adding wrapper
methods for several common use cases that are easier to use correctly.
Also adapts fix_aggregator.dart to make use of the new methods.
EditPlanner.surround remains in the public API for EditPlanner because
there are still use cases for it that aren't supported by the wrapper
methods. My hope is that the remaining use cases are either rare
enough or trivial enough that we don't need wrappers for them; if that
proves to be incorrect we can always add more wrapper methods.
Change-Id: Ia1d6cc8b10ffaedcf8803ff7c8f9460ada1d7c4e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132462
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This CL allows tests based on AnalysisContextCollectionImpl to enable
NNBD by modifying the analysis options and introduce a different
feature set, rather than having to add virtual filesystem files to
convince the analyzer that NNBD is enabled for the package. This is
more consistent with the way we enable NNBD for other unit tests that
invoke analysis more directly, and is less sensitive to details of how
the analyzer infers the current language version.
Currently used in the migration engine's EditPlanTest, which in a
subsequent CL will need this functionality to test editing source code
that contains null checks.
Change-Id: I352fd2d7f6ee71d42f02a31714e3395567967240
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132461
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Consider a generic AST structure like this:
A
/ \
B C
/ \
D E
Previously, if we wanted to build a "pass through" edit plan for A,
incorporating inner plans representing changes to be made to B, D, and
F, we would do the following: (1) pass each inner plan through the
_incorporateParent function, which might leave it unchanged or might
produce a plan targeted at the parent node, and then (2) ask each
inner plan for its set of changes, and produce a new plan for A
containing those changes.
The purpose of step (1) was to allow an edit plan to describe changes
that might affect the node above it. For example, changing an
expression might cause the parentheses surrounding it to become
unnecessary, so those parentheses would be removed (that's the case
that's currently implemented). Or, removing a list element from a
list might necessitate adjusting the comma before or after it, which
belongs to the parent node (this isn't implemented yet).
This had a design flaw: step (1) might produce overlapping changes.
For instance, calling _incorporateParent on the plans for D and E
might conceivably both plans for C, and those plans might try to make
overlapping (and thus incompatible) changes to node C.
It turns out that this isn't a problem for eliminating unnecessary
parens, because it's impossible for two edit plans to target two
different non-overlapping AST nodes whose parents are both the same
ParenthesizedExpression node (because a ParenthesizedExpression has
only one child). But it will be a problem for removing elements
lists, statements from blocks, declarations from classes, etc.
The new strategy is that we will bubble inner plans up the tree one
level at a time. In the example above, we would first combine the
inner plans for D and E into a pass through plan for C. Then we would
combine the plans for B and C into a plan for A. This is a bit more
work, but I believe it can be made efficient in typical use cases, and
it will avoid the problem described above because at each stage, all
the inner plans we combine will have the same parent, so it will be
tractable to figure out their interactions with each other.
Some vestiges of the old _incorporateParent approach still remain; I
plan to remove them in a follow-up CL.
Change-Id: I9ecbdb1549b949177ffc5d66447d4aede77e2dd9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/131400
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
The derived class, NodeProducingEditPlan, represents an edit plan
whose effect will be to transform the source AST node into another AST
node (e.g. replace an expression with one of its subexpressions). The
base class, EditPlan, will be able to represent more general kinds of
edit plans.
Future CLs will introduce edit plans that don't result in an AST node,
e.g. an edit plan that removes a source statement or a collection
element, or an edit plan that replaces one source statement or
collection element with several.
Change-Id: I01455f643b858c6500d864be679b12768029cffb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/130941
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
In upcoming CLs, I'm going to need access to the EditPlanner when
finalizing edit plans, and I'd rather do so by making finalize a
method on EditPlanner. Doing so now to make future code reviews
simpler.
Change-Id: I6182e2224b548b2919f0c8f454f558b72c17e5d5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/130926
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This factory class serves three purposes:
- In a future CL, it will contain fields to customize the global
behavior of the edit plans that are created (e.g. whether code
should be removed or commented out).
- In a future CL, it will contain a pointer to the original (text)
contents of the source file. This will allow edit plans to make
more sophisticated changes such as adjusting indentation.
- In a future CL, it will contain methods for creating common kinds of
"extract" edit plans such as null-checking an expression or making a
type nullable. (Currently the client must create these edit plans
using EditPlanner.extract, which has an error-prone API).
Change-Id: I87ac75b73003d0e7b416e3d2121eadb2770da5ed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/129802
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Initially this will be used in the NNBD migration engine to produce
migration output. Assuming it proves useful, in a future CL I'd like
to consider moving it to the analyzer_plugin package and using it as a
basic for all of the analysis server's refactorings.
Change-Id: I41ffc578ace3945fcfebb8eb824b6b5706dfba6c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/129302
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>