diff --git a/pkg/analyzer/lib/src/dart/sdk/patch.dart b/pkg/analyzer/lib/src/dart/sdk/patch.dart index f6b8a3bdb35..88a122eecf2 100644 --- a/pkg/analyzer/lib/src/dart/sdk/patch.dart +++ b/pkg/analyzer/lib/src/dart/sdk/patch.dart @@ -21,6 +21,7 @@ import 'package:path/src/context.dart'; * [SdkPatcher] applies patches to SDK [CompilationUnit]. */ class SdkPatcher { + bool _allowNewPublicNames; String _baseDesc; String _patchDesc; CompilationUnit _patchUnit; @@ -46,8 +47,10 @@ class SdkPatcher { 'The URI of the unit to patch must have the "dart" scheme: $uri'); } List uriSegments = uri.pathSegments; - libraryUriStr = 'dart:${uriSegments.first}'; + String libraryName = uriSegments.first; + libraryUriStr = 'dart:$libraryName'; isLibraryDefiningUnit = uriSegments.length == 1; + _allowNewPublicNames = libraryName == '_internal'; } // Prepare the patch files to apply. List patchPaths; @@ -90,6 +93,9 @@ class SdkPatcher { } void _failIfPublicName(AstNode node, String name) { + if (_allowNewPublicNames) { + return; + } if (!Identifier.isPrivateName(name)) { _failInPatch('contains a public declaration "$name"', node.offset); } @@ -121,9 +127,9 @@ class SdkPatcher { patchMember.offset); } String name = fields[0].name.name; - if (!Identifier.isPrivateName(className) && + if (!_allowNewPublicNames && + !Identifier.isPrivateName(className) && !Identifier.isPrivateName(name)) { - // TODO(scheglov) allow adding public fields into dart:_internal _failInPatch('contains a public field', patchMember.offset); } membersToAppend.add(patchMember); @@ -206,7 +212,7 @@ class SdkPatcher { } } else { if (name == null) { - if (!Identifier.isPrivateName(className)) { + if (!_allowNewPublicNames && !Identifier.isPrivateName(className)) { _failInPatch( 'contains an unnamed public constructor', patchMember.offset); } diff --git a/pkg/analyzer/test/src/dart/sdk/patch_test.dart b/pkg/analyzer/test/src/dart/sdk/patch_test.dart index 6f3d34609bb..dc3a9034f6a 100644 --- a/pkg/analyzer/test/src/dart/sdk/patch_test.dart +++ b/pkg/analyzer/test/src/dart/sdk/patch_test.dart @@ -279,7 +279,7 @@ class A { }, throwsArgumentError); } - test_class_field_append_publiInPrivateClass() { + test_class_field_append_publicInPrivateClass() { CompilationUnit unit = _doTopLevelPatching( r''' class _C { @@ -480,6 +480,47 @@ final Map LIBRARIES = const { }, throwsArgumentError); } + test_internal_allowNewPublicNames() { + _setSdkLibraries(r''' +final Map LIBRARIES = const { + '_internal' : const LibraryInfo( + 'internal/internal.dart', + patches: {VM_PLATFORM: ['internal/internal_patch.dart']}), +};'''); + File file = provider.newFile( + _p('/sdk/lib/internal/internal.dart'), + r''' +library dart._internal; +class A {} +class B { + B(); +} +'''); + provider.newFile( + _p('/sdk/lib/internal/internal_patch.dart'), + r''' +@patch +class B { + int newField; + B.newConstructor(); + int newMethod() => 1; +} +class NewClass {} +int newFunction() => 2; +'''); + + _createSdk(); + + Source source = file.createSource(FastUri.parse('dart:_internal')); + CompilationUnit unit = SdkPatcher.parse(source, true, listener); + patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit); + _assertUnitCode( + unit, + 'library dart._internal; class A {} ' + 'class B {B(); int newField; B.newConstructor(); int newMethod() => 1;} ' + 'class NewClass {} int newFunction() => 2;'); + } + test_part() { String baseLibCode = r''' library test;