Index: pkg/analyzer/lib/src/dart/sdk/patch.dart |
diff --git a/pkg/analyzer/lib/src/dart/sdk/patch.dart b/pkg/analyzer/lib/src/dart/sdk/patch.dart |
index 3a5e5acab8a4e8b00e2c462dce9b2ddb66cd935a..424e521cd162712d9d316eff9a0aa3c415259a32 100644 |
--- a/pkg/analyzer/lib/src/dart/sdk/patch.dart |
+++ b/pkg/analyzer/lib/src/dart/sdk/patch.dart |
@@ -21,6 +21,10 @@ import 'package:path/src/context.dart'; |
* [SdkPatcher] applies patches to SDK [CompilationUnit]. |
*/ |
class SdkPatcher { |
+ String _baseDesc; |
+ String _patchDesc; |
+ CompilationUnit _patchUnit; |
+ |
/** |
* Patch the given [unit] of a SDK [source] with the patches defined in |
* the [sdk] for the given [platform]. Throw [ArgumentError] if a patch |
@@ -56,10 +60,18 @@ class SdkPatcher { |
File patchFile = sdk.libraryDirectory.getChildAssumingFile(pathInLib); |
if (!patchFile.exists) { |
throw new ArgumentError( |
- 'The patch file ${patchFile.path} does not exist.'); |
+ 'The patch file ${patchFile.path} for $source does not exist.'); |
} |
Source patchSource = patchFile.createSource(); |
CompilationUnit patchUnit = parse(patchSource, strongMode, errorListener); |
+ |
+ // Prepare for reporting errors. |
+ _baseDesc = source.toString(); |
+ _patchDesc = patchFile.path; |
+ _patchUnit = patchUnit; |
+ |
+ _patchDirectives( |
+ source, unit, patchSource, patchUnit, addNewTopLevelDeclarations); |
_patchTopLevelDeclarations( |
source, unit, patchSource, patchUnit, addNewTopLevelDeclarations); |
} |
@@ -70,6 +82,39 @@ class SdkPatcher { |
'The keyword "external" was expected for "$name" in $source @ $offset.'); |
} |
+ void _failIfPublicName(AstNode node, String name) { |
+ if (!Identifier.isPrivateName(name)) { |
+ _failInPatch('contains a public declaration "$name"', node.offset); |
+ } |
+ } |
+ |
+ void _failInPatch(String message, int offset) { |
+ String loc = _getLocationDesc3(_patchUnit, offset); |
+ throw new ArgumentError( |
+ 'The patch file $_patchDesc for $_baseDesc $message at $loc.'); |
+ } |
+ |
+ String _getLocationDesc3(CompilationUnit unit, int offset) { |
+ LineInfo_Location location = unit.lineInfo.getLocation(offset); |
+ return 'the line ${location.lineNumber}'; |
+ } |
+ |
+ void _patchDirectives( |
+ Source baseSource, |
+ CompilationUnit baseUnit, |
+ Source patchSource, |
+ CompilationUnit patchUnit, |
+ bool addNewTopLevelDeclarations) { |
+ for (Directive patchDirective in patchUnit.directives) { |
+ if (patchDirective is ImportDirective) { |
+ baseUnit.directives.add(patchDirective); |
+ } else { |
+ _failInPatch('contains an unsupported "$patchDirective" directive', |
+ patchDirective.offset); |
+ } |
+ } |
+ } |
+ |
void _patchTopLevelDeclarations( |
Source baseSource, |
CompilationUnit baseUnit, |
@@ -100,14 +145,19 @@ class SdkPatcher { |
} |
} |
} else if (addNewTopLevelDeclarations) { |
- // No @patch, must be private. |
- if (!Identifier.isPrivateName(name)) { |
- throw new ArgumentError( |
- 'The patch file $patchSource attempts to append ' |
- 'a non-private declaration "$name".'); |
- } |
+ _failIfPublicName(patchDeclaration, name); |
declarationsToAppend.add(patchDeclaration); |
} |
+ } else if (patchDeclaration is FunctionTypeAlias) { |
+ if (patchDeclaration.metadata.isNotEmpty) { |
+ _failInPatch('contains a function type alias with an annotation', |
+ patchDeclaration.offset); |
+ } |
+ _failIfPublicName(patchDeclaration, patchDeclaration.name.name); |
+ declarationsToAppend.add(patchDeclaration); |
+ } else { |
+ _failInPatch('contains an unsupported top-level declaration', |
+ patchDeclaration.offset); |
} |
} |
// Append new top-level declarations. |