mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 16:44:59 +00:00
Make Analyzer, VM and dart2js accept URI strings as part-of library identifier.
R=brianwilkerson@google.com, floitsch@google.com, hausner@google.com, johnniwinther@google.com, sigmund@google.com
Committed: ef097edad6
Review-Url: https://codereview.chromium.org/2640853005 .
This commit is contained in:
parent
75c23fec4b
commit
5ae186153c
|
@ -1,5 +1,9 @@
|
|||
## 1.23.0
|
||||
|
||||
### Language
|
||||
* Allow using URI strings in `part of` declarations to refer to the
|
||||
importing library.
|
||||
|
||||
### Core library changes
|
||||
* `dart:core`: Added `Uri.isScheme` function to check the scheme of a URI.
|
||||
Example: `uri.isScheme("http")`. Ignores case when comparing.
|
||||
|
|
|
@ -474,7 +474,8 @@ class LibraryAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
if (hasPartDirective && libraryNameNode == null) {
|
||||
if (hasPartDirective && libraryNameNode == null &&
|
||||
!_context.analysisOptions.enableUriInPartOf) {
|
||||
libraryErrorReporter.reportErrorForOffset(
|
||||
ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART, 0, 0);
|
||||
}
|
||||
|
|
|
@ -1422,7 +1422,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
List<String> _excludePatterns;
|
||||
|
||||
@override
|
||||
bool enableUriInPartOf = false;
|
||||
bool enableUriInPartOf = true;
|
||||
|
||||
@override
|
||||
bool generateImplicitErrors = true;
|
||||
|
@ -1686,7 +1686,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
enableStrictCallChecks = false;
|
||||
enableSuperMixins = false;
|
||||
enableTiming = false;
|
||||
enableUriInPartOf = false;
|
||||
enableUriInPartOf = true;
|
||||
_errorProcessors = null;
|
||||
_excludePatterns = null;
|
||||
finerGrainedInvalidation = false;
|
||||
|
|
|
@ -208,7 +208,7 @@ class Parser {
|
|||
* A flag indicating whether the parser is to allow URI's in part-of
|
||||
* directives.
|
||||
*/
|
||||
bool _enableUriInPartOf = false;
|
||||
bool _enableUriInPartOf = true;
|
||||
|
||||
/**
|
||||
* A flag indicating whether parser is to parse function bodies.
|
||||
|
|
|
@ -1372,7 +1372,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
|
|||
|
||||
@override
|
||||
void visitPartOfDirective(PartOfDirective node) {
|
||||
isCoreLibrary = node.libraryName.name == 'dart.core';
|
||||
isCoreLibrary = node.libraryName?.name == 'dart.core';
|
||||
isPartOf = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1626,7 +1626,8 @@ class BuildLibraryElementTask extends SourceBasedAnalysisTask {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (hasPartDirective && libraryNameNode == null) {
|
||||
if (hasPartDirective && libraryNameNode == null &&
|
||||
!context.analysisOptions.enableUriInPartOf) {
|
||||
errors.add(new AnalysisError(librarySource, 0, 0,
|
||||
ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
|
||||
}
|
||||
|
|
|
@ -3460,7 +3460,8 @@ class Foo {
|
|||
|
||||
void test_nonIdentifierLibraryName_partOf() {
|
||||
CompilationUnit unit = parseCompilationUnit(
|
||||
"part of 'lib';", [ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME]);
|
||||
"part of 3;", [ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE,
|
||||
ParserErrorCode.UNEXPECTED_TOKEN]);
|
||||
expect(unit, isNotNull);
|
||||
}
|
||||
|
||||
|
|
|
@ -766,9 +766,14 @@ library lib;
|
|||
Source partSource = addSource("/part.dart", "part of 'lib';");
|
||||
context.parseCompilationUnit(librarySource);
|
||||
List<AnalysisError> errors = context.computeErrors(partSource);
|
||||
if (context.analysisOptions.enableUriInPartOf) {
|
||||
// TODO(28522)
|
||||
// Should report that 'lib' isn't the correct URI.
|
||||
} else {
|
||||
expect(errors, isNotNull);
|
||||
expect(errors.length > 0, isTrue);
|
||||
}
|
||||
}
|
||||
|
||||
void test_computeErrors_dart_some() {
|
||||
Source source = addSource("/lib.dart", "library 'lib';");
|
||||
|
|
|
@ -414,10 +414,15 @@ part of lib;
|
|||
|
||||
AnalysisResult libResult = await driver.getResult(lib);
|
||||
List<AnalysisError> errors = libResult.errors;
|
||||
if (libResult.unit.element.context.analysisOptions.enableUriInPartOf) {
|
||||
// TODO(28522): Should cause an error for wrong library name.
|
||||
expect(errors, hasLength(0));
|
||||
} else {
|
||||
expect(errors, hasLength(1));
|
||||
expect(errors[0].errorCode,
|
||||
ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART);
|
||||
}
|
||||
}
|
||||
|
||||
test_analyze_resolveDirectives_error_partOfDifferentLibrary_byName() async {
|
||||
var lib = _p('/test/lib.dart');
|
||||
|
|
|
@ -870,8 +870,37 @@ part of my_lib;
|
|||
part of my_lib;
|
||||
'''
|
||||
});
|
||||
if (context.analysisOptions.enableUriInPartOf) {
|
||||
// TODO(28522)
|
||||
// Should report that names are wrong.
|
||||
} else {
|
||||
_assertErrorsWithCodes(
|
||||
[ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART]);
|
||||
AnalysisError error = errorListener.errors[0];
|
||||
}
|
||||
}
|
||||
|
||||
test_perform_error_missingLibraryDirectiveWithPart_noCommon() {
|
||||
_performBuildTask({
|
||||
'/lib.dart': '''
|
||||
part 'partA.dart';
|
||||
part 'partB.dart';
|
||||
''',
|
||||
'/partA.dart': '''
|
||||
part of libA;
|
||||
''',
|
||||
'/partB.dart': '''
|
||||
part of libB;
|
||||
'''
|
||||
});
|
||||
if (context.analysisOptions.enableUriInPartOf) {
|
||||
// TODO(28522)
|
||||
// Should report that names are wrong.
|
||||
} else {
|
||||
_assertErrorsWithCodes(
|
||||
[ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART]);
|
||||
AnalysisError error = errorListener.errors[0];
|
||||
}
|
||||
}
|
||||
|
||||
test_perform_error_partDoesNotExist() {
|
||||
|
|
|
@ -244,6 +244,7 @@ enum MessageKind {
|
|||
LIBRARY_NOT_FOUND,
|
||||
LIBRARY_NOT_SUPPORTED,
|
||||
LIBRARY_TAG_MUST_BE_FIRST,
|
||||
LIBRARY_URI_MISMATCH,
|
||||
MAIN_HAS_PART_OF,
|
||||
MAIN_NOT_A_FUNCTION,
|
||||
MAIN_WITH_EXTRA_PARAMETER,
|
||||
|
@ -2025,6 +2026,26 @@ main() {}
|
|||
""",
|
||||
'part.dart': """
|
||||
part of lib.bar;
|
||||
"""
|
||||
}
|
||||
]),
|
||||
|
||||
MessageKind.LIBRARY_URI_MISMATCH: const MessageTemplate(
|
||||
MessageKind.LIBRARY_URI_MISMATCH,
|
||||
"Expected URI of library '#{libraryUri}'.",
|
||||
howToFix: "Try changing the directive to 'part of "
|
||||
"\"#{libraryUri}\";'.",
|
||||
examples: const [
|
||||
const {
|
||||
'main.dart': """
|
||||
library lib.foo;
|
||||
|
||||
part 'part.dart';
|
||||
|
||||
main() {}
|
||||
""",
|
||||
'part.dart': """
|
||||
part of 'not-main.dart';
|
||||
"""
|
||||
}
|
||||
]),
|
||||
|
|
|
@ -767,6 +767,20 @@ class CompilationUnitElementX extends ElementX
|
|||
}
|
||||
partTag = tag;
|
||||
LibraryName libraryTag = library.libraryTag;
|
||||
|
||||
Expression libraryReference = tag.name;
|
||||
if (libraryReference is LiteralString) {
|
||||
// Name is a URI. Resolve and compare to library's URI.
|
||||
String content = libraryReference.dartString.slowToString();
|
||||
Uri uri = this.script.readableUri.resolve(content);
|
||||
Uri expectedUri = library.canonicalUri;
|
||||
if (uri != expectedUri) {
|
||||
// Consider finding a relative URI reference for the error message.
|
||||
reporter.reportWarningMessage(tag.name,
|
||||
MessageKind.LIBRARY_URI_MISMATCH, {'libraryUri': expectedUri});
|
||||
}
|
||||
return;
|
||||
}
|
||||
String actualName = tag.name.toString();
|
||||
if (libraryTag != null) {
|
||||
String expectedName = libraryTag.name.toString();
|
||||
|
|
|
@ -6409,13 +6409,17 @@ void Parser::ParsePartHeader() {
|
|||
ReportError("'part of' expected");
|
||||
}
|
||||
ConsumeToken();
|
||||
// The VM is not required to check that the library name matches the
|
||||
// name of the current library, so we ignore it.
|
||||
// The VM is not required to check that the library name or URI matches the
|
||||
// name or URI of the current library, so we ignore them.
|
||||
if (CurrentToken() == Token::kSTRING) {
|
||||
ParseStringLiteral(false);
|
||||
} else {
|
||||
ExpectIdentifier("library name expected");
|
||||
while (CurrentToken() == Token::kPERIOD) {
|
||||
ConsumeToken();
|
||||
ExpectIdentifier("malformed library name");
|
||||
}
|
||||
}
|
||||
ExpectSemicolon();
|
||||
}
|
||||
|
||||
|
|
|
@ -780,3 +780,10 @@ external_test/13: Crash
|
|||
final_syntax_test/09: Crash
|
||||
constructor_named_arguments_test/01: Crash # Dartk Issue 28301
|
||||
not_enough_positional_arguments_test/05: Crash # Dartk Issue 28301
|
||||
|
||||
[$compiler == dartk && $runtime == vm]
|
||||
part_of_uri_test: DartkCrash
|
||||
part_of_uri2_test: Crash
|
||||
[$compiler == dartkp && $runtime == dart_precompiled]
|
||||
part_of_uri_test: DartkCrash
|
||||
part_of_uri2_test: Crash
|
||||
|
|
9
tests/language/part_of_uri2_part.dart
Normal file
9
tests/language/part_of_uri2_part.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
part of "part_of_uri2_test.dart";
|
||||
|
||||
// Refer to declaration in library and other part.
|
||||
const bar1 = "part1";
|
||||
const baz1 = "$foo${bar2}1";
|
9
tests/language/part_of_uri2_part2.dart
Normal file
9
tests/language/part_of_uri2_part2.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
part of part_of_uri2;
|
||||
|
||||
// Refer to declaration in library and other part.
|
||||
const bar2 = "part2";
|
||||
const baz2 = "$foo${bar1}2";
|
15
tests/language/part_of_uri2_test.dart
Normal file
15
tests/language/part_of_uri2_test.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
library part_of_uri2;
|
||||
|
||||
part "part_of_uri2_part.dart"; // declares bar1, baz1, uses URI.
|
||||
part "part_of_uri2_part2.dart"; // declares bar2, baz2, uses id.
|
||||
|
||||
const foo = 'foo';
|
||||
const qux = "$baz1$baz2";
|
||||
|
||||
main() {
|
||||
if (!identical(qux, "foopart21foopart12")) throw "Fail: $qux";
|
||||
}
|
9
tests/language/part_of_uri_part.dart
Normal file
9
tests/language/part_of_uri_part.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
part of "part_of_uri_test.dart";
|
||||
|
||||
// Refer to declaration in library and other part.
|
||||
const bar1 = "part1";
|
||||
const baz1 = "$foo${bar2}1";
|
9
tests/language/part_of_uri_part2.dart
Normal file
9
tests/language/part_of_uri_part2.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
part of "part_of_uri_test.dart";
|
||||
|
||||
// Refer to declaration in library and other part.
|
||||
const bar2 = "part2";
|
||||
const baz2 = "$foo${bar1}2";
|
14
tests/language/part_of_uri_test.dart
Normal file
14
tests/language/part_of_uri_test.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
// No library declaration
|
||||
part "part_of_uri_part.dart"; // declares bar1, baz1
|
||||
part "part_of_uri_part2.dart"; // declares bar2, baz2
|
||||
|
||||
const foo = 'foo';
|
||||
const qux = "$baz1$baz2";
|
||||
|
||||
main() {
|
||||
if (!identical(qux, "foopart21foopart12")) throw "Fail: $qux";
|
||||
}
|
Loading…
Reference in a new issue