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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 } |
OLD | NEW |