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

Unified Diff: pkg/analyzer/lib/src/summary/summarize_elements.dart

Issue 1602203004: Serialize constant initializers. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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/lib/src/summary/summarize_elements.dart
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 13d568870817c9f97de5ac933963014ac6dd8554..d18f856829781a0b327ba261d743162f3e104444 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -6,8 +6,11 @@ library serialization.elements;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/name_filter.dart';
@@ -50,8 +53,278 @@ class LibrarySerializationResult {
}
/**
+ * Error that described a problem during a constant expression serialization.
Paul Berry 2016/01/19 20:02:10 s/described/describes/
scheglov 2016/01/19 20:59:28 Done.
+ */
+class _ConstExprSerializationError {
+ final String message;
+
+ _ConstExprSerializationError(this.message);
+
+ @override
+ String toString() => message;
+}
+
+/**
* Instances of this class keep track of intermediate state during
- * serialization of a single library.`
+ * serialization of a single constant [Expression].
+ */
+class _ConstExprSerializer {
+ final _LibrarySerializer serializer;
+
+ /**
+ * See [UnlinkedConstBuilder.operations].
+ */
+ final List<UnlinkedConstOperation> operations = <UnlinkedConstOperation>[];
+
+ /**
+ * See [UnlinkedConstBuilder.ints].
+ */
+ final List<int> ints = <int>[];
+
+ /**
+ * See [UnlinkedConstBuilder.doubles].
+ */
+ final List<double> doubles = <double>[];
+
+ /**
+ * See [UnlinkedConstBuilder.strings].
+ */
+ final List<String> strings = <String>[];
+
+ /**
+ * See [UnlinkedConstBuilder.references].
+ */
+ final List<UnlinkedTypeRefBuilder> references = <UnlinkedTypeRefBuilder>[];
+
+ _ConstExprSerializer(this.serializer);
+
+ /**
+ * Serialize the given [expr] expression into this serializer state.
+ */
+ void serialize(Expression expr) {
+ if (expr is IntegerLiteral) {
+ _pushInt(expr.value);
+ } else if (expr is DoubleLiteral) {
+ operations.add(UnlinkedConstOperation.pushDouble);
+ doubles.add(expr.value);
+ } else if (expr is BooleanLiteral) {
+ if (expr.value) {
+ operations.add(UnlinkedConstOperation.pushTrue);
+ } else {
+ operations.add(UnlinkedConstOperation.pushFalse);
+ }
+ } else if (expr is StringLiteral) {
+ _serializeString(expr);
+ } else if (expr is SymbolLiteral) {
+ for (Token component in expr.components) {
Paul Berry 2016/01/19 20:02:10 Nit: why not just concatenate all the components t
scheglov 2016/01/19 20:59:28 Done.
+ operations.add(UnlinkedConstOperation.pushString);
+ strings.add(component.lexeme);
+ }
+ operations.add(UnlinkedConstOperation.makeSymbol);
+ ints.add(expr.components.length);
+ } else if (expr is NullLiteral) {
+ operations.add(UnlinkedConstOperation.pushNull);
+ } else if (expr is Identifier) {
+ Element element = expr.staticElement;
+ assert(element != null);
+ // TODO(scheglov) how to serialize element references?
Paul Berry 2016/01/19 20:02:10 Is this TODO still applicable? At first glance it
scheglov 2016/01/19 20:59:28 Yes, I don't like how we do this. We discussed thi
+ operations.add(UnlinkedConstOperation.pushReference);
+ references.add(_serializeIdentifier(element));
+ } else if (expr is InstanceCreationExpression) {
+ _serializeInstanceCreation(expr);
+ } else if (expr is ListLiteral) {
+ _serializeListLiteral(expr);
+ } else if (expr is MapLiteral) {
+ _serializeMapLiteral(expr);
+ } else if (expr is MethodInvocation) {
+ String name = expr.methodName.name;
+ assert(name == 'identical');
Paul Berry 2016/01/19 20:02:10 Add a TODO noting that these assertions will fail
scheglov 2016/01/19 20:59:28 I've added checks that throw _ConstExprSerializati
+ assert(expr.argumentList != null);
+ assert(expr.argumentList.arguments.length == 2);
+ expr.argumentList.arguments.forEach(serialize);
+ operations.add(UnlinkedConstOperation.identical);
+ } else if (expr is BinaryExpression) {
+ _serializeBinaryExpression(expr);
+ } else if (expr is ConditionalExpression) {
+ serialize(expr.condition);
+ serialize(expr.thenExpression);
+ serialize(expr.elseExpression);
+ operations.add(UnlinkedConstOperation.conditional);
+ } else if (expr is PrefixExpression) {
+ _serializePrefixExpression(expr);
+ } else if (expr is PropertyAccess && expr.propertyName.name == 'length') {
+ serialize(expr.target);
+ operations.add(UnlinkedConstOperation.length);
+ } else if (expr is ParenthesizedExpression) {
+ serialize(expr.expression);
+ } else {
+ throw new _ConstExprSerializationError('Unknown expression type: $expr');
+ }
+ }
+
+ /**
+ * Return the [UnlinkedConstBuilder] that corresponds to the state of this
+ * serializer.
+ */
+ UnlinkedConstBuilder toBuilder() {
+ return new UnlinkedConstBuilder(
+ operations: operations,
+ ints: ints,
+ doubles: doubles,
+ strings: strings,
+ references: references);
+ }
+
+ void _pushInt(int value) {
+ if (value >= (2 << 32)) {
Paul Berry 2016/01/19 20:02:10 I don't think this code handles all possible ints
scheglov 2016/01/19 20:59:28 Done.
+ _pushInt(value >> 32);
+ operations.add(UnlinkedConstOperation.shiftOr);
+ ints.add(value & 0xFFFFFFFF);
+ } else {
+ operations.add(UnlinkedConstOperation.pushInt);
+ ints.add(value & 0xFFFFFFFF);
+ }
+ }
+
+ void _serializeBinaryExpression(BinaryExpression expr) {
+ serialize(expr.leftOperand);
+ serialize(expr.rightOperand);
+ TokenType operator = expr.operator.type;
+ if (operator == TokenType.EQ_EQ) {
+ operations.add(UnlinkedConstOperation.equal);
+ } else if (operator == TokenType.BANG_EQ) {
+ operations.add(UnlinkedConstOperation.equal);
+ operations.add(UnlinkedConstOperation.not);
+ } else if (operator == TokenType.AMPERSAND_AMPERSAND) {
+ operations.add(UnlinkedConstOperation.and);
+ } else if (operator == TokenType.BAR_BAR) {
+ operations.add(UnlinkedConstOperation.or);
+ } else if (operator == TokenType.CARET) {
+ operations.add(UnlinkedConstOperation.bitXor);
+ } else if (operator == TokenType.AMPERSAND) {
+ operations.add(UnlinkedConstOperation.bitAnd);
+ } else if (operator == TokenType.BAR) {
+ operations.add(UnlinkedConstOperation.bitOr);
+ } else if (operator == TokenType.GT_GT) {
+ operations.add(UnlinkedConstOperation.bitShiftRight);
+ } else if (operator == TokenType.LT_LT) {
+ operations.add(UnlinkedConstOperation.bitShiftLeft);
+ } else if (operator == TokenType.PLUS) {
+ operations.add(UnlinkedConstOperation.add);
+ } else if (operator == TokenType.MINUS) {
+ operations.add(UnlinkedConstOperation.subtract);
+ } else if (operator == TokenType.STAR) {
+ operations.add(UnlinkedConstOperation.multiply);
+ } else if (operator == TokenType.SLASH) {
+ operations.add(UnlinkedConstOperation.divide);
+ } else if (operator == TokenType.TILDE_SLASH) {
+ operations.add(UnlinkedConstOperation.floorDivide);
+ } else if (operator == TokenType.GT) {
+ operations.add(UnlinkedConstOperation.greater);
+ } else if (operator == TokenType.LT) {
+ operations.add(UnlinkedConstOperation.less);
+ } else if (operator == TokenType.GT_EQ) {
+ operations.add(UnlinkedConstOperation.greaterEqual);
+ } else if (operator == TokenType.LT_EQ) {
+ operations.add(UnlinkedConstOperation.lessEqual);
+ } else if (operator == TokenType.PERCENT) {
+ operations.add(UnlinkedConstOperation.modulo);
+ } else {
+ throw new _ConstExprSerializationError('Unknown operator: $operator');
+ }
+ }
+
+ UnlinkedTypeRefBuilder _serializeIdentifier(Element element) {
+ return new UnlinkedTypeRefBuilder(
+ reference: serializer._getElementReferenceId(element));
+ }
+
+ void _serializeInstanceCreation(InstanceCreationExpression expr) {
+ List<Expression> arguments = expr.argumentList.arguments;
+ arguments.forEach(serialize);
+ ConstructorElement element = expr.staticElement;
+ assert(element != null);
+ operations.add(UnlinkedConstOperation.invokeConstructor);
+ references.add(serializer.serializeTypeRef(element.returnType, null));
+ strings.add(element.name);
+ // TODO(scheglov) named arguments?
Paul Berry 2016/01/19 20:02:10 Oh yeah, good catch. Let me know if you want to b
+ ints.add(arguments.length);
+ }
+
+ void _serializeListLiteral(ListLiteral expr) {
+ List<Expression> elements = expr.elements;
+ elements.forEach(serialize);
+ DartType typeArgument;
+ if (expr.typeArguments != null &&
+ expr.typeArguments.arguments.length == 1) {
+ typeArgument = expr.typeArguments.arguments[0].type;
+ } else {
+ typeArgument = serializer.typeProvider.dynamicType;
+ }
+ references.add(serializer.serializeTypeRef(typeArgument, null));
+ ints.add(elements.length);
+ operations.add(UnlinkedConstOperation.makeList);
+ }
+
+ void _serializeMapLiteral(MapLiteral expr) {
+ for (MapLiteralEntry entry in expr.entries) {
+ serialize(entry.key);
+ serialize(entry.value);
+ }
+ DartType keyTypeArgument;
+ DartType valueTypeArgument;
+ if (expr.typeArguments != null &&
+ expr.typeArguments.arguments.length == 2) {
+ keyTypeArgument = expr.typeArguments.arguments[0].type;
+ valueTypeArgument = expr.typeArguments.arguments[1].type;
+ } else {
+ keyTypeArgument = serializer.typeProvider.dynamicType;
+ valueTypeArgument = serializer.typeProvider.dynamicType;
+ }
+ references.add(serializer.serializeTypeRef(keyTypeArgument, null));
+ references.add(serializer.serializeTypeRef(valueTypeArgument, null));
+ ints.add(expr.entries.length);
+ operations.add(UnlinkedConstOperation.makeMap);
+ }
+
+ void _serializePrefixExpression(PrefixExpression expr) {
+ serialize(expr.operand);
+ TokenType operator = expr.operator.type;
+ if (operator == TokenType.BANG) {
+ operations.add(UnlinkedConstOperation.not);
+ } else if (operator == TokenType.TILDE) {
+ operations.add(UnlinkedConstOperation.complement);
+ } else {
+ throw new _ConstExprSerializationError('Unknown operator: $operator');
+ }
+ }
+
+ void _serializeString(StringLiteral expr) {
+ if (expr is AdjacentStrings) {
+ operations.add(UnlinkedConstOperation.pushString);
Paul Berry 2016/01/19 20:02:10 I think this does the wrong thing if one or more o
scheglov 2016/01/19 20:59:28 Done.
+ strings.add(expr.stringValue);
+ } else if (expr is SimpleStringLiteral) {
+ operations.add(UnlinkedConstOperation.pushString);
+ strings.add(expr.value);
+ } else {
+ StringInterpolation interpolation = expr as StringInterpolation;
+ for (InterpolationElement element in interpolation.elements) {
+ if (element is InterpolationString) {
+ operations.add(UnlinkedConstOperation.pushString);
+ strings.add(element.value);
+ } else {
+ serialize((element as InterpolationExpression).expression);
+ }
+ }
+ operations.add(UnlinkedConstOperation.concatenate);
+ ints.add(interpolation.elements.length);
+ }
+ }
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single library.
*/
class _LibrarySerializer {
/**
@@ -385,6 +658,15 @@ class _LibrarySerializer {
}
/**
+ * Serialize the given [expression], creating an [UnlinkedConstBuilder].
+ */
+ UnlinkedConstBuilder serializeConstExpr(Expression expression) {
+ _ConstExprSerializer serializer = new _ConstExprSerializer(this);
+ serializer.serialize(expression);
+ return serializer.toBuilder();
+ }
+
+ /**
* Return the index of the entry in the dependency table
* ([LinkedLibrary.dependencies]) for the given [dependentLibrary]. A new
* entry is added to the table if necessary to satisfy the request.
@@ -564,18 +846,7 @@ class _LibrarySerializer {
element.getAncestor((Element e) => e is CompilationUnitElement);
int unit = dependentLibrary.units.indexOf(unitElement);
assert(unit != -1);
- ReferenceKind kind;
- if (element is PropertyAccessorElement) {
- kind = ReferenceKind.topLevelPropertyAccessor;
- } else if (element is FunctionTypeAliasElement) {
- kind = ReferenceKind.typedef;
- } else if (element is ClassElement) {
- kind = ReferenceKind.classOrEnum;
- } else if (element is FunctionElement) {
- kind = ReferenceKind.topLevelFunction;
- } else {
- throw new Exception('Unexpected element kind: ${element.runtimeType}');
- }
+ ReferenceKind kind = _getReferenceKind(element);
exportNames.add(new LinkedExportNameBuilder(
name: name,
dependency: serializeDependency(dependentLibrary),
@@ -694,38 +965,7 @@ class _LibrarySerializer {
b.reference = serializeDynamicReference();
}
} else {
- b.reference = referenceMap.putIfAbsent(element, () {
- assert(unlinkedReferences.length == linkedReferences.length);
- CompilationUnitElement unitElement =
- element.getAncestor((Element e) => e is CompilationUnitElement);
- int unit = dependentLibrary.units.indexOf(unitElement);
- assert(unit != -1);
- int numTypeParameters = 0;
- if (element is TypeParameterizedElement) {
- numTypeParameters = element.typeParameters.length;
- }
- // Figure out a prefix that may be used to refer to the given type.
- // TODO(paulberry): to avoid subtle relinking inconsistencies we
- // should use the actual prefix from the AST (a given type may be
- // reachable via multiple prefixes), but sadly, this information is
- // not recorded in the element model.
- int prefixReference = 0;
- PrefixElement prefix = prefixMap[element];
- if (prefix != null) {
- prefixReference = serializePrefix(prefix);
- }
- int index = unlinkedReferences.length;
- unlinkedReferences.add(new UnlinkedReferenceBuilder(
- name: element.name, prefixReference: prefixReference));
- linkedReferences.add(new LinkedReferenceBuilder(
- dependency: serializeDependency(dependentLibrary),
- kind: element is FunctionTypeAliasElement
- ? ReferenceKind.typedef
- : ReferenceKind.classOrEnum,
- unit: unit,
- numTypeParameters: numTypeParameters));
- return index;
- });
+ b.reference = _getElementReferenceId(element);
}
List<DartType> typeArguments;
if (type is InterfaceType) {
@@ -778,6 +1018,63 @@ class _LibrarySerializer {
b.isConst = variable.isConst;
b.hasImplicitType = variable.hasImplicitType;
b.documentationComment = serializeDocumentation(variable);
+ if (variable.isConst && variable is ConstVariableElement) {
+ ConstVariableElement constVariable = variable as ConstVariableElement;
+ Expression initializer = constVariable.constantInitializer;
+ if (initializer != null) {
+ b.constExpr = serializeConstExpr(initializer);
+ }
+ }
return b;
}
+
+ int _getElementReferenceId(Element element) {
+ LibraryElement dependentLibrary = element.library;
+ return referenceMap.putIfAbsent(element, () {
+ assert(unlinkedReferences.length == linkedReferences.length);
+ CompilationUnitElement unitElement =
+ element.getAncestor((Element e) => e is CompilationUnitElement);
+ int unit = dependentLibrary.units.indexOf(unitElement);
+ assert(unit != -1);
+ int numTypeParameters = 0;
+ if (element is TypeParameterizedElement) {
+ numTypeParameters = element.typeParameters.length;
+ }
+ // Figure out a prefix that may be used to refer to the given type.
+ // TODO(paulberry): to avoid subtle relinking inconsistencies we
+ // should use the actual prefix from the AST (a given type may be
+ // reachable via multiple prefixes), but sadly, this information is
+ // not recorded in the element model.
+ int prefixReference = 0;
+ PrefixElement prefix = prefixMap[element];
+ if (prefix != null) {
+ prefixReference = serializePrefix(prefix);
+ }
+ int index = unlinkedReferences.length;
+ unlinkedReferences.add(new UnlinkedReferenceBuilder(
+ name: element.name, prefixReference: prefixReference));
+ linkedReferences.add(new LinkedReferenceBuilder(
+ dependency: serializeDependency(dependentLibrary),
+ kind: _getReferenceKind(element),
+ unit: unit,
+ numTypeParameters: numTypeParameters));
+ return index;
+ });
+ }
+
+ ReferenceKind _getReferenceKind(Element element) {
+ ReferenceKind kind;
+ if (element is PropertyAccessorElement) {
+ kind = ReferenceKind.topLevelPropertyAccessor;
+ } else if (element is FunctionTypeAliasElement) {
+ kind = ReferenceKind.typedef;
+ } else if (element is ClassElement) {
+ kind = ReferenceKind.classOrEnum;
+ } else if (element is FunctionElement) {
+ kind = ReferenceKind.topLevelFunction;
+ } else {
+ throw new Exception('Unexpected element kind: ${element.runtimeType}');
+ }
+ return kind;
+ }
}

Powered by Google App Engine
This is Rietveld 408576698