| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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.generated.constant; | 5 library analyzer.src.generated.constant; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 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 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 } else if (constant is ConstructorElement) { | 377 } else if (constant is ConstructorElement) { |
| 378 if (constant.isConst) { | 378 if (constant.isConst) { |
| 379 // No evaluation needs to be done; constructor declarations are only in | 379 // No evaluation needs to be done; constructor declarations are only in |
| 380 // the dependency graph to ensure that any constants referred to in | 380 // the dependency graph to ensure that any constants referred to in |
| 381 // initializer lists and parameter defaults are evaluated before | 381 // initializer lists and parameter defaults are evaluated before |
| 382 // invocations of the constructor. However we do need to annotate the | 382 // invocations of the constructor. However we do need to annotate the |
| 383 // element as being free of constant evaluation cycles so that later | 383 // element as being free of constant evaluation cycles so that later |
| 384 // code will know that it is safe to evaluate. | 384 // code will know that it is safe to evaluate. |
| 385 (constant as ConstructorElementImpl).isCycleFree = true; | 385 (constant as ConstructorElementImpl).isCycleFree = true; |
| 386 } | 386 } |
| 387 } else if (constant is ConstantEvaluationTarget_Annotation) { | 387 } else if (constant is ElementAnnotationImpl) { |
| 388 Annotation constNode = constant.annotation; | 388 Annotation constNode = constant.annotationAst; |
| 389 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; | 389 Element element = constant.element; |
| 390 // elementAnnotation is null if the annotation couldn't be resolved, in | 390 if (element is PropertyAccessorElement && |
| 391 // which case we skip it. | 391 element.variable is VariableElementImpl) { |
| 392 if (elementAnnotation != null) { | 392 // The annotation is a reference to a compile-time constant variable. |
| 393 Element element = elementAnnotation.element; | 393 // Just copy the evaluation result. |
| 394 if (element is PropertyAccessorElement && | 394 VariableElementImpl variableElement = |
| 395 element.variable is VariableElementImpl) { | 395 element.variable as VariableElementImpl; |
| 396 // The annotation is a reference to a compile-time constant variable. | 396 if (variableElement.evaluationResult != null) { |
| 397 // Just copy the evaluation result. | 397 constant.evaluationResult = variableElement.evaluationResult; |
| 398 VariableElementImpl variableElement = | |
| 399 element.variable as VariableElementImpl; | |
| 400 if (variableElement.evaluationResult != null) { | |
| 401 elementAnnotation.evaluationResult = | |
| 402 variableElement.evaluationResult; | |
| 403 } else { | |
| 404 // This could happen in the event that the annotation refers to a | |
| 405 // non-constant. The error is detected elsewhere, so just silently | |
| 406 // ignore it here. | |
| 407 elementAnnotation.evaluationResult = new EvaluationResultImpl(null); | |
| 408 } | |
| 409 } else if (element is ConstructorElementImpl && | |
| 410 element.isConst && | |
| 411 constNode.arguments != null) { | |
| 412 RecordingErrorListener errorListener = new RecordingErrorListener(); | |
| 413 CompilationUnit sourceCompilationUnit = | |
| 414 constNode.getAncestor((node) => node is CompilationUnit); | |
| 415 ErrorReporter errorReporter = new ErrorReporter( | |
| 416 errorListener, sourceCompilationUnit.element.source); | |
| 417 ConstantVisitor constantVisitor = | |
| 418 new ConstantVisitor(this, errorReporter); | |
| 419 DartObjectImpl result = evaluateConstructorCall( | |
| 420 constNode, | |
| 421 constNode.arguments.arguments, | |
| 422 element, | |
| 423 constantVisitor, | |
| 424 errorReporter); | |
| 425 elementAnnotation.evaluationResult = | |
| 426 new EvaluationResultImpl(result, errorListener.errors); | |
| 427 } else { | 398 } else { |
| 428 // This may happen for invalid code (e.g. failing to pass arguments | 399 // This could happen in the event that the annotation refers to a |
| 429 // to an annotation which references a const constructor). The error | 400 // non-constant. The error is detected elsewhere, so just silently |
| 430 // is detected elsewhere, so just silently ignore it here. | 401 // ignore it here. |
| 431 elementAnnotation.evaluationResult = new EvaluationResultImpl(null); | 402 constant.evaluationResult = new EvaluationResultImpl(null); |
| 432 } | 403 } |
| 404 } else if (element is ConstructorElementImpl && |
| 405 element.isConst && |
| 406 constNode.arguments != null) { |
| 407 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 408 ErrorReporter errorReporter = |
| 409 new ErrorReporter(errorListener, constant.source); |
| 410 ConstantVisitor constantVisitor = |
| 411 new ConstantVisitor(this, errorReporter); |
| 412 DartObjectImpl result = evaluateConstructorCall( |
| 413 constNode, |
| 414 constNode.arguments.arguments, |
| 415 element, |
| 416 constantVisitor, |
| 417 errorReporter); |
| 418 constant.evaluationResult = |
| 419 new EvaluationResultImpl(result, errorListener.errors); |
| 420 } else { |
| 421 // This may happen for invalid code (e.g. failing to pass arguments |
| 422 // to an annotation which references a const constructor). The error |
| 423 // is detected elsewhere, so just silently ignore it here. |
| 424 constant.evaluationResult = new EvaluationResultImpl(null); |
| 433 } | 425 } |
| 434 } else if (constant is VariableElement) { | 426 } else if (constant is VariableElement) { |
| 435 // constant is a VariableElement but not a VariableElementImpl. This can | 427 // constant is a VariableElement but not a VariableElementImpl. This can |
| 436 // happen sometimes in the case of invalid user code (for example, a | 428 // happen sometimes in the case of invalid user code (for example, a |
| 437 // constant expression that refers to a nonstatic field inside a generic | 429 // constant expression that refers to a nonstatic field inside a generic |
| 438 // class will wind up referring to a FieldMember). The error is detected | 430 // class will wind up referring to a FieldMember). The error is detected |
| 439 // elsewhere, so just silently ignore it here. | 431 // elsewhere, so just silently ignore it here. |
| 440 } else { | 432 } else { |
| 441 // Should not happen. | 433 // Should not happen. |
| 442 assert(false); | 434 assert(false); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 if ((field.isFinal || field.isConst) && | 507 if ((field.isFinal || field.isConst) && |
| 516 !field.isStatic && | 508 !field.isStatic && |
| 517 field.initializer != null) { | 509 field.initializer != null) { |
| 518 callback(field); | 510 callback(field); |
| 519 } | 511 } |
| 520 } | 512 } |
| 521 for (ParameterElement parameterElement in constant.parameters) { | 513 for (ParameterElement parameterElement in constant.parameters) { |
| 522 callback(parameterElement); | 514 callback(parameterElement); |
| 523 } | 515 } |
| 524 } | 516 } |
| 525 } else if (constant is ConstantEvaluationTarget_Annotation) { | 517 } else if (constant is ElementAnnotationImpl) { |
| 526 Annotation constNode = constant.annotation; | 518 Annotation constNode = constant.annotationAst; |
| 527 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; | 519 Element element = constant.element; |
| 528 // elementAnnotation is null if the annotation couldn't be resolved, in | 520 if (element is PropertyAccessorElement && |
| 529 // which case we skip it. | 521 element.variable is VariableElementImpl) { |
| 530 if (elementAnnotation != null) { | 522 // The annotation is a reference to a compile-time constant variable, |
| 531 Element element = elementAnnotation.element; | 523 // so it depends on the variable. |
| 532 if (element is PropertyAccessorElement && | 524 callback(element.variable); |
| 533 element.variable is VariableElementImpl) { | 525 } else if (element is ConstructorElementImpl) { |
| 534 // The annotation is a reference to a compile-time constant variable, | 526 // The annotation is a constructor invocation, so it depends on the |
| 535 // so it depends on the variable. | 527 // constructor. |
| 536 callback(element.variable); | 528 callback(element); |
| 537 } else if (element is ConstructorElementImpl) { | 529 } else { |
| 538 // The annotation is a constructor invocation, so it depends on the | 530 // This could happen in the event of invalid code. The error will be |
| 539 // constructor. | 531 // reported at constant evaluation time. |
| 540 callback(element); | |
| 541 } else { | |
| 542 // This could happen in the event of invalid code. The error will be | |
| 543 // reported at constant evaluation time. | |
| 544 } | |
| 545 } | 532 } |
| 546 if (constNode.arguments != null) { | 533 if (constNode.arguments != null) { |
| 547 constNode.arguments.accept(referenceFinder); | 534 constNode.arguments.accept(referenceFinder); |
| 548 } | 535 } |
| 549 } else if (constant is VariableElement) { | 536 } else if (constant is VariableElement) { |
| 550 // constant is a VariableElement but not a VariableElementImpl. This can | 537 // constant is a VariableElement but not a VariableElementImpl. This can |
| 551 // happen sometimes in the case of invalid user code (for example, a | 538 // happen sometimes in the case of invalid user code (for example, a |
| 552 // constant expression that refers to a nonstatic field inside a generic | 539 // constant expression that refers to a nonstatic field inside a generic |
| 553 // class will wind up referring to a FieldMember). So just don't bother | 540 // class will wind up referring to a FieldMember). So just don't bother |
| 554 // computing any dependencies. | 541 // computing any dependencies. |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1016 static ConstructorElementImpl _getConstructorBase( | 1003 static ConstructorElementImpl _getConstructorBase( |
| 1017 ConstructorElement constructor) { | 1004 ConstructorElement constructor) { |
| 1018 while (constructor is ConstructorMember) { | 1005 while (constructor is ConstructorMember) { |
| 1019 constructor = (constructor as ConstructorMember).baseElement; | 1006 constructor = (constructor as ConstructorMember).baseElement; |
| 1020 } | 1007 } |
| 1021 return constructor; | 1008 return constructor; |
| 1022 } | 1009 } |
| 1023 } | 1010 } |
| 1024 | 1011 |
| 1025 /** | 1012 /** |
| 1026 * Wrapper around an [Annotation] which can be used as a | |
| 1027 * [ConstantEvaluationTarget]. | |
| 1028 */ | |
| 1029 class ConstantEvaluationTarget_Annotation implements ConstantEvaluationTarget { | |
| 1030 final AnalysisContext context; | |
| 1031 final Source source; | |
| 1032 final Source librarySource; | |
| 1033 final Annotation annotation; | |
| 1034 | |
| 1035 ConstantEvaluationTarget_Annotation( | |
| 1036 this.context, this.source, this.librarySource, this.annotation); | |
| 1037 | |
| 1038 @override | |
| 1039 int get hashCode => JenkinsSmiHash.hash3( | |
| 1040 source.hashCode, librarySource.hashCode, annotation.hashCode); | |
| 1041 | |
| 1042 @override | |
| 1043 bool operator ==(other) { | |
| 1044 if (other is ConstantEvaluationTarget_Annotation) { | |
| 1045 return this.context == other.context && | |
| 1046 this.source == other.source && | |
| 1047 this.librarySource == other.librarySource && | |
| 1048 this.annotation == other.annotation; | |
| 1049 } else { | |
| 1050 return false; | |
| 1051 } | |
| 1052 } | |
| 1053 | |
| 1054 @override | |
| 1055 String toString() => 'Constant: $annotation'; | |
| 1056 } | |
| 1057 | |
| 1058 /** | |
| 1059 * Interface used by unit tests to verify correct dependency analysis during | 1013 * Interface used by unit tests to verify correct dependency analysis during |
| 1060 * constant evaluation. | 1014 * constant evaluation. |
| 1061 */ | 1015 */ |
| 1062 abstract class ConstantEvaluationValidator { | 1016 abstract class ConstantEvaluationValidator { |
| 1063 /** | 1017 /** |
| 1064 * This method is called just before computing the constant value associated | 1018 * This method is called just before computing the constant value associated |
| 1065 * with [constant]. Unit tests will override this method to introduce | 1019 * with [constant]. Unit tests will override this method to introduce |
| 1066 * additional error checking. | 1020 * additional error checking. |
| 1067 */ | 1021 */ |
| 1068 void beforeComputeValue(ConstantEvaluationTarget constant); | 1022 void beforeComputeValue(ConstantEvaluationTarget constant); |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1303 /** | 1257 /** |
| 1304 * True if instance variables marked as "final" should be treated as "const". | 1258 * True if instance variables marked as "final" should be treated as "const". |
| 1305 */ | 1259 */ |
| 1306 bool treatFinalInstanceVarAsConst = false; | 1260 bool treatFinalInstanceVarAsConst = false; |
| 1307 | 1261 |
| 1308 ConstantFinder(this.context, this.source, this.librarySource); | 1262 ConstantFinder(this.context, this.source, this.librarySource); |
| 1309 | 1263 |
| 1310 @override | 1264 @override |
| 1311 Object visitAnnotation(Annotation node) { | 1265 Object visitAnnotation(Annotation node) { |
| 1312 super.visitAnnotation(node); | 1266 super.visitAnnotation(node); |
| 1313 AnalysisContext owningContext = _getOwningContext(); | 1267 ElementAnnotation elementAnnotation = node.elementAnnotation; |
| 1314 constantsToCompute.add(new ConstantEvaluationTarget_Annotation( | 1268 if (elementAnnotation == null) { |
| 1315 owningContext, source, librarySource, node)); | 1269 // Analyzer ignores annotations on "part of" directives. |
| 1270 assert(node.parent is PartOfDirective); |
| 1271 } else { |
| 1272 constantsToCompute.add(elementAnnotation); |
| 1273 } |
| 1316 return null; | 1274 return null; |
| 1317 } | 1275 } |
| 1318 | 1276 |
| 1319 @override | 1277 @override |
| 1320 Object visitClassDeclaration(ClassDeclaration node) { | 1278 Object visitClassDeclaration(ClassDeclaration node) { |
| 1321 bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst; | 1279 bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst; |
| 1322 if (node.element.constructors.any((ConstructorElement e) => e.isConst)) { | 1280 if (node.element.constructors.any((ConstructorElement e) => e.isConst)) { |
| 1323 // Instance vars marked "final" need to be included in the dependency | 1281 // Instance vars marked "final" need to be included in the dependency |
| 1324 // graph, since constant constructors implicitly use the values in their | 1282 // graph, since constant constructors implicitly use the values in their |
| 1325 // initializers. | 1283 // initializers. |
| (...skipping 4142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5468 return BoolState.from(_element == rightElement); | 5426 return BoolState.from(_element == rightElement); |
| 5469 } else if (rightOperand is DynamicState) { | 5427 } else if (rightOperand is DynamicState) { |
| 5470 return BoolState.UNKNOWN_VALUE; | 5428 return BoolState.UNKNOWN_VALUE; |
| 5471 } | 5429 } |
| 5472 return BoolState.FALSE_STATE; | 5430 return BoolState.FALSE_STATE; |
| 5473 } | 5431 } |
| 5474 | 5432 |
| 5475 @override | 5433 @override |
| 5476 String toString() => _element == null ? "-unknown-" : _element.name; | 5434 String toString() => _element == null ? "-unknown-" : _element.name; |
| 5477 } | 5435 } |
| OLD | NEW |