| OLD | NEW |
| 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 analyzer.src.task.strong_mode; | 5 library analyzer.src.task.strong_mode; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/src/generated/ast.dart'; | 9 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; | 10 import 'package:analyzer/src/generated/element.dart'; |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 } | 224 } |
| 225 // | 225 // |
| 226 // Then return the type of the parameter. | 226 // Then return the type of the parameter. |
| 227 // | 227 // |
| 228 return matchingParameter == null | 228 return matchingParameter == null |
| 229 ? typeProvider.dynamicType | 229 ? typeProvider.dynamicType |
| 230 : matchingParameter.type; | 230 : matchingParameter.type; |
| 231 } | 231 } |
| 232 | 232 |
| 233 /** | 233 /** |
| 234 * If the given [accessorElement] represents a non-synthetic instance getter | |
| 235 * for which no return type was provided, infer the return type of the getter. | |
| 236 */ | |
| 237 void _inferAccessor(PropertyAccessorElement accessorElement) { | |
| 238 if (!accessorElement.isSynthetic && | |
| 239 accessorElement.isGetter && | |
| 240 !accessorElement.isStatic && | |
| 241 accessorElement.hasImplicitReturnType) { | |
| 242 List<ExecutableElement> overriddenGetters = inheritanceManager | |
| 243 .lookupOverrides( | |
| 244 accessorElement.enclosingElement, accessorElement.name); | |
| 245 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { | |
| 246 DartType newType = _computeReturnType(overriddenGetters); | |
| 247 List<ExecutableElement> overriddenSetters = inheritanceManager | |
| 248 .lookupOverrides( | |
| 249 accessorElement.enclosingElement, accessorElement.name + '='); | |
| 250 PropertyAccessorElement setter = (accessorElement.enclosingElement | |
| 251 as ClassElement).getSetter(accessorElement.name); | |
| 252 if (setter != null) { | |
| 253 overriddenSetters.add(setter); | |
| 254 } | |
| 255 if (!_isCompatible(newType, overriddenSetters)) { | |
| 256 newType = typeProvider.dynamicType; | |
| 257 } | |
| 258 setReturnType(accessorElement, newType); | |
| 259 (accessorElement.variable as FieldElementImpl).type = newType; | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 /** | |
| 265 * Infer type information for all of the instance members in the given | 234 * Infer type information for all of the instance members in the given |
| 266 * [classElement]. | 235 * [classElement]. |
| 267 */ | 236 */ |
| 268 void _inferClass(ClassElement classElement) { | 237 void _inferClass(ClassElement classElement) { |
| 269 if (classElement is ClassElementImpl) { | 238 if (classElement is ClassElementImpl) { |
| 270 if (classElement.hasBeenInferred) { | 239 if (classElement.hasBeenInferred) { |
| 271 return; | 240 return; |
| 272 } | 241 } |
| 273 if (!elementsBeingInferred.add(classElement)) { | 242 if (!elementsBeingInferred.add(classElement)) { |
| 274 // We have found a circularity in the class hierarchy. For now we just | 243 // We have found a circularity in the class hierarchy. For now we just |
| 275 // stop trying to infer any type information for any classes that | 244 // stop trying to infer any type information for any classes that |
| 276 // inherit from any class in the cycle. We could potentially limit the | 245 // inherit from any class in the cycle. We could potentially limit the |
| 277 // algorithm to only not inferring types in the classes in the cycle, | 246 // algorithm to only not inferring types in the classes in the cycle, |
| 278 // but it isn't clear that the results would be significantly better. | 247 // but it isn't clear that the results would be significantly better. |
| 279 throw new _CycleException(); | 248 throw new _CycleException(); |
| 280 } | 249 } |
| 281 try { | 250 try { |
| 282 // | 251 // |
| 283 // Ensure that all of instance members in the supertypes have had types | 252 // Ensure that all of instance members in the supertypes have had types |
| 284 // inferred for them. | 253 // inferred for them. |
| 285 // | 254 // |
| 286 _inferType(classElement.supertype); | 255 _inferType(classElement.supertype); |
| 287 classElement.mixins.forEach(_inferType); | 256 classElement.mixins.forEach(_inferType); |
| 288 classElement.interfaces.forEach(_inferType); | 257 classElement.interfaces.forEach(_inferType); |
| 289 // | 258 // |
| 290 // Then infer the types for the members. | 259 // Then infer the types for the members. |
| 291 // | 260 // |
| 292 classElement.fields.forEach(_inferField); | 261 classElement.fields.forEach(_inferField); |
| 293 classElement.accessors.forEach(_inferAccessor); | 262 classElement.accessors.forEach(_inferExecutable); |
| 294 classElement.methods.forEach(_inferMethod); | 263 classElement.methods.forEach(_inferExecutable); |
| 295 classElement.hasBeenInferred = true; | 264 classElement.hasBeenInferred = true; |
| 296 } finally { | 265 } finally { |
| 297 elementsBeingInferred.remove(classElement); | 266 elementsBeingInferred.remove(classElement); |
| 298 } | 267 } |
| 299 } | 268 } |
| 300 } | 269 } |
| 301 | 270 |
| 302 /** | 271 /** |
| 303 * If the given [fieldElement] represents a non-synthetic instance field for | 272 * If the given [fieldElement] represents a non-synthetic instance field for |
| 304 * which no type was provided, infer the type of the field. | 273 * which no type was provided, infer the type of the field. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 } | 306 } |
| 338 (fieldElement as FieldElementImpl).type = newType; | 307 (fieldElement as FieldElementImpl).type = newType; |
| 339 setReturnType(fieldElement.getter, newType); | 308 setReturnType(fieldElement.getter, newType); |
| 340 if (!fieldElement.isFinal && !fieldElement.isConst) { | 309 if (!fieldElement.isFinal && !fieldElement.isConst) { |
| 341 setParameterType(fieldElement.setter, newType); | 310 setParameterType(fieldElement.setter, newType); |
| 342 } | 311 } |
| 343 } | 312 } |
| 344 } | 313 } |
| 345 | 314 |
| 346 /** | 315 /** |
| 347 * If the given [methodElement] represents a non-synthetic instance method | 316 * If the given [element] represents a non-synthetic instance method, |
| 348 * for which no return type was provided, infer the return type of the method. | 317 * getter or setter, infer the return type and any parameter type(s) where |
| 318 * they were not provided. |
| 349 */ | 319 */ |
| 350 void _inferMethod(MethodElement methodElement) { | 320 void _inferExecutable(ExecutableElement element) { |
| 351 if (methodElement.isSynthetic || methodElement.isStatic) { | 321 if (element.isSynthetic || element.isStatic) { |
| 352 return; | 322 return; |
| 353 } | 323 } |
| 354 List<ExecutableElement> overriddenMethods = null; | 324 List<ExecutableElement> overriddenMethods = null; |
| 355 // | 325 // |
| 356 // Infer the return type. | 326 // Infer the return type. |
| 357 // | 327 // |
| 358 if (methodElement.hasImplicitReturnType) { | 328 if (element.hasImplicitReturnType) { |
| 359 overriddenMethods = inheritanceManager.lookupOverrides( | 329 overriddenMethods = inheritanceManager.lookupOverrides( |
| 360 methodElement.enclosingElement, methodElement.name); | 330 element.enclosingElement, element.name); |
| 361 if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { | 331 if (overriddenMethods.isEmpty || |
| 332 !_allSameElementKind(element, overriddenMethods)) { |
| 362 return; | 333 return; |
| 363 } | 334 } |
| 364 MethodElementImpl element = methodElement as MethodElementImpl; | |
| 365 setReturnType(element, _computeReturnType(overriddenMethods)); | 335 setReturnType(element, _computeReturnType(overriddenMethods)); |
| 336 if (element is PropertyAccessorElement) { |
| 337 _updateSyntheticVariableType(element); |
| 338 } |
| 366 } | 339 } |
| 367 // | 340 // |
| 368 // Infer the parameter types. | 341 // Infer the parameter types. |
| 369 // | 342 // |
| 370 List<ParameterElement> parameters = methodElement.parameters; | 343 List<ParameterElement> parameters = element.parameters; |
| 371 int length = parameters.length; | 344 int length = parameters.length; |
| 372 for (int i = 0; i < length; ++i) { | 345 for (int i = 0; i < length; ++i) { |
| 373 ParameterElement parameter = parameters[i]; | 346 ParameterElement parameter = parameters[i]; |
| 374 if (parameter is ParameterElementImpl && parameter.hasImplicitType) { | 347 if (parameter is ParameterElementImpl && parameter.hasImplicitType) { |
| 375 if (overriddenMethods == null) { | 348 if (overriddenMethods == null) { |
| 376 overriddenMethods = inheritanceManager.lookupOverrides( | 349 overriddenMethods = inheritanceManager.lookupOverrides( |
| 377 methodElement.enclosingElement, methodElement.name); | 350 element.enclosingElement, element.name); |
| 378 } | 351 } |
| 379 if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { | 352 if (overriddenMethods.isEmpty || |
| 353 !_allSameElementKind(element, overriddenMethods)) { |
| 380 return; | 354 return; |
| 381 } | 355 } |
| 382 parameter.type = _computeParameterType(parameter, i, overriddenMethods); | 356 parameter.type = _computeParameterType(parameter, i, overriddenMethods); |
| 357 if (element is PropertyAccessorElement) { |
| 358 _updateSyntheticVariableType(element); |
| 359 } |
| 383 } | 360 } |
| 384 } | 361 } |
| 385 } | 362 } |
| 386 | 363 |
| 387 /** | 364 /** |
| 365 * If the given [element] is a non-synthetic getter or setter, update its |
| 366 * synthetic variable's type to match the getter's return type, or if no |
| 367 * corresponding getter exists, use the setter's parameter type. |
| 368 * |
| 369 * In general, the type of the synthetic variable should not be used, because |
| 370 * getters and setters are independent methods. But this logic matches what |
| 371 * `TypeResolverVisitor.visitMethodDeclaration` would fill in there. |
| 372 */ |
| 373 void _updateSyntheticVariableType(PropertyAccessorElement element) { |
| 374 assert(!element.isSynthetic); |
| 375 PropertyAccessorElement getter = element; |
| 376 if (element.isSetter) { |
| 377 // See if we can find any getter. |
| 378 getter = element.correspondingGetter; |
| 379 } |
| 380 DartType newType; |
| 381 if (getter != null) { |
| 382 newType = getter.returnType; |
| 383 } else if (element.isSetter && element.parameters.isNotEmpty) { |
| 384 newType = element.parameters[0].type; |
| 385 } |
| 386 if (newType != null) { |
| 387 (element.variable as VariableElementImpl).type = newType; |
| 388 } |
| 389 } |
| 390 |
| 391 /** |
| 388 * Infer type information for all of the instance members in the given | 392 * Infer type information for all of the instance members in the given |
| 389 * interface [type]. | 393 * interface [type]. |
| 390 */ | 394 */ |
| 391 void _inferType(InterfaceType type) { | 395 void _inferType(InterfaceType type) { |
| 392 if (type != null) { | 396 if (type != null) { |
| 393 ClassElement element = type.element; | 397 ClassElement element = type.element; |
| 394 if (element != null) { | 398 if (element != null) { |
| 395 _inferClass(element); | 399 _inferClass(element); |
| 396 } | 400 } |
| 397 } | 401 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 419 if (!(element is PropertyAccessorElement && element.isGetter)) { | 423 if (!(element is PropertyAccessorElement && element.isGetter)) { |
| 420 return false; | 424 return false; |
| 421 } | 425 } |
| 422 } | 426 } |
| 423 return true; | 427 return true; |
| 424 } | 428 } |
| 425 | 429 |
| 426 /** | 430 /** |
| 427 * Return `true` if the list of [elements] contains only methods. | 431 * Return `true` if the list of [elements] contains only methods. |
| 428 */ | 432 */ |
| 429 bool _onlyMethods(List<ExecutableElement> elements) { | 433 bool _allSameElementKind( |
| 430 for (ExecutableElement element in elements) { | 434 ExecutableElement element, List<ExecutableElement> elements) { |
| 431 if (element is! MethodElement) { | 435 return elements.every((e) => e.kind == element.kind); |
| 432 return false; | |
| 433 } | |
| 434 } | |
| 435 return true; | |
| 436 } | 436 } |
| 437 } | 437 } |
| 438 | 438 |
| 439 /** | 439 /** |
| 440 * A visitor that will gather all of the variables referenced within a given | 440 * A visitor that will gather all of the variables referenced within a given |
| 441 * AST structure. The collection can be restricted to contain only those | 441 * AST structure. The collection can be restricted to contain only those |
| 442 * variables that pass a specified filter. | 442 * variables that pass a specified filter. |
| 443 */ | 443 */ |
| 444 class VariableGatherer extends RecursiveAstVisitor { | 444 class VariableGatherer extends RecursiveAstVisitor { |
| 445 /** | 445 /** |
| (...skipping 24 matching lines...) Expand all Loading... |
| 470 results.add(element); | 470 results.add(element); |
| 471 } | 471 } |
| 472 } | 472 } |
| 473 } | 473 } |
| 474 } | 474 } |
| 475 | 475 |
| 476 /** | 476 /** |
| 477 * A class of exception that is not used anywhere else. | 477 * A class of exception that is not used anywhere else. |
| 478 */ | 478 */ |
| 479 class _CycleException implements Exception {} | 479 class _CycleException implements Exception {} |
| OLD | NEW |