| Index: pkg/analyzer/lib/src/generated/constant.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
|
| index b15ebc6151b44caa58c8a2cc5cf870a1047fddd2..a09d7adfd91e3238f03be3d1ce43a48ec65f060a 100644
|
| --- a/pkg/analyzer/lib/src/generated/constant.dart
|
| +++ b/pkg/analyzer/lib/src/generated/constant.dart
|
| @@ -23,6 +23,11 @@ import 'utilities_collection.dart';
|
| import 'utilities_dart.dart' show ParameterKind;
|
|
|
| /**
|
| + * Callback used by [ReferenceFinder] to report that a dependency was found.
|
| + */
|
| +typedef void ReferenceFinderCallback(Element dependency);
|
| +
|
| +/**
|
| * The state of an object representing a boolean value.
|
| */
|
| class BoolState extends InstanceState {
|
| @@ -186,7 +191,7 @@ class ConstantAstCloner extends AstCloner {
|
| }
|
|
|
| /**
|
| - * Helper class encapsulating the methods for evaluating constant instance
|
| + * Helper class encapsulating the methods for evaluating constants and
|
| * constant instance creation expressions.
|
| */
|
| class ConstantEvaluationEngine {
|
| @@ -303,6 +308,74 @@ class ConstantEvaluationEngine {
|
| }
|
|
|
| /**
|
| + * Determine which constant elements need to have their values computed
|
| + * prior to computing the value of [element], and report them using
|
| + * [callback].
|
| + */
|
| + void computeDependencies(Element element, ReferenceFinderCallback callback) {
|
| + ReferenceFinder referenceFinder = new ReferenceFinder(callback);
|
| + if (element is ParameterElement) {
|
| + if (element.initializer != null) {
|
| + Expression defaultValue =
|
| + (element as ConstVariableElement).constantInitializer;
|
| + if (defaultValue != null) {
|
| + defaultValue.accept(referenceFinder);
|
| + }
|
| + }
|
| + } else if (element is PotentiallyConstVariableElement) {
|
| + element.constantInitializer.accept(referenceFinder);
|
| + } else if (element is ConstructorElementImpl) {
|
| + element.isCycleFree = false;
|
| + ConstructorElement redirectedConstructor =
|
| + getConstRedirectedConstructor(element);
|
| + if (redirectedConstructor != null) {
|
| + ConstructorElement redirectedConstructorBase =
|
| + ConstantEvaluationEngine._getConstructorBase(redirectedConstructor);
|
| + callback(redirectedConstructorBase);
|
| + return;
|
| + }
|
| + bool superInvocationFound = false;
|
| + List<ConstructorInitializer> initializers = element.constantInitializers;
|
| + for (ConstructorInitializer initializer in initializers) {
|
| + if (initializer is SuperConstructorInvocation) {
|
| + superInvocationFound = true;
|
| + }
|
| + initializer.accept(referenceFinder);
|
| + }
|
| + if (!superInvocationFound) {
|
| + // No explicit superconstructor invocation found, so we need to
|
| + // manually insert a reference to the implicit superconstructor.
|
| + InterfaceType superclass =
|
| + (element.returnType as InterfaceType).superclass;
|
| + if (superclass != null && !superclass.isObject) {
|
| + ConstructorElement unnamedConstructor = ConstantEvaluationEngine
|
| + ._getConstructorBase(superclass.element.unnamedConstructor);
|
| + if (unnamedConstructor != null) {
|
| + callback(unnamedConstructor);
|
| + }
|
| + }
|
| + }
|
| + for (FieldElement field in element.enclosingElement.fields) {
|
| + // Note: non-static const isn't allowed but we handle it anyway so that
|
| + // we won't be confused by incorrect code.
|
| + if ((field.isFinal || field.isConst) &&
|
| + !field.isStatic &&
|
| + field.initializer != null) {
|
| + callback(field);
|
| + }
|
| + }
|
| + for (ParameterElement parameterElement in element.parameters) {
|
| + callback(parameterElement);
|
| + }
|
| + } else {
|
| + // Should not happen.
|
| + assert(false);
|
| + AnalysisEngine.instance.logger.logError(
|
| + "Constant value computer trying to compute the value of a node of type ${element.runtimeType}");
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Evaluate a call to fromEnvironment() on the bool, int, or String class. The
|
| * [environmentValue] is the value fetched from the environment. The
|
| * [builtInDefaultValue] is the value that should be used as the default if no
|
| @@ -1005,73 +1078,9 @@ class ConstantValueComputer {
|
| _annotations = _constantFinder.annotations;
|
| for (Element element in _constantsToCompute) {
|
| referenceGraph.addNode(element);
|
| - if (element is ParameterElement) {
|
| - if (element.initializer != null) {
|
| - Expression defaultValue =
|
| - (element as ConstVariableElement).constantInitializer;
|
| - if (defaultValue != null) {
|
| - ReferenceFinder parameterReferenceFinder =
|
| - new ReferenceFinder(element, referenceGraph);
|
| - defaultValue.accept(parameterReferenceFinder);
|
| - }
|
| - }
|
| - } else if (element is PotentiallyConstVariableElement) {
|
| - ReferenceFinder referenceFinder =
|
| - new ReferenceFinder(element, referenceGraph);
|
| - element.constantInitializer.accept(referenceFinder);
|
| - } else if (element is ConstructorElementImpl) {
|
| - element.isCycleFree = false;
|
| - ConstructorElement redirectedConstructor =
|
| - evaluationEngine.getConstRedirectedConstructor(element);
|
| - if (redirectedConstructor != null) {
|
| - ConstructorElement redirectedConstructorBase =
|
| - ConstantEvaluationEngine
|
| - ._getConstructorBase(redirectedConstructor);
|
| - referenceGraph.addEdge(element, redirectedConstructorBase);
|
| - continue;
|
| - }
|
| - ReferenceFinder referenceFinder =
|
| - new ReferenceFinder(element, referenceGraph);
|
| - bool superInvocationFound = false;
|
| - List<ConstructorInitializer> initializers =
|
| - element.constantInitializers;
|
| - for (ConstructorInitializer initializer in initializers) {
|
| - if (initializer is SuperConstructorInvocation) {
|
| - superInvocationFound = true;
|
| - }
|
| - initializer.accept(referenceFinder);
|
| - }
|
| - if (!superInvocationFound) {
|
| - // No explicit superconstructor invocation found, so we need to
|
| - // manually insert a reference to the implicit superconstructor.
|
| - InterfaceType superclass =
|
| - (element.returnType as InterfaceType).superclass;
|
| - if (superclass != null && !superclass.isObject) {
|
| - ConstructorElement unnamedConstructor = ConstantEvaluationEngine
|
| - ._getConstructorBase(superclass.element.unnamedConstructor);
|
| - if (unnamedConstructor != null) {
|
| - referenceGraph.addEdge(element, unnamedConstructor);
|
| - }
|
| - }
|
| - }
|
| - for (FieldElement field in element.enclosingElement.fields) {
|
| - // Note: non-static const isn't allowed but we handle it anyway so that
|
| - // we won't be confused by incorrect code.
|
| - if ((field.isFinal || field.isConst) &&
|
| - !field.isStatic &&
|
| - field.initializer != null) {
|
| - referenceGraph.addEdge(element, field);
|
| - }
|
| - }
|
| - for (ParameterElement parameterElement in element.parameters) {
|
| - referenceGraph.addEdge(element, parameterElement);
|
| - }
|
| - } else {
|
| - // Should not happen.
|
| - assert(false);
|
| - AnalysisEngine.instance.logger.logError(
|
| - "Constant value computer trying to compute the value of a node of type ${element.runtimeType}");
|
| - }
|
| + evaluationEngine.computeDependencies(element, (Element dependency) {
|
| + referenceGraph.addEdge(element, dependency);
|
| + });
|
| }
|
| List<List<Element>> topologicalSort =
|
| referenceGraph.computeTopologicalSort();
|
| @@ -4865,25 +4874,17 @@ class NumState extends InstanceState {
|
| */
|
| class ReferenceFinder extends RecursiveAstVisitor<Object> {
|
| /**
|
| - * The element representing the construct that will be visited.
|
| - */
|
| - final Element _source;
|
| -
|
| - /**
|
| - * A graph in which the nodes are the constant variables and the edges are
|
| - * from each variable to the other constant variables that are referenced in
|
| - * the head's initializer.
|
| + * The callback which should be used to report any dependencies that were
|
| + * found.
|
| */
|
| - final DirectedGraph<Element> _referenceGraph;
|
| + final ReferenceFinderCallback _callback;
|
|
|
| /**
|
| * Initialize a newly created reference finder to find references from a given
|
| * variable to other variables and to add those references to the given graph.
|
| - * The [source] is the element representing the variable whose initializer
|
| - * will be visited. The [referenceGraph] is a graph recording which variables
|
| - * (heads) reference which other variables (tails) in their initializers.
|
| + * The [_callback] will be invoked for every dependency found.
|
| */
|
| - ReferenceFinder(this._source, this._referenceGraph);
|
| + ReferenceFinder(this._callback);
|
|
|
| @override
|
| Object visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| @@ -4891,7 +4892,7 @@ class ReferenceFinder extends RecursiveAstVisitor<Object> {
|
| ConstructorElement constructor =
|
| ConstantEvaluationEngine._getConstructorBase(node.staticElement);
|
| if (constructor != null) {
|
| - _referenceGraph.addEdge(_source, constructor);
|
| + _callback(constructor);
|
| }
|
| }
|
| return super.visitInstanceCreationExpression(node);
|
| @@ -4904,7 +4905,7 @@ class ReferenceFinder extends RecursiveAstVisitor<Object> {
|
| ConstructorElement target =
|
| ConstantEvaluationEngine._getConstructorBase(node.staticElement);
|
| if (target != null && target.isConst) {
|
| - _referenceGraph.addEdge(_source, target);
|
| + _callback(target);
|
| }
|
| return null;
|
| }
|
| @@ -4917,7 +4918,7 @@ class ReferenceFinder extends RecursiveAstVisitor<Object> {
|
| }
|
| if (element is VariableElement) {
|
| if (element.isConst) {
|
| - _referenceGraph.addEdge(_source, element);
|
| + _callback(element);
|
| }
|
| }
|
| return null;
|
| @@ -4929,7 +4930,7 @@ class ReferenceFinder extends RecursiveAstVisitor<Object> {
|
| ConstructorElement constructor =
|
| ConstantEvaluationEngine._getConstructorBase(node.staticElement);
|
| if (constructor != null && constructor.isConst) {
|
| - _referenceGraph.addEdge(_source, constructor);
|
| + _callback(constructor);
|
| }
|
| return null;
|
| }
|
|
|