Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1085)

Side by Side Diff: pkg/analyzer/lib/src/dart/sdk/patch.dart

Issue 2412453007: Add support for patching class methods. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/analyzer/test/src/dart/sdk/patch_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 Source patchSource = patchFile.createSource(); 65 Source patchSource = patchFile.createSource();
66 CompilationUnit patchUnit = parse(patchSource, strongMode, errorListener); 66 CompilationUnit patchUnit = parse(patchSource, strongMode, errorListener);
67 67
68 // Prepare for reporting errors. 68 // Prepare for reporting errors.
69 _baseDesc = source.toString(); 69 _baseDesc = source.toString();
70 _patchDesc = patchFile.path; 70 _patchDesc = patchFile.path;
71 _patchUnit = patchUnit; 71 _patchUnit = patchUnit;
72 72
73 _patchDirectives( 73 _patchDirectives(
74 source, unit, patchSource, patchUnit, addNewTopLevelDeclarations); 74 source, unit, patchSource, patchUnit, addNewTopLevelDeclarations);
75 _patchTopLevelDeclarations( 75 _patchTopLevelDeclarations(unit, patchUnit, addNewTopLevelDeclarations);
76 source, unit, patchSource, patchUnit, addNewTopLevelDeclarations);
77 } 76 }
78 } 77 }
79 78
80 void _failExternalKeyword(Source source, String name, int offset) { 79 void _failExternalKeyword(String name, int offset) {
81 throw new ArgumentError( 80 throw new ArgumentError(
82 'The keyword "external" was expected for "$name" in $source @ $offset.') ; 81 'The keyword "external" was expected for "$name" in $_baseDesc @ $offset .');
83 } 82 }
84 83
85 void _failIfPublicName(AstNode node, String name) { 84 void _failIfPublicName(AstNode node, String name) {
86 if (!Identifier.isPrivateName(name)) { 85 if (!Identifier.isPrivateName(name)) {
87 _failInPatch('contains a public declaration "$name"', node.offset); 86 _failInPatch('contains a public declaration "$name"', node.offset);
88 } 87 }
89 } 88 }
90 89
91 void _failInPatch(String message, int offset) { 90 void _failInPatch(String message, int offset) {
92 String loc = _getLocationDesc3(_patchUnit, offset); 91 String loc = _getLocationDesc3(_patchUnit, offset);
93 throw new ArgumentError( 92 throw new ArgumentError(
94 'The patch file $_patchDesc for $_baseDesc $message at $loc.'); 93 'The patch file $_patchDesc for $_baseDesc $message at $loc.');
95 } 94 }
96 95
97 String _getLocationDesc3(CompilationUnit unit, int offset) { 96 String _getLocationDesc3(CompilationUnit unit, int offset) {
98 LineInfo_Location location = unit.lineInfo.getLocation(offset); 97 LineInfo_Location location = unit.lineInfo.getLocation(offset);
99 return 'the line ${location.lineNumber}'; 98 return 'the line ${location.lineNumber}';
100 } 99 }
101 100
101 void _patchClassMembers(
102 ClassDeclaration baseClass, ClassDeclaration patchClass) {
103 List<ClassMember> membersToAppend = [];
104 for (ClassMember patchMember in patchClass.members) {
105 if (patchMember is MethodDeclaration) {
106 String name = patchMember.name.name;
107 if (_hasPatchAnnotation(patchMember.metadata)) {
108 for (ClassMember baseMember in baseClass.members) {
109 if (baseMember is MethodDeclaration &&
110 baseMember.name.name == name) {
111 // Remove the "external" keyword.
Paul Berry 2016/10/13 19:09:52 It looks like we have some duplication between thi
scheglov 2016/10/13 20:18:14 It does not seem practical to me. Both "externalKe
112 Token externalKeyword = baseMember.externalKeyword;
113 if (externalKeyword != null) {
114 baseMember.externalKeyword = null;
115 _removeToken(externalKeyword);
116 } else {
117 _failExternalKeyword(name, baseMember.offset);
118 }
119 // Replace the body.
120 FunctionBody oldBody = baseMember.body;
121 FunctionBody newBody = patchMember.body;
122 _replaceNodeTokens(oldBody, newBody);
123 baseMember.body = newBody;
124 }
125 }
126 } else {
127 _failIfPublicName(patchMember, name);
128 membersToAppend.add(patchMember);
129 }
130 } else {
131 // TODO(scheglov) support field
132 // TODO(scheglov) support constructors
133 String className = patchClass.name.name;
134 _failInPatch('contains an unsupported class member in $className',
135 patchMember.offset);
136 }
137 }
138 // Append new top-level declarations.
139 Token lastToken = baseClass.endToken.previous;
140 for (ClassMember newMember in membersToAppend) {
141 newMember.endToken.setNext(lastToken.next);
Paul Berry 2016/10/13 19:09:52 Consider extracting a method for this logic too.
scheglov 2016/10/13 20:18:14 OK https://codereview.chromium.org/2417053002
142 lastToken.setNext(newMember.beginToken);
143 baseClass.members.add(newMember);
144 lastToken = newMember.endToken;
145 }
146 }
147
102 void _patchDirectives( 148 void _patchDirectives(
103 Source baseSource, 149 Source baseSource,
104 CompilationUnit baseUnit, 150 CompilationUnit baseUnit,
105 Source patchSource, 151 Source patchSource,
106 CompilationUnit patchUnit, 152 CompilationUnit patchUnit,
107 bool addNewTopLevelDeclarations) { 153 bool addNewTopLevelDeclarations) {
108 for (Directive patchDirective in patchUnit.directives) { 154 for (Directive patchDirective in patchUnit.directives) {
109 if (patchDirective is ImportDirective) { 155 if (patchDirective is ImportDirective) {
110 baseUnit.directives.add(patchDirective); 156 baseUnit.directives.add(patchDirective);
111 } else { 157 } else {
112 _failInPatch('contains an unsupported "$patchDirective" directive', 158 _failInPatch('contains an unsupported "$patchDirective" directive',
113 patchDirective.offset); 159 patchDirective.offset);
114 } 160 }
115 } 161 }
116 } 162 }
117 163
118 void _patchTopLevelDeclarations( 164 void _patchTopLevelDeclarations(CompilationUnit baseUnit,
119 Source baseSource, 165 CompilationUnit patchUnit, bool addNewTopLevelDeclarations) {
120 CompilationUnit baseUnit,
121 Source patchSource,
122 CompilationUnit patchUnit,
123 bool addNewTopLevelDeclarations) {
124 List<CompilationUnitMember> declarationsToAppend = []; 166 List<CompilationUnitMember> declarationsToAppend = [];
125 for (CompilationUnitMember patchDeclaration in patchUnit.declarations) { 167 for (CompilationUnitMember patchDeclaration in patchUnit.declarations) {
126 if (patchDeclaration is FunctionDeclaration) { 168 if (patchDeclaration is FunctionDeclaration) {
127 String name = patchDeclaration.name.name; 169 String name = patchDeclaration.name.name;
128 if (_hasPatchAnnotation(patchDeclaration.metadata)) { 170 if (_hasPatchAnnotation(patchDeclaration.metadata)) {
129 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) { 171 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) {
130 if (patchDeclaration is FunctionDeclaration && 172 if (patchDeclaration is FunctionDeclaration &&
131 baseDeclaration is FunctionDeclaration && 173 baseDeclaration is FunctionDeclaration &&
132 baseDeclaration.name.name == name) { 174 baseDeclaration.name.name == name) {
133 if (_hasPatchAnnotation(patchDeclaration.metadata)) { 175 // Remove the "external" keyword.
134 // Remove the "external" keyword. 176 Token externalKeyword = baseDeclaration.externalKeyword;
135 Token externalKeyword = baseDeclaration.externalKeyword; 177 if (externalKeyword != null) {
136 if (externalKeyword != null) { 178 baseDeclaration.externalKeyword = null;
137 baseDeclaration.externalKeyword = null; 179 _removeToken(externalKeyword);
138 _removeToken(externalKeyword); 180 } else {
139 } else { 181 _failExternalKeyword(name, baseDeclaration.offset);
140 _failExternalKeyword(
141 baseSource, name, baseDeclaration.offset);
142 }
143 // Replace the body.
144 FunctionExpression oldExpr = baseDeclaration.functionExpression;
145 FunctionBody newBody = patchDeclaration.functionExpression.body;
146 _replaceNodeTokens(oldExpr.body, newBody);
147 oldExpr.body = newBody;
148 } 182 }
183 // Replace the body.
184 FunctionExpression oldExpr = baseDeclaration.functionExpression;
185 FunctionBody newBody = patchDeclaration.functionExpression.body;
186 _replaceNodeTokens(oldExpr.body, newBody);
187 oldExpr.body = newBody;
149 } 188 }
150 } 189 }
151 } else if (addNewTopLevelDeclarations) { 190 } else if (addNewTopLevelDeclarations) {
152 _failIfPublicName(patchDeclaration, name); 191 _failIfPublicName(patchDeclaration, name);
153 declarationsToAppend.add(patchDeclaration); 192 declarationsToAppend.add(patchDeclaration);
154 } 193 }
155 } else if (patchDeclaration is FunctionTypeAlias) { 194 } else if (patchDeclaration is FunctionTypeAlias) {
156 if (patchDeclaration.metadata.isNotEmpty) { 195 if (patchDeclaration.metadata.isNotEmpty) {
157 _failInPatch('contains a function type alias with an annotation', 196 _failInPatch('contains a function type alias with an annotation',
158 patchDeclaration.offset); 197 patchDeclaration.offset);
159 } 198 }
160 _failIfPublicName(patchDeclaration, patchDeclaration.name.name); 199 _failIfPublicName(patchDeclaration, patchDeclaration.name.name);
161 declarationsToAppend.add(patchDeclaration); 200 declarationsToAppend.add(patchDeclaration);
201 } else if (patchDeclaration is ClassDeclaration) {
202 if (_hasPatchAnnotation(patchDeclaration.metadata)) {
203 String name = patchDeclaration.name.name;
204 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) {
205 if (baseDeclaration is ClassDeclaration &&
206 baseDeclaration.name.name == name) {
207 _patchClassMembers(baseDeclaration, patchDeclaration);
208 }
209 }
210 } else {
211 _failIfPublicName(patchDeclaration, patchDeclaration.name.name);
212 declarationsToAppend.add(patchDeclaration);
213 }
162 } else { 214 } else {
163 _failInPatch('contains an unsupported top-level declaration', 215 _failInPatch('contains an unsupported top-level declaration',
164 patchDeclaration.offset); 216 patchDeclaration.offset);
165 } 217 }
166 } 218 }
167 // Append new top-level declarations. 219 // Append new top-level declarations.
168 Token lastToken = baseUnit.endToken.previous; 220 Token lastToken = baseUnit.endToken.previous;
169 for (CompilationUnitMember newDeclaration in declarationsToAppend) { 221 for (CompilationUnitMember newDeclaration in declarationsToAppend) {
170 newDeclaration.endToken.setNext(lastToken.next); 222 newDeclaration.endToken.setNext(lastToken.next);
171 lastToken.setNext(newDeclaration.beginToken); 223 lastToken.setNext(newDeclaration.beginToken);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 } 267 }
216 268
217 /** 269 /**
218 * Replace tokens of the [oldNode] with tokens of the [newNode]. 270 * Replace tokens of the [oldNode] with tokens of the [newNode].
219 */ 271 */
220 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { 272 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) {
221 oldNode.beginToken.previous.setNext(newNode.beginToken); 273 oldNode.beginToken.previous.setNext(newNode.beginToken);
222 newNode.endToken.setNext(oldNode.endToken.next); 274 newNode.endToken.setNext(oldNode.endToken.next);
223 } 275 }
224 } 276 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/dart/sdk/patch_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698