blob: 23c7b975e9c26fbace0d8bf03819987f8b717e89 [file] [log] [blame]
// Copyright (c) 2021, 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.
import 'package:expect/expect.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/src/equivalence.dart';
void testReferenceNames(Map<ReferenceNameKind, List<ReferenceNameObject>> map1,
Map<ReferenceNameKind, List<ReferenceNameObject>> map2) {
Expect.setEquals(map1.keys, map2.keys);
map1.forEach((ReferenceNameKind kind1, List<ReferenceNameObject> list1) {
map1.forEach((ReferenceNameKind kind2, List<ReferenceNameObject> list2) {
for (int index1 = 0; index1 < list1.length; index1++) {
for (int index2 = 0; index2 < list2.length; index2++) {
ReferenceName name1 = list1[index1].referenceName;
Object object1 = list1[index1].object;
ReferenceName name2 = list2[index2].referenceName;
Object object2 = list2[index2].object;
if (kind1 == kind2 && index1 == index2) {
Expect.equals(
name1,
name2,
"Expected $name1 for ${object1} (${object1.runtimeType}) and "
"$name2 for $object2 (${object2.runtimeType}) to be equal.");
} else {
Expect.notEquals(
name1,
name2,
"Expected $name1 for ${object1} (${object1.runtimeType}) and "
"$name2 for $object2 (${object2.runtimeType}) to be unequal.");
}
}
}
});
});
}
void main() {
Component component1 = createComponent();
Map<ReferenceNameKind, List<ReferenceNameObject>> referenceNames1 =
computeReferenceNamesFromComponent(component1);
Component component2 = createComponent();
Map<ReferenceNameKind, List<ReferenceNameObject>> referenceNames2 =
computeReferenceNamesFromComponent(component2);
Component component3 = createComponent();
component3.computeCanonicalNames();
CanonicalName root3 = component3.root;
Map<ReferenceNameKind, List<ReferenceNameObject>> referenceNames3 =
computeReferenceNamesFromCanonicalName(root3);
Component component4 = createComponent();
component4.computeCanonicalNames();
CanonicalName root4 = component3.root;
Map<ReferenceNameKind, List<ReferenceNameObject>> referenceNames4 =
computeReferenceNamesFromCanonicalName(root4);
testReferenceNames(referenceNames1, referenceNames2);
testReferenceNames(referenceNames1, referenceNames3);
testReferenceNames(referenceNames3, referenceNames4);
}
Component createComponent() {
Component component = new Component();
Library library1 = new Library(Uri.parse('test:library1'), fileUri: dummyUri);
component.libraries.add(library1);
Library library2 = new Library(Uri.parse('test:library2'), fileUri: dummyUri);
component.libraries.add(library2);
library1.addProcedure(new Procedure(
new Name('foo'), ProcedureKind.Method, new FunctionNode(null),
fileUri: dummyUri));
library1.addProcedure(new Procedure(
new Name('bar'), ProcedureKind.Operator, new FunctionNode(null),
fileUri: dummyUri));
library1.addProcedure(new Procedure(
new Name('baz'), ProcedureKind.Factory, new FunctionNode(null),
fileUri: dummyUri));
library1.addProcedure(new Procedure(
new Name('boz'), ProcedureKind.Getter, new FunctionNode(null),
fileUri: dummyUri));
// The setter should be distinct from the getter even when they have the same
// name.
library1.addProcedure(new Procedure(
new Name('boz'), ProcedureKind.Setter, new FunctionNode(null),
fileUri: dummyUri));
library1.addProcedure(new Procedure(
new Name('_boz', library2), ProcedureKind.Getter, new FunctionNode(null),
fileUri: dummyUri));
// The setter should be distinct from the getter even when they have the same
// name.
library1.addProcedure(new Procedure(
new Name('_boz', library2), ProcedureKind.Setter, new FunctionNode(null),
fileUri: dummyUri));
library1.addField(
new Field.immutable(new Name('_foo', library1), fileUri: dummyUri));
library1.addField(
new Field.mutable(new Name('_bar', library2), fileUri: dummyUri));
Class class1 = new Class(name: 'Foo', fileUri: dummyUri);
library2.addClass(class1);
Class class2 = new Class(name: 'Bar', fileUri: dummyUri);
library2.addClass(class2);
class2.addConstructor(new Constructor(new FunctionNode(null),
name: new Name(''), fileUri: dummyUri));
class2.addConstructor(new Constructor(new FunctionNode(null),
name: new Name('_', library1), fileUri: dummyUri));
class2.addProcedure(new Procedure(
new Name('foo'), ProcedureKind.Method, new FunctionNode(null),
fileUri: dummyUri));
class2.addProcedure(new Procedure(
new Name('bar'), ProcedureKind.Operator, new FunctionNode(null),
fileUri: dummyUri));
class2.addProcedure(new Procedure(
new Name('baz'), ProcedureKind.Factory, new FunctionNode(null),
fileUri: dummyUri));
class2.addProcedure(new Procedure(
new Name('boz'), ProcedureKind.Getter, new FunctionNode(null),
fileUri: dummyUri));
// The setter should be distinct from the getter even when they have the same
// name.
class2.addProcedure(new Procedure(
new Name('boz'), ProcedureKind.Setter, new FunctionNode(null),
fileUri: dummyUri));
class2.addProcedure(new Procedure(
new Name('_boz', library2), ProcedureKind.Getter, new FunctionNode(null),
fileUri: dummyUri));
// The setter should be distinct from the getter even when they have the same
// name.
class2.addProcedure(new Procedure(
new Name('_boz', library2), ProcedureKind.Setter, new FunctionNode(null),
fileUri: dummyUri));
class2.addField(
new Field.immutable(new Name('_foo', library1), fileUri: dummyUri));
class2.addField(
new Field.mutable(new Name('_bar', library2), fileUri: dummyUri));
class2.addRedirectingFactory(new RedirectingFactory(null,
name: new Name('_boz', library1),
function: new FunctionNode(null),
fileUri: dummyUri));
library1.addExtension(new Extension(name: 'Baz', fileUri: dummyUri));
library1.addTypedef(new Typedef('Boz', dummyDartType, fileUri: dummyUri));
return component;
}
void sortReferenceNames(Map<ReferenceNameKind, List<ReferenceNameObject>> map) {
map.forEach((key, value) {
value.sort(
(n1, n2) => n1.referenceName.name!.compareTo(n2.referenceName.name!));
});
}
Map<ReferenceNameKind, List<ReferenceNameObject>>
computeReferenceNamesFromComponent(Component component) {
Map<ReferenceNameKind, List<ReferenceNameObject>> map = {};
void add(ReferenceNameKind kind, ReferenceNameObject object) {
(map[kind] ??= []).add(object);
}
for (Library library in component.libraries) {
add(ReferenceNameKind.Library,
new ReferenceNameObject(ReferenceName.fromNamedNode(library), library));
for (Typedef typedef in library.typedefs) {
add(
ReferenceNameKind.Typedef,
new ReferenceNameObject(
ReferenceName.fromNamedNode(typedef), typedef));
}
for (Field field in library.fields) {
add(
ReferenceNameKind.Field,
new ReferenceNameObject(
ReferenceName.fromNamedNode(field, ReferenceNameKind.Field),
field));
add(
ReferenceNameKind.Getter,
new ReferenceNameObject(
ReferenceName.fromNamedNode(field, ReferenceNameKind.Getter),
field));
if (field.hasSetter) {
add(
ReferenceNameKind.Setter,
new ReferenceNameObject(
ReferenceName.fromNamedNode(field, ReferenceNameKind.Setter),
field));
}
}
for (Procedure procedure in library.procedures) {
ReferenceNameKind kind;
if (procedure.isGetter) {
kind = ReferenceNameKind.Getter;
} else if (procedure.isSetter) {
kind = ReferenceNameKind.Setter;
} else {
kind = ReferenceNameKind.Function;
}
add(
kind,
new ReferenceNameObject(
ReferenceName.fromNamedNode(procedure), procedure));
}
for (Class cls in library.classes) {
add(ReferenceNameKind.Declaration,
new ReferenceNameObject(ReferenceName.fromNamedNode(cls), cls));
for (Constructor constructor in cls.constructors) {
add(
ReferenceNameKind.Function,
new ReferenceNameObject(
ReferenceName.fromNamedNode(constructor), constructor));
}
for (Procedure procedure in cls.procedures) {
ReferenceNameKind kind;
if (procedure.isGetter) {
kind = ReferenceNameKind.Getter;
} else if (procedure.isSetter) {
kind = ReferenceNameKind.Setter;
} else {
kind = ReferenceNameKind.Function;
}
add(
kind,
new ReferenceNameObject(
ReferenceName.fromNamedNode(procedure), procedure));
}
for (Field field in cls.fields) {
add(ReferenceNameKind.Field,
new ReferenceNameObject(ReferenceName.fromNamedNode(field), field));
add(
ReferenceNameKind.Getter,
new ReferenceNameObject(
ReferenceName.fromNamedNode(field, ReferenceNameKind.Getter),
field));
if (field.hasSetter) {
add(
ReferenceNameKind.Setter,
new ReferenceNameObject(
ReferenceName.fromNamedNode(field, ReferenceNameKind.Setter),
field));
}
}
for (RedirectingFactory redirectingFactory in cls.redirectingFactories) {
add(
ReferenceNameKind.Function,
new ReferenceNameObject(
ReferenceName.fromNamedNode(redirectingFactory),
redirectingFactory));
}
}
for (Extension extension in library.extensions) {
add(
ReferenceNameKind.Declaration,
new ReferenceNameObject(
ReferenceName.fromNamedNode(extension), extension));
}
}
sortReferenceNames(map);
return map;
}
Map<ReferenceNameKind, List<ReferenceNameObject>>
computeReferenceNamesFromCanonicalName(CanonicalName root) {
Map<ReferenceNameKind, List<ReferenceNameObject>> map = {};
void visit(CanonicalName canonicalName, ReferenceNameKind kind) {
void addObject() {
(map[kind] ??= []).add(new ReferenceNameObject(
ReferenceName.fromCanonicalName(canonicalName), canonicalName));
}
switch (kind) {
case ReferenceNameKind.Unknown:
for (CanonicalName child in canonicalName.children) {
visit(child, ReferenceNameKind.Library);
}
break;
case ReferenceNameKind.Library:
addObject();
for (CanonicalName child in canonicalName.children) {
ReferenceNameKind childKind = ReferenceNameKind.Declaration;
if (CanonicalName.isSymbolicName(child.name)) {
childKind = ReferenceName.kindFromSymbolicName(child.name);
}
visit(child, childKind);
}
break;
case ReferenceNameKind.Declaration:
addObject();
for (CanonicalName child in canonicalName.children) {
visit(child, ReferenceName.kindFromSymbolicName(child.name));
}
break;
case ReferenceNameKind.Typedef:
case ReferenceNameKind.Function:
case ReferenceNameKind.Field:
case ReferenceNameKind.Getter:
case ReferenceNameKind.Setter:
if (canonicalName.childrenOrNull != null) {
// Private name
for (CanonicalName child in canonicalName.children) {
visit(child, kind);
}
} else {
addObject();
}
break;
}
}
visit(root, ReferenceNameKind.Unknown);
sortReferenceNames(map);
return map;
}
class ReferenceNameObject {
final ReferenceName referenceName;
final Object object;
ReferenceNameObject(this.referenceName, this.object);
}