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

Side by Side Diff: pkg/compiler/lib/src/io/source_information.dart

Issue 1196433002: Create and test source mapping for invocations. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Rebased Created 5 years, 5 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 dart2js.source_information; 5 library dart2js.source_information;
6 6
7 import '../dart2jslib.dart' show SourceSpan, MessageKind; 7 import '../dart2jslib.dart' show SourceSpan, MessageKind;
8 import '../elements/elements.dart' show 8 import '../elements/elements.dart' show
9 AstElement, 9 AstElement,
10 LocalElement; 10 LocalElement;
11 import '../scanner/scannerlib.dart' show Token; 11 import '../tree/tree.dart' show Node, Send;
12 import '../tree/tree.dart' show Node; 12 import '../js/js.dart' show
13 import '../js/js.dart' show JavaScriptNodeSourceInformation; 13 JavaScriptNodeSourceInformation;
14 import 'source_file.dart'; 14 import 'source_file.dart';
15 15
16 bool useNewSourceInfo =
17 const bool.fromEnvironment('USE_NEW_SOURCE_INFO', defaultValue: false);
18
16 /// Interface for passing source information, for instance for use in source 19 /// Interface for passing source information, for instance for use in source
17 /// maps, through the backend. 20 /// maps, through the backend.
18 abstract class SourceInformation extends JavaScriptNodeSourceInformation { 21 abstract class SourceInformation extends JavaScriptNodeSourceInformation {
19 SourceSpan get sourceSpan; 22 SourceSpan get sourceSpan;
20 23
21 /// The source location associated with the start of the JS node. 24 /// The source location associated with the start of the JS node.
22 SourceLocation get startPosition => null; 25 SourceLocation get startPosition => null;
23 26
24 /// The source location associated with the closing of the JS node. 27 /// The source location associated with the closing of the JS node.
25 SourceLocation get closingPosition => null; 28 SourceLocation get closingPosition => null;
26 29
27 /// The source location associated with the end of the JS node. 30 /// The source location associated with the end of the JS node.
28 SourceLocation get endPosition => null; 31 SourceLocation get endPosition => null;
32
33 /// All source locations associated with this source information.
34 List<SourceLocation> get sourceLocations;
35
36 /// Return a short textual representation of the source location.
37 String get shortText;
29 } 38 }
30 39
31 /// Factory for creating [SourceInformationBuilder]s. 40 /// Strategy for creating, processing and applying [SourceInformation].
32 class SourceInformationFactory { 41 class SourceInformationStrategy {
33 const SourceInformationFactory(); 42 const SourceInformationStrategy();
34 43
35 /// Create a [SourceInformationBuilder] for [element]. 44 /// Create a [SourceInformationBuilder] for [element].
36 SourceInformationBuilder forContext(AstElement element) { 45 SourceInformationBuilder createBuilderForContext(AstElement element) {
37 return const SourceInformationBuilder(); 46 return const SourceInformationBuilder();
38 } 47 }
39 } 48 }
40 49
41 /// Interface for generating [SourceInformation]. 50 /// Interface for generating [SourceInformation].
42 class SourceInformationBuilder { 51 class SourceInformationBuilder {
43 const SourceInformationBuilder(); 52 const SourceInformationBuilder();
44 53
45 /// Create a [SourceInformationBuilder] for [element]. 54 /// Create a [SourceInformationBuilder] for [element].
46 SourceInformationBuilder forContext(AstElement element) { 55 SourceInformationBuilder forContext(AstElement element) => this;
47 return this;
48 }
49 56
50 /// Generate [SourceInformation] the declaration of [element]. 57 /// Generate [SourceInformation] the declaration of [element].
51 SourceInformation buildDeclaration(AstElement element) => null; 58 SourceInformation buildDeclaration(AstElement element) => null;
52 59
53 /// Generate [SourceInformation] for the generic [node]. 60 /// Generate [SourceInformation] for the generic [node].
54 @deprecated 61 @deprecated
55 SourceInformation buildGeneric(Node node) => null; 62 SourceInformation buildGeneric(Node node) => null;
56 63
57 /// Generate [SourceInformation] for the return [node]. 64 /// Generate [SourceInformation] for the return [node].
58 SourceInformation buildReturn(Node node) => null; 65 SourceInformation buildReturn(Node node) => null;
59 66
67 /// Generate [SourceInformation] for an implicit return in [element].
68 SourceInformation buildImplicitReturn(AstElement element) => null;
69
60 /// Generate [SourceInformation] for the loop [node]. 70 /// Generate [SourceInformation] for the loop [node].
61 SourceInformation buildLoop(Node node) => null; 71 SourceInformation buildLoop(Node node) => null;
62 72
63 /// Generate [SourceInformation] for the read access in [node]. 73 /// Generate [SourceInformation] for the read access in [node].
64 SourceInformation buildGet(Node node) => null; 74 SourceInformation buildGet(Node node) => null;
65 75
66 /// Generate [SourceInformation] for the invocation in [node]. 76 /// Generate [SourceInformation] for an invocation like `a.b()` where
67 SourceInformation buildCall(Node node) => null; 77 /// [receiver] points to the left-most part of the invocation, `a` in the
68 } 78 /// example, and [call] points the 'name' of the call, `b` or `()` depending
79 /// on whether `b` is a method or a field/getter.
80 SourceInformation buildCall(Node receiver, Node call) => null;
69 81
70 /// Source information that contains start source position and optionally an 82 /// Generate [SourceInformation] for the if statement in [node].
71 /// end source position. 83 SourceInformation buildIf(Node node) => null;
72 class StartEndSourceInformation extends SourceInformation {
73 @override
74 final SourceLocation startPosition;
75 84
76 @override 85 /// Generate [SourceInformation] for the constructor invocation in [node].
77 final SourceLocation endPosition; 86 SourceInformation buildNew(Node node) => null;
78 87
79 StartEndSourceInformation(this.startPosition, [this.endPosition]); 88 /// Generate [SourceInformation] for the throw in [node].
89 SourceInformation buildThrow(Node node) => null;
80 90
81 @override 91 /// Generate [SourceInformation] for the assignment in [node].
82 SourceSpan get sourceSpan { 92 SourceInformation buildAssignment(Node node) => null;
83 Uri uri = startPosition.sourceUri;
84 int begin = startPosition.offset;
85 int end = endPosition == null ? begin : endPosition.offset;
86 return new SourceSpan(uri, begin, end);
87 }
88
89 int get hashCode {
90 return 0x7FFFFFFF &
91 (startPosition.hashCode * 17 + endPosition.hashCode * 19);
92 }
93
94 bool operator ==(other) {
95 if (identical(this, other)) return true;
96 if (other is! StartEndSourceInformation) return false;
97 return startPosition == other.startPosition &&
98 endPosition == other.endPosition;
99 }
100
101 // TODO(johnniwinther): Remove this method. Source information should be
102 // computed based on the element by provided from statements and expressions.
103 static StartEndSourceInformation computeSourceInformation(
104 AstElement element) {
105
106 AstElement implementation = element.implementation;
107 SourceFile sourceFile = implementation.compilationUnit.script.file;
108 String name = computeElementNameForSourceMaps(element);
109 Node node = implementation.node;
110 Token beginToken;
111 Token endToken;
112 if (node == null) {
113 // Synthesized node. Use the enclosing element for the location.
114 beginToken = endToken = element.position;
115 } else {
116 beginToken = node.getBeginToken();
117 endToken = node.getEndToken();
118 }
119 // TODO(podivilov): find the right sourceFile here and remove offset
120 // checks below.
121 SourceLocation sourcePosition, endSourcePosition;
122 if (beginToken.charOffset < sourceFile.length) {
123 sourcePosition =
124 new OffsetSourceLocation(sourceFile, beginToken.charOffset, name);
125 }
126 if (endToken.charOffset < sourceFile.length) {
127 endSourcePosition =
128 new OffsetSourceLocation(sourceFile, endToken.charOffset, name);
129 }
130 return new StartEndSourceInformation(sourcePosition, endSourcePosition);
131 }
132
133 String toString() {
134 StringBuffer sb = new StringBuffer();
135 sb.write('${startPosition.sourceUri}:');
136 // Use 1-based line/column info to match usual dart tool output.
137 sb.write('[${startPosition.line + 1},${startPosition.column + 1}]');
138 if (endPosition != null) {
139 sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]');
140 }
141 return sb.toString();
142 }
143 }
144
145 class StartEndSourceInformationFactory implements SourceInformationFactory {
146 const StartEndSourceInformationFactory();
147
148 @override
149 SourceInformationBuilder forContext(AstElement element) {
150 return new StartEndSourceInformationBuilder(element);
151 }
152 }
153
154 /// [SourceInformationBuilder] that generates [PositionSourceInformation].
155 class StartEndSourceInformationBuilder extends SourceInformationBuilder {
156 final SourceFile sourceFile;
157 final String name;
158
159 StartEndSourceInformationBuilder(AstElement element)
160 : sourceFile = element.compilationUnit.script.file,
161 name = computeElementNameForSourceMaps(element);
162
163 SourceInformation buildDeclaration(AstElement element) {
164 return StartEndSourceInformation.computeSourceInformation(element);
165 }
166
167 SourceLocation sourceFileLocationForToken(Token token) {
168 SourceLocation location =
169 new OffsetSourceLocation(sourceFile, token.charOffset, name);
170 checkValidSourceFileLocation(location, sourceFile, token.charOffset);
171 return location;
172 }
173
174 void checkValidSourceFileLocation(
175 SourceLocation location, SourceFile sourceFile, int offset) {
176 if (!location.isValid) {
177 throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message(
178 {'offset': offset,
179 'fileName': sourceFile.filename,
180 'length': sourceFile.length});
181 }
182 }
183
184 @override
185 SourceInformation buildLoop(Node node) {
186 return new StartEndSourceInformation(
187 sourceFileLocationForToken(node.getBeginToken()),
188 sourceFileLocationForToken(node.getEndToken()));
189 }
190
191 @override
192 SourceInformation buildGeneric(Node node) {
193 return new StartEndSourceInformation(
194 sourceFileLocationForToken(node.getBeginToken()));
195 }
196
197 @override
198 SourceInformation buildReturn(Node node) => buildGeneric(node);
199
200 @override
201 SourceInformation buildGet(Node node) => buildGeneric(node);
202
203 @override
204 SourceInformation buildCall(Node node) => buildGeneric(node);
205
206 @override
207 SourceInformationBuilder forContext(
208 AstElement element, {SourceInformation sourceInformation}) {
209 return new StartEndSourceInformationBuilder(element);
210 }
211 }
212
213 /// [SourceInformation] that consists of an offset position into the source
214 /// code.
215 class PositionSourceInformation extends SourceInformation {
216 @override
217 final SourceLocation startPosition;
218
219 @override
220 final SourceLocation closingPosition;
221
222 PositionSourceInformation(this.startPosition,
223 [this.closingPosition]);
224
225 @override
226 SourceSpan get sourceSpan {
227 SourceLocation location =
228 startPosition != null ? startPosition : closingPosition;
229 Uri uri = location.sourceUri;
230 int offset = location.offset;
231 return new SourceSpan(uri, offset, offset);
232 }
233
234 int get hashCode {
235 return 0x7FFFFFFF &
236 (startPosition.hashCode * 17 + closingPosition.hashCode * 19);
237 }
238
239 bool operator ==(other) {
240 if (identical(this, other)) return true;
241 if (other is! PositionSourceInformation) return false;
242 return startPosition == other.startPosition &&
243 closingPosition == other.closingPosition;
244 }
245
246 String toString() {
247 StringBuffer sb = new StringBuffer();
248 if (startPosition != null) {
249 sb.write('${startPosition.sourceUri}:');
250 } else {
251 sb.write('${closingPosition.sourceUri}:');
252 }
253 // Use 1-based line/column info to match usual dart tool output.
254 if (startPosition != null) {
255 sb.write('[${startPosition.line + 1},'
256 '${startPosition.column + 1}]');
257 }
258 if (closingPosition != null) {
259 sb.write('-[${closingPosition.line + 1},'
260 '${closingPosition.column + 1}]');
261 }
262 return sb.toString();
263 }
264 } 93 }
265 94
266 /// A location in a source file. 95 /// A location in a source file.
267 abstract class SourceLocation { 96 abstract class SourceLocation {
268 final SourceFile _sourceFile; 97 final SourceFile _sourceFile;
269 int _line; 98 int _line;
270 99
271 SourceLocation(this._sourceFile) { 100 SourceLocation(this._sourceFile) {
272 assert(isValid); 101 assert(isValid);
273 } 102 }
(...skipping 26 matching lines...) Expand all
300 } 129 }
301 130
302 bool operator ==(other) { 131 bool operator ==(other) {
303 if (identical(this, other)) return true; 132 if (identical(this, other)) return true;
304 if (other is! SourceLocation) return false; 133 if (other is! SourceLocation) return false;
305 return sourceUri == other.sourceUri && 134 return sourceUri == other.sourceUri &&
306 offset == other.offset && 135 offset == other.offset &&
307 sourceName == other.sourceName; 136 sourceName == other.sourceName;
308 } 137 }
309 138
139 String get shortText {
140 // Use 1-based line/column info to match usual dart tool output.
141 return '${sourceUri.pathSegments.last}:[${line + 1},${column + 1}]';
142 }
143
310 String toString() { 144 String toString() {
311 // Use 1-based line/column info to match usual dart tool output. 145 // Use 1-based line/column info to match usual dart tool output.
312 return '${sourceUri}:[${line + 1},${column + 1}]'; 146 return '${sourceUri}:[${line + 1},${column + 1}]';
313 } 147 }
314 } 148 }
315 149
316 class OffsetSourceLocation extends SourceLocation { 150 class OffsetSourceLocation extends SourceLocation {
317 final int offset; 151 final int offset;
318 final String sourceName; 152 final String sourceName;
319 153
320 OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName) 154 OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName)
321 : super(sourceFile); 155 : super(sourceFile);
322 156
157 String get shortText {
158 return '${super.shortText}:$sourceName';
159 }
160
323 String toString() { 161 String toString() {
324 return '${super.toString()}:$sourceName'; 162 return '${super.toString()}:$sourceName';
325 } 163 }
326 } 164 }
327 165
328 class PositionSourceInformationFactory implements SourceInformationFactory {
329 const PositionSourceInformationFactory();
330
331 @override
332 SourceInformationBuilder forContext(AstElement element) {
333 return new PositionSourceInformationBuilder(element);
334 }
335 }
336
337 /// [SourceInformationBuilder] that generates [PositionSourceInformation].
338 class PositionSourceInformationBuilder implements SourceInformationBuilder {
339 final SourceFile sourceFile;
340 final String name;
341
342 PositionSourceInformationBuilder(AstElement element)
343 : sourceFile = element.implementation.compilationUnit.script.file,
344 name = computeElementNameForSourceMaps(element);
345
346 SourceInformation buildDeclaration(AstElement element) {
347 if (element.isSynthesized) {
348 return new PositionSourceInformation(
349 new OffsetSourceLocation(
350 sourceFile, element.position.charOffset, name));
351 } else {
352 return new PositionSourceInformation(
353 null,
354 new OffsetSourceLocation(sourceFile,
355 element.resolvedAst.node.getEndToken().charOffset, name));
356 }
357 }
358
359 SourceInformation buildBegin(Node node) {
360 return new PositionSourceInformation(new OffsetSourceLocation(
361 sourceFile, node.getBeginToken().charOffset, name));
362 }
363
364 @override
365 SourceInformation buildGeneric(Node node) => buildBegin(node);
366
367 @override
368 SourceInformation buildReturn(Node node) => buildBegin(node);
369
370 @override
371 SourceInformation buildLoop(Node node) => buildBegin(node);
372
373 @override
374 SourceInformation buildGet(Node node) => buildBegin(node);
375
376 @override
377 SourceInformation buildCall(Node node) => buildBegin(node);
378
379 @override
380 SourceInformationBuilder forContext(AstElement element) {
381 return new PositionSourceInformationBuilder(element);
382 }
383 }
384
385 /// Compute the source map name for [element]. 166 /// Compute the source map name for [element].
386 String computeElementNameForSourceMaps(AstElement element) { 167 String computeElementNameForSourceMaps(AstElement element) {
387 if (element.isClosure) { 168 if (element.isClosure) {
388 return computeElementNameForSourceMaps(element.enclosingElement); 169 return computeElementNameForSourceMaps(element.enclosingElement);
389 } else if (element.isClass) { 170 } else if (element.isClass) {
390 return element.name; 171 return element.name;
391 } else if (element.isConstructor || element.isGenerativeConstructorBody) { 172 } else if (element.isConstructor || element.isGenerativeConstructorBody) {
392 String className = element.enclosingClass.name; 173 String className = element.enclosingClass.name;
393 if (element.name == '') { 174 if (element.name == '') {
394 return className; 175 return className;
395 } 176 }
396 return '$className.${element.name}'; 177 return '$className.${element.name}';
397 } else if (element.isLocal) { 178 } else if (element.isLocal) {
398 LocalElement local = element; 179 LocalElement local = element;
399 String name = local.name; 180 String name = local.name;
400 if (name == '') { 181 if (name == '') {
401 name = '<anonymous function>'; 182 name = '<anonymous function>';
402 } 183 }
403 return '${computeElementNameForSourceMaps(local.executableContext)}.$name'; 184 return '${computeElementNameForSourceMaps(local.executableContext)}.$name';
404 } else if (element.enclosingClass != null) { 185 } else if (element.enclosingClass != null) {
405 if (element.enclosingClass.isClosure) { 186 if (element.enclosingClass.isClosure) {
406 return computeElementNameForSourceMaps(element.enclosingClass); 187 return computeElementNameForSourceMaps(element.enclosingClass);
407 } 188 }
408 return '${element.enclosingClass.name}.${element.name}'; 189 return '${element.enclosingClass.name}.${element.name}';
409 } else { 190 } else {
410 return element.name; 191 return element.name;
411 } 192 }
412 } 193 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/io/source_file.dart ('k') | pkg/compiler/lib/src/io/start_end_information.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698