OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library analyzer.src.dart.sdk.patch; | 5 library analyzer.src.dart.sdk.patch; |
6 | 6 |
7 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
8 import 'package:analyzer/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
9 import 'package:analyzer/error/listener.dart'; | 9 import 'package:analyzer/error/listener.dart'; |
10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 FunctionBody oldBody = baseMember.body; | 120 FunctionBody oldBody = baseMember.body; |
121 FunctionBody newBody = patchMember.body; | 121 FunctionBody newBody = patchMember.body; |
122 _replaceNodeTokens(oldBody, newBody); | 122 _replaceNodeTokens(oldBody, newBody); |
123 baseMember.body = newBody; | 123 baseMember.body = newBody; |
124 } | 124 } |
125 } | 125 } |
126 } else { | 126 } else { |
127 _failIfPublicName(patchMember, name); | 127 _failIfPublicName(patchMember, name); |
128 membersToAppend.add(patchMember); | 128 membersToAppend.add(patchMember); |
129 } | 129 } |
| 130 } else if (patchMember is ConstructorDeclaration) { |
| 131 String name = patchMember.name?.name; |
| 132 if (_hasPatchAnnotation(patchMember.metadata)) { |
| 133 for (ClassMember baseMember in baseClass.members) { |
| 134 if (baseMember is ConstructorDeclaration && |
| 135 baseMember.name?.name == name) { |
| 136 // Remove the "external" keyword. |
| 137 Token externalKeyword = baseMember.externalKeyword; |
| 138 if (externalKeyword != null) { |
| 139 baseMember.externalKeyword = null; |
| 140 _removeToken(externalKeyword); |
| 141 } else { |
| 142 _failExternalKeyword(name, baseMember.offset); |
| 143 } |
| 144 // Factory vs. generative. |
| 145 if (baseMember.factoryKeyword == null && |
| 146 patchMember.factoryKeyword != null) { |
| 147 _failInPatch( |
| 148 'attempts to replace generative constructor with a factory o
ne', |
| 149 patchMember.offset); |
| 150 } else if (baseMember.factoryKeyword != null && |
| 151 patchMember.factoryKeyword == null) { |
| 152 _failInPatch( |
| 153 'attempts to replace factory constructor with a generative o
ne', |
| 154 patchMember.offset); |
| 155 } |
| 156 // The base constructor should not have initializers. |
| 157 if (baseMember.initializers.isNotEmpty) { |
| 158 throw new ArgumentError( |
| 159 'Cannot patch external constructors with initializers ' |
| 160 'in $_baseDesc.'); |
| 161 } |
| 162 // Prepare nodes. |
| 163 FunctionBody baseBody = baseMember.body; |
| 164 FunctionBody patchBody = patchMember.body; |
| 165 NodeList<ConstructorInitializer> baseInitializers = |
| 166 baseMember.initializers; |
| 167 NodeList<ConstructorInitializer> patchInitializers = |
| 168 patchMember.initializers; |
| 169 // Replace initializers and link tokens. |
| 170 if (patchInitializers.isNotEmpty) { |
| 171 baseMember.parameters.endToken |
| 172 .setNext(patchInitializers.beginToken.previous); |
| 173 baseInitializers.addAll(patchInitializers); |
| 174 patchBody.endToken.setNext(baseBody.endToken.next); |
| 175 } else { |
| 176 _replaceNodeTokens(baseBody, patchBody); |
| 177 } |
| 178 // Replace the body. |
| 179 baseMember.body = patchBody; |
| 180 } |
| 181 } |
| 182 } else { |
| 183 if (name == null) { |
| 184 if (!Identifier.isPrivateName(baseClass.name.name)) { |
| 185 _failInPatch( |
| 186 'contains an unnamed public constructor', patchMember.offset); |
| 187 } |
| 188 } else { |
| 189 _failIfPublicName(patchMember, name); |
| 190 } |
| 191 membersToAppend.add(patchMember); |
| 192 } |
130 } else { | 193 } else { |
131 // TODO(scheglov) support field | 194 // TODO(scheglov) support field |
132 // TODO(scheglov) support constructors | |
133 String className = patchClass.name.name; | 195 String className = patchClass.name.name; |
134 _failInPatch('contains an unsupported class member in $className', | 196 _failInPatch('contains an unsupported class member in $className', |
135 patchMember.offset); | 197 patchMember.offset); |
136 } | 198 } |
137 } | 199 } |
138 // Append new top-level declarations. | 200 // Append new top-level declarations. |
139 Token lastToken = baseClass.endToken.previous; | 201 Token lastToken = baseClass.endToken.previous; |
140 for (ClassMember newMember in membersToAppend) { | 202 for (ClassMember newMember in membersToAppend) { |
141 newMember.endToken.setNext(lastToken.next); | 203 newMember.endToken.setNext(lastToken.next); |
142 lastToken.setNext(newMember.beginToken); | 204 lastToken.setNext(newMember.beginToken); |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 } | 329 } |
268 | 330 |
269 /** | 331 /** |
270 * Replace tokens of the [oldNode] with tokens of the [newNode]. | 332 * Replace tokens of the [oldNode] with tokens of the [newNode]. |
271 */ | 333 */ |
272 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { | 334 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { |
273 oldNode.beginToken.previous.setNext(newNode.beginToken); | 335 oldNode.beginToken.previous.setNext(newNode.beginToken); |
274 newNode.endToken.setNext(oldNode.endToken.next); | 336 newNode.endToken.setNext(oldNode.endToken.next); |
275 } | 337 } |
276 } | 338 } |
OLD | NEW |