OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:async'; | |
6 import 'dart:convert'; | |
7 import 'dart:io'; | |
8 | |
9 import 'package:analyzer/dart/ast/ast.dart'; | 5 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart'; | 6 import 'package:analyzer/dart/ast/token.dart'; |
11 import 'package:analyzer/dart/ast/visitor.dart'; | 7 import 'package:analyzer/dart/ast/visitor.dart'; |
12 import 'package:analyzer/dart/element/element.dart'; | 8 import 'package:analyzer/dart/element/element.dart'; |
13 import 'package:analyzer/dart/element/type.dart'; | 9 import 'package:analyzer/dart/element/type.dart'; |
14 import 'package:analyzer/src/dart/analysis/driver.dart'; | 10 import 'package:analyzer/src/generated/resolver.dart'; |
15 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; | |
16 import 'package:analyzer/src/generated/parser.dart'; | |
17 import 'package:analyzer/src/generated/scanner.dart'; | 11 import 'package:analyzer/src/generated/scanner.dart'; |
18 import 'package:analyzer/src/generated/source.dart'; | |
19 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
20 import 'package:front_end/src/base/instrumentation.dart' as fasta; | 12 import 'package:front_end/src/base/instrumentation.dart' as fasta; |
21 import 'package:front_end/src/fasta/compiler_context.dart' as fasta; | 13 import 'package:front_end/src/fasta/compiler_context.dart' as fasta; |
22 import 'package:front_end/src/fasta/testing/validating_instrumentation.dart' | 14 import 'package:front_end/src/fasta/testing/validating_instrumentation.dart' |
23 as fasta; | 15 as fasta; |
24 import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri; | |
25 import 'package:kernel/kernel.dart' as fasta; | 16 import 'package:kernel/kernel.dart' as fasta; |
26 import 'package:path/path.dart' as pathos; | |
27 import 'package:test/test.dart'; | 17 import 'package:test/test.dart'; |
28 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 18 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
29 | 19 |
30 import '../../dart/analysis/base.dart'; | 20 import 'front_end_test_common.dart'; |
31 | 21 |
32 main() { | 22 main() { |
33 // Use a group() wrapper to specify the timeout. | 23 // Use a group() wrapper to specify the timeout. |
34 group('front_end_inference_test', () { | 24 group('front_end_inference_test', () { |
35 defineReflectiveSuite(() { | 25 defineReflectiveSuite(() { |
36 defineReflectiveTests(RunFrontEndInferenceTest); | 26 defineReflectiveTests(RunFrontEndInferenceTest); |
37 }); | 27 }); |
38 }, timeout: new Timeout(const Duration(seconds: 120))); | 28 }, timeout: new Timeout(const Duration(seconds: 120))); |
39 } | 29 } |
40 | 30 |
41 /// Set this to `true` to cause expectation comments to be updated. | |
42 const bool fixProblems = false; | |
43 | |
44 @reflectiveTest | 31 @reflectiveTest |
45 class RunFrontEndInferenceTest { | 32 class RunFrontEndInferenceTest extends RunFrontEndTest { |
46 test_run() async { | |
47 String pkgPath = _findPkgRoot(); | |
48 String fePath = pathos.join(pkgPath, 'front_end', 'testcases', 'inference'); | |
49 List<File> dartFiles = new Directory(fePath) | |
50 .listSync() | |
51 .where((entry) => entry is File && entry.path.endsWith('.dart')) | |
52 .map((entry) => entry as File) | |
53 .toList(); | |
54 | |
55 var allProblems = new StringBuffer(); | |
56 for (File file in dartFiles) { | |
57 var test = new _FrontEndInferenceTest(); | |
58 await test.setUp(); | |
59 try { | |
60 String code = file.readAsStringSync(); | |
61 String problems = await test.runTest(file.path, code); | |
62 if (problems != null) { | |
63 allProblems.writeln(problems); | |
64 } | |
65 } finally { | |
66 await test.tearDown(); | |
67 } | |
68 } | |
69 if (allProblems.isNotEmpty) { | |
70 fail(allProblems.toString()); | |
71 } | |
72 } | |
73 | |
74 /** | |
75 * Expects that the [Platform.script] is a test inside of `pkg/analyzer/test` | |
76 * folder, and return the absolute path of the `pkg` folder. | |
77 */ | |
78 String _findPkgRoot() { | |
79 String scriptPath = pathos.fromUri(Platform.script); | |
80 List<String> parts = pathos.split(scriptPath); | |
81 for (int i = 0; i < parts.length - 2; i++) { | |
82 if (parts[i] == 'pkg' && | |
83 parts[i + 1] == 'analyzer' && | |
84 parts[i + 2] == 'test') { | |
85 return pathos.joinAll(parts.sublist(0, i + 1)); | |
86 } | |
87 } | |
88 throw new StateError('Unable to find sdk/pkg/ in $scriptPath'); | |
89 } | |
90 } | |
91 | |
92 class _ElementNamer { | |
93 final ConstructorElement currentFactoryConstructor; | |
94 | |
95 _ElementNamer(this.currentFactoryConstructor); | |
96 | |
97 void appendElementName(StringBuffer buffer, Element element) { | |
98 // Synthetic FunctionElement(s) don't have a name or enclosing library. | |
99 if (element.isSynthetic && element is FunctionElement) { | |
100 return; | |
101 } | |
102 | |
103 var enclosing = element.enclosingElement; | |
104 if (enclosing is CompilationUnitElement) { | |
105 enclosing = enclosing.enclosingElement; | |
106 } else if (enclosing is ClassElement && | |
107 currentFactoryConstructor != null && | |
108 identical(enclosing, currentFactoryConstructor.enclosingElement) && | |
109 element is TypeParameterElement) { | |
110 enclosing = currentFactoryConstructor; | |
111 } | |
112 if (enclosing != null) { | |
113 if (enclosing is LibraryElement && | |
114 (enclosing.name == 'dart.core' || | |
115 enclosing.name == 'dart.async' || | |
116 enclosing.name == 'test')) { | |
117 // For brevity, omit library name | |
118 } else { | |
119 appendElementName(buffer, enclosing); | |
120 buffer.write('::'); | |
121 } | |
122 } | |
123 | |
124 String name = element.name ?? ''; | |
125 if (element is ConstructorElement && name == '') { | |
126 name = '•'; | |
127 } else if (name.endsWith('=') && | |
128 element is PropertyAccessorElement && | |
129 element.isSetter) { | |
130 name = name.substring(0, name.length - 1); | |
131 } | |
132 buffer.write(name); | |
133 } | |
134 } | |
135 | |
136 class _FrontEndInferenceTest extends BaseAnalysisDriverTest { | |
137 @override | 33 @override |
138 AnalysisOptionsImpl createAnalysisOptions() => | 34 get testSubdir => 'inference'; |
139 super.createAnalysisOptions()..enableAssertInitializer = true; | |
140 | |
141 Future<String> runTest(String path, String code) { | |
142 return fasta.CompilerContext.runWithDefaultOptions((_) async { | |
143 Uri uri = provider.pathContext.toUri(path); | |
144 | |
145 List<int> lineStarts = new LineInfo.fromContent(code).lineStarts; | |
146 fasta.CompilerContext.current.uriToSource[relativizeUri(uri).toString()] = | |
147 new fasta.Source(lineStarts, UTF8.encode(code)); | |
148 | |
149 var validation = new fasta.ValidatingInstrumentation(); | |
150 await validation.loadExpectations(uri); | |
151 | |
152 _addFileAndImports(path, code); | |
153 | |
154 AnalysisResult result = await driver.getResult(path); | |
155 result.unit.accept(new _InstrumentationVisitor(validation, uri)); | |
156 | |
157 validation.finish(); | |
158 | |
159 if (validation.hasProblems) { | |
160 if (fixProblems) { | |
161 validation.fixSource(uri, true); | |
162 return null; | |
163 } else { | |
164 return validation.problemsAsString; | |
165 } | |
166 } else { | |
167 return null; | |
168 } | |
169 }); | |
170 } | |
171 | |
172 void _addFileAndImports(String path, String code) { | |
173 provider.newFile(path, code); | |
174 var source = null; | |
175 var analysisErrorListener = null; | |
176 var scanner = new Scanner( | |
177 source, new CharSequenceReader(code), analysisErrorListener); | |
178 var token = scanner.tokenize(); | |
179 var compilationUnit = | |
180 new Parser(source, analysisErrorListener).parseDirectives(token); | |
181 for (var directive in compilationUnit.directives) { | |
182 if (directive is UriBasedDirective) { | |
183 Uri uri = Uri.parse(directive.uri.stringValue); | |
184 if (uri.scheme == 'dart') { | |
185 // Ignore these--they should be in the mock SDK. | |
186 } else if (uri.scheme == '') { | |
187 var pathSegments = uri.pathSegments; | |
188 // For these tests we don't support any directory traversal; we just | |
189 // assume the URI is the name of a file in the same directory as all | |
190 // the other tests. | |
191 if (pathSegments.length != 1) fail('URI too complex: $uri'); | |
192 var referencedPath = | |
193 pathos.join(pathos.dirname(path), pathSegments[0]); | |
194 if (!provider.getFile(referencedPath).exists) { | |
195 var referencedCode = new File(referencedPath).readAsStringSync(); | |
196 _addFileAndImports(referencedPath, referencedCode); | |
197 } | |
198 } | |
199 } | |
200 } | |
201 } | |
202 } | |
203 | |
204 /// Instance of [InstrumentationValue] describing an [ExecutableElement]. | |
205 class _InstrumentationValueForExecutableElement | |
206 extends fasta.InstrumentationValue { | |
207 final ExecutableElement element; | |
208 final _ElementNamer elementNamer; | |
209 | |
210 _InstrumentationValueForExecutableElement(this.element, this.elementNamer); | |
211 | 35 |
212 @override | 36 @override |
213 String toString() { | 37 void visitUnit(TypeProvider typeProvider, CompilationUnit unit, |
214 StringBuffer buffer = new StringBuffer(); | 38 fasta.ValidatingInstrumentation validation, Uri uri) { |
215 elementNamer.appendElementName(buffer, element); | 39 unit.accept(new _InstrumentationVisitor(validation, uri)); |
216 return buffer.toString(); | |
217 } | 40 } |
218 } | 41 } |
219 | 42 |
220 /** | 43 /** |
221 * Instance of [InstrumentationValue] describing a [DartType]. | |
222 */ | |
223 class _InstrumentationValueForType extends fasta.InstrumentationValue { | |
224 final DartType type; | |
225 final _ElementNamer elementNamer; | |
226 | |
227 _InstrumentationValueForType(this.type, this.elementNamer); | |
228 | |
229 @override | |
230 String toString() { | |
231 StringBuffer buffer = new StringBuffer(); | |
232 _appendType(buffer, type); | |
233 return buffer.toString(); | |
234 } | |
235 | |
236 void _appendList<T>(StringBuffer buffer, String open, String close, | |
237 List<T> items, String separator, writeItem(T item), | |
238 {bool includeEmpty: false}) { | |
239 if (!includeEmpty && items.isEmpty) { | |
240 return; | |
241 } | |
242 buffer.write(open); | |
243 bool first = true; | |
244 for (T item in items) { | |
245 if (!first) { | |
246 buffer.write(separator); | |
247 } | |
248 writeItem(item); | |
249 first = false; | |
250 } | |
251 buffer.write(close); | |
252 } | |
253 | |
254 void _appendParameters( | |
255 StringBuffer buffer, List<ParameterElement> parameters) { | |
256 buffer.write('('); | |
257 bool first = true; | |
258 ParameterKind lastKind = ParameterKind.REQUIRED; | |
259 for (var parameter in parameters) { | |
260 if (!first) { | |
261 buffer.write(', '); | |
262 } | |
263 if (lastKind != parameter.parameterKind) { | |
264 if (parameter.parameterKind == ParameterKind.POSITIONAL) { | |
265 buffer.write('['); | |
266 } else if (parameter.parameterKind == ParameterKind.NAMED) { | |
267 buffer.write('{'); | |
268 } | |
269 } | |
270 if (parameter.parameterKind == ParameterKind.NAMED) { | |
271 buffer.write(parameter.name); | |
272 buffer.write(': '); | |
273 } | |
274 _appendType(buffer, parameter.type); | |
275 lastKind = parameter.parameterKind; | |
276 first = false; | |
277 } | |
278 if (lastKind == ParameterKind.POSITIONAL) { | |
279 buffer.write(']'); | |
280 } else if (lastKind == ParameterKind.NAMED) { | |
281 buffer.write('}'); | |
282 } | |
283 buffer.write(')'); | |
284 } | |
285 | |
286 void _appendType(StringBuffer buffer, DartType type) { | |
287 if (type is FunctionType) { | |
288 if (type.typeFormals.isNotEmpty) { | |
289 _appendTypeFormals(buffer, type.typeFormals); | |
290 } | |
291 _appendParameters(buffer, type.parameters); | |
292 buffer.write(' -> '); | |
293 _appendType(buffer, type.returnType); | |
294 } else if (type is InterfaceType) { | |
295 ClassElement element = type.element; | |
296 elementNamer.appendElementName(buffer, element); | |
297 _appendTypeArguments(buffer, type.typeArguments); | |
298 } else if (type.isBottom) { | |
299 buffer.write('<BottomType>'); | |
300 } else if (type is TypeParameterType) { | |
301 elementNamer.appendElementName(buffer, type.element); | |
302 } else { | |
303 buffer.write(type.toString()); | |
304 } | |
305 } | |
306 | |
307 void _appendTypeArguments(StringBuffer buffer, List<DartType> typeArguments) { | |
308 _appendList<DartType>(buffer, '<', '>', typeArguments, ', ', | |
309 (type) => _appendType(buffer, type)); | |
310 } | |
311 | |
312 void _appendTypeFormals( | |
313 StringBuffer buffer, List<TypeParameterElement> typeFormals) { | |
314 _appendList<TypeParameterElement>(buffer, '<', '>', typeFormals, ', ', | |
315 (formal) { | |
316 buffer.write(formal.name); | |
317 buffer.write(' extends '); | |
318 if (formal.bound == null) { | |
319 buffer.write('Object'); | |
320 } else { | |
321 _appendType(buffer, formal.bound); | |
322 } | |
323 }); | |
324 } | |
325 } | |
326 | |
327 /** | |
328 * Instance of [InstrumentationValue] describing a list of [DartType]s. | |
329 */ | |
330 class _InstrumentationValueForTypeArgs extends fasta.InstrumentationValue { | |
331 final List<DartType> types; | |
332 final _ElementNamer elementNamer; | |
333 | |
334 const _InstrumentationValueForTypeArgs(this.types, this.elementNamer); | |
335 | |
336 @override | |
337 String toString() => types | |
338 .map((type) => | |
339 new _InstrumentationValueForType(type, elementNamer).toString()) | |
340 .join(', '); | |
341 } | |
342 | |
343 /** | |
344 * Visitor for ASTs that reports instrumentation for types. | 44 * Visitor for ASTs that reports instrumentation for types. |
345 */ | 45 */ |
346 class _InstrumentationVisitor extends RecursiveAstVisitor<Null> { | 46 class _InstrumentationVisitor extends RecursiveAstVisitor<Null> { |
347 final fasta.Instrumentation _instrumentation; | 47 final fasta.Instrumentation _instrumentation; |
348 final Uri uri; | 48 final Uri uri; |
349 _ElementNamer elementNamer = new _ElementNamer(null); | 49 ElementNamer elementNamer = new ElementNamer(null); |
350 | 50 |
351 _InstrumentationVisitor(this._instrumentation, this.uri); | 51 _InstrumentationVisitor(this._instrumentation, this.uri); |
352 | 52 |
353 visitBinaryExpression(BinaryExpression node) { | 53 visitBinaryExpression(BinaryExpression node) { |
354 super.visitBinaryExpression(node); | 54 super.visitBinaryExpression(node); |
355 _recordTarget(node.operator.charOffset, node.staticElement); | 55 _recordTarget(node.operator.charOffset, node.staticElement); |
356 } | 56 } |
357 | 57 |
358 @override | 58 @override |
359 visitConstructorDeclaration(ConstructorDeclaration node) { | 59 visitConstructorDeclaration(ConstructorDeclaration node) { |
360 _ElementNamer oldElementNamer = elementNamer; | 60 ElementNamer oldElementNamer = elementNamer; |
361 if (node.factoryKeyword != null) { | 61 if (node.factoryKeyword != null) { |
362 // Factory constructors are represented in kernel as static methods, so | 62 // Factory constructors are represented in kernel as static methods, so |
363 // their type parameters get replicated, e.g.: | 63 // their type parameters get replicated, e.g.: |
364 // class C<T> { | 64 // class C<T> { |
365 // factory C.ctor() { | 65 // factory C.ctor() { |
366 // T t; // Refers to C::T | 66 // T t; // Refers to C::T |
367 // ... | 67 // ... |
368 // } | 68 // } |
369 // } | 69 // } |
370 // gets converted to: | 70 // gets converted to: |
371 // class C<T> { | 71 // class C<T> { |
372 // static C<T> C.ctor<T>() { | 72 // static C<T> C.ctor<T>() { |
373 // T t; // Refers to C::ctor::T | 73 // T t; // Refers to C::ctor::T |
374 // ... | 74 // ... |
375 // } | 75 // } |
376 // } | 76 // } |
377 // So to match kernel behavior, we have to arrange for this renaming to | 77 // So to match kernel behavior, we have to arrange for this renaming to |
378 // happen during output. | 78 // happen during output. |
379 elementNamer = new _ElementNamer(node.element); | 79 elementNamer = new ElementNamer(node.element); |
380 } | 80 } |
381 super.visitConstructorDeclaration(node); | 81 super.visitConstructorDeclaration(node); |
382 elementNamer = oldElementNamer; | 82 elementNamer = oldElementNamer; |
383 } | 83 } |
384 | 84 |
385 @override | 85 @override |
386 visitDeclaredIdentifier(DeclaredIdentifier node) { | 86 visitDeclaredIdentifier(DeclaredIdentifier node) { |
387 super.visitDeclaredIdentifier(node); | 87 super.visitDeclaredIdentifier(node); |
388 if (node.type == null) { | 88 if (node.type == null) { |
389 _recordType(node.identifier.offset, node.element.type); | 89 _recordType(node.identifier.offset, node.element.type); |
390 } | 90 } |
391 } | 91 } |
392 | 92 |
393 @override | 93 @override |
394 visitFunctionDeclaration(FunctionDeclaration node) { | 94 visitFunctionDeclaration(FunctionDeclaration node) { |
395 super.visitFunctionDeclaration(node); | 95 super.visitFunctionDeclaration(node); |
396 | 96 |
397 bool isSetter = node.element.kind == ElementKind.SETTER; | 97 bool isSetter = node.element.kind == ElementKind.SETTER; |
398 bool isLocalFunction = node.element is LocalElement && | 98 bool isLocalFunction = node.element is LocalElement && |
399 node.element.enclosingElement is! CompilationUnitElement; | 99 node.element.enclosingElement is! CompilationUnitElement; |
400 | 100 |
401 if (isSetter || isLocalFunction) { | 101 if (isSetter || isLocalFunction) { |
402 if (node.returnType == null) { | 102 if (node.returnType == null) { |
403 _instrumentation.record( | 103 _instrumentation.record( |
404 uri, | 104 uri, |
405 node.name.offset, | 105 node.name.offset, |
406 isSetter ? 'topType' : 'returnType', | 106 isSetter ? 'topType' : 'returnType', |
407 new _InstrumentationValueForType( | 107 new InstrumentationValueForType( |
408 node.element.returnType, elementNamer)); | 108 node.element.returnType, elementNamer)); |
409 } | 109 } |
410 var parameters = node.functionExpression.parameters; | 110 var parameters = node.functionExpression.parameters; |
411 for (var parameter in parameters.parameters) { | 111 for (var parameter in parameters.parameters) { |
412 // Note: it's tempting to check `parameter.type == null`, but that | 112 // Note: it's tempting to check `parameter.type == null`, but that |
413 // doesn't work because of function-typed formal parameter syntax. | 113 // doesn't work because of function-typed formal parameter syntax. |
414 if (parameter.element.hasImplicitType) { | 114 if (parameter.element.hasImplicitType) { |
415 _recordType(parameter.identifier.offset, parameter.element.type); | 115 _recordType(parameter.identifier.offset, parameter.element.type); |
416 } | 116 } |
417 } | 117 } |
418 } | 118 } |
419 } | 119 } |
420 | 120 |
421 visitFunctionExpression(FunctionExpression node) { | 121 visitFunctionExpression(FunctionExpression node) { |
422 super.visitFunctionExpression(node); | 122 super.visitFunctionExpression(node); |
423 if (node.parent is! FunctionDeclaration) { | 123 if (node.parent is! FunctionDeclaration) { |
424 DartType type = node.staticType; | 124 DartType type = node.staticType; |
425 if (type is FunctionType) { | 125 if (type is FunctionType) { |
426 _instrumentation.record(uri, node.parameters.offset, 'returnType', | 126 _instrumentation.record(uri, node.parameters.offset, 'returnType', |
427 new _InstrumentationValueForType(type.returnType, elementNamer)); | 127 new InstrumentationValueForType(type.returnType, elementNamer)); |
428 List<FormalParameter> parameters = node.parameters.parameters; | 128 List<FormalParameter> parameters = node.parameters.parameters; |
429 for (int i = 0; i < parameters.length; i++) { | 129 for (int i = 0; i < parameters.length; i++) { |
430 FormalParameter parameter = parameters[i]; | 130 FormalParameter parameter = parameters[i]; |
431 NormalFormalParameter normalParameter = | 131 NormalFormalParameter normalParameter = |
432 parameter is DefaultFormalParameter | 132 parameter is DefaultFormalParameter |
433 ? parameter.parameter | 133 ? parameter.parameter |
434 : parameter; | 134 : parameter; |
435 if (normalParameter is SimpleFormalParameter && | 135 if (normalParameter is SimpleFormalParameter && |
436 normalParameter.type == null) { | 136 normalParameter.type == null) { |
437 _recordType(parameter.offset, type.parameters[i].type); | 137 _recordType(parameter.offset, type.parameters[i].type); |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 !node.inDeclarationContext() && | 262 !node.inDeclarationContext() && |
563 (node.inGetterContext() || node.inSetterContext())) { | 263 (node.inGetterContext() || node.inSetterContext())) { |
564 _recordTarget(node.offset, element); | 264 _recordTarget(node.offset, element); |
565 } | 265 } |
566 void recordPromotions(DartType elementType) { | 266 void recordPromotions(DartType elementType) { |
567 if (node.inGetterContext() && !node.inDeclarationContext()) { | 267 if (node.inGetterContext() && !node.inDeclarationContext()) { |
568 int offset = node.offset; | 268 int offset = node.offset; |
569 DartType type = node.staticType; | 269 DartType type = node.staticType; |
570 if (!identical(type, elementType)) { | 270 if (!identical(type, elementType)) { |
571 _instrumentation.record(uri, offset, 'promotedType', | 271 _instrumentation.record(uri, offset, 'promotedType', |
572 new _InstrumentationValueForType(type, elementNamer)); | 272 new InstrumentationValueForType(type, elementNamer)); |
573 } | 273 } |
574 } | 274 } |
575 } | 275 } |
576 | 276 |
577 if (element is LocalVariableElement) { | 277 if (element is LocalVariableElement) { |
578 recordPromotions(element.type); | 278 recordPromotions(element.type); |
579 } else if (element is ParameterElement) { | 279 } else if (element is ParameterElement) { |
580 recordPromotions(element.type); | 280 recordPromotions(element.type); |
581 } | 281 } |
582 } | 282 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 f.typeFormals.isEmpty) { | 317 f.typeFormals.isEmpty) { |
618 return _recoverTypeArguments(g, f); | 318 return _recoverTypeArguments(g, f); |
619 } else { | 319 } else { |
620 return const []; | 320 return const []; |
621 } | 321 } |
622 } | 322 } |
623 | 323 |
624 void _recordTarget(int offset, Element element) { | 324 void _recordTarget(int offset, Element element) { |
625 if (element is ExecutableElement) { | 325 if (element is ExecutableElement) { |
626 _instrumentation.record(uri, offset, 'target', | 326 _instrumentation.record(uri, offset, 'target', |
627 new _InstrumentationValueForExecutableElement(element, elementNamer)); | 327 new InstrumentationValueForExecutableElement(element, elementNamer)); |
628 } | 328 } |
629 } | 329 } |
630 | 330 |
631 void _recordTopType(int offset, DartType type) { | 331 void _recordTopType(int offset, DartType type) { |
632 _instrumentation.record(uri, offset, 'topType', | 332 _instrumentation.record(uri, offset, 'topType', |
633 new _InstrumentationValueForType(type, elementNamer)); | 333 new InstrumentationValueForType(type, elementNamer)); |
634 } | 334 } |
635 | 335 |
636 void _recordType(int offset, DartType type) { | 336 void _recordType(int offset, DartType type) { |
637 _instrumentation.record(uri, offset, 'type', | 337 _instrumentation.record(uri, offset, 'type', |
638 new _InstrumentationValueForType(type, elementNamer)); | 338 new InstrumentationValueForType(type, elementNamer)); |
639 } | 339 } |
640 | 340 |
641 void _recordTypeArguments(int offset, List<DartType> typeArguments) { | 341 void _recordTypeArguments(int offset, List<DartType> typeArguments) { |
642 _instrumentation.record(uri, offset, 'typeArgs', | 342 _instrumentation.record(uri, offset, 'typeArgs', |
643 new _InstrumentationValueForTypeArgs(typeArguments, elementNamer)); | 343 new InstrumentationValueForTypeArgs(typeArguments, elementNamer)); |
644 } | 344 } |
645 | 345 |
646 /// Based on DDC code generator's `_recoverTypeArguments` | 346 /// Based on DDC code generator's `_recoverTypeArguments` |
647 Iterable<DartType> _recoverTypeArguments(FunctionType g, FunctionType f) { | 347 Iterable<DartType> _recoverTypeArguments(FunctionType g, FunctionType f) { |
648 assert(identical(g.element, f.element)); | 348 assert(identical(g.element, f.element)); |
649 assert(g.typeFormals.isNotEmpty && f.typeFormals.isEmpty); | 349 assert(g.typeFormals.isNotEmpty && f.typeFormals.isEmpty); |
650 assert(g.typeFormals.length + g.typeArguments.length == | 350 assert(g.typeFormals.length + g.typeArguments.length == |
651 f.typeArguments.length); | 351 f.typeArguments.length); |
652 return f.typeArguments.skip(g.typeArguments.length); | 352 return f.typeArguments.skip(g.typeArguments.length); |
653 } | 353 } |
654 } | 354 } |
OLD | NEW |