Check for references/writes to superclass members.

R=brianwilkerson@google.com

Change-Id: I9907df6d773923fe6801034208a21f17fc86178b
Reviewed-on: https://dart-review.googlesource.com/47581
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-03-21 19:42:25 +00:00 committed by commit-bot@chromium.org
parent 15bf72615d
commit 8658a7403e
2 changed files with 74 additions and 2 deletions

View file

@ -274,6 +274,8 @@ class _ParametersCollector extends RecursiveAstVisitor<void> {
final RefactoringStatus status = new RefactoringStatus();
final List<_Parameter> parameters = [];
List<ClassElement> enclosingClasses;
_ParametersCollector(this.enclosingClass, this.expressionRange);
@override
@ -286,7 +288,7 @@ class _ParametersCollector extends RecursiveAstVisitor<void> {
DartType type;
if (element is MethodElement) {
if (element.enclosingElement == enclosingClass) {
if (_isMemberOfEnclosingClass(element)) {
status.addError(
"Reference to an enclosing class method cannot be extracted.");
}
@ -300,7 +302,7 @@ class _ParametersCollector extends RecursiveAstVisitor<void> {
}
} else if (element is PropertyAccessorElement) {
PropertyInducingElement field = element.variable;
if (field.enclosingElement == enclosingClass) {
if (_isMemberOfEnclosingClass(field)) {
if (node.inSetterContext()) {
status.addError("Write to '$elementName' cannot be extracted.");
} else {
@ -313,4 +315,20 @@ class _ParametersCollector extends RecursiveAstVisitor<void> {
parameters.add(new _Parameter(elementName, type));
}
}
/**
* Return `true` if the given [element] is a member of the [enclosingClass]
* or one of its supertypes, interfaces, or mixins.
*/
bool _isMemberOfEnclosingClass(Element element) {
if (enclosingClass != null) {
if (enclosingClasses == null) {
enclosingClasses = <ClassElement>[]
..add(enclosingClass)
..addAll(enclosingClass.allSupertypes.map((t) => t.element));
}
return enclosingClasses.contains(element.enclosingElement);
}
return false;
}
}

View file

@ -226,6 +226,33 @@ class MyWidget extends StatelessWidget {
assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR);
}
test_invocation_enclosingSuperClass() async {
addFlutterPackage();
await indexTestUnit(r'''
import 'package:flutter/material.dart';
abstract class MyInterface {
void foo();
}
abstract class MyWidget extends StatelessWidget implements MyInterface {
@override
Widget build(BuildContext context) {
return new GestureDetector(
child: new Text(''),
onTap: () {
foo();
},
);
}
}
''');
_createRefactoringForStringOffset('new GestureDetector');
RefactoringStatus status = await refactoring.checkAllConditions();
assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR);
}
test_invocation_otherClass() async {
addFlutterPackage();
await indexTestUnit(r'''
@ -437,6 +464,33 @@ class MyWidget extends StatelessWidget {
assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR);
}
test_parameters_field_write_enclosingSuperClass() async {
addFlutterPackage();
await indexTestUnit(r'''
import 'package:flutter/material.dart';
abstract class MySuperWidget extends StatelessWidget {
String field;
}
class MyWidget extends MySuperWidget {
@override
Widget build(BuildContext context) {
return new GestureDetector(
child: new Text(''),
onTap: () {
field = '';
},
);
}
}
''');
_createRefactoringForStringOffset('new GestureDetector');
RefactoringStatus status = await refactoring.checkAllConditions();
assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR);
}
test_parameters_field_write_otherClass() async {
addFlutterPackage();
await indexTestUnit(r'''