Chromium Code Reviews| 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 |