Skip to content

Commit

Permalink
Report EXTENSION_AS_EXPRESSION, set type fo dynamic.
Browse files Browse the repository at this point in the history
R=brianwilkerson@google.com

Bug: dart-lang/sdk#38203
Change-Id: Iee270b7b3fecbeaba202c304f21ef703a8567674
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/116055
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
  • Loading branch information
scheglov authored and commit-bot@chromium.org committed Sep 6, 2019
1 parent 254d077 commit ffd50c0
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/analyzer/lib/error/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const List<ErrorCode> errorCodeValues = const [
CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.EXTENDS_NON_CLASS,
CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
CompileTimeErrorCode.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE,
CompileTimeErrorCode.EXTENSION_DECLARES_MEMBER_OF_OBJECT,
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
Expand Down
9 changes: 9 additions & 0 deletions pkg/analyzer/lib/src/error/codes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,15 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
correction: "Try specifying a different superclass, or "
"removing the extends clause.");

/**
* Parameters:
* 0: the name of the extension
*/
static const CompileTimeErrorCode EXTENSION_AS_EXPRESSION =
const CompileTimeErrorCode('EXTENSION_AS_EXPRESSION',
"Extension '{0}' can't be used as an expression.",
correction: "Try replacing it with a valid expression.");

/**
* It is for an extension to define a static member and an instance member
* with the same base name.
Expand Down
36 changes: 36 additions & 0 deletions pkg/analyzer/lib/src/generated/static_type_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
Element staticElement = prefixedIdentifier.staticElement;

if (staticElement is ExtensionElement) {
_setExtensionIdentifierType(node);
return;
}

Expand Down Expand Up @@ -1092,6 +1093,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
Element element = node.staticElement;

if (element is ExtensionElement) {
_setExtensionIdentifierType(node);
return;
}

Expand Down Expand Up @@ -2043,6 +2045,40 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
}
}

void _setExtensionIdentifierType(Identifier node) {
if (node is SimpleIdentifier && node.inDeclarationContext()) {
return;
}

var parent = node.parent;

if (parent is PrefixedIdentifier && parent.identifier == node) {
node = parent;
parent = node.parent;
}

if (parent is CommentReference ||
parent is ExtensionOverride && parent.extensionName == node ||
parent is MethodInvocation && parent.target == node ||
parent is PrefixedIdentifier && parent.prefix == node ||
parent is PropertyAccess && parent.target == node) {
return;
}

_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
node,
[node.name],
);

if (node is PrefixedIdentifier) {
node.identifier.staticType = _dynamicType;
node.staticType = _dynamicType;
} else if (node is SimpleIdentifier) {
node.staticType = _dynamicType;
}
}

DartType _toMapType(SetOrMapLiteral node, DartType contextType,
List<_InferredCollectionElementTypeInformation> inferredTypes) {
DartType dynamicType = _typeProvider.dynamicType;
Expand Down
29 changes: 29 additions & 0 deletions pkg/analyzer/test/generated/invalid_code_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

import 'dart:async';

import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../src/dart/resolution/driver_resolution.dart';
Expand All @@ -16,6 +18,7 @@ main() {
} else {
defineReflectiveTests(InvalidCodeTest);
}
defineReflectiveTests(InvalidCodeWithExtensionMethodsTest);
});
}

Expand Down Expand Up @@ -219,3 +222,29 @@ class C {
assertHasTestErrors();
}
}

@reflectiveTest
class InvalidCodeWithExtensionMethodsTest extends DriverResolutionTest {
@override
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);

@failingTest
test_fuzz_14() async {
// This crashes because parser produces `ConstructorDeclaration`.
// So, we try to create `ConstructorElement` for it, and it wants
// `ClassElement` as the enclosing element. But we have `ExtensionElement`.
await _assertCanBeAnalyzed(r'''
extension E {
factory S() {}
}
''');
}

Future<void> _assertCanBeAnalyzed(String text) async {
addTestFile(text);
await resolveTestFile();
assertHasTestErrors();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../dart/resolution/driver_resolution.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(ExtensionAsExpressionTest);
});
}

@reflectiveTest
class ExtensionAsExpressionTest extends DriverResolutionTest {
@override
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);

test_prefixedIdentifier() async {
newFile('/test/lib/a.dart', content: r'''
extension E on int {}
''');
await assertErrorsInCode('''
import 'a.dart' as p;
var v = p.E;
''', [
error(CompileTimeErrorCode.EXTENSION_AS_EXPRESSION, 30, 3),
]);
assertTypeDynamic(findNode.simple('E;'));
assertTypeDynamic(findNode.prefixed('p.E;'));
}

test_simpleIdentifier() async {
await assertErrorsInCode('''
extension E on int {}
var v = E;
''', [
error(CompileTimeErrorCode.EXTENSION_AS_EXPRESSION, 30, 1),
]);
assertTypeDynamic(findNode.simple('E;'));
}
}
19 changes: 19 additions & 0 deletions pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../dart/resolution/driver_resolution.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(NotATypeTest);
defineReflectiveTests(NotATypeWithExtensionMethodsTest);
});
}

Expand All @@ -26,3 +29,19 @@ main() {
]);
}
}

@reflectiveTest
class NotATypeWithExtensionMethodsTest extends NotATypeTest {
@override
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);

test_extension() async {
await assertErrorsInCode('''
extension E on int {}
E a;
''', [error(StaticWarningCode.NOT_A_TYPE, 22, 1)]);
assertTypeDynamic(findNode.simple('E a;'));
}
}
2 changes: 2 additions & 0 deletions pkg/analyzer/test/src/diagnostics/test_all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import 'export_suplicated_library_named_test.dart'
as export_suplicated_library_named;
import 'expression_in_map_test.dart' as expression_in_map;
import 'extends_non_class_test.dart' as extends_non_class;
import 'extension_as_expression_test.dart' as extension_as_expression;
import 'extension_conflicting_static_and_instance_test.dart'
as extension_conflicting_static_and_instance;
import 'extension_declares_abstract_method_test.dart'
Expand Down Expand Up @@ -353,6 +354,7 @@ main() {
export_suplicated_library_named.main();
expression_in_map.main();
extends_non_class.main();
extension_as_expression.main();
extension_conflicting_static_and_instance.main();
extension_declares_abstract_method.main();
extension_declares_constructor.main();
Expand Down

0 comments on commit ffd50c0

Please sign in to comment.