Skip to content

Commit

Permalink
Check for consistency of language version overrides between library a…
Browse files Browse the repository at this point in the history
…nd parts.

Change-Id: I209cbcda3d96c4e2f1f7a0352b563c886a22e687
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153702
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 Jul 9, 2020
1 parent aff2260 commit 849cdb2
Show file tree
Hide file tree
Showing 6 changed files with 179 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 @@ -180,6 +180,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES,
CompileTimeErrorCode.INCONSISTENT_INHERITANCE,
CompileTimeErrorCode.INCONSISTENT_INHERITANCE_GETTER_AND_METHOD,
CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE,
CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD,
CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD,
CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD,
Expand Down
40 changes: 40 additions & 0 deletions pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class LibraryAnalyzer {

assert(units.values.every(LegacyTypeAsserter.assertLegacyTypes));

_checkForInconsistentLanguageVersionOverride(units);

timerLibraryAnalyzerVerify.stop();

// Return full results.
Expand All @@ -198,6 +200,44 @@ class LibraryAnalyzer {
return results;
}

void _checkForInconsistentLanguageVersionOverride(
Map<FileState, CompilationUnit> units,
) {
var libraryUnit = units.values.first;
var libraryOverrideToken = libraryUnit.languageVersionToken;

for (var partEntry in units.entries.skip(1)) {
var partUnit = partEntry.value;
var partOverrideToken = partUnit.languageVersionToken;
if (libraryOverrideToken != null) {
if (partOverrideToken != null) {
if (partOverrideToken.major != libraryOverrideToken.major ||
partOverrideToken.minor != libraryOverrideToken.minor) {
_getErrorReporter(partEntry.key).reportErrorForToken(
CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE,
partOverrideToken,
);
}
} else {
var partDirectives = partUnit.directives;
for (var partOf in partDirectives.whereType<PartOfDirective>()) {
var partOffset = partOf.partKeyword.offset;
_getErrorReporter(partEntry.key).reportErrorForOffset(
CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE,
partOffset,
partOf.ofKeyword.end - partOffset,
);
}
}
} else if (partOverrideToken != null) {
_getErrorReporter(partEntry.key).reportErrorForToken(
CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE,
partOverrideToken,
);
}
}
}

void _computeConstantErrors(
ErrorReporter errorReporter, CompilationUnit unit) {
ConstantVerifier constantVerifier = ConstantVerifier(
Expand Down
14 changes: 14 additions & 0 deletions pkg/analyzer/lib/src/error/codes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3032,6 +3032,20 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
"Try adjusting the supertypes of this class to remove the "
"inconsistency.");

/**
* It is a compile-time error if a part file has a different language version
* override than its library.
*
* https://github.com/dart-lang/language/blob/master/accepted/
* future-releases/language-versioning/feature-specification.md
* #individual-library-language-version-override
*/
static const CompileTimeErrorCode INCONSISTENT_LANGUAGE_VERSION_OVERRIDE =
CompileTimeErrorCode(
'INCONSISTENT_LANGUAGE_VERSION_OVERRIDE',
"Parts must have exactly the same language version override as "
"the library.");

/**
* Parameters:
* 0: the name of the initializing formal that is not an instance variable in
Expand Down
10 changes: 10 additions & 0 deletions pkg/analyzer/test/src/dart/resolution/resolution.dart
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ mixin ResolutionTest implements ResourceProviderMixin {
return result;
}

Future<void> assertErrorsInFile2(
String path,
List<ExpectedError> expectedErrors,
) async {
path = convertPath(path);

var result = await resolveFile(path);
assertErrorsInResolvedUnit(result, expectedErrors);
}

void assertErrorsInList(
List<AnalysisError> errors,
List<ExpectedError> expectedErrors,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// 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/src/error/codes.dart';
import 'package:meta/meta.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

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

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

@reflectiveTest
class InconsistentLanguageVersionOverrideTest extends DriverResolutionTest {
CompileTimeErrorCode get _errorCode =>
CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE;

test_both_different() async {
await _checkLibraryAndPart(
libraryContent: r'''
// @dart = 2.5
part 'b.dart';
''',
partContent: r'''
// @dart = 2.6
part of 'a.dart';
''',
partErrors: [
error(_errorCode, 0, 14),
],
);
}

test_both_same() async {
await _checkLibraryAndPart(
libraryContent: r'''
// @dart = 2.5
part 'b.dart';
''',
partContent: r'''
// @dart = 2.5
part of 'a.dart';
''',
partErrors: [],
);
}

test_none() async {
await _checkLibraryAndPart(
libraryContent: r'''
part 'b.dart';
''',
partContent: r'''
part of 'a.dart';
''',
partErrors: [],
);
}

test_onlyLibrary() async {
await _checkLibraryAndPart(
libraryContent: r'''
// @dart = 2.5
part 'b.dart';
''',
partContent: r'''
part of 'a.dart';
''',
partErrors: [
error(_errorCode, 0, 7),
],
);
}

test_onlyPart() async {
await _checkLibraryAndPart(
libraryContent: r'''
part 'b.dart';
''',
partContent: r'''
// @dart = 2.5
part of 'a.dart';
''',
partErrors: [
error(_errorCode, 0, 14),
],
);
}

Future<void> _checkLibraryAndPart({
@required String libraryContent,
@required String partContent,
@required List<ExpectedError> partErrors,
}) async {
var libraryPath = convertPath('/test/lib/a.dart');
var partPath = convertPath('/test/lib/b.dart');

newFile(libraryPath, content: libraryContent);

newFile(partPath, content: partContent);

await resolveFile(libraryPath);

await assertErrorsInFile2(partPath, partErrors);
}
}
3 changes: 3 additions & 0 deletions pkg/analyzer/test/src/diagnostics/test_all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ import 'inconsistent_case_expression_types_test.dart'
import 'inconsistent_inheritance_getter_and_method_test.dart'
as inconsistent_inheritance_getter_and_method;
import 'inconsistent_inheritance_test.dart' as inconsistent_inheritance;
import 'inconsistent_language_version_override_test.dart'
as inconsistent_language_version_override;
import 'inference_failure_on_collection_literal_test.dart'
as inference_failure_on_collection_literal;
import 'inference_failure_on_function_return_type_test.dart'
Expand Down Expand Up @@ -663,6 +665,7 @@ main() {
inconsistent_case_expression_types.main();
inconsistent_inheritance_getter_and_method.main();
inconsistent_inheritance.main();
inconsistent_language_version_override.main();
inference_failure_on_collection_literal.main();
inference_failure_on_function_return_type.main();
inference_failure_on_uninitialized_variable.main();
Expand Down

0 comments on commit 849cdb2

Please sign in to comment.