Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Unified Diff: pkg/analyzer/lib/src/task/dart.dart

Issue 1204373002: Initial version of limiting invalidation. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fixes for review comments. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)
« no previous file with comments | « pkg/analyzer/lib/src/generated/engine.dart ('k') | pkg/analyzer/lib/src/task/incremental_element_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698