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'; | 5 import 'dart:async'; |
6 import 'dart:convert'; | 6 import 'dart:convert'; |
7 import 'dart:io'; | 7 import 'dart:io'; |
8 | 8 |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/visitor.dart'; | 10 import 'package:analyzer/dart/ast/visitor.dart'; |
(...skipping 12 matching lines...) Expand all Loading... |
23 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 23 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
24 | 24 |
25 import '../../dart/analysis/base.dart'; | 25 import '../../dart/analysis/base.dart'; |
26 | 26 |
27 main() { | 27 main() { |
28 // Use a group() wrapper to specify the timeout. | 28 // Use a group() wrapper to specify the timeout. |
29 group('front_end_inference_test', () { | 29 group('front_end_inference_test', () { |
30 defineReflectiveSuite(() { | 30 defineReflectiveSuite(() { |
31 defineReflectiveTests(RunFrontEndInferenceTest); | 31 defineReflectiveTests(RunFrontEndInferenceTest); |
32 }); | 32 }); |
33 }, timeout: new Timeout(const Duration(seconds: 60))); | 33 }, timeout: new Timeout(const Duration(seconds: 120))); |
34 } | 34 } |
35 | 35 |
36 /// Set this to `true` to cause expectation comments to be updated. | 36 /// Set this to `true` to cause expectation comments to be updated. |
37 const bool fixProblems = false; | 37 const bool fixProblems = false; |
38 | 38 |
| 39 void _appendElementName(StringBuffer buffer, Element element) { |
| 40 // Synthetic FunctionElement(s) don't have a name or enclosing library. |
| 41 if (element.isSynthetic && element is FunctionElement) { |
| 42 return; |
| 43 } |
| 44 |
| 45 LibraryElement library = element.library; |
| 46 if (library == null) { |
| 47 throw new StateError('Unexpected element without library: $element'); |
| 48 } |
| 49 String libraryName = library.name; |
| 50 |
| 51 String name = element.name ?? ''; |
| 52 if (libraryName != 'dart.core' && |
| 53 libraryName != 'dart.async' && |
| 54 libraryName != 'test') { |
| 55 buffer.write('$libraryName::'); |
| 56 } |
| 57 var enclosing = element.enclosingElement; |
| 58 if (enclosing is ClassElement) { |
| 59 buffer.write('${enclosing.name}::'); |
| 60 } |
| 61 buffer.write('$name'); |
| 62 } |
| 63 |
39 @reflectiveTest | 64 @reflectiveTest |
40 class RunFrontEndInferenceTest { | 65 class RunFrontEndInferenceTest { |
41 test_run() async { | 66 test_run() async { |
42 String pkgPath = _findPkgRoot(); | 67 String pkgPath = _findPkgRoot(); |
43 String fePath = pathos.join(pkgPath, 'front_end', 'testcases', 'inference'); | 68 String fePath = pathos.join(pkgPath, 'front_end', 'testcases', 'inference'); |
44 List<File> dartFiles = new Directory(fePath) | 69 List<File> dartFiles = new Directory(fePath) |
45 .listSync() | 70 .listSync() |
46 .where((entry) => entry is File && entry.path.endsWith('.dart')) | 71 .where((entry) => entry is File && entry.path.endsWith('.dart')) |
47 .map((entry) => entry as File) | 72 .map((entry) => entry as File) |
48 .toList(); | 73 .toList(); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 return null; | 133 return null; |
109 } else { | 134 } else { |
110 return validation.problemsAsString; | 135 return validation.problemsAsString; |
111 } | 136 } |
112 } else { | 137 } else { |
113 return null; | 138 return null; |
114 } | 139 } |
115 } | 140 } |
116 } | 141 } |
117 | 142 |
| 143 /// Instance of [InstrumentationValue] describing a [MethodElement]. |
| 144 class _InstrumentationValueForMethodElement extends fasta.InstrumentationValue { |
| 145 final MethodElement element; |
| 146 |
| 147 _InstrumentationValueForMethodElement(this.element); |
| 148 |
| 149 @override |
| 150 String toString() { |
| 151 StringBuffer buffer = new StringBuffer(); |
| 152 _appendElementName(buffer, element); |
| 153 return buffer.toString(); |
| 154 } |
| 155 } |
| 156 |
118 /** | 157 /** |
119 * Instance of [InstrumentationValue] describing a [DartType]. | 158 * Instance of [InstrumentationValue] describing a [DartType]. |
120 */ | 159 */ |
121 class _InstrumentationValueForType extends fasta.InstrumentationValue { | 160 class _InstrumentationValueForType extends fasta.InstrumentationValue { |
122 final DartType type; | 161 final DartType type; |
123 | 162 |
124 _InstrumentationValueForType(this.type); | 163 _InstrumentationValueForType(this.type); |
125 | 164 |
126 @override | 165 @override |
127 String toString() { | 166 String toString() { |
128 StringBuffer buffer = new StringBuffer(); | 167 StringBuffer buffer = new StringBuffer(); |
129 _appendType(buffer, type); | 168 _appendType(buffer, type); |
130 return buffer.toString(); | 169 return buffer.toString(); |
131 } | 170 } |
132 | 171 |
133 void _appendElementName(StringBuffer buffer, Element element) { | |
134 // Synthetic FunctionElement(s) don't have a name or enclosing library. | |
135 if (element.isSynthetic && element is FunctionElement) { | |
136 return; | |
137 } | |
138 | |
139 LibraryElement library = element.library; | |
140 if (library == null) { | |
141 throw new StateError('Unexpected element without library: $element'); | |
142 } | |
143 String libraryName = library.name; | |
144 | |
145 String name = element.name ?? ''; | |
146 if (libraryName != 'dart.core' && | |
147 libraryName != 'dart.async' && | |
148 libraryName != 'test') { | |
149 buffer.write('$libraryName::$name'); | |
150 } else { | |
151 buffer.write('$name'); | |
152 } | |
153 } | |
154 | |
155 void _appendList<T>(StringBuffer buffer, String open, String close, | 172 void _appendList<T>(StringBuffer buffer, String open, String close, |
156 List<T> items, String separator, writeItem(T item), | 173 List<T> items, String separator, writeItem(T item), |
157 {bool includeEmpty: false}) { | 174 {bool includeEmpty: false}) { |
158 if (!includeEmpty && items.isEmpty) { | 175 if (!includeEmpty && items.isEmpty) { |
159 return; | 176 return; |
160 } | 177 } |
161 buffer.write(open); | 178 buffer.write(open); |
162 bool first = true; | 179 bool first = true; |
163 for (T item in items) { | 180 for (T item in items) { |
164 if (!first) { | 181 if (!first) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 | 234 |
218 /** | 235 /** |
219 * Visitor for ASTs that reports instrumentation for types. | 236 * Visitor for ASTs that reports instrumentation for types. |
220 */ | 237 */ |
221 class _InstrumentationVisitor extends RecursiveAstVisitor<Null> { | 238 class _InstrumentationVisitor extends RecursiveAstVisitor<Null> { |
222 final fasta.Instrumentation _instrumentation; | 239 final fasta.Instrumentation _instrumentation; |
223 final Uri uri; | 240 final Uri uri; |
224 | 241 |
225 _InstrumentationVisitor(this._instrumentation, this.uri); | 242 _InstrumentationVisitor(this._instrumentation, this.uri); |
226 | 243 |
| 244 visitBinaryExpression(BinaryExpression node) { |
| 245 super.visitBinaryExpression(node); |
| 246 _recordMethodTarget(node.operator.charOffset, node.staticElement); |
| 247 } |
| 248 |
227 visitFunctionExpression(FunctionExpression node) { | 249 visitFunctionExpression(FunctionExpression node) { |
228 super.visitFunctionExpression(node); | 250 super.visitFunctionExpression(node); |
229 if (node.parent is! FunctionDeclaration) { | 251 if (node.parent is! FunctionDeclaration) { |
230 DartType type = node.staticType; | 252 DartType type = node.staticType; |
231 if (type is FunctionType) { | 253 if (type is FunctionType) { |
232 _instrumentation.record(uri, node.offset, 'returnType', | 254 _instrumentation.record(uri, node.offset, 'returnType', |
233 new _InstrumentationValueForType(type.returnType)); | 255 new _InstrumentationValueForType(type.returnType)); |
234 List<FormalParameter> parameters = node.parameters.parameters; | 256 List<FormalParameter> parameters = node.parameters.parameters; |
235 for (int i = 0; i < parameters.length; i++) { | 257 for (int i = 0; i < parameters.length; i++) { |
236 FormalParameter parameter = parameters[i]; | 258 FormalParameter parameter = parameters[i]; |
237 if (parameter is SimpleFormalParameter && parameter.type == null) { | 259 if (parameter is SimpleFormalParameter && parameter.type == null) { |
238 _recordType(parameter.offset, type.parameters[i].type); | 260 _recordType(parameter.offset, type.parameters[i].type); |
239 } | 261 } |
240 } | 262 } |
241 } | 263 } |
242 } | 264 } |
243 } | 265 } |
244 | 266 |
| 267 visitIndexExpression(IndexExpression node) { |
| 268 super.visitIndexExpression(node); |
| 269 _recordMethodTarget(node.leftBracket.charOffset, node.staticElement); |
| 270 } |
| 271 |
245 visitInstanceCreationExpression(InstanceCreationExpression node) { | 272 visitInstanceCreationExpression(InstanceCreationExpression node) { |
246 super.visitInstanceCreationExpression(node); | 273 super.visitInstanceCreationExpression(node); |
247 DartType type = node.staticType; | 274 DartType type = node.staticType; |
248 if (type is InterfaceType) { | 275 if (type is InterfaceType) { |
249 if (type.typeParameters.isNotEmpty && | 276 if (type.typeParameters.isNotEmpty && |
250 node.constructorName.type.typeArguments == null) { | 277 node.constructorName.type.typeArguments == null) { |
251 _recordTypeArguments(node.constructorName.offset, type.typeArguments); | 278 _recordTypeArguments(node.constructorName.offset, type.typeArguments); |
252 } | 279 } |
253 } | 280 } |
254 } | 281 } |
(...skipping 13 matching lines...) Expand all Loading... |
268 if (node.typeArguments == null) { | 295 if (node.typeArguments == null) { |
269 DartType type = node.staticType; | 296 DartType type = node.staticType; |
270 if (type is InterfaceType) { | 297 if (type is InterfaceType) { |
271 _recordTypeArguments(node.offset, type.typeArguments); | 298 _recordTypeArguments(node.offset, type.typeArguments); |
272 } | 299 } |
273 } | 300 } |
274 } | 301 } |
275 | 302 |
276 visitMethodInvocation(MethodInvocation node) { | 303 visitMethodInvocation(MethodInvocation node) { |
277 super.visitMethodInvocation(node); | 304 super.visitMethodInvocation(node); |
| 305 _recordMethodTarget(node.methodName.offset, node.methodName.staticElement); |
278 if (node.typeArguments == null) { | 306 if (node.typeArguments == null) { |
279 var inferredTypeArguments = _getInferredFunctionTypeArguments( | 307 var inferredTypeArguments = _getInferredFunctionTypeArguments( |
280 node.function.staticType, | 308 node.function.staticType, |
281 node.staticInvokeType, | 309 node.staticInvokeType, |
282 node.typeArguments) | 310 node.typeArguments) |
283 .toList(); | 311 .toList(); |
284 if (inferredTypeArguments.isNotEmpty) { | 312 if (inferredTypeArguments.isNotEmpty) { |
285 _recordTypeArguments(node.methodName.offset, inferredTypeArguments); | 313 _recordTypeArguments(node.methodName.offset, inferredTypeArguments); |
286 } | 314 } |
287 } | 315 } |
288 } | 316 } |
289 | 317 |
| 318 visitPrefixExpression(PrefixExpression node) { |
| 319 super.visitPrefixExpression(node); |
| 320 _recordMethodTarget(node.operator.charOffset, node.staticElement); |
| 321 } |
| 322 |
290 visitSimpleIdentifier(SimpleIdentifier node) { | 323 visitSimpleIdentifier(SimpleIdentifier node) { |
291 super.visitSimpleIdentifier(node); | 324 super.visitSimpleIdentifier(node); |
292 Element element = node.staticElement; | 325 Element element = node.staticElement; |
293 void recordPromotions(DartType elementType) { | 326 void recordPromotions(DartType elementType) { |
294 if (node.inGetterContext() && !node.inDeclarationContext()) { | 327 if (node.inGetterContext() && !node.inDeclarationContext()) { |
295 int offset = node.offset; | 328 int offset = node.offset; |
296 DartType type = node.staticType; | 329 DartType type = node.staticType; |
297 if (identical(type, elementType)) { | 330 if (identical(type, elementType)) { |
298 _instrumentation.record(uri, offset, 'promotedType', | 331 _instrumentation.record(uri, offset, 'promotedType', |
299 const fasta.InstrumentationValueLiteral('none')); | 332 const fasta.InstrumentationValueLiteral('none')); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 if (g is FunctionType && | 364 if (g is FunctionType && |
332 g.typeFormals.isNotEmpty && | 365 g.typeFormals.isNotEmpty && |
333 f is FunctionType && | 366 f is FunctionType && |
334 f.typeFormals.isEmpty) { | 367 f.typeFormals.isEmpty) { |
335 return _recoverTypeArguments(g, f); | 368 return _recoverTypeArguments(g, f); |
336 } else { | 369 } else { |
337 return const []; | 370 return const []; |
338 } | 371 } |
339 } | 372 } |
340 | 373 |
| 374 void _recordMethodTarget(int offset, Element element) { |
| 375 if (element is MethodElement) { |
| 376 _instrumentation.record(uri, offset, 'target', |
| 377 new _InstrumentationValueForMethodElement(element)); |
| 378 } |
| 379 } |
| 380 |
341 void _recordTopType(int offset, DartType type) { | 381 void _recordTopType(int offset, DartType type) { |
342 _instrumentation.record( | 382 _instrumentation.record( |
343 uri, offset, 'topType', new _InstrumentationValueForType(type)); | 383 uri, offset, 'topType', new _InstrumentationValueForType(type)); |
344 } | 384 } |
345 | 385 |
346 void _recordType(int offset, DartType type) { | 386 void _recordType(int offset, DartType type) { |
347 _instrumentation.record( | 387 _instrumentation.record( |
348 uri, offset, 'type', new _InstrumentationValueForType(type)); | 388 uri, offset, 'type', new _InstrumentationValueForType(type)); |
349 } | 389 } |
350 | 390 |
351 void _recordTypeArguments(int offset, List<DartType> typeArguments) { | 391 void _recordTypeArguments(int offset, List<DartType> typeArguments) { |
352 _instrumentation.record(uri, offset, 'typeArgs', | 392 _instrumentation.record(uri, offset, 'typeArgs', |
353 new _InstrumentationValueForTypeArgs(typeArguments)); | 393 new _InstrumentationValueForTypeArgs(typeArguments)); |
354 } | 394 } |
355 | 395 |
356 /// Based on DDC code generator's `_recoverTypeArguments` | 396 /// Based on DDC code generator's `_recoverTypeArguments` |
357 Iterable<DartType> _recoverTypeArguments(FunctionType g, FunctionType f) { | 397 Iterable<DartType> _recoverTypeArguments(FunctionType g, FunctionType f) { |
358 assert(identical(g.element, f.element)); | 398 assert(identical(g.element, f.element)); |
359 assert(g.typeFormals.isNotEmpty && f.typeFormals.isEmpty); | 399 assert(g.typeFormals.isNotEmpty && f.typeFormals.isEmpty); |
360 assert(g.typeFormals.length + g.typeArguments.length == | 400 assert(g.typeFormals.length + g.typeArguments.length == |
361 f.typeArguments.length); | 401 f.typeArguments.length); |
362 return f.typeArguments.skip(g.typeArguments.length); | 402 return f.typeArguments.skip(g.typeArguments.length); |
363 } | 403 } |
364 } | 404 } |
OLD | NEW |