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

Unified Diff: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/constant/ConstantValueComputer.java

Issue 270813004: Evaluate constant instance creation expressions in ConstantValueComputer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 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: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/constant/ConstantValueComputer.java
diff --git a/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/constant/ConstantValueComputer.java b/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/constant/ConstantValueComputer.java
index a6029e2419d27d996aa4b8bab41cda7227f44fff..34d80d7c637fb5c5c805f6f1d5bf2e7607406446 100644
--- a/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/constant/ConstantValueComputer.java
+++ b/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/constant/ConstantValueComputer.java
@@ -16,18 +16,33 @@ package com.google.dart.engine.internal.constant;
import com.google.dart.engine.AnalysisEngine;
import com.google.dart.engine.ast.AstNode;
import com.google.dart.engine.ast.CompilationUnit;
+import com.google.dart.engine.ast.ConstructorDeclaration;
+import com.google.dart.engine.ast.Expression;
import com.google.dart.engine.ast.InstanceCreationExpression;
+import com.google.dart.engine.ast.NamedExpression;
+import com.google.dart.engine.ast.NodeList;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.element.CompilationUnitElement;
+import com.google.dart.engine.element.ConstructorElement;
+import com.google.dart.engine.element.Element;
+import com.google.dart.engine.element.FieldElement;
+import com.google.dart.engine.element.FieldFormalParameterElement;
+import com.google.dart.engine.element.ParameterElement;
import com.google.dart.engine.element.VariableElement;
import com.google.dart.engine.error.AnalysisError;
import com.google.dart.engine.internal.element.VariableElementImpl;
+import com.google.dart.engine.internal.object.DartObjectImpl;
+import com.google.dart.engine.internal.object.GenericState;
+import com.google.dart.engine.internal.object.SymbolState;
import com.google.dart.engine.internal.resolver.TypeProvider;
import com.google.dart.engine.source.Source;
+import com.google.dart.engine.type.InterfaceType;
import com.google.dart.engine.utilities.collection.DirectedGraph;
+import com.google.dart.engine.utilities.dart.ParameterKind;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -63,6 +78,16 @@ public class ConstantValueComputer {
private HashMap<VariableElement, VariableDeclaration> variableDeclarationMap;
/**
+ * A table mapping constant constructors to the declarations of those constructors.
+ */
+ private HashMap<ConstructorElement, ConstructorDeclaration> constructorDeclarationMap;
+
+ /**
+ * A collection of constant constructor invocations.
+ */
+ private HashSet<InstanceCreationExpression> constructorInvocations;
+
+ /**
* Initialize a newly created constant value computer.
*
* @param typeProvider the type provider used to access known types
@@ -86,16 +111,34 @@ public class ConstantValueComputer {
*/
public void computeValues() {
variableDeclarationMap = constantFinder.getVariableMap();
+ constructorDeclarationMap = constantFinder.getConstructorMap();
+ constructorInvocations = constantFinder.getConstructorInvocations();
for (Map.Entry<VariableElement, VariableDeclaration> entry : variableDeclarationMap.entrySet()) {
VariableDeclaration declaration = entry.getValue();
ReferenceFinder referenceFinder = new ReferenceFinder(
declaration,
referenceGraph,
- variableDeclarationMap);
+ variableDeclarationMap,
+ constructorDeclarationMap);
referenceGraph.addNode(declaration);
declaration.getInitializer().accept(referenceFinder);
}
- // TODO(paulberry): Do the same for constant constructor invocations.
+ for (InstanceCreationExpression expression : constructorInvocations) {
+ ConstructorElement constructor = expression.getStaticElement();
+ referenceGraph.addNode(expression);
+ ConstructorDeclaration declaration = constructorDeclarationMap.get(constructor);
+ // An instance creation expression depends both on the constructor and the arguments passed
+ // to it.
+ ReferenceFinder referenceFinder = new ReferenceFinder(
+ expression,
+ referenceGraph,
+ variableDeclarationMap,
+ constructorDeclarationMap);
+ if (declaration != null) {
+ declaration.accept(referenceFinder);
+ }
+ expression.getArgumentList().accept(referenceFinder);
+ }
beforeGraphWalk();
while (!referenceGraph.isEmpty()) {
AstNode node = referenceGraph.removeSink();
@@ -153,31 +196,127 @@ public class ConstantValueComputer {
*/
private void computeValueFor(AstNode constNode) {
beforeComputeValue(constNode);
+ EvaluationResultImpl result;
+ Element element;
if (constNode instanceof VariableDeclaration) {
VariableDeclaration declaration = (VariableDeclaration) constNode;
- VariableElement variable = declaration.getElement();
- EvaluationResultImpl result = declaration.getInitializer().accept(createConstantVisitor());
- ((VariableElementImpl) variable).setEvaluationResult(result);
- if (result instanceof ErrorResult) {
- ArrayList<AnalysisError> errors = new ArrayList<AnalysisError>();
- for (ErrorResult.ErrorData data : ((ErrorResult) result).getErrorData()) {
- AstNode node = data.getNode();
- Source source = variable.getAncestor(CompilationUnitElement.class).getSource();
- errors.add(new AnalysisError(
- source,
- node.getOffset(),
- node.getLength(),
- data.getErrorCode()));
- }
- }
+ element = declaration.getElement();
+ result = declaration.getInitializer().accept(createConstantVisitor());
+ ((VariableElementImpl) element).setEvaluationResult(result);
} else if (constNode instanceof InstanceCreationExpression) {
- // TODO(paulberry): compute constant value for constant constructor invocations.
+ InstanceCreationExpression expression = (InstanceCreationExpression) constNode;
+ ConstructorElement constructor = expression.getStaticElement();
+ if (constructor == null) {
+ // Couldn't resolve the constructor so we can't compute a value. No problem--the error
+ // has already been reported.
+ return;
+ }
+ element = constructor;
+ ConstantVisitor constantVisitor = createConstantVisitor();
+ result = evaluateInstanceCreationExpression(expression, constructor, constantVisitor);
+ expression.setEvaluationResult(result);
} else {
// Should not happen.
AnalysisEngine.getInstance().getLogger().logError(
"Constant value computer trying to compute the value of a node which is neither a "
+ "VariableDeclaration nor an InstanceCreationExpression");
+ return;
+ }
+ if (result instanceof ErrorResult) {
+ ArrayList<AnalysisError> errors = new ArrayList<AnalysisError>();
Brian Wilkerson 2014/05/08 22:12:49 Am I missing something? It looks like we're popula
Paul Berry 2014/05/08 23:12:46 Wow, you're right. It looks like the entire if-bl
+ for (ErrorResult.ErrorData data : ((ErrorResult) result).getErrorData()) {
+ AstNode node = data.getNode();
+ Source source = element.getAncestor(CompilationUnitElement.class).getSource();
Brian Wilkerson 2014/05/08 22:12:49 Can the source be computed outside the loop?
+ errors.add(new AnalysisError(
+ source,
+ node.getOffset(),
+ node.getLength(),
+ data.getErrorCode()));
+ }
+ }
+ }
+
+ private EvaluationResultImpl evaluateInstanceCreationExpression(
+ InstanceCreationExpression expression, ConstructorElement constructor,
+ ConstantVisitor constantVisitor) {
+ NodeList<Expression> arguments = expression.getArgumentList().getArguments();
+ int argumentCount = arguments.size();
+ DartObjectImpl[] argumentValues = new DartObjectImpl[argumentCount];
+ HashMap<String, DartObjectImpl> namedArgumentValues = new HashMap<String, DartObjectImpl>();
+ for (int i = 0; i < argumentCount; i++) {
+ Expression argument = arguments.get(i);
+ if (argument instanceof NamedExpression) {
+ NamedExpression namedExpression = (NamedExpression) argument;
+ String name = namedExpression.getName().getLabel().getName();
+ namedArgumentValues.put(name, constantVisitor.valueOf(namedExpression.getExpression()));
+ argumentValues[i] = constantVisitor.getNull();
+ } else {
+ argumentValues[i] = constantVisitor.valueOf(argument);
+ }
+ }
+ HashSet<ConstructorElement> constructorsVisited = new HashSet<ConstructorElement>();
+ InterfaceType definingClass = (InterfaceType) constructor.getReturnType();
+ while (constructor.isFactory()) {
+ if (definingClass.getElement().getLibrary().isDartCore()) {
+ String className = definingClass.getName();
+ if (className.equals("Symbol") && argumentCount == 1) {
+ String argumentValue = argumentValues[0].getStringValue();
+ if (argumentValue != null) {
+ return constantVisitor.valid(definingClass, new SymbolState(argumentValue));
+ }
+ }
+ }
+ constructorsVisited.add(constructor);
+ ConstructorElement redirectedConstructor = constructor.getRedirectedConstructor();
+ if (redirectedConstructor == null) {
+ // This can happen if constructor is an external factory constructor. Since there is no
+ // constructor to delegate to, we currently can't evaluate the constant.
+ // TODO(paulberry): if the constructor is one of {bool,int,String}.fromEnvironment(),
+ // we may be able to infer the value based on -D flags provided to the analyzer (see
+ // dartbug.com/17234).
+ return constantVisitor.validWithUnknownValue(definingClass);
+ }
+ if (!redirectedConstructor.isConst()) {
+ // Delegating to a non-const constructor--this is not allowed (and
+ // is checked elsewhere--see [ErrorVerifier.checkForRedirectToNonConstConstructor()]).
+ // So if we encounter it just consider it an unknown value to suppress further errors.
+ return constantVisitor.validWithUnknownValue(definingClass);
+ }
+ if (constructorsVisited.contains(redirectedConstructor)) {
+ // Cycle in redirecting factory constructors--this is not allowed
+ // and is checked elsewhere--see [ErrorVerifier.checkForRecursiveFactoryRedirect()]).
+ // So if we encounter it just consider it an unknown value to suppress further errors.
+ return constantVisitor.validWithUnknownValue(definingClass);
+ }
+ constructor = redirectedConstructor;
+ definingClass = (InterfaceType) constructor.getReturnType();
+ }
+ HashMap<String, DartObjectImpl> fieldMap = new HashMap<String, DartObjectImpl>();
+ ParameterElement[] parameters = constructor.getParameters();
+ int parameterCount = parameters.length;
+ for (int i = 0; i < parameterCount; i++) {
+ ParameterElement parameter = parameters[i];
+ if (parameter.isInitializingFormal()) {
+ FieldElement field = ((FieldFormalParameterElement) parameter).getField();
+ if (field != null) {
+ String fieldName = field.getName();
+ if (parameter.getParameterKind() == ParameterKind.NAMED) {
+ DartObjectImpl argumentValue = namedArgumentValues.get(parameter.getName());
+ if (argumentValue != null) {
+ fieldMap.put(fieldName, argumentValue);
+ }
+ } else if (i < argumentCount) {
+ fieldMap.put(fieldName, argumentValues[i]);
+ // Otherwise, the parameter is assumed to be an optional positional parameter for which
+ // no value was provided.
+ }
+ }
+ }
}
+ // TODO(brianwilkerson) This doesn't handle fields initialized in an initializer. We should be
+ // able to handle fields initialized by the superclass' constructor fairly easily, but other
+ // initializers will be harder.
+ return constantVisitor.valid(definingClass, new GenericState(fieldMap));
}
/**

Powered by Google App Engine
This is Rietveld 408576698