| Index: pkg/analyzer/lib/src/task/dart.dart
|
| diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
|
| index 839024650b1c6a60c16dafa26abba80aec9b1c60..a24e8d85ee021dc67e401ab090275d7ebd41b7b8 100644
|
| --- a/pkg/analyzer/lib/src/task/dart.dart
|
| +++ b/pkg/analyzer/lib/src/task/dart.dart
|
| @@ -282,6 +282,14 @@ final ListResultDescriptor<AnalysisError> PARSE_ERRORS =
|
| 'PARSE_ERRORS', AnalysisError.NO_ERRORS);
|
|
|
| /**
|
| + * The names (resolved and not) referenced by a unit.
|
| + *
|
| + * The result is only available for [Source]s representing a compilation unit.
|
| + */
|
| +final ResultDescriptor<ReferencedNames> REFERENCED_NAMES =
|
| + new ResultDescriptor<ReferencedNames>('REFERENCED_NAMES', null);
|
| +
|
| +/**
|
| * The errors produced while resolving references.
|
| *
|
| * The list will be empty if there were no errors, but will not be `null`.
|
| @@ -1915,6 +1923,84 @@ class ContainingLibrariesTask extends SourceBasedAnalysisTask {
|
| }
|
|
|
| /**
|
| + * The description for a change in a Dart source.
|
| + */
|
| +class DartDelta extends Delta {
|
| + bool hasDirectiveChange = false;
|
| +
|
| + final Set<String> addedNames = new Set<String>();
|
| + final Set<String> changedNames = new Set<String>();
|
| + final Set<String> removedNames = new Set<String>();
|
| +
|
| + final Set<Source> invalidatedSources = new Set<Source>();
|
| +
|
| + DartDelta(Source source) : super(source) {
|
| + invalidatedSources.add(source);
|
| + }
|
| +
|
| + @override
|
| + bool affects(InternalAnalysisContext context, AnalysisTarget target,
|
| + ResultDescriptor descriptor) {
|
| + if (hasDirectiveChange) {
|
| + return true;
|
| + }
|
| + Source targetSource = null;
|
| + if (target is Source) {
|
| + targetSource = target;
|
| + }
|
| + if (target is LibrarySpecificUnit) {
|
| + targetSource = target.library;
|
| + }
|
| + if (target is Element) {
|
| + targetSource = target.source;
|
| + }
|
| + if (targetSource == source) {
|
| + return true;
|
| + }
|
| + if (targetSource != null) {
|
| + List<Source> librarySources =
|
| + context.getLibrariesContaining(targetSource);
|
| + for (Source librarySource in librarySources) {
|
| + AnalysisCache cache = context.analysisCache;
|
| + ReferencedNames referencedNames =
|
| + cache.getValue(librarySource, REFERENCED_NAMES);
|
| + if (referencedNames == null) {
|
| + return true;
|
| + }
|
| + referencedNames.addChangedElements(this);
|
| + if (referencedNames.isAffectedBy(this)) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + void elementAdded(Element element) {
|
| + addedNames.add(element.name);
|
| + }
|
| +
|
| + void elementChanged(Element element) {
|
| + changedNames.add(element.name);
|
| + }
|
| +
|
| + void elementRemoved(Element element) {
|
| + removedNames.add(element.name);
|
| + }
|
| +
|
| + bool isNameAffected(String name) {
|
| + return addedNames.contains(name) ||
|
| + changedNames.contains(name) ||
|
| + removedNames.contains(name);
|
| + }
|
| +
|
| + bool nameChanged(String name) {
|
| + return changedNames.add(name);
|
| + }
|
| +}
|
| +
|
| +/**
|
| * A task that merges all of the errors for a single source into a single list
|
| * of errors.
|
| */
|
| @@ -2791,6 +2877,104 @@ class PublicNamespaceBuilder {
|
| }
|
|
|
| /**
|
| + * Information about a library - which names it uses, which names it defines
|
| + * with their externally visible dependencies.
|
| + */
|
| +class ReferencedNames {
|
| + final Set<String> names = new Set<String>();
|
| + final Map<String, Set<String>> userToDependsOn = <String, Set<String>>{};
|
| +
|
| + /**
|
| + * Updates [delta] by adding names that are changed in this library.
|
| + */
|
| + void addChangedElements(DartDelta delta) {
|
| + bool hasProgress = true;
|
| + while (hasProgress) {
|
| + hasProgress = false;
|
| + userToDependsOn.forEach((user, dependencies) {
|
| + for (String dependency in dependencies) {
|
| + if (delta.isNameAffected(dependency)) {
|
| + if (delta.nameChanged(user)) {
|
| + hasProgress = true;
|
| + }
|
| + }
|
| + }
|
| + });
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Returns `true` if the library described by this object is affected by
|
| + * the given [delta].
|
| + */
|
| + bool isAffectedBy(DartDelta delta) {
|
| + for (String name in names) {
|
| + if (delta.isNameAffected(name)) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * A builder for creating [ReferencedNames].
|
| + *
|
| + * TODO(scheglov) Record dependencies for all other top-level declarations.
|
| + */
|
| +class ReferencedNamesBuilder extends RecursiveAstVisitor {
|
| + final ReferencedNames names;
|
| + int bodyLevel = 0;
|
| + Set<String> dependsOn;
|
| +
|
| + ReferencedNamesBuilder(this.names);
|
| +
|
| + ReferencedNames build(CompilationUnit unit) {
|
| + unit.accept(this);
|
| + return names;
|
| + }
|
| +
|
| + @override
|
| + visitBlockFunctionBody(BlockFunctionBody node) {
|
| + try {
|
| + bodyLevel++;
|
| + super.visitBlockFunctionBody(node);
|
| + } finally {
|
| + bodyLevel--;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitClassDeclaration(ClassDeclaration node) {
|
| + dependsOn = new Set<String>();
|
| + super.visitClassDeclaration(node);
|
| + names.userToDependsOn[node.name.name] = dependsOn;
|
| + dependsOn = null;
|
| + }
|
| +
|
| + @override
|
| + visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
| + try {
|
| + bodyLevel++;
|
| + super.visitExpressionFunctionBody(node);
|
| + } finally {
|
| + bodyLevel--;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitSimpleIdentifier(SimpleIdentifier node) {
|
| + if (!node.inDeclarationContext()) {
|
| + String name = node.name;
|
| + names.names.add(name);
|
| + if (dependsOn != null && bodyLevel == 0) {
|
| + dependsOn.add(name);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| * A task that finishes resolution by requesting [RESOLVED_UNIT_NO_CONSTANTS] for every
|
| * unit in the libraries closure and produces [LIBRARY_ELEMENT].
|
| */
|
| @@ -2801,11 +2985,16 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
|
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
|
|
|
| /**
|
| + * The name of the [RESOLVED_UNIT6] input.
|
| + */
|
| + static const String UNITS_INPUT = 'UNITS_INPUT';
|
| +
|
| + /**
|
| * The task descriptor describing this kind of task.
|
| */
|
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
|
| 'ResolveLibraryReferencesTask', createTask, buildInputs,
|
| - <ResultDescriptor>[LIBRARY_ELEMENT]);
|
| + <ResultDescriptor>[LIBRARY_ELEMENT, REFERENCED_NAMES]);
|
|
|
| ResolveLibraryReferencesTask(
|
| InternalAnalysisContext context, AnalysisTarget target)
|
| @@ -2816,8 +3005,21 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
|
|
|
| @override
|
| void internalPerform() {
|
| + //
|
| + // Prepare inputs.
|
| + //
|
| LibraryElement library = getRequiredInput(LIBRARY_INPUT);
|
| + List<CompilationUnit> units = getRequiredInput(UNITS_INPUT);
|
| + // Compute referenced names.
|
| + ReferencedNames referencedNames = new ReferencedNames();
|
| + for (CompilationUnit unit in units) {
|
| + new ReferencedNamesBuilder(referencedNames).build(unit);
|
| + }
|
| + //
|
| + // Record outputs.
|
| + //
|
| outputs[LIBRARY_ELEMENT] = library;
|
| + outputs[REFERENCED_NAMES] = referencedNames;
|
| }
|
|
|
| /**
|
| @@ -2829,6 +3031,8 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
|
| Source source = target;
|
| return <String, TaskInput>{
|
| LIBRARY_INPUT: LIBRARY_ELEMENT6.of(source),
|
| + UNITS_INPUT: UNITS.of(source).toList((Source unit) =>
|
| + RESOLVED_UNIT6.of(new LibrarySpecificUnit(source, unit))),
|
| 'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE
|
| .of(source)
|
| .toMapOf(UNITS)
|
| @@ -3057,7 +3261,7 @@ class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask {
|
| LibrarySpecificUnit unit = target;
|
| return <String, TaskInput>{
|
| 'importsExportNamespace':
|
| - IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4),
|
| + IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4),
|
| LIBRARY_INPUT: LIBRARY_ELEMENT4.of(unit.library),
|
| UNIT_INPUT: RESOLVED_UNIT2.of(unit),
|
| TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
|
|
|