mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
Fix for inlining async methods/getters.
R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org/2463493002 .
This commit is contained in:
parent
f9cf78a1af
commit
3319e6d0e3
|
@ -216,6 +216,7 @@ class InlineMethodRefactoringImpl extends RefactoringImpl
|
||||||
_SourcePart _methodExpressionPart;
|
_SourcePart _methodExpressionPart;
|
||||||
_SourcePart _methodStatementsPart;
|
_SourcePart _methodStatementsPart;
|
||||||
List<_ReferenceProcessor> _referenceProcessors = [];
|
List<_ReferenceProcessor> _referenceProcessors = [];
|
||||||
|
Set<FunctionBody> _alreadyMadeAsync = new Set<FunctionBody>();
|
||||||
|
|
||||||
InlineMethodRefactoringImpl(this.searchEngine, this.unit, this.offset) {
|
InlineMethodRefactoringImpl(this.searchEngine, this.unit, this.offset) {
|
||||||
utils = new CorrectionUtils(unit);
|
utils = new CorrectionUtils(unit);
|
||||||
|
@ -287,6 +288,11 @@ class InlineMethodRefactoringImpl extends RefactoringImpl
|
||||||
result = new RefactoringStatus.fatal('Cannot inline operator.');
|
result = new RefactoringStatus.fatal('Cannot inline operator.');
|
||||||
return new Future<RefactoringStatus>.value(result);
|
return new Future<RefactoringStatus>.value(result);
|
||||||
}
|
}
|
||||||
|
// maybe [a]sync*
|
||||||
|
if (_methodElement.isGenerator) {
|
||||||
|
result = new RefactoringStatus.fatal('Cannot inline a generator.');
|
||||||
|
return new Future<RefactoringStatus>.value(result);
|
||||||
|
}
|
||||||
// analyze method body
|
// analyze method body
|
||||||
result.addStatus(_prepareMethodParts());
|
result.addStatus(_prepareMethodParts());
|
||||||
// process references
|
// process references
|
||||||
|
@ -560,6 +566,33 @@ class _ReferenceProcessor {
|
||||||
if (!_shouldProcess()) {
|
if (!_shouldProcess()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// If the element being inlined is async, ensure that the function
|
||||||
|
// body that encloses the method is also async.
|
||||||
|
if (ref._methodElement.isAsynchronous) {
|
||||||
|
FunctionBody body = _node.getAncestor((n) => n is FunctionBody);
|
||||||
|
if (body != null) {
|
||||||
|
if (body.isSynchronous) {
|
||||||
|
if (body.isGenerator) {
|
||||||
|
status.addFatalError(
|
||||||
|
'Cannot inline async into sync*.', newLocation_fromNode(_node));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refElement is ExecutableElement) {
|
||||||
|
var executable = refElement as ExecutableElement;
|
||||||
|
if (!executable.returnType.isDartAsyncFuture) {
|
||||||
|
status.addFatalError(
|
||||||
|
'Cannot inline async into a function that does not return a Future.',
|
||||||
|
newLocation_fromNode(_node));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ref._alreadyMadeAsync.add(body)) {
|
||||||
|
SourceRange bodyStart = rangeStartLength(body.offset, 0);
|
||||||
|
_addRefEdit(newSourceEdit_range(bodyStart, 'async '));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// may be invocation of inline method
|
// may be invocation of inline method
|
||||||
if (nodeParent is MethodInvocation) {
|
if (nodeParent is MethodInvocation) {
|
||||||
MethodInvocation invocation = nodeParent;
|
MethodInvocation invocation = nodeParent;
|
||||||
|
|
|
@ -66,6 +66,56 @@ class A {
|
||||||
expect(refactoring.isDeclaration, isTrue);
|
expect(refactoring.isDeclaration, isTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_bad_async_intoSyncStar() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> get test async => 42;
|
||||||
|
Iterable<Future<int>> foo() sync* {
|
||||||
|
yield test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test async');
|
||||||
|
// error
|
||||||
|
return _assertConditionsFatal('Cannot inline async into sync*.');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_bad_async_targetIsSync_doesNotReturnFuture() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> get test async => 42;
|
||||||
|
double foo() {
|
||||||
|
test;
|
||||||
|
return 1.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test async');
|
||||||
|
// error
|
||||||
|
return _assertConditionsFatal(
|
||||||
|
'Cannot inline async into a function that does not return a Future.');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_bad_asyncStar() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Stream<int> test() async* {
|
||||||
|
yield 1;
|
||||||
|
yield 2;
|
||||||
|
}
|
||||||
|
foo() {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test() async*');
|
||||||
|
// error
|
||||||
|
return _assertConditionsFatal('Cannot inline a generator.');
|
||||||
|
}
|
||||||
|
|
||||||
test_bad_cascadeInvocation() async {
|
test_bad_cascadeInvocation() async {
|
||||||
indexTestUnit(r'''
|
indexTestUnit(r'''
|
||||||
class A {
|
class A {
|
||||||
|
@ -711,6 +761,100 @@ main() {
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_getter_async_targetIsAsync() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> get test async => 42;
|
||||||
|
Future<int> foo() async {
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test async');
|
||||||
|
// validate change
|
||||||
|
return _assertSuccessfulRefactoring(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> foo() async {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_getter_async_targetIsAsyncStar() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> get test async => 42;
|
||||||
|
Stream<int> foo() async {
|
||||||
|
return await test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test async');
|
||||||
|
// validate change
|
||||||
|
return _assertSuccessfulRefactoring(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Stream<int> foo() async {
|
||||||
|
return await 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_getter_async_targetIsSync() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> get test async => 42;
|
||||||
|
Future<int> foo() {
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test async');
|
||||||
|
// validate change
|
||||||
|
return _assertSuccessfulRefactoring(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> foo() async {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_getter_async_targetIsSync2() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> get test async => 42;
|
||||||
|
Future<int> foo1() {
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
Future<int> foo2() {
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test async');
|
||||||
|
// validate change
|
||||||
|
return _assertSuccessfulRefactoring(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> foo1() async {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
Future<int> foo2() async {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
test_getter_classMember_instance() {
|
test_getter_classMember_instance() {
|
||||||
indexTestUnit(r'''
|
indexTestUnit(r'''
|
||||||
class A {
|
class A {
|
||||||
|
@ -803,6 +947,50 @@ main() {
|
||||||
expect(refactoring.inlineAll, false);
|
expect(refactoring.inlineAll, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_method_async() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> test() async => 42;
|
||||||
|
Future<int> foo() {
|
||||||
|
return test();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test() async');
|
||||||
|
// validate change
|
||||||
|
return _assertSuccessfulRefactoring(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> foo() async {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_method_async2() {
|
||||||
|
indexTestUnit(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future<int> test() async => 42;
|
||||||
|
Future foo() {
|
||||||
|
return [test(), test()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
_createRefactoring('test() async');
|
||||||
|
// validate change
|
||||||
|
return _assertSuccessfulRefactoring(r'''
|
||||||
|
import 'dart:async';
|
||||||
|
class A {
|
||||||
|
Future foo() async {
|
||||||
|
return [42, 42];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
test_method_emptyBody() {
|
test_method_emptyBody() {
|
||||||
indexTestUnit(r'''
|
indexTestUnit(r'''
|
||||||
abstract class A {
|
abstract class A {
|
||||||
|
|
Loading…
Reference in a new issue