Skip to content

Commit 9603871

Browse files
johnniwinthercommit-bot@chromium.org
authored and
commit-bot@chromium.org
committed
[cfe] Report error on 'new' used invalidly as selector
Part of #46232 Closes #47075 Change-Id: I6aece2236d6f45ec50bda3622b133c16761dd990 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215764 Reviewed-by: Chloe Stefantsova <dmitryas@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
1 parent c52a426 commit 9603871

23 files changed

+2110
-51
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7456,6 +7456,13 @@ const MessageCode messageNeverValueWarning = const MessageCode(
74567456
problemMessage:
74577457
r"""The expression can not result in a value with sound null safety because the expression type is `Never`.""");
74587458

7459+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7460+
const Code<Null> codeNewAsSelector = messageNewAsSelector;
7461+
7462+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7463+
const MessageCode messageNewAsSelector = const MessageCode("NewAsSelector",
7464+
problemMessage: r"""'new' can only be used as a constructor reference.""");
7465+
74597466
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
74607467
const Template<
74617468
Message Function(Token token)> templateNoFormals = const Template<

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

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -220,20 +220,21 @@ abstract class Generator {
220220
{bool isTypeArgumentsInForest = false});
221221

222222
Expression_Generator buildSelectorAccess(
223-
Selector send, int operatorOffset, bool isNullAware) {
224-
if (send is InvocationSelector) {
225-
return _helper.buildMethodInvocation(buildSimpleRead(), send.name,
226-
send.arguments, offsetForToken(send.token),
223+
Selector selector, int operatorOffset, bool isNullAware) {
224+
selector.reportNewAsSelector();
225+
if (selector is InvocationSelector) {
226+
return _helper.buildMethodInvocation(buildSimpleRead(), selector.name,
227+
selector.arguments, offsetForToken(selector.token),
227228
isNullAware: isNullAware,
228-
isConstantExpression: send.isPotentiallyConstant);
229+
isConstantExpression: selector.isPotentiallyConstant);
229230
} else {
230231
if (_helper.constantContext != ConstantContext.none &&
231-
send.name != lengthName) {
232+
selector.name != lengthName) {
232233
_helper.addProblem(
233234
messageNotAConstantExpression, fileOffset, token.length);
234235
}
235-
return PropertyAccessGenerator.make(
236-
_helper, send.token, buildSimpleRead(), send.name, isNullAware);
236+
return PropertyAccessGenerator.make(_helper, selector.token,
237+
buildSimpleRead(), selector.name, isNullAware);
237238
}
238239
}
239240

@@ -2642,17 +2643,18 @@ class ExplicitExtensionAccessGenerator extends Generator {
26422643

26432644
@override
26442645
Expression_Generator buildSelectorAccess(
2645-
Selector send, int operatorOffset, bool isNullAware) {
2646+
Selector selector, int operatorOffset, bool isNullAware) {
2647+
selector.reportNewAsSelector();
26462648
if (_helper.constantContext != ConstantContext.none) {
26472649
_helper.addProblem(
26482650
messageNotAConstantExpression, fileOffset, token.length);
26492651
}
2650-
Generator generator =
2651-
_createInstanceAccess(send.token, send.name, isNullAware: isNullAware);
2652-
if (send.arguments != null) {
2653-
return generator.doInvocation(offsetForToken(send.token),
2654-
send.typeArguments, send.arguments! as ArgumentsImpl,
2655-
isTypeArgumentsInForest: send.isTypeArgumentsInForest);
2652+
Generator generator = _createInstanceAccess(selector.token, selector.name,
2653+
isNullAware: isNullAware);
2654+
if (selector.arguments != null) {
2655+
return generator.doInvocation(offsetForToken(selector.token),
2656+
selector.typeArguments, selector.arguments! as ArgumentsImpl,
2657+
isTypeArgumentsInForest: selector.isTypeArgumentsInForest);
26562658
} else {
26572659
return generator;
26582660
}
@@ -2878,9 +2880,10 @@ class DeferredAccessGenerator extends Generator {
28782880

28792881
@override
28802882
Expression_Generator buildSelectorAccess(
2881-
Selector send, int operatorOffset, bool isNullAware) {
2882-
Object propertyAccess =
2883-
suffixGenerator.buildSelectorAccess(send, operatorOffset, isNullAware);
2883+
Selector selector, int operatorOffset, bool isNullAware) {
2884+
selector.reportNewAsSelector();
2885+
Object propertyAccess = suffixGenerator.buildSelectorAccess(
2886+
selector, operatorOffset, isNullAware);
28842887
if (propertyAccess is Generator) {
28852888
return new DeferredAccessGenerator(
28862889
_helper, token, prefixGenerator, propertyAccess);
@@ -4059,14 +4062,15 @@ class PrefixUseGenerator extends Generator {
40594062

40604063
@override
40614064
Expression_Generator buildSelectorAccess(
4062-
Selector send, int operatorOffset, bool isNullAware) {
4063-
assert(send.name.text == send.token.lexeme,
4064-
"'${send.name.text}' != ${send.token.lexeme}");
4065-
Object result = qualifiedLookup(send.token);
4066-
if (send is InvocationSelector) {
4067-
result = _helper.finishSend(result, send.typeArguments,
4068-
send.arguments as ArgumentsImpl, send.fileOffset,
4069-
isTypeArgumentsInForest: send.isTypeArgumentsInForest);
4065+
Selector selector, int operatorOffset, bool isNullAware) {
4066+
assert(selector.name.text == selector.token.lexeme,
4067+
"'${selector.name.text}' != ${selector.token.lexeme}");
4068+
selector.reportNewAsSelector();
4069+
Object result = qualifiedLookup(selector.token);
4070+
if (selector is InvocationSelector) {
4071+
result = _helper.finishSend(result, selector.typeArguments,
4072+
selector.arguments as ArgumentsImpl, selector.fileOffset,
4073+
isTypeArgumentsInForest: selector.isTypeArgumentsInForest);
40704074
}
40714075
if (isNullAware) {
40724076
result = _helper.wrapInLocatedProblem(
@@ -4442,21 +4446,22 @@ class ThisAccessGenerator extends Generator {
44424446

44434447
@override
44444448
Expression_Generator buildSelectorAccess(
4445-
Selector send, int operatorOffset, bool isNullAware) {
4446-
Name name = send.name;
4447-
Arguments? arguments = send.arguments;
4448-
int offset = offsetForToken(send.token);
4449-
if (isInitializer && send is InvocationSelector) {
4449+
Selector selector, int operatorOffset, bool isNullAware) {
4450+
Name name = selector.name;
4451+
Arguments? arguments = selector.arguments;
4452+
int offset = offsetForToken(selector.token);
4453+
if (isInitializer && selector is InvocationSelector) {
44504454
if (isNullAware) {
44514455
_helper.addProblem(
44524456
messageInvalidUseOfNullAwareAccess, operatorOffset, 2);
44534457
}
44544458
return buildConstructorInitializer(offset, name, arguments!);
44554459
}
4460+
selector.reportNewAsSelector();
44564461
if (inFieldInitializer && !inLateFieldInitializer && !isInitializer) {
44574462
return buildFieldInitializerError(null);
44584463
}
4459-
if (send is InvocationSelector) {
4464+
if (selector is InvocationSelector) {
44604465
// Notice that 'this' or 'super' can't be null. So we can ignore the
44614466
// value of [isNullAware].
44624467
if (isNullAware) {
@@ -4465,8 +4470,8 @@ class ThisAccessGenerator extends Generator {
44654470
return _helper.buildMethodInvocation(
44664471
_forest.createThisExpression(fileOffset),
44674472
name,
4468-
send.arguments,
4469-
offsetForToken(send.token),
4473+
selector.arguments,
4474+
offsetForToken(selector.token),
44704475
isSuper: isSuper);
44714476
} else {
44724477
if (isSuper) {
@@ -4476,15 +4481,15 @@ class ThisAccessGenerator extends Generator {
44764481
return new SuperPropertyAccessGenerator(
44774482
_helper,
44784483
// TODO(ahe): This is not the 'super' token.
4479-
send.token,
4484+
selector.token,
44804485
name,
44814486
getter,
44824487
setter);
44834488
} else {
44844489
return new ThisPropertyAccessGenerator(
44854490
_helper,
44864491
// TODO(ahe): This is not the 'this' token.
4487-
send.token,
4492+
selector.token,
44884493
name,
44894494
thisOffset: fileOffset,
44904495
isNullAware: isNullAware);
@@ -4751,20 +4756,21 @@ class ParenthesizedExpressionGenerator extends AbstractReadOnlyAccessGenerator {
47514756

47524757
@override
47534758
Expression_Generator buildSelectorAccess(
4754-
Selector send, int operatorOffset, bool isNullAware) {
4755-
if (send is InvocationSelector) {
4756-
return _helper.buildMethodInvocation(
4757-
_createRead(), send.name, send.arguments, offsetForToken(send.token),
4759+
Selector selector, int operatorOffset, bool isNullAware) {
4760+
selector.reportNewAsSelector();
4761+
if (selector is InvocationSelector) {
4762+
return _helper.buildMethodInvocation(_createRead(), selector.name,
4763+
selector.arguments, offsetForToken(selector.token),
47584764
isNullAware: isNullAware,
4759-
isConstantExpression: send.isPotentiallyConstant);
4765+
isConstantExpression: selector.isPotentiallyConstant);
47604766
} else {
47614767
if (_helper.constantContext != ConstantContext.none &&
4762-
send.name != lengthName) {
4768+
selector.name != lengthName) {
47634769
_helper.addProblem(
47644770
messageNotAConstantExpression, fileOffset, token.length);
47654771
}
47664772
return PropertyAccessGenerator.make(
4767-
_helper, send.token, _createRead(), send.name, isNullAware);
4773+
_helper, selector.token, _createRead(), selector.name, isNullAware);
47684774
}
47694775
}
47704776
}
@@ -4822,6 +4828,14 @@ abstract class Selector {
48224828

48234829
void printOn(StringSink sink);
48244830

4831+
/// Report an error if the selector name "new" when the constructor-tearoff
4832+
/// feature is enabled.
4833+
void reportNewAsSelector() {
4834+
if (name.text == 'new' && _helper.enableConstructorTearOffsInLibrary) {
4835+
_helper.addProblem(messageNewAsSelector, fileOffset, name.text.length);
4836+
}
4837+
}
4838+
48254839
@override
48264840
String toString() {
48274841
StringBuffer buffer = new StringBuffer();
@@ -4875,6 +4889,7 @@ class InvocationSelector extends Selector {
48754889
if (receiver is Generator) {
48764890
return receiver.buildSelectorAccess(this, operatorOffset, isNullAware);
48774891
}
4892+
reportNewAsSelector();
48784893
return _helper.buildMethodInvocation(
48794894
_helper.toValue(receiver), name, arguments, fileOffset,
48804895
isNullAware: isNullAware);
@@ -4917,6 +4932,7 @@ class PropertySelector extends Selector {
49174932
if (receiver is Generator) {
49184933
return receiver.buildSelectorAccess(this, operatorOffset, isNullAware);
49194934
}
4935+
reportNewAsSelector();
49204936
return PropertyAccessGenerator.make(
49214937
_helper, token, _helper.toValue(receiver), name, isNullAware);
49224938
}

pkg/front_end/messages.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ NeverValueError/analyzerCode: Fail
608608
NeverValueError/example: Fail
609609
NeverValueWarning/analyzerCode: Fail
610610
NeverValueWarning/example: Fail
611+
NewAsSelector/analyzerCode: Fail
611612
NoFormals/example: Fail
612613
NoSuchNamedParameter/example: Fail
613614
NoUnnamedConstructorInObject/analyzerCode: Fail

pkg/front_end/messages.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5409,3 +5409,9 @@ ConstructorTearOffWithTypeArguments:
54095409
experiments: constructor-tearoffs
54105410
script:
54115411
- "class C<X> { C.foo(); } bar() { C.foo<int>; }"
5412+
5413+
NewAsSelector:
5414+
problemMessage: "'new' can only be used as a constructor reference."
5415+
experiments: constructor-tearoffs
5416+
script: |
5417+
method(dynamic d) => d.new;

pkg/front_end/testcases/constructor_tearoffs/issue47075.dart.strong.expect

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ library /*isNonNullableByDefault*/;
77
// int new = 42;
88
// ^^^
99
//
10+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:10:11: Error: 'new' can only be used as a constructor reference.
11+
// new C().new is int;
12+
// ^^^
13+
//
14+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:12:7: Error: 'new' can only be used as a constructor reference.
15+
// foo.new;
16+
// ^^^
17+
//
18+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:13:7: Error: 'new' can only be used as a constructor reference.
19+
// foo.new();
20+
// ^^^
21+
//
1022
import self as self;
1123
import "dart:core" as core;
1224

pkg/front_end/testcases/constructor_tearoffs/issue47075.dart.strong.transformed.expect

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ library /*isNonNullableByDefault*/;
77
// int new = 42;
88
// ^^^
99
//
10+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:10:11: Error: 'new' can only be used as a constructor reference.
11+
// new C().new is int;
12+
// ^^^
13+
//
14+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:12:7: Error: 'new' can only be used as a constructor reference.
15+
// foo.new;
16+
// ^^^
17+
//
18+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:13:7: Error: 'new' can only be used as a constructor reference.
19+
// foo.new();
20+
// ^^^
21+
//
1022
import self as self;
1123
import "dart:core" as core;
1224

pkg/front_end/testcases/constructor_tearoffs/issue47075.dart.weak.expect

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ library /*isNonNullableByDefault*/;
77
// int new = 42;
88
// ^^^
99
//
10+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:10:11: Error: 'new' can only be used as a constructor reference.
11+
// new C().new is int;
12+
// ^^^
13+
//
14+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:12:7: Error: 'new' can only be used as a constructor reference.
15+
// foo.new;
16+
// ^^^
17+
//
18+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:13:7: Error: 'new' can only be used as a constructor reference.
19+
// foo.new();
20+
// ^^^
21+
//
1022
import self as self;
1123
import "dart:core" as core;
1224

pkg/front_end/testcases/constructor_tearoffs/issue47075.dart.weak.transformed.expect

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ library /*isNonNullableByDefault*/;
77
// int new = 42;
88
// ^^^
99
//
10+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:10:11: Error: 'new' can only be used as a constructor reference.
11+
// new C().new is int;
12+
// ^^^
13+
//
14+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:12:7: Error: 'new' can only be used as a constructor reference.
15+
// foo.new;
16+
// ^^^
17+
//
18+
// pkg/front_end/testcases/constructor_tearoffs/issue47075.dart:13:7: Error: 'new' can only be used as a constructor reference.
19+
// foo.new();
20+
// ^^^
21+
//
1022
import self as self;
1123
import "dart:core" as core;
1224

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright (c) 2021, 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+
import 'new_as_selector.dart' as prefix1;
6+
import 'new_as_selector.dart' deferred as prefix2 hide E;
7+
8+
int new = 87; // error
9+
10+
C c = C();
11+
12+
class Super {}
13+
14+
class C extends Super {
15+
int new = 42; // error
16+
17+
C() : super.new(); // ok
18+
C.named() : this.new(); // ok
19+
20+
method() {
21+
this.new; // error
22+
this.new(); // error
23+
this.new<int>(); // error
24+
this.new = 87; // error
25+
}
26+
}
27+
28+
extension E on int {
29+
external int new; // error
30+
31+
call<T>() {}
32+
}
33+
34+
method(dynamic d) => d.new; // error
35+
36+
test() {
37+
new C().new; // error
38+
new C().new(); // error
39+
new C().new = 87; // error
40+
C c = C();
41+
c.new; // error
42+
c.new = 87; // error
43+
dynamic foo;
44+
foo.new; // error
45+
foo.new(); // error
46+
foo.new<int>(); // error
47+
foo?.new; // error
48+
foo?.new(); // error
49+
foo?.new<int>(); // error
50+
foo..new; // error
51+
foo..new(); // error
52+
foo..new<int>(); // error
53+
(foo).new; // error
54+
(foo).new(); // error
55+
(foo).new<int>(); // error
56+
prefix1.new; // error
57+
prefix1.new(); // error
58+
prefix1.new<int>(); // error
59+
prefix2.c.new; // error
60+
prefix2.c.new(); // error
61+
prefix2.c.new<int>(); // error
62+
E(0).new; // error
63+
E(0).new(); // error
64+
E(0).new<int>(); // error
65+
unresolved.new; // error
66+
unresolved.new(); // error
67+
unresolved.new<int>(); // error
68+
}
69+
70+
main() {
71+
C.new; // ok
72+
C.new(); // ok
73+
}

0 commit comments

Comments
 (0)