Simplify how we discover libraries in the checker.

R=vsm@google.com

Review URL: https://chromereviews.googleplex.com/125187013
This commit is contained in:
Sigmund Cherem
2014-12-08 09:15:22 -08:00
parent 3546759833
commit dfd1237146
3 changed files with 30 additions and 123 deletions
+1 -18
View File
@@ -59,9 +59,7 @@ testChecker(Map<String, String> testFiles, {bool mockSdk: true}) {
var visitor = new _ErrorMarkerVisitor(expectedErrors);
var initialLibrary =
resolver.context.getLibraryElement(testUriResolver.files[mainFile]);
List reachableLibraries = [];
_findReachable(initialLibrary, reachableLibraries);
for (var lib in reachableLibraries) {
for (var lib in reachableLibraries(initialLibrary)) {
for (var unit in lib.units) {
unit.unit.accept(visitor);
}
@@ -137,21 +135,6 @@ SourceSpan _spanFor(AstNode node) {
return source.spanFor(node);
}
/// Recursively visits all libraries loaded by the test files.
_findReachable(lib, results, [Set seen]) {
if (seen == null) seen = new Set();
if (seen.contains(lib)) return results;
seen.add(lib);
results.add(lib);
for (var other in lib.importedLibraries) {
_findReachable(other, results, seen);
}
for (var other in lib.exportedLibraries) {
_findReachable(other, results, seen);
}
}
/// Visitor that extracts expected errors from comments.
class _ErrorMarkerVisitor extends UnifyingAstVisitor {
Map<AstNode, List<_ErrorExpectation>> expectedErrors;
+16
View File
@@ -2,8 +2,24 @@
library ddc.src.utils;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:source_span/source_span.dart';
/// Returns all libraries transitively imported or exported from [start].
List<LibraryElement> reachableLibraries(LibraryElement start) {
var results = <LibraryElement>[];
var seen = new Set();
void find(LibraryElement lib) {
if (seen.contains(lib)) return;
seen.add(lib);
results.add(lib);
lib.importedLibraries.forEach(find);
lib.exportedLibraries.forEach(find);
}
find(start);
return results;
}
/// Cache of [SourceFile]s per [Source], so we avoid recomputing line-breaks and
/// source-span information on a file multiple times.
// TODO(sigmund): consider truncating the size of this cache.
+13 -105
View File
@@ -10,6 +10,7 @@ import 'package:logging/logging.dart' as logger;
import 'src/resolver.dart';
import 'src/static_info.dart';
import 'src/type_rules.dart';
import 'src/utils.dart';
final _log = new logger.Logger('ddc.checker');
@@ -58,13 +59,6 @@ class Library {
Library(this.uri, this.source, this.lib);
}
class _WorkListItem {
final Uri uri;
final Source source;
final bool isLibrary;
_WorkListItem(this.uri, this.source, this.isLibrary);
}
class ProgramChecker extends RecursiveAstVisitor {
final TypeResolver _resolver;
final TypeRules _rules;
@@ -72,33 +66,6 @@ class ProgramChecker extends RecursiveAstVisitor {
final bool _checkSdk;
final Map<Uri, CompilationUnit> _unitMap = <Uri, CompilationUnit>{};
final Map<Uri, Library> libraries = <Uri, Library>{};
Library _currentLibrary;
final List<_WorkListItem> _workList = [];
final List<_WorkListItem> _partWorkList = [];
Uri toUri(String string) {
// FIXME: Use analyzer's resolver logic.
if (string.startsWith('package:')) {
String package = string.substring(8);
string = 'packages/' + package;
return _root.resolve(string);
} else {
return _currentLibrary.uri.resolve(string);
}
}
void add(Uri uri, Source source, bool isLibrary) {
if (isLibrary) {
_workList.add(new _WorkListItem(uri, source, isLibrary));
if (_currentLibrary != null) {
// This is an import / export.
// Record the key. Fill in the library later.
_currentLibrary.imports[uri] = null;
}
} else {
_partWorkList.add(new _WorkListItem(uri, source, isLibrary));
}
}
void finalizeImports() {
libraries.forEach((Uri uri, Library lib) {
@@ -108,82 +75,23 @@ class ProgramChecker extends RecursiveAstVisitor {
});
}
CompilationUnit load(Uri uri, Source source, bool isLibrary) {
if (!_checkSdk && uri.scheme == 'dart') {
return null;
}
if (_unitMap.containsKey(uri)) {
assert(isLibrary);
return _unitMap[uri];
}
final unit = getCompilationUnit(source, isLibrary);
_rules.setCompilationUnit(unit);
_unitMap[uri] = unit;
final last = _currentLibrary;
if (isLibrary) {
assert(!libraries.containsKey(uri));
var lib = new Library(uri, source, unit);
libraries[uri] = lib;
_currentLibrary = lib;
} else {
var lib = _currentLibrary;
assert(!lib.parts.containsKey(uri));
lib.parts[uri] = unit;
}
unit.visitChildren(this);
if (isLibrary) {
while (_partWorkList.isNotEmpty) {
_WorkListItem item = _partWorkList.removeAt(0);
assert(!item.isLibrary);
load(item.uri, item.source, item.isLibrary);
}
assert(_currentLibrary.uri == uri);
_currentLibrary = last;
}
return unit;
}
void loadFromDirective(UriBasedDirective directive, bool isLibrary) {
String content = directive.uri.stringValue;
Uri uri = toUri(content);
Source source = directive.source;
add(uri, source, isLibrary);
}
CompilationUnit getCompilationUnit(Source source, bool isLibrary) {
var container = isLibrary ? source : _currentLibrary.source;
var res = _resolver.context.resolveCompilationUnit2(source, container);
failure = _resolver.logErrors(source) || failure;
return res;
}
ProgramChecker(this._resolver, this._rules, this._root, this._checkSdk) {
add(_root, _resolver.findSource(_root), true);
}
ProgramChecker(this._resolver, this._rules, this._root, this._checkSdk);
void check() {
while (_workList.isNotEmpty) {
_WorkListItem item = _workList.removeAt(0);
assert(item.isLibrary);
load(item.uri, item.source, item.isLibrary);
var startLibrary = _resolver.context.computeLibraryElement(
_resolver.findSource(_root));
for (var lib in reachableLibraries(startLibrary)) {
if (!_checkSdk && lib.isInSdk) continue;
var source = lib.source;
libraries[source.uri] =
new Library(source.uri, source, lib.definingCompilationUnit.node);
for (var unit in lib.units) {
_rules.setCompilationUnit(unit.node);
unit.node.visitChildren(this);
}
}
}
visitExportDirective(ExportDirective node) {
loadFromDirective(node, true);
node.visitChildren(this);
}
visitImportDirective(ImportDirective node) {
loadFromDirective(node, true);
node.visitChildren(this);
}
visitPartDirective(PartDirective node) {
loadFromDirective(node, false);
node.visitChildren(this);
}
visitAssignmentExpression(AssignmentExpression node) {
DartType staticType = _rules.getStaticType(node.leftHandSide);
checkAssignment(node.rightHandSide, staticType);