Skip to content

Commit 9f8aaf6

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Issue an error if a prefix in a type name is shadowed by a local variable.
See #42620. Change-Id: Ifd18c939082935390df0c2aa0bd724cf6f76c27c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153705 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent fe9596b commit 9f8aaf6

File tree

10 files changed

+124
-2
lines changed

10 files changed

+124
-2
lines changed

pkg/analyzer/lib/error/error.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ const List<ErrorCode> errorCodeValues = [
286286
CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY,
287287
CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
288288
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
289+
CompileTimeErrorCode.PREFIX_SHADOWED_BY_LOCAL_DECLARATION,
289290
CompileTimeErrorCode.PRIVATE_COLLISION_IN_MIXIN_APPLICATION,
290291
CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER,
291292
CompileTimeErrorCode.PRIVATE_SETTER,

pkg/analyzer/lib/src/error/codes.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5589,6 +5589,24 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
55895589
"prefix, or renaming the prefix.",
55905590
hasPublishedDocs: true);
55915591

5592+
/**
5593+
* From the `Static Types` section of the spec:
5594+
*
5595+
* A type T is malformed if:
5596+
* - T has the form id or the form prefix.id, and in the enclosing lexical
5597+
* scope, the name id (respectively prefix.id) does not denote a type.
5598+
*
5599+
* In particular, this means that if an import prefix is shadowed by a local
5600+
* declaration, it is an error to try to use it as a prefix for a type name.
5601+
*/
5602+
static const CompileTimeErrorCode PREFIX_SHADOWED_BY_LOCAL_DECLARATION =
5603+
CompileTimeErrorCode(
5604+
'PREFIX_SHADOWED_BY_LOCAL_DECLARATION',
5605+
"The prefix '{0}' can't be used here because it is shadowed by a "
5606+
"local declaration.",
5607+
correction:
5608+
"Try renaming either the prefix or the local declaration.");
5609+
55925610
/**
55935611
* It is an error for a mixin to add a private name that conflicts with a
55945612
* private name added by a superclass or another mixin.

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
11551155
@override
11561156
void visitTypeName(TypeName node) {
11571157
_typeArgumentsVerifier.checkTypeName(node);
1158+
_checkForTypeNamePrefixShadowedByLocal(node);
11581159
super.visitTypeName(node);
11591160
}
11601161

@@ -4088,6 +4089,21 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
40884089
}
40894090
}
40904091

4092+
void _checkForTypeNamePrefixShadowedByLocal(TypeName node) {
4093+
var name = node.name;
4094+
if (name is PrefixedIdentifier &&
4095+
name.staticElement is TypeDefiningElement) {
4096+
var prefix = name.prefix;
4097+
var prefixElement = prefix.staticElement;
4098+
if (prefixElement != null && prefixElement is! PrefixElement) {
4099+
_errorReporter.reportErrorForNode(
4100+
CompileTimeErrorCode.PREFIX_SHADOWED_BY_LOCAL_DECLARATION,
4101+
prefix,
4102+
[prefix.name]);
4103+
}
4104+
}
4105+
}
4106+
40914107
/// Check that none of the type [parameters] references itself in its bound.
40924108
///
40934109
/// See [StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND].

pkg/analyzer/test/src/diagnostics/new_with_non_type_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ void f() {
5151
]);
5252
}
5353

54+
test_malformed_constructor_call() async {
55+
await assertErrorsInCode('''
56+
class C {
57+
C.x();
58+
}
59+
main() {
60+
new C.x.y();
61+
}
62+
''', [
63+
error(StaticWarningCode.NEW_WITH_NON_TYPE, 36, 3),
64+
]);
65+
}
66+
5467
test_typeParameter() async {
5568
await assertErrorsInCode('''
5669
void foo<T>() {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) 2020, 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 'package:analyzer/src/error/codes.dart';
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import '../dart/resolution/driver_resolution.dart';
9+
10+
main() {
11+
defineReflectiveSuite(() {
12+
defineReflectiveTests(PrefixShadowedByLocalDeclarationTest);
13+
});
14+
}
15+
16+
@reflectiveTest
17+
class PrefixShadowedByLocalDeclarationTest extends DriverResolutionTest {
18+
test_function_return_type_not_shadowed_by_parameter() async {
19+
await assertNoErrorsInCode('''
20+
import 'dart:async' as a;
21+
a.Future f(int a) {
22+
return null;
23+
}
24+
''');
25+
}
26+
27+
test_local_variable_type_inside_function_with_shadowing_parameter() async {
28+
await assertErrorsInCode('''
29+
import 'dart:async' as a;
30+
f(int a) {
31+
a.Future x = null;
32+
return x;
33+
}
34+
''', [
35+
error(HintCode.UNUSED_IMPORT, 7, 12),
36+
error(CompileTimeErrorCode.PREFIX_SHADOWED_BY_LOCAL_DECLARATION, 39, 1),
37+
]);
38+
}
39+
40+
test_local_variable_type_inside_function_with_shadowing_variable_after() async {
41+
await assertErrorsInCode('''
42+
import 'dart:async' as a;
43+
f() {
44+
a.Future x = null;
45+
int a = 0;
46+
return [x, a];
47+
}
48+
''', [
49+
error(HintCode.UNUSED_IMPORT, 7, 12),
50+
error(CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, 34, 1,
51+
contextMessages: [message('/test/lib/test.dart', 59, 1)]),
52+
error(CompileTimeErrorCode.PREFIX_SHADOWED_BY_LOCAL_DECLARATION, 34, 1),
53+
]);
54+
}
55+
56+
test_local_variable_type_inside_function_with_shadowing_variable_before() async {
57+
await assertErrorsInCode('''
58+
import 'dart:async' as a;
59+
f() {
60+
int a = 0;
61+
a.Future x = null;
62+
return [x, a];
63+
}
64+
''', [
65+
error(HintCode.UNUSED_IMPORT, 7, 12),
66+
error(CompileTimeErrorCode.PREFIX_SHADOWED_BY_LOCAL_DECLARATION, 47, 1),
67+
]);
68+
}
69+
}

pkg/analyzer/test/src/diagnostics/test_all.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ import 'prefix_collides_with_top_level_member_test.dart'
394394
as prefix_collides_with_top_level_member;
395395
import 'prefix_identifier_not_followed_by_dot_test.dart'
396396
as prefix_identifier_not_followed_by_dot;
397+
import 'prefix_shadowed_by_local_declaration_test.dart'
398+
as prefix_shadowed_by_local_declaration;
397399
import 'private_collision_in_mixin_application_test.dart'
398400
as private_collision_in_mixin_application;
399401
import 'private_optional_parameter_test.dart' as private_optional_parameter;
@@ -804,6 +806,7 @@ main() {
804806
part_of_non_part.main();
805807
prefix_collides_with_top_level_member.main();
806808
prefix_identifier_not_followed_by_dot.main();
809+
prefix_shadowed_by_local_declaration.main();
807810
private_collision_in_mixin_application.main();
808811
private_optional_parameter.main();
809812
private_setter.main();

tests/language/class/variable_shadow_class_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ main() {
1717
var i = new Test.named(10);
1818
// ^^^^^^^^^^
1919
// [analyzer] STATIC_WARNING.CREATION_WITH_NON_TYPE
20-
// ^^^^
2120
// [cfe] Method not found: 'Test.named'.
2221
Expect.equals(10, i.field);
2322
}

tests/language/prefix/shadow_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import "../library10.dart" as lib10;
1111
class P<T> {
1212
test() {
1313
new T.Library10(10);
14+
// ^
15+
// [analyzer] COMPILE_TIME_ERROR.PREFIX_SHADOWED_BY_LOCAL_DECLARATION
1416
// ^
1517
// [cfe] Method not found: 'T.Library10'.
1618
}

tests/language_2/class/variable_shadow_class_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ main() {
1717
var i = new Test.named(10);
1818
// ^^^^^^^^^^
1919
// [analyzer] STATIC_WARNING.CREATION_WITH_NON_TYPE
20-
// ^^^^
2120
// [cfe] Method not found: 'Test.named'.
2221
Expect.equals(10, i.field);
2322
}

tests/language_2/prefix/shadow_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import "../library10.dart" as lib10;
1111
class P<T> {
1212
test() {
1313
new T.Library10(10);
14+
// ^
15+
// [analyzer] COMPILE_TIME_ERROR.PREFIX_SHADOWED_BY_LOCAL_DECLARATION
1416
// ^
1517
// [cfe] Method not found: 'T.Library10'.
1618
}

0 commit comments

Comments
 (0)