blob: 39d8fc91ec4cb6a9d822297d03ef666c5cb5bb72 [file] [log] [blame]
// Copyright (c) 2019, 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:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:nnbd_migration/src/utilities/permissive_mode.dart';
/// Mixin that verifies (via assertion checks) that a visitor does not miss any
/// annotations when processing a compilation unit.
///
/// Mixing in this class should have very low overhead when assertions are
/// disabled.
mixin AnnotationTracker<T> on AstVisitor<T>, PermissiveModeVisitor<T> {
static _AnnotationTracker _annotationTracker;
@override
T visitAnnotation(Annotation node) {
assert(() {
_annotationTracker._nodeVisited(node);
return true;
}());
return super.visitAnnotation(node);
}
@override
T visitCompilationUnit(CompilationUnit node) {
T result;
reportExceptionsIfPermissive(() {
_AnnotationTracker oldAnnotationTracker;
assert(() {
oldAnnotationTracker = _annotationTracker;
_annotationTracker = _AnnotationTracker();
node.accept(_annotationTracker);
return true;
}());
try {
result = super.visitCompilationUnit(node);
assert(_annotationTracker._nodes.isEmpty,
'Annotation nodes not visited: ${_annotationTracker._nodes}');
} finally {
_annotationTracker = oldAnnotationTracker;
}
});
return result;
}
}
class _AnnotationTracker extends RecursiveAstVisitor<void> {
final Set<Annotation> _nodes = {};
@override
void visitAnnotation(Annotation node) {
_nodes.add(node);
}
void _nodeVisited(Annotation node) {
if (!_nodes.remove(node)) {
throw StateError('Visited unexpected annotation $node');
}
}
}