Add support for patching fields.

R=brianwilkerson@google.com, paulberry@google.com
BUG=

Review URL: https://codereview.chromium.org/2416073002 .
This commit is contained in:
Konstantin Shcheglov 2016-10-13 14:04:58 -07:00
parent 2022348b11
commit 2b40c57781
2 changed files with 109 additions and 3 deletions

View file

@ -100,9 +100,26 @@ class SdkPatcher {
void _patchClassMembers(
ClassDeclaration baseClass, ClassDeclaration patchClass) {
String className = baseClass.name.name;
List<ClassMember> membersToAppend = [];
for (ClassMember patchMember in patchClass.members) {
if (patchMember is MethodDeclaration) {
if (patchMember is FieldDeclaration) {
if (_hasPatchAnnotation(patchMember.metadata)) {
_failInPatch('attempts to patch a field', patchMember.offset);
}
List<VariableDeclaration> fields = patchMember.fields.variables;
if (fields.length != 1) {
_failInPatch('contains a field declaration with more than one field',
patchMember.offset);
}
String name = fields[0].name.name;
if (!Identifier.isPrivateName(className) &&
!Identifier.isPrivateName(name)) {
// TODO(scheglov) allow adding public fields into dart:_internal
_failInPatch('contains a public field', patchMember.offset);
}
membersToAppend.add(patchMember);
} else if (patchMember is MethodDeclaration) {
String name = patchMember.name.name;
if (_hasPatchAnnotation(patchMember.metadata)) {
for (ClassMember baseMember in baseClass.members) {
@ -181,7 +198,7 @@ class SdkPatcher {
}
} else {
if (name == null) {
if (!Identifier.isPrivateName(baseClass.name.name)) {
if (!Identifier.isPrivateName(className)) {
_failInPatch(
'contains an unnamed public constructor', patchMember.offset);
}
@ -191,7 +208,6 @@ class SdkPatcher {
membersToAppend.add(patchMember);
}
} else {
// TODO(scheglov) support field
String className = patchClass.name.name;
_failInPatch('contains an unsupported class member in $className',
patchMember.offset);

View file

@ -226,6 +226,96 @@ class C {
_assertPrevNextToken(constructor.endToken, clazz.rightBracket);
}
test_class_field_append() {
CompilationUnit unit = _doTopLevelPatching(
r'''
class C {
void a() {}
}
''',
r'''
@patch
class C {
int _b = 42;
}
''');
_assertUnitCode(unit, 'class C {void a() {} int _b = 42;}');
ClassDeclaration clazz = unit.declarations[0];
MethodDeclaration a = clazz.members[0];
FieldDeclaration b = clazz.members[1];
_assertPrevNextToken(a.endToken, b.beginToken);
_assertPrevNextToken(b.endToken, clazz.rightBracket);
}
test_class_field_append_fail_moreThanOne() {
expect(() {
_doTopLevelPatching(
r'''
class A {}
''',
r'''
@patch
class A {
@patch
int _f1, _f2;
}
''');
}, throwsArgumentError);
}
test_class_field_append_fail_notPrivate() {
expect(() {
_doTopLevelPatching(
r'''
class A {}
''',
r'''
@patch
class A {
@patch
int b;
}
''');
}, throwsArgumentError);
}
test_class_field_append_publiInPrivateClass() {
CompilationUnit unit = _doTopLevelPatching(
r'''
class _C {
void a() {}
}
''',
r'''
@patch
class _C {
int b = 42;
}
''');
_assertUnitCode(unit, 'class _C {void a() {} int b = 42;}');
ClassDeclaration clazz = unit.declarations[0];
MethodDeclaration a = clazz.members[0];
FieldDeclaration b = clazz.members[1];
_assertPrevNextToken(a.endToken, b.beginToken);
_assertPrevNextToken(b.endToken, clazz.rightBracket);
}
test_class_field_patch_fail() {
expect(() {
_doTopLevelPatching(
r'''
class A {}
''',
r'''
@patch
class A {
@patch
int _f;
}
''');
}, throwsArgumentError);
}
test_class_getter_append() {
CompilationUnit unit = _doTopLevelPatching(
r'''