Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 69b9af2

Browse files
johnniwintherCommit Bot
authored and
Commit Bot
committedMay 31, 2022
[cfe] Handle extensions in Extension?.member check
Closes #49127 Change-Id: I26ce537dbed908789333f4aa6baa6b8487e5e993 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246447 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
1 parent 40ad7ae commit 69b9af2

13 files changed

+170
-12
lines changed
 

‎pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

+23
Original file line numberDiff line numberDiff line change
@@ -3845,6 +3845,29 @@ const MessageCode messageExtensionDeclaresInstanceField = const MessageCode(
38453845
correctionMessage:
38463846
r"""Try removing the field declaration or making it a static field""");
38473847

3848+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3849+
const Template<Message Function(String name)>
3850+
templateExtensionInNullAwareReceiver =
3851+
const Template<Message Function(String name)>(
3852+
problemMessageTemplate: r"""The extension '#name' cannot be null.""",
3853+
correctionMessageTemplate: r"""Try replacing '?.' with '.'""",
3854+
withArguments: _withArgumentsExtensionInNullAwareReceiver);
3855+
3856+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3857+
const Code<Message Function(String name)> codeExtensionInNullAwareReceiver =
3858+
const Code<Message Function(String name)>("ExtensionInNullAwareReceiver",
3859+
severity: Severity.warning);
3860+
3861+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3862+
Message _withArgumentsExtensionInNullAwareReceiver(String name) {
3863+
if (name.isEmpty) throw 'No name provided';
3864+
name = demangleMixinApplicationName(name);
3865+
return new Message(codeExtensionInNullAwareReceiver,
3866+
problemMessage: """The extension '${name}' cannot be null.""",
3867+
correctionMessage: """Try replacing '?.' with '.'""",
3868+
arguments: {'name': name});
3869+
}
3870+
38483871
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
38493872
const Template<Message Function(String name)>
38503873
templateExtensionMemberConflictsWithObjectMember =

‎pkg/front_end/lib/src/fasta/kernel/body_builder.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -2947,7 +2947,7 @@ class BodyBuilder extends StackListenerImpl
29472947
assert(declaration.isStatic || declaration.isTopLevel);
29482948
MemberBuilder memberBuilder = declaration as MemberBuilder;
29492949
return new StaticAccessGenerator(
2950-
this, token, name, memberBuilder.member, null);
2950+
this, token, name, memberBuilder.parent, memberBuilder.member, null);
29512951
} else if (declaration is PrefixBuilder) {
29522952
assert(prefix == null);
29532953
return new PrefixUseGenerator(this, token, declaration);

‎pkg/front_end/lib/src/fasta/kernel/expression_generator.dart

+42-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import '../builder/class_builder.dart';
2020
import '../builder/declaration_builder.dart';
2121
import '../builder/extension_builder.dart';
2222
import '../builder/invalid_type_declaration_builder.dart';
23+
import '../builder/library_builder.dart';
2324
import '../builder/member_builder.dart';
2425
import '../builder/named_type_builder.dart';
2526
import '../builder/nullability_builder.dart';
@@ -1386,12 +1387,18 @@ class StaticAccessGenerator extends Generator {
13861387
final int? typeOffset;
13871388
final bool isNullAware;
13881389

1390+
/// The builder for the parent of [readTarget] and [writeTarget]. This is
1391+
/// either the builder for the enclosing library, class, or extension.
1392+
final Builder? parentBuilder;
1393+
13891394
StaticAccessGenerator(ExpressionGeneratorHelper helper, Token token,
1390-
this.targetName, this.readTarget, this.writeTarget,
1395+
this.targetName, this.parentBuilder, this.readTarget, this.writeTarget,
13911396
{this.typeOffset, this.isNullAware: false})
13921397
// ignore: unnecessary_null_comparison
13931398
: assert(targetName != null),
13941399
assert(readTarget != null || writeTarget != null),
1400+
assert(parentBuilder is DeclarationBuilder ||
1401+
parentBuilder is LibraryBuilder),
13951402
super(helper, token);
13961403

13971404
factory StaticAccessGenerator.fromBuilder(
@@ -1402,19 +1409,44 @@ class StaticAccessGenerator extends Generator {
14021409
MemberBuilder? setterBuilder,
14031410
{int? typeOffset,
14041411
bool isNullAware: false}) {
1405-
return new StaticAccessGenerator(helper, token, targetName,
1406-
getterBuilder?.readTarget, setterBuilder?.writeTarget,
1407-
typeOffset: typeOffset, isNullAware: isNullAware);
1412+
// If both [getterBuilder] and [setterBuilder] exist, they must both be
1413+
// either top level (potentially from different libraries) or from the same
1414+
// class/extension.
1415+
assert(getterBuilder == null ||
1416+
setterBuilder == null ||
1417+
(getterBuilder.parent is LibraryBuilder &&
1418+
setterBuilder.parent is LibraryBuilder) ||
1419+
getterBuilder.parent == setterBuilder.parent);
1420+
return new StaticAccessGenerator(
1421+
helper,
1422+
token,
1423+
targetName,
1424+
getterBuilder?.parent ?? setterBuilder?.parent,
1425+
getterBuilder?.readTarget,
1426+
setterBuilder?.writeTarget,
1427+
typeOffset: typeOffset,
1428+
isNullAware: isNullAware);
14081429
}
14091430

14101431
void _reportNonNullableInNullAwareWarningIfNeeded() {
14111432
if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
1412-
String className = (readTarget ?? writeTarget)!.enclosingClass!.name;
1413-
_helper.libraryBuilder.addProblem(
1414-
templateClassInNullAwareReceiver.withArguments(className),
1415-
typeOffset ?? fileOffset,
1416-
typeOffset != null ? className.length : noLength,
1417-
_helper.uri);
1433+
DeclarationBuilder declarationBuilder =
1434+
parentBuilder as DeclarationBuilder;
1435+
if (declarationBuilder.isExtension) {
1436+
String extensionName = declarationBuilder.name;
1437+
_helper.libraryBuilder.addProblem(
1438+
templateExtensionInNullAwareReceiver.withArguments(extensionName),
1439+
typeOffset ?? fileOffset,
1440+
typeOffset != null ? extensionName.length : noLength,
1441+
_helper.uri);
1442+
} else {
1443+
String className = declarationBuilder.name;
1444+
_helper.libraryBuilder.addProblem(
1445+
templateClassInNullAwareReceiver.withArguments(className),
1446+
typeOffset ?? fileOffset,
1447+
typeOffset != null ? className.length : noLength,
1448+
_helper.uri);
1449+
}
14181450
}
14191451
}
14201452

‎pkg/front_end/messages.status

+1
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ ExtendsVoid/example: Fail # Feature not yet enabled by default.
314314
ExtensionDeclaresAbstractMember/example: Fail
315315
ExtensionDeclaresConstructor/example: Fail
316316
ExtensionDeclaresInstanceField/example: Fail
317+
ExtensionInNullAwareReceiver/analyzerCode: Fail
317318
ExtensionMemberConflictsWithObjectMember/analyzerCode: Fail
318319
ExternalConstructorWithBody/part_wrapped_script1: Fail
319320
ExternalConstructorWithBody/script1: Fail

‎pkg/front_end/messages.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -5223,6 +5223,19 @@ ClassInNullAwareReceiver:
52235223
C?.field;
52245224
}
52255225
5226+
ExtensionInNullAwareReceiver:
5227+
problemMessage: "The extension '#name' cannot be null."
5228+
correctionMessage: "Try replacing '?.' with '.'"
5229+
severity: WARNING
5230+
configuration: nnbd-strong
5231+
script: |
5232+
extension E on int {
5233+
static var field;
5234+
}
5235+
method() {
5236+
E?.field;
5237+
}
5238+
52265239
NonNullableNotAssignedError:
52275240
problemMessage: "Non-nullable variable '#name' must be assigned before it can be used."
52285241
configuration: nnbd-strong

‎pkg/front_end/test/fasta/generator_to_string_test.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ Future<void> main() async {
187187
"StaticAccessGenerator(offset: 4, targetName: foo,"
188188
" readTarget: $uri::myGetter,"
189189
" writeTarget: $uri::mySetter)",
190-
new StaticAccessGenerator(helper, token, 'foo', getter, setter));
190+
new StaticAccessGenerator(
191+
helper, token, 'foo', libraryBuilder, getter, setter));
191192
check(
192193
"LoadLibraryGenerator(offset: 4,"
193194
" builder: Instance of 'LoadLibraryBuilder')",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
extension E on int {
6+
static String s = "Lily was here";
7+
}
8+
9+
test() {
10+
E?.s;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extension E on int {
2+
static String s = "Lily was here";
3+
}
4+
5+
test() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extension E on int {
2+
static String s = "Lily was here";
3+
}
4+
5+
test() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/issue49127.dart:10:3: Warning: The extension 'E' cannot be null.
6+
// Try replacing '?.' with '.'
7+
// E?.s;
8+
// ^
9+
//
10+
import self as self;
11+
import "dart:core" as core;
12+
13+
extension E on core::int {
14+
static field s = self::E|s;
15+
}
16+
static field core::String E|s = "Lily was here";
17+
static method test() → dynamic {
18+
self::E|s;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/issue49127.dart:10:3: Warning: The extension 'E' cannot be null.
6+
// Try replacing '?.' with '.'
7+
// E?.s;
8+
// ^
9+
//
10+
import self as self;
11+
import "dart:core" as core;
12+
13+
extension E on core::int {
14+
static field s = self::E|s;
15+
}
16+
static field core::String E|s = "Lily was here";
17+
static method test() → dynamic {
18+
self::E|s;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
extension E on core::int {
6+
static field s = self::E|s;
7+
}
8+
static field core::String E|s;
9+
static method test() → dynamic
10+
;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/issue49127.dart:10:3: Warning: The extension 'E' cannot be null.
6+
// Try replacing '?.' with '.'
7+
// E?.s;
8+
// ^
9+
//
10+
import self as self;
11+
import "dart:core" as core;
12+
13+
extension E on core::int {
14+
static field s = self::E|s;
15+
}
16+
static field core::String E|s = "Lily was here";
17+
static method test() → dynamic {
18+
self::E|s;
19+
}

0 commit comments

Comments
 (0)
Failed to load comments.