| 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 60ac49d2ac31494671ce00e11c0baedbff2795a4..44f6765ddfc3be2fcfa0f36977d6bb8868cac162 100644
|
| --- a/pkg/analyzer/lib/src/dart/sdk/patch.dart
|
| +++ b/pkg/analyzer/lib/src/dart/sdk/patch.dart
|
| @@ -99,6 +99,78 @@ class SdkPatcher {
|
| return 'the line ${location.lineNumber}';
|
| }
|
|
|
| + void _matchParameterLists(FormalParameterList baseParameters,
|
| + FormalParameterList patchParameters, String context()) {
|
| + if (baseParameters == null && patchParameters == null) return;
|
| + if (baseParameters == null || patchParameters == null) {
|
| + throw new ArgumentError("${context()}, parameter lists don't match");
|
| + }
|
| + if (baseParameters.parameters.length != patchParameters.parameters.length) {
|
| + throw new ArgumentError(
|
| + '${context()}, parameter lists have different lengths');
|
| + }
|
| + for (var i = 0; i < baseParameters.parameters.length; i++) {
|
| + _matchParameters(baseParameters.parameters[i],
|
| + patchParameters.parameters[i], () => '${context()}, parameter $i');
|
| + }
|
| + }
|
| +
|
| + void _matchParameters(FormalParameter baseParameter,
|
| + FormalParameter patchParameter, String whichParameter()) {
|
| + if (baseParameter.identifier.name != patchParameter.identifier.name) {
|
| + throw new ArgumentError('${whichParameter()} has different name');
|
| + }
|
| + NormalFormalParameter baseParameterWithoutDefault =
|
| + _withoutDefault(baseParameter);
|
| + NormalFormalParameter patchParameterWithoutDefault =
|
| + _withoutDefault(patchParameter);
|
| + if (baseParameterWithoutDefault is SimpleFormalParameter &&
|
| + patchParameterWithoutDefault is SimpleFormalParameter) {
|
| + _matchTypes(baseParameterWithoutDefault.type,
|
| + patchParameterWithoutDefault.type, () => '${whichParameter()} type');
|
| + } else if (baseParameterWithoutDefault is FunctionTypedFormalParameter &&
|
| + patchParameterWithoutDefault is FunctionTypedFormalParameter) {
|
| + _matchTypes(
|
| + baseParameterWithoutDefault.returnType,
|
| + patchParameterWithoutDefault.returnType,
|
| + () => '${whichParameter()} return type');
|
| + _matchParameterLists(
|
| + baseParameterWithoutDefault.parameters,
|
| + patchParameterWithoutDefault.parameters,
|
| + () => '${whichParameter()} parameters');
|
| + } else if (baseParameterWithoutDefault is FieldFormalParameter &&
|
| + patchParameter is FieldFormalParameter) {
|
| + throw new ArgumentError(
|
| + '${whichParameter()} cannot be patched (field formal parameters are not supported)');
|
| + } else {
|
| + throw new ArgumentError(
|
| + '${whichParameter()} mismatch (different parameter kinds)');
|
| + }
|
| + }
|
| +
|
| + void _matchTypes(TypeName baseType, TypeName patchType, String whichType()) {
|
| + error() => new ArgumentError("${whichType()} doesn't match");
|
| + if (baseType == null && patchType == null) return;
|
| + if (baseType == null || patchType == null) throw error();
|
| + // Match up the types token by token; this is more restrictive than strictly
|
| + // necessary, but it's easy and sufficient for patching purposes.
|
| + Token baseToken = baseType.beginToken;
|
| + Token patchToken = patchType.beginToken;
|
| + while (true) {
|
| + if (baseToken.lexeme != patchToken.lexeme) throw error();
|
| + if (identical(baseToken, baseType.endToken) &&
|
| + identical(patchToken, patchType.endToken)) {
|
| + break;
|
| + }
|
| + if (identical(baseToken, baseType.endToken) ||
|
| + identical(patchToken, patchType.endToken)) {
|
| + throw error();
|
| + }
|
| + baseToken = baseToken.next;
|
| + patchToken = patchToken.next;
|
| + }
|
| + }
|
| +
|
| void _patchClassMembers(
|
| ClassDeclaration baseClass, ClassDeclaration patchClass) {
|
| String className = baseClass.name.name;
|
| @@ -134,6 +206,12 @@ class SdkPatcher {
|
| } else {
|
| _failExternalKeyword(name, baseMember.offset);
|
| }
|
| + _matchParameterLists(
|
| + baseMember.parameters,
|
| + patchMember.parameters,
|
| + () => 'While patching $className.$name');
|
| + _matchTypes(baseMember.returnType, patchMember.returnType,
|
| + () => 'While patching $className.$name, return type');
|
| // Replace the body.
|
| FunctionBody oldBody = baseMember.body;
|
| FunctionBody newBody = patchMember.body;
|
| @@ -177,6 +255,11 @@ class SdkPatcher {
|
| 'Cannot patch external constructors with initializers '
|
| 'in $_baseDesc.');
|
| }
|
| + _matchParameterLists(
|
| + baseMember.parameters, patchMember.parameters, () {
|
| + String nameSuffix = name == null ? '' : '.$name';
|
| + return 'While patching $className$nameSuffix';
|
| + });
|
| // Prepare nodes.
|
| FunctionBody baseBody = baseMember.body;
|
| FunctionBody patchBody = patchMember.body;
|
| @@ -250,6 +333,14 @@ class SdkPatcher {
|
| } else {
|
| _failExternalKeyword(name, baseDeclaration.offset);
|
| }
|
| + _matchParameterLists(
|
| + baseDeclaration.functionExpression.parameters,
|
| + patchDeclaration.functionExpression.parameters,
|
| + () => 'While patching $name');
|
| + _matchTypes(
|
| + baseDeclaration.returnType,
|
| + patchDeclaration.returnType,
|
| + () => 'While patching $name, return type');
|
| // Replace the body.
|
| FunctionExpression oldExpr = baseDeclaration.functionExpression;
|
| FunctionBody newBody = patchDeclaration.functionExpression.body;
|
| @@ -300,6 +391,18 @@ class SdkPatcher {
|
| }
|
| }
|
|
|
| + NormalFormalParameter _withoutDefault(FormalParameter parameter) {
|
| + if (parameter is NormalFormalParameter) {
|
| + return parameter;
|
| + } else if (parameter is DefaultFormalParameter) {
|
| + return parameter.parameter;
|
| + } else {
|
| + // Should not happen.
|
| + assert(false);
|
| + return null;
|
| + }
|
| + }
|
| +
|
| /**
|
| * Parse the given [source] into AST.
|
| */
|
|
|