| Index: pkg/kernel/lib/checks.dart
|
| diff --git a/pkg/kernel/lib/checks.dart b/pkg/kernel/lib/checks.dart
|
| index 3d9a8651d1422f8a4fcac5e0d1e672c2abf2d614..5d77332d64fd873e8c544e54ccd4b020a9267558 100644
|
| --- a/pkg/kernel/lib/checks.dart
|
| +++ b/pkg/kernel/lib/checks.dart
|
| @@ -4,79 +4,90 @@
|
| library kernel.checks;
|
|
|
| import 'ast.dart';
|
| +import 'transformations/flags.dart';
|
|
|
| void runSanityChecks(Program program) {
|
| - CheckParentPointers.check(program);
|
| - CheckReferences.check(program);
|
| -}
|
| -
|
| -class CheckParentPointers extends Visitor {
|
| - static void check(TreeNode node) {
|
| - node.accept(new CheckParentPointers(node.parent));
|
| - }
|
| -
|
| - TreeNode parent;
|
| -
|
| - CheckParentPointers([this.parent]);
|
| -
|
| - defaultTreeNode(TreeNode node) {
|
| - if (node.parent != parent) {
|
| - throw 'Parent pointer on ${node.runtimeType} '
|
| - 'is ${node.parent.runtimeType} '
|
| - 'but should be ${parent.runtimeType}';
|
| - }
|
| - var oldParent = parent;
|
| - parent = node;
|
| - node.visitChildren(this);
|
| - parent = oldParent;
|
| - }
|
| + SanityCheck.check(program);
|
| }
|
|
|
| /// Checks that references refer to something in scope.
|
| ///
|
| /// Currently only checks member, class, and type parameter references.
|
| -class CheckReferences extends RecursiveVisitor {
|
| - final Set<Member> members = new Set<Member>();
|
| +class SanityCheck extends RecursiveVisitor {
|
| final Set<Class> classes = new Set<Class>();
|
| final Set<TypeParameter> typeParameters = new Set<TypeParameter>();
|
|
|
| Member currentMember;
|
| Class currentClass;
|
| + TreeNode currentParent;
|
|
|
| TreeNode get context => currentMember ?? currentClass;
|
|
|
| static void check(Program program) {
|
| - program.accept(new CheckReferences());
|
| + program.accept(new SanityCheck());
|
| + }
|
| +
|
| + defaultTreeNode(TreeNode node) {
|
| + visitChildren(node);
|
| + }
|
| +
|
| + void visitChildren(TreeNode node) {
|
| + if (!identical(node.parent, currentParent)) {
|
| + throw 'Parent pointer on ${node.runtimeType} '
|
| + 'is ${node.parent.runtimeType} '
|
| + 'but should be ${currentParent.runtimeType}';
|
| + }
|
| + var oldParent = currentParent;
|
| + currentParent = node;
|
| + node.visitChildren(this);
|
| + currentParent = oldParent;
|
| + }
|
| +
|
| + void declareMember(Member member) {
|
| + if (member.transformerFlags & TransformerFlag.seenBySanityCheck != 0) {
|
| + throw '$member has been declared more than once';
|
| + }
|
| + member.transformerFlags |= TransformerFlag.seenBySanityCheck;
|
| + }
|
| +
|
| + void undeclareMember(Member member) {
|
| + member.transformerFlags &= ~TransformerFlag.seenBySanityCheck;
|
| }
|
|
|
| visitProgram(Program program) {
|
| for (var library in program.libraries) {
|
| classes.addAll(library.classes);
|
| - members.addAll(library.members);
|
| + library.members.forEach(declareMember);
|
| + for (var class_ in library.classes) {
|
| + class_.members.forEach(declareMember);
|
| + }
|
| + }
|
| + visitChildren(program);
|
| + for (var library in program.libraries) {
|
| + library.members.forEach(undeclareMember);
|
| for (var class_ in library.classes) {
|
| - members.addAll(class_.members);
|
| + class_.members.forEach(undeclareMember);
|
| }
|
| }
|
| - program.visitChildren(this);
|
| }
|
|
|
| defaultMember(Member node) {
|
| currentMember = node;
|
| - node.visitChildren(this);
|
| + visitChildren(node);
|
| currentMember = null;
|
| }
|
|
|
| visitClass(Class node) {
|
| currentClass = node;
|
| typeParameters.addAll(node.typeParameters);
|
| - node.visitChildren(this);
|
| + visitChildren(node);
|
| typeParameters.removeAll(node.typeParameters);
|
| currentClass = null;
|
| }
|
|
|
| visitFunctionNode(FunctionNode node) {
|
| typeParameters.addAll(node.typeParameters);
|
| - node.visitChildren(this);
|
| + visitChildren(node);
|
| typeParameters.removeAll(node.typeParameters);
|
| }
|
|
|
| @@ -87,12 +98,19 @@ class CheckReferences extends RecursiveVisitor {
|
| '$context';
|
| }
|
| }
|
| - node.visitChildren(this);
|
| + typeParameters.addAll(node.typeParameters);
|
| + for (var typeParameter in node.typeParameters) {
|
| + typeParameter.bound?.accept(this);
|
| + }
|
| + visitList(node.positionalParameters, this);
|
| + visitList(node.namedParameters, this);
|
| + node.returnType.accept(this);
|
| + typeParameters.removeAll(node.typeParameters);
|
| }
|
|
|
| @override
|
| defaultMemberReference(Member node) {
|
| - if (!members.contains(node)) {
|
| + if (node.transformerFlags & TransformerFlag.seenBySanityCheck == 0) {
|
| throw 'Dangling reference to $node found in $context.\n'
|
| 'Parent pointer is set to ${node.parent}';
|
| }
|
| @@ -126,23 +144,24 @@ class CheckReferences extends RecursiveVisitor {
|
| }
|
| }
|
|
|
| -class SizeCounter extends RecursiveVisitor {
|
| - int size = 0;
|
| - int emptyArguments = 0;
|
| +class CheckParentPointers extends Visitor {
|
| + static void check(TreeNode node) {
|
| + node.accept(new CheckParentPointers(node.parent));
|
| + }
|
| +
|
| + TreeNode parent;
|
|
|
| - void visit(TreeNode node) => node.accept(this);
|
| + CheckParentPointers([this.parent]);
|
|
|
| - visitArguments(Arguments node) {
|
| - super.visitArguments(node);
|
| - if (node.positional.isEmpty &&
|
| - node.positional.isEmpty &&
|
| - node.types.isEmpty) {
|
| - ++emptyArguments;
|
| + defaultTreeNode(TreeNode node) {
|
| + if (node.parent != parent) {
|
| + throw 'Parent pointer on ${node.runtimeType} '
|
| + 'is ${node.parent.runtimeType} '
|
| + 'but should be ${parent.runtimeType}';
|
| }
|
| - }
|
| -
|
| - defaultNode(Node node) {
|
| - ++size;
|
| + var oldParent = parent;
|
| + parent = node;
|
| node.visitChildren(this);
|
| + parent = oldParent;
|
| }
|
| }
|
|
|