blob: c19fb6145296975bb3bebd62d252b6ff80d29750 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.serialization_test;
import 'dart:io';
import 'memory_compiler.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/constants/constructors.dart';
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/dart_types.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/diagnostics/invariant.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/elements/visitor.dart';
import 'package:compiler/src/ordered_typeset.dart';
import 'package:compiler/src/serialization/element_serialization.dart';
import 'package:compiler/src/serialization/equivalence.dart';
import 'package:compiler/src/serialization/json_serializer.dart';
import 'package:compiler/src/serialization/serialization.dart';
main(List<String> arguments) {
// Ensure that we can print out constant expressions.
DEBUG_MODE = true;
Uri entryPoint;
String outPath;
bool prettyPrint = false;
for (String arg in arguments) {
if (arg.startsWith('--')) {
if (arg.startsWith('--out=')) {
outPath = arg.substring('--out='.length);
} else if (arg == '--pretty-print') {
prettyPrint = true;
} else {
print("Unknown option $arg");
}
} else {
if (entryPoint != null) {
print("Multiple entrypoints is not supported.");
}
entryPoint = Uri.parse(arg);
}
}
if (entryPoint == null) {
entryPoint = Uri.parse('dart:core');
}
asyncTest(() async {
CompilationResult result = await runCompiler(
entryPoint: entryPoint, options: [Flags.analyzeAll]);
Compiler compiler = result.compiler;
testSerialization(compiler.libraryLoader.libraries,
outPath: outPath,
prettyPrint: prettyPrint);
});
}
void testSerialization(Iterable<LibraryElement> libraries1,
{String outPath,
bool prettyPrint}) {
Serializer serializer = new Serializer();
for (LibraryElement library1 in libraries1) {
serializer.serialize(library1);
}
String text = serializer.toText(const JsonSerializationEncoder());
String outText = text;
if (prettyPrint) {
outText = serializer.prettyPrint();
}
if (outPath != null) {
new File(outPath).writeAsStringSync(outText);
} else if (prettyPrint) {
print(outText);
}
Deserializer deserializer = new Deserializer.fromText(
new DeserializationContext(),
text, const JsonSerializationDecoder());
List<LibraryElement> libraries2 = <LibraryElement>[];
for (LibraryElement library1 in libraries1) {
LibraryElement library2 =
deserializer.lookupLibrary(library1.canonicalUri);
if (library2 == null) {
throw new ArgumentError('No library ${library1.canonicalUri} found.');
}
checkLibraryContent('library1', 'library2', 'library', library1, library2);
libraries2.add(library2);
}
Serializer serializer2 = new Serializer();
for (LibraryElement library2 in libraries2) {
serializer2.serialize(library2);
}
String text2 = serializer2.toText(const JsonSerializationEncoder());
Deserializer deserializer3 = new Deserializer.fromText(
new DeserializationContext(),
text2, const JsonSerializationDecoder());
for (LibraryElement library1 in libraries1) {
LibraryElement library2 =
deserializer.lookupLibrary(library1.canonicalUri);
if (library2 == null) {
throw new ArgumentError('No library ${library1.canonicalUri} found.');
}
LibraryElement library3 =
deserializer3.lookupLibrary(library1.canonicalUri);
if (library3 == null) {
throw new ArgumentError('No library ${library1.canonicalUri} found.');
}
checkLibraryContent('library1', 'library3', 'library', library1, library3);
checkLibraryContent('library2', 'library3', 'library', library2, library3);
}
}
/// Check the equivalence of [library1] and [library2] and their content.
///
/// Uses [object1], [object2] and [property] to provide context for failures.
checkLibraryContent(
Object object1, object2, String property,
LibraryElement library1, LibraryElement library2) {
checkElementProperties(object1, object2, property, library1, library2);
}
/// Check the equivalence of [element1] and [element2] and their properties.
///
/// Uses [object1], [object2] and [property] to provide context for failures.
checkElementProperties(
Object object1, object2, String property,
Element element1, Element element2) {
const ElementPropertyEquivalence().visit(element1, element2);
}
/// Check the equivalence of the two lists of elements, [list1] and [list2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
checkElementLists(Object object1, Object object2, String property,
Iterable<Element> list1, Iterable<Element> list2) {
checkListEquivalence(object1, object2, property,
list1, list2, checkElementProperties);
}
/// Check equivalence of the two lists, [list1] and [list2], using
/// [checkEquivalence] to check the pair-wise equivalence.
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkListEquivalence(
Object object1, Object object2, String property,
Iterable list1, Iterable list2,
void checkEquivalence(o1, o2, property, a, b)) {
for (int i = 0; i < list1.length && i < list2.length; i++) {
checkEquivalence(
object1, object2, property,
list1.elementAt(i), list2.elementAt(i));
}
for (int i = list1.length; i < list2.length; i++) {
throw
'Missing equivalent for element '
'#$i ${list2.elementAt(i)} in `${property}` on $object2.\n'
'`${property}` on $object1:\n ${list1.join('\n ')}\n'
'`${property}` on $object2:\n ${list2.join('\n ')}';
}
for (int i = list2.length; i < list1.length; i++) {
throw
'Missing equivalent for element '
'#$i ${list1.elementAt(i)} in `${property}` on $object1.\n'
'`${property}` on $object1:\n ${list1.join('\n ')}\n'
'`${property}` on $object2:\n ${list2.join('\n ')}';
}
return true;
}
/// Computes the set difference between [set1] and [set2] using
/// [elementEquivalence] to determine element equivalence.
///
/// Elements both in [set1] and [set2] are added to [common], elements in [set1]
/// but not in [set2] are added to [unfound], and the set of elements in [set2]
/// but not in [set1] are returned.
Set computeSetDifference(
Iterable set1,
Iterable set2,
List common,
List unfound,
[bool sameElement(a, b) = equality]) {
// TODO(johnniwinther): Avoid the quadratic cost here. Some ideas:
// - convert each set to a list and sort it first, then compare by walking
// both lists in parallel
// - map each element to a canonical object, create a map containing those
// mappings, use the mapped sets to compare (then operations like
// set.difference would work)
Set remaining = set2.toSet();
for (var element1 in set1) {
bool found = false;
for (var element2 in remaining) {
if (sameElement(element1, element2)) {
found = true;
remaining.remove(element2);
break;
}
}
if (found) {
common.add(element1);
} else {
unfound.add(element1);
}
}
return remaining;
}
/// Check equivalence of the two iterables, [set1] and [set1], as sets using
/// [elementEquivalence] to compute the pair-wise equivalence.
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkSetEquivalence(
var object1,
var object2,
String property,
Iterable set1,
Iterable set2,
bool sameElement(a, b)) {
List common = [];
List unfound = [];
Set remaining =
computeSetDifference(set1, set2, common, unfound, sameElement);
if (unfound.isNotEmpty || remaining.isNotEmpty) {
String message =
"Set mismatch for `$property` on $object1 vs $object2: \n"
"Common:\n ${common.join('\n ')}\n"
"Unfound:\n ${unfound.join('\n ')}\n"
"Extra: \n ${remaining.join('\n ')}";
throw message;
}
return true;
}
/// Checks the equivalence of the identity (but not properties) of [element1]
/// and [element2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkElementIdentities(
Object object1, Object object2, String property,
Element element1, Element element2) {
if (identical(element1, element2)) return true;
if (element1 == null || element2 == null) {
return check(object1, object2, property, element1, element2);
} else {
return const ElementIdentityEquivalence(const CheckStrategy())
.visit(element1, element2);
}
}
/// Checks the pair-wise equivalence of the identity (but not properties) of the
/// elements in [list] and [list2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkElementListIdentities(
Object object1, Object object2, String property,
Iterable<Element> list1, Iterable<Element> list2) {
return checkListEquivalence(
object1, object2, property,
list1, list2, checkElementIdentities);
}
/// Checks the equivalence of [type1] and [type2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkTypes(
Object object1, Object object2, String property,
DartType type1, DartType type2) {
if (identical(type1, type2)) return true;
if (type1 == null || type2 == null) {
return check(object1, object2, property, type1, type2);
} else {
return const TypeEquivalence(const CheckStrategy()).visit(type1, type2);
}
}
/// Checks the pair-wise equivalence of the types in [list1] and [list2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkTypeLists(
Object object1, Object object2, String property,
List<DartType> list1, List<DartType> list2) {
return checkListEquivalence(
object1, object2, property, list1, list2, checkTypes);
}
/// Checks the equivalence of [exp1] and [exp2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkConstants(
Object object1, Object object2, String property,
ConstantExpression exp1, ConstantExpression exp2) {
if (identical(exp1, exp2)) return true;
if (exp1 == null || exp2 == null) {
return check(object1, object2, property, exp1, exp2);
} else {
return const ConstantEquivalence(const CheckStrategy()).visit(exp1, exp2);
}
}
/// Checks the pair-wise equivalence of the contants in [list1] and [list2].
///
/// Uses [object1], [object2] and [property] to provide context for failures.
bool checkConstantLists(
Object object1, Object object2, String property,
List<ConstantExpression> list1,
List<ConstantExpression> list2) {
return checkListEquivalence(
object1, object2, property,
list1, list2, checkConstants);
}
/// Strategy for checking equivalence.
///
/// Use this strategy to fail early with contextual information in the event of
/// inequivalence.
class CheckStrategy implements TestStrategy {
const CheckStrategy();
@override
bool test(var object1, var object2, String property, var value1, var value2) {
return check(object1, object2, property, value1, value2);
}
@override
bool testLists(
Object object1, Object object2, String property,
List list1, List list2,
[bool elementEquivalence(a, b) = equality]) {
return checkListEquivalence(
object1, object2, property, list1, list2,
(o1, o2, p, v1, v2) {
if (!elementEquivalence(v1, v2)) {
throw "$o1.$p = '${v1}' <> "
"$o2.$p = '${v2}'";
}
return true;
});
}
@override
bool testSets(
var object1, var object2, String property,
Iterable set1, Iterable set2,
[bool elementEquivalence(a, b) = equality]) {
return checkSetEquivalence(
object1, object2,property, set1, set2, elementEquivalence);
}
@override
bool testElements(
Object object1, Object object2, String property,
Element element1, Element element2) {
return checkElementIdentities(
object1, object2, property, element1, element2);
}
@override
bool testTypes(
Object object1, Object object2, String property,
DartType type1, DartType type2) {
return checkTypes(object1, object2, property, type1, type2);
}
@override
bool testConstants(
Object object1, Object object2, String property,
ConstantExpression exp1, ConstantExpression exp2) {
return checkConstants(object1, object2, property, exp1, exp2);
}
@override
bool testTypeLists(
Object object1, Object object2, String property,
List<DartType> list1, List<DartType> list2) {
return checkTypeLists(object1, object2, property, list1, list2);
}
@override
bool testConstantLists(
Object object1, Object object2, String property,
List<ConstantExpression> list1,
List<ConstantExpression> list2) {
return checkConstantLists(object1, object2, property, list1, list2);
}
}
/// Checks the equivalence of [constructor1] and [constructor2].
void constantConstructorEquivalence(ConstantConstructor constructor1,
ConstantConstructor constructor2) {
const ConstantConstructorEquivalence().visit(constructor1, constructor2);
}
/// Visitor that checks the equivalence of [ConstantConstructor]s.
class ConstantConstructorEquivalence
extends ConstantConstructorVisitor<dynamic, ConstantConstructor> {
const ConstantConstructorEquivalence();
@override
void visit(ConstantConstructor constructor1,
ConstantConstructor constructor2) {
if (identical(constructor1, constructor2)) return;
check(constructor1, constructor2, 'kind',
constructor1.kind, constructor2.kind);
constructor1.accept(this, constructor2);
}
@override
visitGenerative(
GenerativeConstantConstructor constructor1,
GenerativeConstantConstructor constructor2) {
checkTypes(
constructor1, constructor2, 'type',
constructor1.type, constructor2.type);
check(constructor1, constructor2, 'defaultValues.length',
constructor1.defaultValues.length,
constructor2.defaultValues.length);
constructor1.defaultValues.forEach((k, v) {
checkConstants(
constructor1, constructor2, 'defaultValue[$k]',
v, constructor2.defaultValues[k]);
});
check(constructor1, constructor2, 'fieldMap.length',
constructor1.fieldMap.length,
constructor2.fieldMap.length);
constructor1.fieldMap.forEach((k1, v1) {
bool matched = false;
constructor2.fieldMap.forEach((k2, v2) {
if (k1.name == k2.name &&
k1.library.canonicalUri == k2.library.canonicalUri) {
checkElementIdentities(
constructor1, constructor2, 'fieldMap[${k1.name}].key', k1, k2);
checkConstants(
constructor1, constructor2, 'fieldMap[${k1.name}].value', v1, v2);
matched = true;
}
});
if (!matched) {
throw 'Unmatched field $k1 = $v1';
}
});
checkConstants(
constructor1, constructor2, 'superConstructorInvocation',
constructor1.superConstructorInvocation,
constructor2.superConstructorInvocation);
}
@override
visitRedirectingFactory(
RedirectingFactoryConstantConstructor constructor1,
RedirectingFactoryConstantConstructor constructor2) {
checkConstants(
constructor1, constructor2, 'targetConstructorInvocation',
constructor1.targetConstructorInvocation,
constructor2.targetConstructorInvocation);
}
@override
visitRedirectingGenerative(
RedirectingGenerativeConstantConstructor constructor1,
RedirectingGenerativeConstantConstructor constructor2) {
check(constructor1, constructor2, 'defaultValues.length',
constructor1.defaultValues.length,
constructor2.defaultValues.length);
constructor1.defaultValues.forEach((k, v) {
checkConstants(
constructor1, constructor2, 'defaultValue[$k]',
v, constructor2.defaultValues[k]);
});
checkConstants(
constructor1, constructor2, 'thisConstructorInvocation',
constructor1.thisConstructorInvocation,
constructor2.thisConstructorInvocation);
}
}
/// Check that the values [property] of [object1] and [object2], [value1] and
/// [value2] respectively, are equal and throw otherwise.
bool check(var object1, var object2, String property, var value1, value2) {
if (value1 != value2) {
throw "$object1.$property = '${value1}' <> "
"$object2.$property = '${value2}'";
}
return true;
}
/// Visitor that checks for equivalence of [Element] properties.
class ElementPropertyEquivalence extends BaseElementVisitor<dynamic, Element> {
const ElementPropertyEquivalence();
void visit(Element element1, Element element2) {
if (element1 == null && element2 == null) return;
element1 = element1.declaration;
element2 = element2.declaration;
if (element1 == element2) return;
check(element1, element2, 'kind', element1.kind, element2.kind);
element1.accept(this, element2);
}
@override
void visitElement(Element e, Element arg) {
throw new UnsupportedError("Unsupported element $e");
}
@override
void visitLibraryElement(LibraryElement element1, LibraryElement element2) {
checkElementIdentities(null, null, null, element1, element2);
check(element1, element2, 'name', element1.name, element2.name);
check(element1, element2, 'libraryName',
element1.libraryName, element2.libraryName);
visitMembers(element1, element2);
visit(element1.entryCompilationUnit, element2.entryCompilationUnit);
checkElementLists(
element1, element2, 'compilationUnits',
LibrarySerializer.getCompilationUnits(element1),
LibrarySerializer.getCompilationUnits(element2));
checkElementListIdentities(
element1, element2, 'imports',
LibrarySerializer.getImports(element1),
LibrarySerializer.getImports(element2));
checkElementListIdentities(
element1, element2, 'exports', element1.exports, element2.exports);
checkElementListIdentities(
element1, element2, 'importScope',
LibrarySerializer.getImportedElements(element1),
LibrarySerializer.getImportedElements(element2));
checkElementListIdentities(
element1, element2, 'exportScope',
LibrarySerializer.getExportedElements(element1),
LibrarySerializer.getExportedElements(element2));
}
@override
void visitCompilationUnitElement(CompilationUnitElement element1,
CompilationUnitElement element2) {
check(element1, element2,
'name',
element1.name, element2.name);
checkElementIdentities(
element1, element2, 'library',
element1.library, element2.library);
check(element1, element2,
'script.resourceUri',
element1.script.resourceUri, element2.script.resourceUri);
List<Element> members1 = <Element>[];
List<Element> members2 = <Element>[];
element1.forEachLocalMember((Element member) {
members1.add(member);
});
element2.forEachLocalMember((Element member) {
members2.add(member);
});
checkElementListIdentities(
element1, element2, 'localMembers', members1, members2);
}
void visitMembers(ScopeContainerElement element1,
ScopeContainerElement element2) {
Set<String> names = new Set<String>();
Iterable<Element> members1 = element1.isLibrary
? LibrarySerializer.getMembers(element1)
: ClassSerializer.getMembers(element1);
Iterable<Element> members2 = element2.isLibrary
? LibrarySerializer.getMembers(element2)
: ClassSerializer.getMembers(element2);
for (Element member in members1) {
names.add(member.name);
}
for (Element member in members2) {
names.add(member.name);
}
element1 = element1.implementation;
element2 = element2.implementation;
for (String name in names) {
Element member1 = element1.localLookup(name);
Element member2 = element2.localLookup(name);
if (member1 == null) {
String message =
'Missing member for $member2 in\n ${members1.join('\n ')}';
if (member2.isAbstractField) {
// TODO(johnniwinther): Ensure abstract fields are handled correctly.
//print(message);
continue;
} else {
throw message;
}
}
if (member2 == null) {
String message =
'Missing member for $member1 in\n ${members2.join('\n ')}';
if (member1.isAbstractField) {
// TODO(johnniwinther): Ensure abstract fields are handled correctly.
//print(message);
continue;
} else {
throw message;
}
}
//print('Checking member ${member1} against ${member2}');
visit(member1, member2);
}
}
@override
void visitClassElement(ClassElement element1, ClassElement element2) {
checkElementIdentities(null, null, null, element1, element2);
check(element1, element2, 'name',
element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
checkElementIdentities(
element1, element2, 'library',
element1.library, element2.library);
checkElementIdentities(
element1, element2, 'compilationUnit',
element1.compilationUnit, element2.compilationUnit);
check(element1, element2, 'isObject',
element1.isObject, element2.isObject);
checkTypeLists(element1, element2, 'typeVariables',
element1.typeVariables, element2.typeVariables);
check(element1, element2, 'isAbstract',
element1.isAbstract, element2.isAbstract);
check(element1, element2, 'isUnnamedMixinApplication',
element1.isUnnamedMixinApplication, element2.isUnnamedMixinApplication);
check(element1, element2, 'isEnumClass',
element1.isEnumClass, element2.isEnumClass);
if (element1.isEnumClass) {
EnumClassElement enum1 = element1;
EnumClassElement enum2 = element2;
checkElementLists(enum1, enum2, 'enumValues',
enum1.enumValues, enum2.enumValues);
}
if (!element1.isObject) {
checkTypes(element1, element2, 'supertype',
element1.supertype, element2.supertype);
}
check(element1, element2, 'hierarchyDepth',
element1.hierarchyDepth, element2.hierarchyDepth);
checkTypeLists(
element1, element2, 'allSupertypes',
element1.allSupertypes.toList(),
element2.allSupertypes.toList());
OrderedTypeSet typeSet1 = element1.allSupertypesAndSelf;
OrderedTypeSet typeSet2 = element1.allSupertypesAndSelf;
checkListEquivalence(
element1, element2, 'allSupertypes',
typeSet1.levelOffsets,
typeSet2.levelOffsets,
check);
check(element1, element2, 'allSupertypesAndSelf.levels',
typeSet1.levels, typeSet2.levels);
checkTypeLists(
element1, element2, 'supertypes',
typeSet1.supertypes.toList(),
typeSet2.supertypes.toList());
checkTypeLists(
element1, element2, 'types',
typeSet1.types.toList(),
typeSet2.types.toList());
checkTypeLists(
element1, element2, 'interfaces',
element1.interfaces.toList(),
element2.interfaces.toList());
List<ConstructorElement> getConstructors(ClassElement cls) {
return cls.implementation.constructors.map((c) => c.declaration).toList();
}
checkElementLists(
element1, element2, 'constructors',
getConstructors(element1),
getConstructors(element2));
visitMembers(element1, element2);
}
@override
void visitFieldElement(FieldElement element1, FieldElement element2) {
checkElementIdentities(null, null, null, element1, element2);
check(element1, element2, 'name',
element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
check(element1, element2, 'isConst',
element1.isConst, element2.isConst);
check(element1, element2, 'isFinal',
element1.isFinal, element2.isFinal);
if (element1.isConst) {
checkConstants(
element1, element2, 'constant',
element1.constant, element2.constant);
}
check(element1, element2, 'isTopLevel',
element1.isTopLevel, element2.isTopLevel);
check(element1, element2, 'isStatic',
element1.isStatic, element2.isStatic);
check(element1, element2, 'isInstanceMember',
element1.isInstanceMember, element2.isInstanceMember);
checkElementIdentities(
element1, element2, 'library',
element1.library, element2.library);
checkElementIdentities(
element1, element2, 'compilationUnit',
element1.compilationUnit, element2.compilationUnit);
checkElementIdentities(
element1, element2, 'enclosingClass',
element1.enclosingClass, element2.enclosingClass);
}
@override
void visitFunctionElement(FunctionElement element1,
FunctionElement element2) {
checkElementIdentities(null, null, null, element1, element2);
check(element1, element2, 'name',
element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
checkListEquivalence(
element1, element2, 'parameters',
element1.parameters, element2.parameters,
checkElementProperties);
check(element1, element2, 'isOperator',
element1.isOperator, element2.isOperator);
checkElementIdentities(
element1, element2, 'library',
element1.library, element2.library);
checkElementIdentities(
element1, element2, 'compilationUnit',
element1.compilationUnit, element2.compilationUnit);
checkElementIdentities(
element1, element2, 'enclosingClass',
element1.enclosingClass, element2.enclosingClass);
}
@override
void visitConstructorElement(ConstructorElement element1,
ConstructorElement element2) {
checkElementIdentities(null, null, null, element1, element2);
checkElementIdentities(
element1, element2, 'enclosingClass',
element1.enclosingClass, element2.enclosingClass);
check(
element1, element2, 'name',
element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
checkListEquivalence(
element1, element2, 'parameters',
element1.parameters, element2.parameters,
checkElementProperties);
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
check(element1, element2, 'isConst',
element1.isConst, element2.isConst);
check(element1, element2, 'isExternal',
element1.isExternal, element2.isExternal);
if (element1.isConst && !element1.isExternal) {
constantConstructorEquivalence(
element1.constantConstructor,
element2.constantConstructor);
}
}
@override
void visitAbstractFieldElement(AbstractFieldElement element1,
AbstractFieldElement element2) {
visit(element1.getter, element2.getter);
visit(element1.setter, element2.setter);
}
@override
void visitTypeVariableElement(TypeVariableElement element1,
TypeVariableElement element2) {
checkElementIdentities(null, null, null, element1, element2);
check(element1, element2, 'name', element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
check(element1, element2, 'index', element1.index, element2.index);
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
checkTypes(
element1, element2, 'bound',
element1.bound, element2.bound);
}
@override
void visitTypedefElement(TypedefElement element1,
TypedefElement element2) {
checkElementIdentities(null, null, null, element1, element2);
check(element1, element2, 'name', element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
checkTypes(
element1, element2, 'alias',
element1.alias, element2.alias);
checkTypeLists(
element1, element2, 'typeVariables',
element1.typeVariables, element2.typeVariables);
checkElementIdentities(
element1, element2, 'library',
element1.library, element2.library);
checkElementIdentities(
element1, element2, 'compilationUnit',
element1.compilationUnit, element2.compilationUnit);
// TODO(johnniwinther): Check the equivalence of typedef parameters.
}
@override
void visitParameterElement(ParameterElement element1,
ParameterElement element2) {
checkElementIdentities(null, null, null, element1, element2);
checkElementIdentities(
element1, element2, 'functionDeclaration',
element1.functionDeclaration, element2.functionDeclaration);
check(element1, element2, 'name', element1.name, element2.name);
check(element1, element2, 'sourcePosition',
element1.sourcePosition, element2.sourcePosition);
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
check(
element1, element2, 'isOptional',
element1.isOptional, element2.isOptional);
check(
element1, element2, 'isNamed',
element1.isNamed, element2.isNamed);
check(element1, element2, 'name', element1.name, element2.name);
if (element1.isOptional) {
checkConstants(
element1, element2, 'constant',
element1.constant, element2.constant);
}
checkElementIdentities(
element1, element2, 'compilationUnit',
element1.compilationUnit, element2.compilationUnit);
}
@override
void visitFieldParameterElement(InitializingFormalElement element1,
InitializingFormalElement element2) {
visitParameterElement(element1, element2);
checkElementIdentities(
element1, element2, 'fieldElement',
element1.fieldElement, element2.fieldElement);
}
@override
void visitImportElement(ImportElement element1, ImportElement element2) {
check(element1, element2, 'uri', element1.uri, element2.uri);
check(
element1, element2, 'isDeferred',
element1.isDeferred, element2.isDeferred);
checkElementProperties(
element1, element2, 'prefix',
element1.prefix, element2.prefix);
checkElementIdentities(
element1, element2, 'importedLibrary',
element1.importedLibrary, element2.importedLibrary);
}
@override
void visitExportElement(ExportElement element1, ExportElement element2) {
check(element1, element2, 'uri', element1.uri, element2.uri);
checkElementIdentities(
element1, element2, 'importedLibrary',
element1.exportedLibrary, element2.exportedLibrary);
}
@override
void visitPrefixElement(PrefixElement element1, PrefixElement element2) {
check(
element1, element2, 'isDeferred',
element1.isDeferred, element2.isDeferred);
checkElementIdentities(
element1, element2, 'importedLibrary',
element1.deferredImport, element2.deferredImport);
// TODO(johnniwinther): Check members.
}
}