02e8bbb036
This adds a new generated file into _fe_analyzer_shared for the experimental flags. This is now used by the parser when generating messages about features not being available. The default implementation uses whether the feature is enabled by default or not, to emit different messages. This change will therefore ensure that when a missing feature changes from 'experimental' to 'enabled by default', the message reported by the parser will be updated accordingly. Currently errors are only reported from the parser on features that are enabled by default, so the message for experimental features is not currently used. The reporting is performed through the Listener, such that implementations can override the reporting to improve the messaging. This is done in the CFE where the message is improved to take into account whether the language version is explicit in the parsed library. In response to https://github.com/dart-lang/sdk/issues/46329 Change-Id: Ief812817c7eb4b1e433389f6f49d6a1f77604fa7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/269860 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Jens Johansen <jensj@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
206 lines
7.1 KiB
Dart
206 lines
7.1 KiB
Dart
// Copyright (c) 2020, 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/dart/ast/ast.dart';
|
|
import 'package:analyzer/error/error.dart';
|
|
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
|
import 'package:analyzer/src/dart/ast/ast.dart';
|
|
import 'package:analyzer/src/dart/scanner/scanner.dart';
|
|
import 'package:test/test.dart';
|
|
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
|
|
|
import 'parser_test_base.dart';
|
|
import 'test_support.dart';
|
|
|
|
main() {
|
|
defineReflectiveSuite(() {
|
|
defineReflectiveTests(VarianceParserTest);
|
|
});
|
|
}
|
|
|
|
@reflectiveTest
|
|
class VarianceParserTest extends FastaParserTestCase {
|
|
final FeatureSet _disabledFeatureSet = FeatureSet.latestLanguageVersion();
|
|
|
|
final FeatureSet _enabledFeatureSet = FeatureSet.fromEnableFlags2(
|
|
sdkLanguageVersion: ExperimentStatus.currentVersion,
|
|
flags: [EnableString.variance],
|
|
);
|
|
|
|
@override
|
|
CompilationUnitImpl parseCompilationUnit(String content,
|
|
{List<ErrorCode>? codes,
|
|
List<ExpectedError>? errors,
|
|
FeatureSet? featureSet}) {
|
|
return super.parseCompilationUnit(
|
|
content,
|
|
codes: codes,
|
|
errors: errors,
|
|
featureSet: featureSet ?? _enabledFeatureSet,
|
|
);
|
|
}
|
|
|
|
void test_class_disabled_multiple() {
|
|
parseCompilationUnit('class A<in T, inout U, out V> { }',
|
|
errors: [
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 8, 2),
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 14, 5),
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 23, 3)
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_class_disabled_single() {
|
|
parseCompilationUnit('class A<out T> { }',
|
|
errors: [
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 8, 3),
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_class_enabled_multiple() {
|
|
var unit = parseCompilationUnit('class A<in T, inout U, out V, W> { }');
|
|
expect(unit.declarations, hasLength(1));
|
|
var classDecl = unit.declarations[0] as ClassDeclaration;
|
|
expect(classDecl.name.lexeme, 'A');
|
|
|
|
var typeParameters = classDecl.typeParameters!;
|
|
expect(typeParameters.typeParameters, hasLength(4));
|
|
expect(typeParameters.typeParameters[0].name.lexeme, 'T');
|
|
expect(typeParameters.typeParameters[1].name.lexeme, 'U');
|
|
expect(typeParameters.typeParameters[2].name.lexeme, 'V');
|
|
expect(typeParameters.typeParameters[3].name.lexeme, 'W');
|
|
|
|
var typeParameterImplList = typeParameters.typeParameters;
|
|
expect((typeParameterImplList[0] as TypeParameterImpl).varianceKeyword,
|
|
isNotNull);
|
|
expect(
|
|
(typeParameterImplList[0] as TypeParameterImpl).varianceKeyword!.lexeme,
|
|
"in");
|
|
expect((typeParameterImplList[1] as TypeParameterImpl).varianceKeyword,
|
|
isNotNull);
|
|
expect(
|
|
(typeParameterImplList[1] as TypeParameterImpl).varianceKeyword!.lexeme,
|
|
"inout");
|
|
expect((typeParameterImplList[2] as TypeParameterImpl).varianceKeyword,
|
|
isNotNull);
|
|
expect(
|
|
(typeParameterImplList[2] as TypeParameterImpl).varianceKeyword!.lexeme,
|
|
"out");
|
|
expect((typeParameterImplList[3] as TypeParameterImpl).varianceKeyword,
|
|
isNull);
|
|
}
|
|
|
|
void test_class_enabled_multipleVariances() {
|
|
var unit = parseCompilationUnit('class A<in out inout T> { }', errors: [
|
|
expectedError(ParserErrorCode.MULTIPLE_VARIANCE_MODIFIERS, 11, 3),
|
|
expectedError(ParserErrorCode.MULTIPLE_VARIANCE_MODIFIERS, 15, 5)
|
|
]);
|
|
expect(unit.declarations, hasLength(1));
|
|
var classDecl = unit.declarations[0] as ClassDeclaration;
|
|
expect(classDecl.name.lexeme, 'A');
|
|
|
|
var typeParameters = classDecl.typeParameters!;
|
|
expect(typeParameters.typeParameters, hasLength(1));
|
|
expect(typeParameters.typeParameters[0].name.lexeme, 'T');
|
|
}
|
|
|
|
void test_class_enabled_single() {
|
|
var unit = parseCompilationUnit('class A<in T> { }');
|
|
expect(unit.declarations, hasLength(1));
|
|
var classDecl = unit.declarations[0] as ClassDeclaration;
|
|
expect(classDecl.name.lexeme, 'A');
|
|
|
|
var typeParameters = classDecl.typeParameters!;
|
|
expect(typeParameters.typeParameters, hasLength(1));
|
|
expect(typeParameters.typeParameters[0].name.lexeme, 'T');
|
|
|
|
var typeParameterImpl =
|
|
typeParameters.typeParameters[0] as TypeParameterImpl;
|
|
expect(typeParameterImpl.varianceKeyword, isNotNull);
|
|
expect(typeParameterImpl.varianceKeyword!.lexeme, "in");
|
|
}
|
|
|
|
void test_function_disabled() {
|
|
parseCompilationUnit('void A(in int value) {}',
|
|
errors: [
|
|
expectedError(
|
|
ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 7, 2),
|
|
expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 3),
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_function_enabled() {
|
|
parseCompilationUnit('void A(in int value) {}', errors: [
|
|
expectedError(ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 7, 2),
|
|
expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 3),
|
|
]);
|
|
}
|
|
|
|
void test_list_disabled() {
|
|
parseCompilationUnit('List<out String> stringList = [];',
|
|
errors: [
|
|
expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 6),
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_list_enabled() {
|
|
parseCompilationUnit('List<out String> stringList = [];', errors: [
|
|
expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 6),
|
|
]);
|
|
}
|
|
|
|
void test_mixin_disabled_multiple() {
|
|
parseCompilationUnit('mixin A<inout T, out U> { }',
|
|
errors: [
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 8, 5),
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 17, 3),
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_mixin_disabled_single() {
|
|
parseCompilationUnit('mixin A<inout T> { }',
|
|
errors: [
|
|
expectedError(
|
|
ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, 8, 5),
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_mixin_enabled_single() {
|
|
var unit = parseCompilationUnit('mixin A<inout T> { }');
|
|
expect(unit.declarations, hasLength(1));
|
|
var mixinDecl = unit.declarations[0] as MixinDeclaration;
|
|
expect(mixinDecl.name.lexeme, 'A');
|
|
|
|
var typeParameters = mixinDecl.typeParameters!;
|
|
expect(typeParameters.typeParameters, hasLength(1));
|
|
expect(typeParameters.typeParameters[0].name.lexeme, 'T');
|
|
}
|
|
|
|
void test_typedef_disabled() {
|
|
parseCompilationUnit('typedef A<inout X> = X Function(X);',
|
|
errors: [
|
|
expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1),
|
|
],
|
|
featureSet: _disabledFeatureSet);
|
|
}
|
|
|
|
void test_typedef_enabled() {
|
|
parseCompilationUnit('typedef A<inout X> = X Function(X);', errors: [
|
|
expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1),
|
|
]);
|
|
}
|
|
}
|