Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(513)

Unified Diff: pkg/analyzer_experimental/lib/src/generated/constant.dart

Issue 14308011: New Analysis Engine snapshot. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer_experimental/lib/src/generated/constant.dart
diff --git a/pkg/analyzer_experimental/lib/src/generated/constant.dart b/pkg/analyzer_experimental/lib/src/generated/constant.dart
index 6dfbb47179c983c80778a73b24012cd3283705f5..4f7f0abd35f3af86bfe1bfe768d357320f404dd5 100644
--- a/pkg/analyzer_experimental/lib/src/generated/constant.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/constant.dart
@@ -9,6 +9,7 @@ import 'error.dart' show AnalysisError, ErrorCode, CompileTimeErrorCode;
import 'scanner.dart' show TokenType;
import 'ast.dart';
import 'element.dart';
+import 'engine.dart' show AnalysisEngine;
/**
* Instances of the class {@code ConstantEvaluator} evaluate constant expressions to produce their
@@ -124,6 +125,131 @@ class EvaluationResult {
bool isValid() => _errors == null;
}
/**
+ * Instances of the class {@code ConstantFinder} are used to traverse the AST structures of all of
+ * the compilation units being resolved and build a table mapping constant variable elements to the
+ * declarations of those variables.
+ */
+class ConstantFinder extends RecursiveASTVisitor<Object> {
+ /**
+ * A table mapping constant variable elements to the declarations of those variables.
+ */
+ Map<VariableElement, VariableDeclaration> _variableMap = new Map<VariableElement, VariableDeclaration>();
+ /**
+ * Initialize a newly created constant finder.
+ */
+ ConstantFinder() : super() {
+ }
+ /**
+ * Return a table mapping constant variable elements to the declarations of those variables.
+ * @return a table mapping constant variable elements to the declarations of those variables
+ */
+ Map<VariableElement, VariableDeclaration> get variableMap => _variableMap;
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ super.visitVariableDeclaration(node);
+ Expression initializer4 = node.initializer;
+ if (initializer4 != null && node.isConst()) {
+ VariableElement element23 = node.element;
+ if (element23 != null) {
+ _variableMap[element23] = node;
+ }
+ }
+ return null;
+ }
+}
+/**
+ * Instances of the class {@code ConstantValueComputer} compute the values of constant variables in
+ * one or more compilation units. The expected usage pattern is for the compilation units to be
+ * added to this computer using the method {@link #add(CompilationUnit)} and then for the method{@link #computeValues()} to invoked exactly once. Any use of an instance after invoking the
+ * method {@link #computeValues()} will result in unpredictable behavior.
+ */
+class ConstantValueComputer {
+ /**
+ * The object used to find constant variables in the compilation units that were added.
+ */
+ ConstantFinder _constantFinder = new ConstantFinder();
+ /**
+ * 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.
+ */
+ DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableElement>();
+ /**
+ * A table mapping constant variables to the declarations of those variables.
+ */
+ Map<VariableElement, VariableDeclaration> _declarationMap;
+ /**
+ * Initialize a newly created constant value computer.
+ */
+ ConstantValueComputer() : super() {
+ }
+ /**
+ * Add the constant variables in the given compilation unit to the list of constant variables
+ * whose value needs to be computed.
+ * @param unit the compilation unit defining the constant variables to be added
+ */
+ void add(CompilationUnit unit) {
+ unit.accept(_constantFinder);
+ }
+ /**
+ * Compute values for all of the constant variables in the compilation units that were added.
+ */
+ void computeValues() {
+ _declarationMap = _constantFinder.variableMap;
+ for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(_declarationMap)) {
+ VariableElement element = entry.getKey();
+ ReferenceFinder referenceFinder = new ReferenceFinder(element, _referenceGraph);
+ _referenceGraph.addNode(element);
+ entry.getValue().initializer.accept(referenceFinder);
+ }
+ while (!_referenceGraph.isEmpty()) {
+ VariableElement element = _referenceGraph.removeSink();
+ while (element != null) {
+ computeValueFor(element);
+ element = _referenceGraph.removeSink();
+ }
+ if (!_referenceGraph.isEmpty()) {
+ List<VariableElement> variablesInCycle = _referenceGraph.findCycle();
+ if (variablesInCycle == null) {
+ AnalysisEngine.instance.logger.logError("Exiting constant value computer with ${_referenceGraph.nodeCount} variables that are neither sinks no in a cycle");
+ return;
+ }
+ for (VariableElement variable in variablesInCycle) {
+ generateCycleError(variablesInCycle, variable);
+ }
+ _referenceGraph.removeAllNodes(variablesInCycle);
+ }
+ }
+ }
+ /**
+ * Compute a value for the given variable.
+ * @param variable the variable for which a value is to be computed
+ */
+ void computeValueFor(VariableElement variable) {
+ VariableDeclaration declaration = _declarationMap[variable];
+ if (declaration == null) {
+ return;
+ }
+ EvaluationResultImpl result = declaration.initializer.accept(new ConstantVisitor());
+ ((variable as VariableElementImpl)).evaluationResult = result;
+ if (result is ErrorResult) {
+ List<AnalysisError> errors = new List<AnalysisError>();
+ for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) {
+ ASTNode node3 = data.node;
+ Source source10 = variable.getAncestor(CompilationUnitElement).source;
+ errors.add(new AnalysisError.con2(source10, node3.offset, node3.length, data.errorCode, []));
+ }
+ }
+ }
+ /**
+ * Generate an error indicating that the given variable is not a valid compile-time constant
+ * because it references at least one of the variables in the given cycle, each of which directly
+ * or indirectly references the variable.
+ * @param variablesInCycle the variables in the cycle that includes the given variable
+ * @param variable the variable that is not a valid compile-time constant
+ */
+ void generateCycleError(List<VariableElement> variablesInCycle, VariableElement variable) {
+ }
+}
+/**
* Instances of the class {@code ConstantVisitor} evaluate constant expressions to produce their
* compile-time value. According to the Dart Language Specification: <blockquote> A constant
* expression is one of the following:
@@ -251,16 +377,16 @@ class ConstantVisitor extends GeneralizingASTVisitor<EvaluationResultImpl> {
return ValidResult.RESULT_OBJECT;
}
EvaluationResultImpl visitMethodInvocation(MethodInvocation node) {
- Element element23 = node.methodName.element;
- if (element23 is FunctionElement) {
- FunctionElement function = element23 as FunctionElement;
+ Element element24 = node.methodName.element;
+ if (element24 is FunctionElement) {
+ FunctionElement function = element24 as FunctionElement;
if (function.name == "identical") {
NodeList<Expression> arguments3 = node.argumentList.arguments;
if (arguments3.length == 2) {
Element enclosingElement2 = function.enclosingElement;
if (enclosingElement2 is CompilationUnitElement) {
- LibraryElement library20 = ((enclosingElement2 as CompilationUnitElement)).library;
- if (library20.isDartCore()) {
+ LibraryElement library30 = ((enclosingElement2 as CompilationUnitElement)).library;
+ if (library30.isDartCore()) {
EvaluationResultImpl leftArgument = arguments3[0].accept(this);
EvaluationResultImpl rightArgument = arguments3[1].accept(this);
return leftArgument.equalEqual(node, rightArgument);
@@ -317,14 +443,16 @@ class ConstantVisitor extends GeneralizingASTVisitor<EvaluationResultImpl> {
* @return the constant value of the static constant
*/
EvaluationResultImpl getConstantValue(ASTNode node, Element element) {
- if (element is PropertyAccessorElementImpl) {
- element = ((element as PropertyAccessorElementImpl)).variable;
+ if (element is PropertyAccessorElement) {
+ element = ((element as PropertyAccessorElement)).variable;
}
if (element is VariableElementImpl) {
EvaluationResultImpl value = ((element as VariableElementImpl)).evaluationResult;
if (value != null) {
return value;
}
+ } else if (element is ExecutableElement) {
+ return new ValidResult(element);
}
return error(node, null);
}
@@ -348,6 +476,147 @@ class ConstantVisitor extends GeneralizingASTVisitor<EvaluationResultImpl> {
}
}
/**
+ * Instances of the class {@code DirectedGraph} implement a directed graph in which the nodes are
+ * arbitrary (client provided) objects and edges are represented implicitly. The graph will allow an
+ * edge from any node to any other node, including itself, but will not represent multiple edges
+ * between the same pair of nodes.
+ * @param N the type of the nodes in the graph
+ */
+class DirectedGraph<N> {
+ /**
+ * The table encoding the edges in the graph. An edge is represented by an entry mapping the head
+ * to a set of tails. Nodes that are not the head of any edge are represented by an entry mapping
+ * the node to an empty set of tails.
+ */
+ Map<N, Set<N>> _edges = new Map<N, Set<N>>();
+ /**
+ * Initialize a newly create directed graph to be empty.
+ */
+ DirectedGraph() : super() {
+ }
+ /**
+ * Add an edge from the given head node to the given tail node. Both nodes will be a part of the
+ * graph after this method is invoked, whether or not they were before.
+ * @param head the node at the head of the edge
+ * @param tail the node at the tail of the edge
+ */
+ void addEdge(N head, N tail) {
+ Set<N> tails = _edges[tail];
+ if (tails == null) {
+ _edges[tail] = new Set<N>();
+ }
+ tails = _edges[head];
+ if (tails == null) {
+ tails = new Set<N>();
+ _edges[head] = tails;
+ }
+ javaSetAdd(tails, tail);
+ }
+ /**
+ * Add the given node to the set of nodes in the graph.
+ * @param node the node to be added
+ */
+ void addNode(N node) {
+ Set<N> tails = _edges[node];
+ if (tails == null) {
+ _edges[node] = new Set<N>();
+ }
+ }
+ /**
+ * Return a list of nodes that form a cycle, or {@code null} if there are no cycles in this graph.
+ * @return a list of nodes that form a cycle
+ */
+ List<N> findCycle() => null;
+ /**
+ * Return the number of nodes in this graph.
+ * @return the number of nodes in this graph
+ */
+ int get nodeCount => _edges.length;
+ /**
+ * Return a set containing the tails of edges that have the given node as their head. The set will
+ * be empty if there are no such edges or if the node is not part of the graph. Clients must not
+ * modify the returned set.
+ * @param head the node at the head of all of the edges whose tails are to be returned
+ * @return a set containing the tails of edges that have the given node as their head
+ */
+ Set<N> getTails(N head) {
+ Set<N> tails = _edges[head];
+ if (tails == null) {
+ return new Set<N>();
+ }
+ return tails;
+ }
+ /**
+ * Return {@code true} if this graph is empty.
+ * @return {@code true} if this graph is empty
+ */
+ bool isEmpty() => _edges.isEmpty;
+ /**
+ * Remove all of the given nodes from this graph. As a consequence, any edges for which those
+ * nodes were either a head or a tail will also be removed.
+ * @param nodes the nodes to be removed
+ */
+ void removeAllNodes(List<N> nodes) {
+ for (N node in nodes) {
+ removeNode(node);
+ }
+ }
+ /**
+ * Remove the edge from the given head node to the given tail node. If there was no such edge then
+ * the graph will be unmodified: the number of edges will be the same and the set of nodes will be
+ * the same (neither node will either be added or removed).
+ * @param head the node at the head of the edge
+ * @param tail the node at the tail of the edge
+ * @return {@code true} if the graph was modified as a result of this operation
+ */
+ void removeEdge(N head, N tail) {
+ Set<N> tails = _edges[head];
+ if (tails != null) {
+ tails.remove(tail);
+ }
+ }
+ /**
+ * Remove the given node from this graph. As a consequence, any edges for which that node was
+ * either a head or a tail will also be removed.
+ * @param node the node to be removed
+ */
+ void removeNode(N node) {
+ _edges.remove(node);
+ for (Set<N> tails in _edges.values) {
+ tails.remove(node);
+ }
+ }
+ /**
+ * Find one node (referred to as a sink node) that has no outgoing edges (that is, for which there
+ * are no edges that have that node as the head of the edge) and remove it from this graph. Return
+ * the node that was removed, or {@code null} if there are no such nodes either because the graph
+ * is empty or because every node in the graph has at least one outgoing edge. As a consequence of
+ * removing the node from the graph any edges for which that node was a tail will also be removed.
+ * @return the sink node that was removed
+ */
+ N removeSink() {
+ N sink = findSink();
+ if (sink == null) {
+ return null;
+ }
+ removeNode(sink);
+ return sink;
+ }
+ /**
+ * Return one node that has no outgoing edges (that is, for which there are no edges that have
+ * that node as the head of the edge), or {@code null} if there are no such nodes.
+ * @return a sink node
+ */
+ N findSink() {
+ for (MapEntry<N, Set<N>> entry in getMapEntrySet(_edges)) {
+ if (entry.getValue().isEmpty) {
+ return entry.getKey();
+ }
+ }
+ return null;
+ }
+}
+/**
* Instances of the class {@code ErrorResult} represent the result of evaluating an expression that
* is not a valid compile time constant.
*/
@@ -363,9 +632,9 @@ class ErrorResult extends EvaluationResultImpl {
* @param errorCode the error code for the error to be generated
*/
ErrorResult.con1(ASTNode node, ErrorCode errorCode) {
- _jtd_constructor_157_impl(node, errorCode);
+ _jtd_constructor_162_impl(node, errorCode);
}
- _jtd_constructor_157_impl(ASTNode node, ErrorCode errorCode) {
+ _jtd_constructor_162_impl(ASTNode node, ErrorCode errorCode) {
_errors.add(new ErrorResult_ErrorData(node, errorCode));
}
/**
@@ -375,9 +644,9 @@ class ErrorResult extends EvaluationResultImpl {
* @param secondResult the second set of results being merged
*/
ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) {
- _jtd_constructor_158_impl(firstResult, secondResult);
+ _jtd_constructor_163_impl(firstResult, secondResult);
}
- _jtd_constructor_158_impl(ErrorResult firstResult, ErrorResult secondResult) {
+ _jtd_constructor_163_impl(ErrorResult firstResult, ErrorResult secondResult) {
_errors.addAll(firstResult._errors);
_errors.addAll(secondResult._errors);
}
@@ -390,7 +659,6 @@ class ErrorResult extends EvaluationResultImpl {
EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideError(node, this);
EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualError(node, this);
List<ErrorResult_ErrorData> get errorData => _errors;
- List<AnalysisError> get errors => new List.from(_errors);
EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanError(node, this);
EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualError(node, this);
EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideError(node, this);
@@ -549,6 +817,45 @@ abstract class EvaluationResultImpl {
EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand);
}
/**
+ * Instances of the class {@code ReferenceFinder} add reference information for a given variable to
+ * the bi-directional mapping used to order the evaluation of constants.
+ */
+class ReferenceFinder extends RecursiveASTVisitor<Object> {
+ /**
+ * The element representing the variable whose initializer will be visited.
+ */
+ VariableElement _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.
+ */
+ DirectedGraph<VariableElement> _referenceGraph;
+ /**
+ * Initialize a newly created reference finder to find references from the given variable to other
+ * variables and to add those references to the given graph.
+ * @param source the element representing the variable whose initializer will be visited
+ * @param referenceGraph a graph recording which variables (heads) reference which other variables
+ * (tails) in their initializers
+ */
+ ReferenceFinder(VariableElement source, DirectedGraph<VariableElement> referenceGraph) {
+ this._source = source;
+ this._referenceGraph = referenceGraph;
+ }
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ Element element25 = node.element;
+ if (element25 is PropertyAccessorElement) {
+ element25 = ((element25 as PropertyAccessorElement)).variable;
+ }
+ if (element25 is VariableElement) {
+ VariableElement variable = element25 as VariableElement;
+ if (variable.isConst()) {
+ _referenceGraph.addEdge(_source, variable);
+ }
+ }
+ return null;
+ }
+}
+/**
* Instances of the class {@code ValidResult} represent the result of attempting to evaluate a valid
* compile time constant expression.
*/
@@ -742,7 +1049,7 @@ class ValidResult extends EvaluationResultImpl {
} else if (leftValue is int) {
if (_value is int) {
if (((_value as int)) == 0) {
- return error2(node.rightOperand, CompileTimeErrorCode.COMPILE_TIME_CONSTANT_RAISES_EXCEPTION_DIVIDE_BY_ZERO);
+ return valueOf3(((leftValue as int)).toDouble() / ((_value as int)).toDouble());
}
return valueOf(((leftValue as int)) ~/ (_value as int));
} else if (_value is double) {
@@ -843,7 +1150,7 @@ class ValidResult extends EvaluationResultImpl {
} else if (leftValue is int) {
if (_value is int) {
if (((_value as int)) == 0) {
- return error2(node.rightOperand, CompileTimeErrorCode.COMPILE_TIME_CONSTANT_RAISES_EXCEPTION_DIVIDE_BY_ZERO);
+ return valueOf3(((leftValue as int)).toDouble() / ((_value as int)).toDouble());
}
return valueOf(((leftValue as int)) ~/ (_value as int));
} else if (_value is double) {
@@ -983,10 +1290,10 @@ class ValidResult extends EvaluationResultImpl {
} else if (_value == null) {
return error(node.rightOperand);
} else if (leftValue is int) {
- if (((_value as int)) == 0) {
- return error2(node.rightOperand, CompileTimeErrorCode.COMPILE_TIME_CONSTANT_RAISES_EXCEPTION_DIVIDE_BY_ZERO);
- }
if (_value is int) {
+ if (((_value as int)) == 0) {
+ return valueOf3(((leftValue as int)).toDouble() % ((_value as int)).toDouble());
+ }
return valueOf(((leftValue as int)).remainder((_value as int)));
} else if (_value is double) {
return valueOf3(((leftValue as int)).toDouble() % ((_value as double)));
« no previous file with comments | « pkg/analyzer_experimental/lib/src/generated/ast.dart ('k') | pkg/analyzer_experimental/lib/src/generated/element.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698