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

Side by Side Diff: tool/patch_sdk.dart

Issue 955513007: merge class extensions from patch files (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 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 | « test/generated_sdk/lib/core/string_buffer.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env dart 1 #!/usr/bin/env dart
2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
3 // for details. All rights reserved. Use of this source code is governed by a 3 // for details. All rights reserved. Use of this source code is governed by a
4 // BSD-style license that can be found in the LICENSE file. 4 // BSD-style license that can be found in the LICENSE file.
5 5
6 /// Command line tool to merge the SDK libraries and our patch files. 6 /// Command line tool to merge the SDK libraries and our patch files.
7 /// This is currently designed as an offline tool, but we could automate it. 7 /// This is currently designed as an offline tool, but we could automate it.
8 library ddc.tool.patch_sdk; 8 library ddc.tool.patch_sdk;
9 9
10 import 'dart:io'; 10 import 'dart:io';
11 import 'dart:math' as math;
12 11
13 import 'package:analyzer/analyzer.dart'; 12 import 'package:analyzer/analyzer.dart';
14 import 'package:path/path.dart' as path; 13 import 'package:path/path.dart' as path;
15 14
16 import 'input_sdk_src/lib/_internal/libraries.dart' as sdk; 15 import 'input_sdk_src/lib/_internal/libraries.dart' as sdk;
17 16
18 void main(List<String> argv) { 17 void main(List<String> argv) {
19 var toolDir = path.relative(path.dirname(Platform.script.path)); 18 var toolDir = path.relative(path.dirname(Platform.script.path));
20 var sdkIn = path.join(toolDir, 'input_sdk_src', 'lib'); 19 var sdkIn = path.join(toolDir, 'input_sdk_src', 'lib');
21 var patchIn = path.join(toolDir, 'input_sdk_patch'); 20 var patchIn = path.join(toolDir, 'input_sdk_patch');
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 /// Editorializing: the dart2js approach requires a Dart front end such as 92 /// Editorializing: the dart2js approach requires a Dart front end such as
94 /// package:analyzer to semantically model a feature beyond what is specified 93 /// package:analyzer to semantically model a feature beyond what is specified
95 /// in the Dart language. Since this feature is only for the convenience of 94 /// in the Dart language. Since this feature is only for the convenience of
96 /// writing the dart:* libraries, and not a tool given to Dart developers, it 95 /// writing the dart:* libraries, and not a tool given to Dart developers, it
97 /// seems like a non-ideal situation. Instead we keep the preprocessing simple. 96 /// seems like a non-ideal situation. Instead we keep the preprocessing simple.
98 List<String> _patchLibrary(List<String> partsContents, String patchContents) { 97 List<String> _patchLibrary(List<String> partsContents, String patchContents) {
99 var results = <StringEditBuffer>[]; 98 var results = <StringEditBuffer>[];
100 99
101 // Parse the patch first. We'll need to extract bits of this as we go through 100 // Parse the patch first. We'll need to extract bits of this as we go through
102 // the other files. 101 // the other files.
103 var patchUnit = parseCompilationUnit(patchContents); 102 var patchFinder = new PatchFinder.parseAndVisit(patchContents);
104 var patchInfo = (new PatchFinder()..visitCompilationUnit(patchUnit)).patches;
105 103
106 // Merge `external` declarations with the corresponding `@patch` code. 104 // Merge `external` declarations with the corresponding `@patch` code.
107 var libraryUnit = null; 105 bool first = true;
108 for (var partContent in partsContents) { 106 for (var partContent in partsContents) {
109 var partEdits = new StringEditBuffer(partContent); 107 var partEdits = new StringEditBuffer(partContent);
110 var partUnit = parseCompilationUnit(partContent); 108 var partUnit = parseCompilationUnit(partContent);
111 if (libraryUnit == null) libraryUnit = partUnit; 109 partUnit.accept(new PatchApplier(partEdits, patchFinder));
112 partUnit.accept(new PatchApplier(partEdits, patchInfo, patchContents));
113 results.add(partEdits); 110 results.add(partEdits);
114 } 111 }
115
116 // Add code from the patch that isn't `@patch`
117 _mergeUnpatched(results[0], libraryUnit, patchUnit, patchContents);
118 return new List<String>.from(results.map((e) => e.toString())); 112 return new List<String>.from(results.map((e) => e.toString()));
119 } 113 }
120 114
121 /// Merges directives and declarations that are not `@patch` into the library. 115 /// Merge `@patch` declarations into `external` declarations.
122 void _mergeUnpatched(StringEditBuffer edits, CompilationUnit lib, 116 class PatchApplier extends GeneralizingAstVisitor {
123 CompilationUnit patchUnit, String patchContents) { 117 final StringEditBuffer edits;
118 final PatchFinder patch;
124 119
125 // Merge directives from the patch 120 bool _isLibrary = true; // until proven otherwise.
126 // TODO(jmesserly): remove duplicate imports 121
127 var directivePos = lib.directives.last.end; 122 PatchApplier(this.edits, this.patch);
128 for (var directive in patchUnit.directives) { 123
129 var uri = directive.uri.stringValue; 124 @override visitCompilationUnit(CompilationUnit node) {
130 // TODO(jmesserly): figure out what to do about these 125 super.visitCompilationUnit(node);
131 if (uri.startsWith('dart:_') && uri != 'dart:_internal') continue; 126 if (_isLibrary) _mergeUnpatched(node);
132 var code = patchContents.substring(directive.offset, directive.end);
133 edits.insert(directivePos, '\n' + code);
134 } 127 }
135 128
136 // Merge declarations from the patch 129 /// Merges directives and declarations that are not `@patch` into the library.
137 var declarationPos = edits.original.length; 130 void _mergeUnpatched(CompilationUnit unit) {
138 for (var declaration in patchUnit.declarations) { 131 // Merge directives from the patch
139 if (_isPatch(declaration)) continue; 132 // TODO(jmesserly): remove duplicate imports
140 var code = patchContents.substring(declaration.offset, declaration.end); 133 var directivePos = unit.directives.last.end;
141 edits.insert(declarationPos, '\n' + code); 134 for (var directive in patch.unit.directives) {
135 var uri = directive.uri.stringValue;
136 // TODO(jmesserly): figure out what to do about these
137 if (uri.startsWith('dart:_') && uri != 'dart:_internal') continue;
138 var code = patch.contents.substring(directive.offset, directive.end);
139 edits.insert(directivePos, '\n' + code);
140 }
141
142 // Merge declarations from the patch
143 var declarationPos = edits.original.length;
144 for (var declaration in patch.mergeDeclarations) {
145 var code = patch.contents.substring(declaration.offset, declaration.end);
146 edits.insert(declarationPos, '\n' + code);
147 }
142 } 148 }
143 }
144 149
145 /// Merge `@patch` declarations into `external` declarations. 150 @override visitPartOfDirective(PartOfDirective node) {
146 class PatchApplier extends RecursiveAstVisitor { 151 _isLibrary = false;
147 final StringEditBuffer edits; 152 }
148 final Map<String, Declaration> patches;
149 final String patchCode;
150
151 PatchApplier(this.edits, this.patches, this.patchCode);
152 153
153 @override visitFunctionDeclaration(FunctionDeclaration node) { 154 @override visitFunctionDeclaration(FunctionDeclaration node) {
154 _maybePatch(node); 155 _maybePatch(node);
155 return super.visitFunctionDeclaration(node);
156 } 156 }
157 @override visitMethodDeclaration(MethodDeclaration node) { 157
158 _maybePatch(node); 158 /// Merge patches and extensions into the class
159 return super.visitMethodDeclaration(node); 159 @override visitClassDeclaration(ClassDeclaration node) {
160 } 160 node.members.forEach(_maybePatch);
161 @override visitConstructorDeclaration(ConstructorDeclaration node) { 161
162 _maybePatch(node); 162 var mergeMembers = patch.mergeMembers[_qualifiedName(node)];
163 return super.visitConstructorDeclaration(node); 163 if (mergeMembers == null) return;
164
165 // Merge members from the patch
166 var pos = node.members.last.end;
167 for (var member in mergeMembers) {
168 var code = patch.contents.substring(member.offset, member.end);
169 edits.insert(pos, '\n\n ' + code);
170 }
164 } 171 }
165 172
166 void _maybePatch(AstNode node) { 173 void _maybePatch(AstNode node) {
174 if (node is FieldDeclaration) return;
175
167 var externalKeyword = (node as dynamic).externalKeyword; 176 var externalKeyword = (node as dynamic).externalKeyword;
168 if (externalKeyword == null) return; 177 if (externalKeyword == null) return;
169 178
170 var name = _qualifiedName(node); 179 var name = _qualifiedName(node);
171 var patchNode = patches[name]; 180 var patchNode = patch.patches[name];
172 if (patchNode == null) throw 'patch not found for $name: $node'; 181 if (patchNode == null) throw 'patch not found for $name: $node';
173 182
174 Annotation patch = patchNode.metadata.lastWhere(_isPatchAnnotation); 183 Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation);
175 var code = patchCode.substring(patch.endToken.next.offset, patchNode.end); 184 int start = patchMeta.endToken.next.offset;
185 var code = patch.contents.substring(start, patchNode.end);
176 186
177 // For some node like static fields, the node's offset doesn't include 187 // For some node like static fields, the node's offset doesn't include
178 // the external keyword. Also starting from the keyword lets us preserve 188 // the external keyword. Also starting from the keyword lets us preserve
179 // documentation comments. 189 // documentation comments.
180 edits.replace(externalKeyword.offset, node.end, code); 190 edits.replace(externalKeyword.offset, node.end, code);
181 } 191 }
182 } 192 }
183 193
184 class PatchFinder extends RecursiveAstVisitor { 194 class PatchFinder extends GeneralizingAstVisitor {
195 final String contents;
196 final CompilationUnit unit;
197
185 final Map patches = <String, Declaration>{}; 198 final Map patches = <String, Declaration>{};
199 final Map mergeMembers = <String, List<ClassMember>>{};
200 final List mergeDeclarations = <CompilationUnitMember>[];
201
202 PatchFinder.parseAndVisit(String contents)
203 : contents = contents,
204 unit = parseCompilationUnit(contents) {
205 visitCompilationUnit(unit);
206 }
207
208 @override visitCompilationUnitMember(CompilationUnitMember node) {
209 mergeDeclarations.add(node);
210 }
211
212 @override visitClassDeclaration(ClassDeclaration node) {
213 if (_isPatch(node)) {
214 var members = <ClassMember>[];
215 for (var member in node.members) {
216 if (_isPatch(member)) {
217 patches[_qualifiedName(member)] = member;
218 } else {
219 members.add(member);
220 }
221 }
222 if (members.isNotEmpty) {
223 mergeMembers[_qualifiedName(node)] = members;
224 }
225 } else {
226 mergeDeclarations.add(node);
227 }
228 }
186 229
187 @override visitFunctionDeclaration(FunctionDeclaration node) { 230 @override visitFunctionDeclaration(FunctionDeclaration node) {
188 _maybeStorePatch(node); 231 if (_isPatch(node)) {
189 return super.visitFunctionDeclaration(node); 232 patches[_qualifiedName(node)] = node;
190 } 233 } else {
191 @override visitMethodDeclaration(MethodDeclaration node) { 234 mergeDeclarations.add(node);
192 _maybeStorePatch(node); 235 }
193 return super.visitMethodDeclaration(node);
194 }
195 @override visitConstructorDeclaration(ConstructorDeclaration node) {
196 _maybeStorePatch(node);
197 return super.visitConstructorDeclaration(node);
198 } 236 }
199 237
200 void _maybeStorePatch(Declaration node) { 238 @override visitFunctionBody(node) {} // skip method bodies
201 if (!_isPatch(node)) return;
202
203 var parent = node.parent;
204 if (parent is ClassDeclaration) {
205 if (!_isPatch(parent)) throw 'class $parent is not a patch but $node is';
206 }
207
208 patches[_qualifiedName(node)] = node;
209 }
210 } 239 }
211 240
212 String _qualifiedName(Declaration node) { 241 String _qualifiedName(Declaration node) {
213 assert(node is MethodDeclaration || 242 assert(node is MethodDeclaration ||
214 node is FunctionDeclaration || 243 node is FunctionDeclaration ||
215 node is ConstructorDeclaration); 244 node is ConstructorDeclaration);
216 245
217 var parent = node.parent; 246 var parent = node.parent;
218 var className = ''; 247 var className = '';
219 if (parent is ClassDeclaration) { 248 if (parent is ClassDeclaration) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 int get length => end - begin; 342 int get length => end - begin;
314 343
315 String toString() => '(Edit @ $begin,$end: "$replace")'; 344 String toString() => '(Edit @ $begin,$end: "$replace")';
316 345
317 int compareTo(_StringEdit other) { 346 int compareTo(_StringEdit other) {
318 int diff = begin - other.begin; 347 int diff = begin - other.begin;
319 if (diff != 0) return diff; 348 if (diff != 0) return diff;
320 return end - other.end; 349 return end - other.end;
321 } 350 }
322 } 351 }
OLDNEW
« no previous file with comments | « test/generated_sdk/lib/core/string_buffer.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698