Skip to content

Commit

Permalink
fix extension factory declaration in AST
Browse files Browse the repository at this point in the history
Constructor declarations within extensions are invalid and the parser
reports an error. This modifies AstBuilder to add the declaration
as a method declaration in order to get navigation, search, etc.

Fix dart-lang/sdk#38202

Change-Id: I6071a8d5a742d6598f18a831688ddc97e411f76f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/116100
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
  • Loading branch information
danrubel authored and commit-bot@chromium.org committed Sep 9, 2019
1 parent 618b56d commit b6f6240
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
57 changes: 52 additions & 5 deletions pkg/analyzer/lib/src/fasta/ast_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -910,12 +910,59 @@ class AstBuilder extends StackListener {
@override
void endExtensionFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
assert(optional('factory', factoryKeyword));
assert(optional(';', endToken) || optional('}', endToken));
debugEvent("ExtensionFactoryMethod");
// TODO(danrubel) Decide how to handle constructor declarations within
// extensions. They are invalid and the parser has already reported an
// error at this point, but we include them in order to get navigation,
// search, etc.
endClassFactoryMethod(beginToken, factoryKeyword, endToken);

Object bodyObject = pop();
FormalParameterList parameters = pop();
TypeParameterList typeParameters = pop();
Object constructorName = pop();
_Modifiers modifiers = pop();
List<Annotation> metadata = pop();

FunctionBody body;
if (bodyObject is FunctionBody) {
body = bodyObject;
} else if (bodyObject is _RedirectingFactoryBody) {
body = ast.emptyFunctionBody(endToken);
} else {
// Unhandled situation which should never happen.
// Since this event handler is just a recovery attempt,
// don't bother adding this declaration to the AST.
return;
}
Comment comment = _findComment(metadata, beginToken);

assert(parameters != null);

// Constructor declarations within extensions are invalid and the parser
// has already reported an error at this point, but we include them in as
// a method declaration in order to get navigation, search, etc.

SimpleIdentifier methodName;
if (constructorName is SimpleIdentifier) {
methodName = constructorName;
} else if (constructorName is PrefixedIdentifier) {
methodName = constructorName.identifier;
} else {
// Unsure what the method name should be in this situation.
// Since this event handler is just a recovery attempt,
// don't bother adding this declaration to the AST.
return;
}
currentDeclarationMembers.add(ast.methodDeclaration(
comment,
metadata,
modifiers?.externalKeyword,
modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
null, // returnType
null, // getOrSet
null, // operatorKeyword
methodName,
typeParameters,
parameters,
body));
}

void endFieldInitializer(Token assignment, Token token) {
Expand Down
1 change: 0 additions & 1 deletion pkg/analyzer/test/generated/invalid_code_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@ class InvalidCodeWithExtensionMethodsTest extends DriverResolutionTest {
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);

@failingTest
test_fuzz_14() async {
// This crashes because parser produces `ConstructorDeclaration`.
// So, we try to create `ConstructorElement` for it, and it wants
Expand Down
26 changes: 26 additions & 0 deletions pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
Expand Down Expand Up @@ -48,6 +49,31 @@ extension E on Object {
])
];

test_constructor() async {
await assertErrorsInCode('''
extension E {
E() {}
}
''', [
error(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
error(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 16, 1),
]);
}

test_factory() async {
await assertErrorsInCode('''
extension E {
factory S() {}
}
''', [
error(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
error(CompileTimeErrorCode.UNDEFINED_CLASS, 12, 0),
error(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 16, 7),
]);
}

test_fromPlatform() async {
await assertNoErrorsInCode('''
import 'dart:test2';
Expand Down

0 comments on commit b6f6240

Please sign in to comment.