Skip to content

Commit

Permalink
Flow analysis is not available outside of function bodies and initial…
Browse files Browse the repository at this point in the history
…izers.

This fixes a group of crashes during fuzz testing.

FAILURE: z({=?[
[NoSuchMethodError: The getter 'flow' was called on null.
Receiver: null
Tried calling: flow
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
flutter#1      ResolverVisitor.startNullAwareIndexExpression (package:analyzer/src/generated/resolver.dart:743:21)
flutter#2      ResolverVisitor.visitIndexExpression (package:analyzer/src/generated/resolver.dart:1552:5)
flutter#3      IndexExpressionImpl.accept (package:analyzer/src/dart/ast/ast.dart:5993:49)
flutter#4      AstResolver.resolve (package:analyzer/src/summary2/ast_resolver.dart:85:10)
#5      DefaultValueResolver._parameter (package:analyzer/src/summary2/default_value_resolver.dart:107:18)
flutter#6      DefaultValueResolver._parameters (package:analyzer/src/summary2/default_value_resolver.dart:121:7)
flutter#7      DefaultValueResolver._function (package:analyzer/src/summary2/default_value_resolver.dart:89:5)
flutter#8      DefaultValueResolver.resolve (package:analyzer/src/summary2/default_value_resolver.dart:47:9)
flutter#9      LibraryBuilder.resolveDefaultValues (package:analyzer/src/summary2/library_builder.dart:313:43)
flutter#10     Linker._resolveDefaultValues (package:analyzer/src/summary2/link.dart:230:15)
flutter#11     Linker._buildOutlines (package:analyzer/src/summary2/link.dart:89:5)
flutter#12     Linker.link (package:analyzer/src/summary2/link.dart:69:5)
flutter#13     link (package:analyzer/src/summary2/link.dart:33:10)


Change-Id: I6145a1f728d432be8d0fa55235858e091030461c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175187
Reviewed-by: Brian Wilkerson <[email protected]>
Commit-Queue: Konstantin Shcheglov <[email protected]>
  • Loading branch information
scheglov authored and [email protected] committed Dec 6, 2020
1 parent ce74d6e commit c9854e3
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 4 deletions.
8 changes: 4 additions & 4 deletions pkg/analyzer/lib/src/generated/resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ class ResolverVisitor extends ScopedVisitor {

void startNullAwareIndexExpression(IndexExpression node) {
if (_migratableAstInfoProvider.isIndexExpressionNullAware(node) &&
_isNonNullableByDefault) {
_flowAnalysis != null) {
_flowAnalysis.flow.nullAwareAccess_rightBegin(
node.target, node.realTarget.staticType ?? typeProvider.dynamicType);
_unfinishedNullShorts.add(node.nullShortingTermination);
Expand All @@ -750,7 +750,7 @@ class ResolverVisitor extends ScopedVisitor {
PropertyAccess node,
) {
if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
_isNonNullableByDefault) {
_flowAnalysis != null) {
var target = node.target;
if (target is SimpleIdentifier && target.staticElement is ClassElement) {
// `?.` to access static methods is equivalent to `.`, so do nothing.
Expand Down Expand Up @@ -948,7 +948,7 @@ class ResolverVisitor extends ScopedVisitor {
InferenceContext.setTypeFromNode(node.target, node);
node.target.accept(this);

if (node.isNullAware && _isNonNullableByDefault) {
if (node.isNullAware && _flowAnalysis != null) {
_flowAnalysis.flow.nullAwareAccess_rightBegin(
node.target, node.target.staticType ?? typeProvider.dynamicType);
_unfinishedNullShorts.add(node.nullShortingTermination);
Expand Down Expand Up @@ -1652,7 +1652,7 @@ class ResolverVisitor extends ScopedVisitor {
target?.accept(this);

if (_migratableAstInfoProvider.isMethodInvocationNullAware(node) &&
_isNonNullableByDefault) {
_flowAnalysis != null) {
if (target is SimpleIdentifier && target.staticElement is ClassElement) {
// `?.` to access static methods is equivalent to `.`, so do nothing.
} else {
Expand Down
13 changes: 13 additions & 0 deletions pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ main() {

@reflectiveTest
class IndexExpressionTest extends PubPackageResolutionTest {
test_invalid_inDefaultValue_nullAware() async {
await assertInvalidTestCode(r'''
void f({a = b?[0]}) {}
''');

assertIndexExpression(
findNode.index('[0]'),
readElement: null,
writeElement: null,
type: 'dynamic',
);
}

test_read() async {
await assertNoErrorsInCode(r'''
class A {
Expand Down
14 changes: 14 additions & 0 deletions pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,20 @@ class B extends A {
assertSuperExpression(invocation.target);
}

test_invalid_inDefaultValue_nullAware() async {
await assertInvalidTestCode('''
void f({a = b?.foo()}) {}
''');

assertMethodInvocation2(
findNode.methodInvocation('?.foo()'),
element: null,
typeArgumentTypes: [],
invokeType: 'dynamic',
type: 'dynamic',
);
}

test_namedArgument() async {
var question = typeToStringWithNullability ? '?' : '';
await assertNoErrorsInCode('''
Expand Down
24 changes: 24 additions & 0 deletions pkg/analyzer/test/src/dart/resolution/property_access_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,30 @@ void f() {
}
}

test_invalid_inDefaultValue_nullAware() async {
await assertInvalidTestCode('''
void f({a = b?.foo}) {}
''');

assertPropertyAccess2(
findNode.propertyAccess('?.foo'),
element: null,
type: 'dynamic',
);
}

test_invalid_inDefaultValue_nullAware_cascade() async {
await assertInvalidTestCode('''
void f({a = b?..foo}) {}
''');

assertPropertyAccess2(
findNode.propertyAccess('?..foo'),
element: null,
type: 'dynamic',
);
}

test_ofExtension_read() async {
await assertNoErrorsInCode('''
class A {}
Expand Down
7 changes: 7 additions & 0 deletions pkg/analyzer/test/src/dart/resolution/resolution.dart
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,13 @@ mixin ResolutionTest implements ResourceProviderMixin {
expectedPrefix: expectedPrefix);
}

/// Resolve the [code], and ensure that it can be resolved without a crash,
/// and is invalid, i.e. produces a diagnostic.
Future<void> assertInvalidTestCode(String code) async {
await resolveTestCode(code);
assertHasTestErrors();
}

void assertInvokeType(Expression node, String expected) {
DartType actual;
if (node is BinaryExpression) {
Expand Down

0 comments on commit c9854e3

Please sign in to comment.