| Index: pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| index a01122dae50b314def9fa90d85546fffcd756be4..4896b5d64ad13feb8afe74fea95a1ed77d60f951 100644
|
| --- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| +++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| @@ -13,35 +13,68 @@ import 'package:analyzer/src/generated/scanner.dart';
|
| import 'package:analyzer/src/generated/source.dart';
|
|
|
| /**
|
| + * The change of a single [CompilationUnitElement].
|
| + */
|
| +class CompilationUnitElementDelta {
|
| + /**
|
| + * One or more directives were added/removed.
|
| + */
|
| + bool hasDirectiveChange = false;
|
| +
|
| + /**
|
| + * The list of added top-level element.
|
| + */
|
| + final List<Element> addedDeclarations = <Element>[];
|
| +
|
| + /**
|
| + * The list of removed top-level elements.
|
| + */
|
| + final List<Element> removedDeclarations = <Element>[];
|
| +}
|
| +
|
| +/**
|
| * Incrementally updates the existing [unitElement] and builds elements for
|
| * the [newUnit].
|
| */
|
| class IncrementalCompilationUnitElementBuilder {
|
| - final Source source;
|
| + final Source unitSource;
|
| final Source librarySource;
|
| final CompilationUnit oldUnit;
|
| final CompilationUnitElementImpl unitElement;
|
| final CompilationUnit newUnit;
|
| final ElementHolder holder = new ElementHolder();
|
|
|
| - IncrementalCompilationUnitElementBuilder(
|
| - CompilationUnit oldUnit, this.newUnit)
|
| - : oldUnit = oldUnit,
|
| - unitElement = oldUnit.element,
|
| - source = oldUnit.element.source,
|
| - librarySource = (oldUnit.element as CompilationUnitElementImpl).librarySource;
|
| + /**
|
| + * The change between element models of [oldUnit] and [newUnit].
|
| + */
|
| + final CompilationUnitElementDelta unitDelta =
|
| + new CompilationUnitElementDelta();
|
|
|
| + factory IncrementalCompilationUnitElementBuilder(
|
| + CompilationUnit oldUnit, CompilationUnit newUnit) {
|
| + CompilationUnitElementImpl unitElement = oldUnit.element;
|
| + return new IncrementalCompilationUnitElementBuilder._(unitElement.source,
|
| + unitElement.librarySource, oldUnit, newUnit, unitElement);
|
| + }
|
| +
|
| + IncrementalCompilationUnitElementBuilder._(this.unitSource,
|
| + this.librarySource, this.oldUnit, this.newUnit, this.unitElement);
|
| +
|
| + /**
|
| + * Updates [oldUnit] to have the same directives and declarations, in the
|
| + * same order as in [newUnit]. Existing resolution is kept where possible.
|
| + *
|
| + * Updates [unitElement] by adding/removing elements as needed.
|
| + *
|
| + * Fills [unitDelta] with added/remove elements.
|
| + */
|
| void build() {
|
| new CompilationUnitBuilder().buildCompilationUnit(
|
| - source, newUnit, librarySource);
|
| + unitSource, newUnit, librarySource);
|
| _processDirectives();
|
| _processUnitMembers();
|
| newUnit.element = unitElement;
|
| - }
|
| -
|
| - void _addElementsToHolder(CompilationUnitMember node) {
|
| - List<Element> elements = _getElements(node);
|
| - elements.forEach(_addElementToHolder);
|
| + _replaceUnitContents(oldUnit, newUnit);
|
| }
|
|
|
| void _addElementToHolder(Element element) {
|
| @@ -69,11 +102,13 @@ class IncrementalCompilationUnitElementBuilder {
|
| oldDirectiveMap[code] = oldDirective;
|
| }
|
| // Replace new nodes with the identical old nodes.
|
| + Set<Directive> removedDirectives = oldUnit.directives.toSet();
|
| for (Directive newDirective in newUnit.directives) {
|
| String code = TokenUtils.getFullCode(newDirective);
|
| // Prepare an old directive.
|
| Directive oldDirective = oldDirectiveMap[code];
|
| if (oldDirective == null) {
|
| + unitDelta.hasDirectiveChange = true;
|
| continue;
|
| }
|
| // URI's must be resolved to the same sources.
|
| @@ -85,6 +120,11 @@ class IncrementalCompilationUnitElementBuilder {
|
| }
|
| // Do replacement.
|
| _replaceNode(newDirective, oldDirective);
|
| + removedDirectives.remove(oldDirective);
|
| + }
|
| + // If there are any directives left, then these directives were removed.
|
| + if (removedDirectives.isNotEmpty) {
|
| + unitDelta.hasDirectiveChange = true;
|
| }
|
| }
|
|
|
| @@ -95,19 +135,32 @@ class IncrementalCompilationUnitElementBuilder {
|
| String code = TokenUtils.getFullCode(oldNode);
|
| oldNodeMap[code] = oldNode;
|
| }
|
| + // Prepare all old top-level elements.
|
| + Set<Element> removedElements = new Set<Element>();
|
| + removedElements.addAll(unitElement.accessors);
|
| + removedElements.addAll(unitElement.enums);
|
| + removedElements.addAll(unitElement.functions);
|
| + removedElements.addAll(unitElement.functionTypeAliases);
|
| + removedElements.addAll(unitElement.types);
|
| + removedElements.addAll(unitElement.topLevelVariables);
|
| // Replace new nodes with the identical old nodes.
|
| for (CompilationUnitMember newNode in newUnit.declarations) {
|
| String code = TokenUtils.getFullCode(newNode);
|
| // Prepare an old node.
|
| CompilationUnitMember oldNode = oldNodeMap[code];
|
| if (oldNode == null) {
|
| - _addElementsToHolder(newNode);
|
| + List<Element> elements = _getElements(newNode);
|
| + elements.forEach(_addElementToHolder);
|
| + elements.forEach(unitDelta.addedDeclarations.add);
|
| continue;
|
| }
|
| // Do replacement.
|
| _replaceNode(newNode, oldNode);
|
| - _addElementsToHolder(oldNode);
|
| + List<Element> elements = _getElements(oldNode);
|
| + elements.forEach(_addElementToHolder);
|
| + elements.forEach(removedElements.remove);
|
| }
|
| + unitDelta.removedDeclarations.addAll(removedElements);
|
| // Update CompilationUnitElement.
|
| unitElement.accessors = holder.accessors;
|
| unitElement.enums = holder.enums;
|
| @@ -177,6 +230,20 @@ class IncrementalCompilationUnitElementBuilder {
|
| }
|
| return elements;
|
| }
|
| +
|
| + /**
|
| + * Replaces contents of the [to] unit with the contenxts of the [from] unit.
|
| + */
|
| + static void _replaceUnitContents(CompilationUnit to, CompilationUnit from) {
|
| + to.directives.clear();
|
| + to.declarations.clear();
|
| + to.beginToken = from.beginToken;
|
| + to.scriptTag = from.scriptTag;
|
| + to.directives.addAll(from.directives);
|
| + to.declarations.addAll(from.declarations);
|
| + to.element = to.element;
|
| + to.lineInfo = from.lineInfo;
|
| + }
|
| }
|
|
|
| /**
|
|
|