| 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 |