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

Unified Diff: pkg/fletchc/lib/incremental/reuser.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 11 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/fletchc/lib/incremental/reuser.dart
diff --git a/pkg/fletchc/lib/incremental/reuser.dart b/pkg/fletchc/lib/incremental/reuser.dart
deleted file mode 100644
index 776c6fca1847725e57757a9d36e48fce4d357c1d..0000000000000000000000000000000000000000
--- a/pkg/fletchc/lib/incremental/reuser.dart
+++ /dev/null
@@ -1,1185 +0,0 @@
-// Copyright (c) 2014, 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.
-
-library fletchc_incremental.reuser;
-
-import 'dart:async' show
- Future;
-
-import 'package:compiler/compiler.dart' as api;
-
-import 'package:compiler/src/compiler.dart' show
- Compiler;
-
-import 'package:compiler/src/diagnostics/messages.dart' show
- MessageKind;
-
-import 'package:compiler/src/script.dart' show
- Script;
-
-import 'package:compiler/src/elements/elements.dart' show
- ClassElement,
- CompilationUnitElement,
- Element,
- LibraryElement,
- STATE_NOT_STARTED,
- ScopeContainerElement,
- TypeDeclarationElement;
-
-import 'package:compiler/src/tokens/token_constants.dart' show
- EOF_TOKEN;
-
-import 'package:compiler/src/tokens/token.dart' show
- Token;
-
-import 'package:compiler/src/parser/partial_elements.dart' show
- PartialClassElement,
- PartialElement,
- PartialFieldList,
- PartialFunctionElement;
-
-import 'package:compiler/src/scanner/scanner.dart' show
- Scanner;
-
-import 'package:compiler/src/parser/parser.dart' show
- Parser;
-
-import 'package:compiler/src/parser/listener.dart' show
- Listener;
-
-import 'package:compiler/src/parser/node_listener.dart' show
- NodeListener;
-
-import 'package:compiler/src/io/source_file.dart' show
- CachingUtf8BytesSourceFile,
- SourceFile,
- StringSourceFile;
-
-import 'package:compiler/src/tree/tree.dart' show
- ClassNode,
- FunctionExpression,
- LibraryTag,
- NodeList,
- unparse;
-
-import 'package:compiler/src/util/util.dart' show
- Link;
-
-import 'package:compiler/src/elements/modelx.dart' show
- ClassElementX,
- CompilationUnitElementX,
- DeclarationSite,
- ElementX,
- FieldElementX,
- LibraryElementX;
-
-import 'package:compiler/src/constants/values.dart' show
- ConstantValue;
-
-import 'package:compiler/src/library_loader.dart' show
- TagState;
-
-import '../incremental_backend.dart' show
- IncrementalBackend;
-
-import 'diff.dart' show
- Difference,
- computeDifference;
-
-import 'fletchc_incremental.dart' show
- IncrementalCompilationFailed;
-
-typedef void Logger(message);
-
-typedef bool ReuseFunction(
- Token diffToken,
- PartialElement before,
- PartialElement after);
-
-class FailedUpdate {
- /// Either an [Element] or a [Difference].
- final context;
- final String message;
-
- FailedUpdate(this.context, this.message);
-
- String toString() {
- if (context == null) return '$message';
- return 'In $context:\n $message';
- }
-}
-
-abstract class Reuser {
- final Compiler compiler;
-
- final api.CompilerInputProvider inputProvider;
-
- final Logger logTime;
-
- final Logger logVerbose;
-
- final List<Update> updates = <Update>[];
-
- final List<FailedUpdate> _failedUpdates = <FailedUpdate>[];
-
- final Set<ElementX> _elementsToInvalidate = new Set<ElementX>();
-
- final Set<ElementX> _removedElements = new Set<ElementX>();
-
- final Map<Uri, Future> _sources = <Uri, Future>{};
-
- /// Cached tokens of entry compilation units.
- final Map<LibraryElementX, Token> _entryUnitTokens =
- <LibraryElementX, Token>{};
-
- /// Cached source files for entry compilation units.
- final Map<LibraryElementX, SourceFile> _entrySourceFiles =
- <LibraryElementX, SourceFile>{};
-
- Reuser(
- this.compiler,
- this.inputProvider,
- this.logTime,
- this.logVerbose);
-
- IncrementalBackend get backend;
-
- /// When [true], updates must be applied (using [applyUpdates]) before the
- /// [compiler]'s state correctly reflects the updated program.
- bool get hasPendingUpdates => updates.isNotEmpty;
-
- bool get failed => _failedUpdates.isNotEmpty;
-
- /// Used as tear-off passed to [LibraryLoaderTask.resetLibraries].
- Future<Iterable<LibraryElement>> reuseLibraries(
- Iterable<LibraryElement> libraries) async {
- List<LibraryElement> reusedLibraries = <LibraryElement>[];
- for (LibraryElement library in libraries) {
- if (await _reuseLibrary(library)) {
- reusedLibraries.add(library);
- }
- }
- return reusedLibraries;
- }
-
- Future<bool> _reuseLibrary(LibraryElement library) async {
- assert(compiler != null);
- if (library.isPlatformLibrary) {
- logTime('Reusing $library (assumed read-only).');
- return true;
- }
- try {
- if (await _haveTagsChanged(library)) {
- cannotReuse(
- library,
- "Changes to library, import, export, or part declarations not"
- " supported.");
- // We return true to here to avoid that the library loader tries to
- // load a different version of this library.
- return true;
- }
-
- bool isChanged = false;
- List<Script> scripts = <Script>[];
-
- for (CompilationUnitElementX unit in library.compilationUnits) {
- Uri uri = unit.script.resourceUri;
- if (uriHasUpdate(uri)) {
- isChanged = true;
- scripts.add(await _updatedScript(unit.script, library));
- } else {
- scripts.add(unit.script);
- }
- }
-
- if (!isChanged) {
- logTime("Reusing $library, source didn't change.");
- return true;
- }
-
- return canReuseLibrary(library, scripts);
- } finally {
- _cleanUp(library);
- }
- }
-
- void _cleanUp(LibraryElementX library) {
- _entryUnitTokens.remove(library);
- _entrySourceFiles.remove(library);
- }
-
- Future<Script> _updatedScript(Script before, LibraryElementX library) {
- if (before == library.entryCompilationUnit.script &&
- _entrySourceFiles.containsKey(library)) {
- return new Future.value(before.copyWithFile(_entrySourceFiles[library]));
- }
-
- return _readUri(before.resourceUri).then((bytes) {
- Uri uri = before.file.uri;
- String filename = before.file.filename;
- SourceFile sourceFile = bytes is String
- ? new StringSourceFile(uri, filename, bytes)
- : new CachingUtf8BytesSourceFile(uri, filename, bytes);
- return before.copyWithFile(sourceFile);
- });
- }
-
- Future<bool> _haveTagsChanged(LibraryElementX library) {
- Script before = library.entryCompilationUnit.script;
- if (!uriHasUpdate(before.resourceUri)) {
- // The entry compilation unit hasn't been updated. So the tags aren't
- // changed.
- return new Future<bool>.value(false);
- }
-
- return _updatedScript(before, library).then((Script script) {
- _entrySourceFiles[library] = script.file;
- Token token = new Scanner(_entrySourceFiles[library]).tokenize();
- _entryUnitTokens[library] = token;
- // Using two parsers to only create the nodes we want ([LibraryTag]).
- Parser parser = new Parser(new Listener());
- Element entryCompilationUnit = library.entryCompilationUnit;
- NodeListener listener = new NodeListener(
- compiler.resolution.parsing
- .getScannerOptionsFor(entryCompilationUnit),
- compiler.reporter, entryCompilationUnit);
- Parser nodeParser = new Parser(listener);
- Iterator<LibraryTag> tags = library.tags.iterator;
- while (token.kind != EOF_TOKEN) {
- token = parser.parseMetadataStar(token);
- if (parser.optional('library', token) ||
- parser.optional('import', token) ||
- parser.optional('export', token) ||
- parser.optional('part', token)) {
- if (!tags.moveNext()) return true;
- token = nodeParser.parseTopLevelDeclaration(token);
- LibraryTag tag = listener.popNode();
- assert(listener.nodes.isEmpty);
- if (unparse(tags.current) != unparse(tag)) {
- return true;
- }
- } else {
- break;
- }
- }
- return tags.moveNext();
- });
- }
-
- Future _readUri(Uri uri) {
- return _sources.putIfAbsent(uri, () => inputProvider(uri));
- }
-
- /// Returns true if [library] can be reused.
- ///
- /// This methods also computes the [updates] (patches) needed to have
- /// [library] reflect the modifications in [scripts].
- bool canReuseLibrary(LibraryElement library, List<Script> scripts) {
- logTime('Attempting to reuse ${library}.');
-
- Uri entryUri = library.entryCompilationUnit.script.resourceUri;
- Script entryScript =
- scripts.singleWhere((Script script) => script.resourceUri == entryUri);
- LibraryElementX newLibrary =
- new LibraryElementX(entryScript, library.canonicalUri);
- if (_entryUnitTokens.containsKey(library)) {
- compiler.dietParser.dietParse(
- newLibrary.entryCompilationUnit, _entryUnitTokens[library]);
- } else {
- compiler.scanner.scanLibrary(newLibrary);
- }
-
- TagState tagState = new TagState();
- for (LibraryTag tag in newLibrary.tags) {
- if (tag.isImport) {
- tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler.reporter);
- } else if (tag.isExport) {
- tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler.reporter);
- } else if (tag.isLibraryName) {
- tagState.checkTag(TagState.LIBRARY, tag, compiler.reporter);
- if (newLibrary.libraryTag == null) {
- // Use the first if there are multiple (which is reported as an
- // error in [TagState.checkTag]).
- newLibrary.libraryTag = tag;
- }
- } else if (tag.isPart) {
- tagState.checkTag(TagState.PART, tag, compiler.reporter);
- }
- }
-
- // TODO(ahe): Process tags using TagState, not
- // LibraryLoaderTask.processLibraryTags.
- Link<CompilationUnitElement> units = library.compilationUnits;
- for (Script script in scripts) {
- CompilationUnitElementX unit = units.head;
- units = units.tail;
- if (script != entryScript) {
- // TODO(ahe): Copied from library_loader.
- CompilationUnitElement newUnit =
- new CompilationUnitElementX(script, newLibrary);
- compiler.reporter.withCurrentElement(newUnit, () {
- compiler.scanner.scan(newUnit);
- if (unit.partTag == null) {
- compiler.reporter.reportErrorMessage(
- unit, MessageKind.MISSING_PART_OF_TAG);
- }
- });
- }
- }
-
- logTime('New library synthesized.');
- return canReuseScopeContainerElement(library, newLibrary);
- }
-
- bool cannotReuse(context, String message) {
- _failedUpdates.add(new FailedUpdate(context, message));
- logVerbose(message);
- return false;
- }
-
- bool canReuseScopeContainerElement(
- ScopeContainerElement element,
- ScopeContainerElement newElement) {
- if (checkForGenericTypes(element)) return false;
- if (checkForGenericTypes(newElement)) return false;
- List<Difference> differences = computeDifference(element, newElement);
- logTime('Differences computed.');
- for (Difference difference in differences) {
- logTime('Looking at difference: $difference');
-
- if (difference.before == null && difference.after is PartialElement) {
- canReuseAddedElement(difference.after, element, newElement);
- continue;
- }
- if (difference.after == null && difference.before is PartialElement) {
- canReuseRemovedElement(difference.before, element);
- continue;
- }
- Token diffToken = difference.token;
- if (diffToken == null) {
- cannotReuse(difference, "No difference token.");
- continue;
- }
- if (difference.after is! PartialElement &&
- difference.before is! PartialElement) {
- cannotReuse(difference, "Don't know how to recompile.");
- continue;
- }
- PartialElement before = difference.before;
- PartialElement after = difference.after;
-
- ReuseFunction reuser;
-
- if (before is PartialFunctionElement && after is PartialFunctionElement) {
- reuser = canReuseFunction;
- } else if (before is PartialClassElement &&
- after is PartialClassElement) {
- reuser = canReuseClass;
- } else {
- reuser = unableToReuse;
- }
- if (!reuser(diffToken, before, after)) {
- assert(_failedUpdates.isNotEmpty);
- continue;
- }
- }
-
- return _failedUpdates.isEmpty;
- }
-
- bool canReuseAddedElement(
- PartialElement element,
- ScopeContainerElement container,
- ScopeContainerElement syntheticContainer) {
- if (!allowAddedElement(element)) return false;
- if (element is PartialFunctionElement) {
- addFunction(element, container);
- return true;
- } else if (element is PartialClassElement) {
- addClass(element, container);
- return true;
- } else if (element is PartialFieldList) {
- addFields(element, container, syntheticContainer);
- return true;
- }
- return cannotReuse(element, "Adding ${element.runtimeType} not supported.");
- }
-
- void addFunction(
- PartialFunctionElement element,
- /* ScopeContainerElement */ container) {
- invalidateScopesAffectedBy(element, container);
-
- addAddedFunctionUpdate(compiler, element, container);
- }
-
- void addClass(
- PartialClassElement element,
- LibraryElementX library) {
- invalidateScopesAffectedBy(element, library);
-
- addAddedClassUpdate(compiler, element, library);
- }
-
- /// Called when a field in [definition] has changed.
- ///
- /// There's no direct link from a [PartialFieldList] to its implied
- /// [FieldElementX], so instead we use [syntheticContainer], the (synthetic)
- /// container created by [canReuseLibrary], or [canReuseClass] (through
- /// [PartialClassElement.parseNode]). This container is scanned looking for
- /// fields whose declaration site is [definition].
- // TODO(ahe): It would be nice if [computeDifference] returned this
- // information directly.
- void addFields(
- PartialFieldList definition,
- ScopeContainerElement container,
- ScopeContainerElement syntheticContainer) {
- List<FieldElementX> fields = <FieldElementX>[];
- syntheticContainer.forEachLocalMember((ElementX member) {
- if (member.declarationSite == definition) {
- fields.add(member);
- }
- });
- for (FieldElementX field in fields) {
- // TODO(ahe): This only works when there's one field per
- // PartialFieldList.
- addField(field, container);
- }
- }
-
- void addField(FieldElementX element, ScopeContainerElement container) {
- logVerbose("Add field $element to $container.");
- invalidateScopesAffectedBy(element, container);
- addAddedFieldUpdate(compiler, element, container);
- }
-
- bool canReuseRemovedElement(
- PartialElement element,
- ScopeContainerElement container) {
- if (!allowRemovedElement(element)) return false;
- if (element is PartialFunctionElement) {
- removeFunction(element);
- return true;
- } else if (element is PartialClassElement) {
- removeClass(element);
- return true;
- } else if (element is PartialFieldList) {
- removeFields(element, container);
- return true;
- }
- return cannotReuse(
- element, "Removing ${element.runtimeType} not supported.");
- }
-
- void removeFunction(PartialFunctionElement element) {
- logVerbose("Removed method $element.");
-
- invalidateScopesAffectedBy(element, element.enclosingElement);
-
- _removedElements.add(element);
-
- addRemovedFunctionUpdate(compiler, element);
- }
-
- void removeClass(PartialClassElement element) {
- logVerbose("Removed class $element.");
-
- invalidateScopesAffectedBy(element, element.library);
-
- _removedElements.add(element);
- element.forEachLocalMember((ElementX member) {
- _removedElements.add(member);
- });
-
- addRemovedClassUpdate(compiler, element);
- }
-
- void removeFields(
- PartialFieldList definition,
- ScopeContainerElement container) {
- List<FieldElementX> fields = <FieldElementX>[];
- container.forEachLocalMember((ElementX member) {
- if (member.declarationSite == definition) {
- fields.add(member);
- }
- });
- for (FieldElementX field in fields) {
- // TODO(ahe): This only works when there's one field per
- // PartialFieldList.
- removeField(field);
- }
- }
-
- void removeField(FieldElementX element) {
- logVerbose("Removed field $element.");
- if (!element.isInstanceMember) {
- cannotReuse(element, "Not an instance field.");
- } else {
- removeInstanceField(element);
- }
- }
-
- void removeInstanceField(FieldElementX element) {
- PartialClassElement cls = element.enclosingClass;
-
- invalidateScopesAffectedBy(element, cls);
-
- _removedElements.add(element);
-
- addRemovedFieldUpdate(compiler, element);
- }
-
- /// Returns true if [element] has generic types (or if we cannot rule out
- /// that it has generic types).
- bool checkForGenericTypes(Element element) {
- if (element is TypeDeclarationElement) {
- if (!element.isResolved) {
- if (element is PartialClassElement) {
- ClassNode node = element.parseNode(compiler.parsing).asClassNode();
- if (node == null) {
- cannotReuse(
- element, "Class body isn't a ClassNode on $element");
- return true;
- }
- bool isGeneric =
- node.typeParameters != null && !node.typeParameters.isEmpty;
- if (isGeneric) {
- // TODO(ahe): Support generic types.
- cannotReuse(
- element,
- "Type variables not supported: '${node.typeParameters}'");
- return true;
- }
- } else {
- cannotReuse(
- element, "Can't check for generic types on $element");
- return true;
- }
- } else if (!element.thisType.isRaw) {
- cannotReuse(
- element, "Generic types not supported: '${element.thisType}'");
- return true;
- }
- }
- return false;
- }
-
- void invalidateScopesAffectedBy(
- ElementX element,
- /* ScopeContainerElement */ container) {
- if (checkForGenericTypes(element)) return;
- for (ScopeContainerElement scope in scopesAffectedBy(element, container)) {
- scanSites(scope, (Element member, DeclarationSite site) {
- // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
- Set<String> names = qualifiedNamesIn(site);
- if (canNamesResolveStaticallyTo(names, element, container)) {
- if (checkForGenericTypes(member)) return;
- if (member is TypeDeclarationElement) {
- if (!member.isResolved) {
- // TODO(ahe): This is a bug in dart2js' forgetElement which
- // attempts to check if member is a generic type.
- cannotReuse(member, "Not resolved");
- return;
- }
- }
- _elementsToInvalidate.add(member);
- }
- });
- }
- }
-
- void replaceFunctionInBackend(
- ElementX element,
- /* ScopeContainerElement */ container) {
- List<Element> elements = <Element>[];
- if (checkForGenericTypes(element)) return;
- for (ScopeContainerElement scope in scopesAffectedBy(element, container)) {
- scanSites(scope, (Element member, DeclarationSite site) {
- // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
- Set<String> names = qualifiedNamesIn(site);
- if (canNamesResolveStaticallyTo(names, element, container)) {
- if (checkForGenericTypes(member)) return;
- if (member is TypeDeclarationElement) {
- if (!member.isResolved) {
- // TODO(ahe): This is a bug in dart2js' forgetElement which
- // attempts to check if member is a generic type.
- cannotReuse(member, "Not resolved");
- return;
- }
- }
- elements.add(member);
- }
- });
- }
- backend.replaceFunctionUsageElement(element, elements);
- }
-
- /// Invoke [f] on each [DeclarationSite] in [element]. If [element] is a
- /// [ScopeContainerElement], invoke f on all local members as well.
- void scanSites(
- Element element,
- void f(ElementX element, DeclarationSite site)) {
- DeclarationSite site = declarationSite(element);
- if (site != null) {
- f(element, site);
- }
- if (element is ScopeContainerElement) {
- element.forEachLocalMember((member) { scanSites(member, f); });
- }
- }
-
- /// Assume [element] is either removed from or added to [container], and
- /// return all [ScopeContainerElement] that can see this change.
- List<ScopeContainerElement> scopesAffectedBy(
- Element element,
- /* ScopeContainerElement */ container) {
- // TODO(ahe): Use library export graph to compute this.
- // TODO(ahe): Should return all user-defined libraries and packages.
- LibraryElement library = container.library;
- List<ScopeContainerElement> result = <ScopeContainerElement>[library];
-
- if (!container.isClass) return result;
-
- ClassElement cls = container;
-
- if (!cls.declaration.isResolved) {
- // TODO(ahe): This test fails otherwise: experimental/add_static_field.
- throw new IncrementalCompilationFailed(
- "Unresolved class ${cls.declaration}");
- }
- var externalSubtypes =
- compiler.world.subclassesOf(cls).where((e) => e.library != library);
-
- return result..addAll(externalSubtypes);
- }
-
- /// Returns true if function [before] can be reused to reflect the changes in
- /// [after].
- ///
- /// If [before] can be reused, an update (patch) is added to [updates].
- bool canReuseFunction(
- Token diffToken,
- PartialFunctionElement before,
- PartialFunctionElement after) {
- FunctionExpression node =
- after.parseNode(compiler.parsing).asFunctionExpression();
- if (node == null) {
- return cannotReuse(after, "Not a function expression: '$node'");
- }
- Token last = after.endToken;
- if (node.body != null) {
- last = node.body.getBeginToken();
- }
- if (before.isMalformed ||
- compiler.elementHasCompileTimeError(before) ||
- isTokenBetween(diffToken, after.beginToken, last)) {
- removeFunction(before);
- addFunction(after, before.enclosingElement);
- if (compiler.mainFunction == before) {
- return cannotReuse(
- after,
- "Unable to handle when signature of '${after.name}' changes");
- }
- return allowSignatureChanged(before, after);
- }
- logVerbose('Simple modification of ${after} detected');
- if (!before.isInstanceMember) {
- if (!allowNonInstanceMemberModified(after)) return false;
- }
- updates.add(new FunctionUpdate(compiler, before, after));
- return true;
- }
-
- bool canReuseClass(
- Token diffToken,
- PartialClassElement before,
- PartialClassElement after) {
- ClassNode node = after.parseNode(compiler.parsing).asClassNode();
- if (node == null) {
- return cannotReuse(after, "Not a ClassNode: '$node'");
- }
- NodeList body = node.body;
- if (body == null) {
- return cannotReuse(after, "Class has no body.");
- }
- if (isTokenBetween(diffToken, node.beginToken, body.beginToken.next)) {
- if (!allowClassHeaderModified(after)) return false;
- logVerbose('Class header modified in ${after}');
- addClassUpdate(compiler, before, after);
- before.forEachLocalMember((ElementX member) {
- // TODO(ahe): Quadratic.
- invalidateScopesAffectedBy(member, before);
- });
- } else {
- logVerbose('Simple modification of ${after} detected');
- }
- return canReuseScopeContainerElement(before, after);
- }
-
- /// Returns true if [token] is found between [first] (included) and [last]
- /// (excluded).
- bool isTokenBetween(Token token, Token first, Token last) {
- Token current = first;
- while (current != last && current.kind != EOF_TOKEN) {
- if (current == token) {
- return true;
- }
- current = current.next;
- }
- return false;
- }
-
- bool unableToReuse(
- Token diffToken,
- PartialElement before,
- PartialElement after) {
- return cannotReuse(
- after,
- 'Unhandled change:'
- ' ${before} (${before.runtimeType} -> ${after.runtimeType}).');
- }
-
- /// Apply the collected [updates]. Return a list of elements that needs to be
- /// recompiled after applying the updates.
- List<Element> applyUpdates() {
- for (Update update in updates) {
- update.captureState();
- }
- if (_failedUpdates.isNotEmpty) {
- throw new IncrementalCompilationFailed(_failedUpdates.join('\n\n'));
- }
- for (ElementX element in _elementsToInvalidate) {
- compiler.forgetElement(element);
- element.reuseElement();
- if (element.isFunction) {
- replaceFunctionInBackend(element, element.enclosingElement);
- }
- }
- List<Element> elementsToInvalidate = <Element>[];
- for (ElementX element in _elementsToInvalidate) {
- if (!_removedElements.contains(element)) {
- elementsToInvalidate.add(element);
- }
- }
- for (Update update in updates) {
- Element element = update.apply(backend);
- if (!update.isRemoval) {
- elementsToInvalidate.add(element);
- }
- if (update is FunctionUpdate) {
- replaceFunctionInBackend(element, element.enclosingElement);
- }
- }
- return elementsToInvalidate;
- }
-
- void addClassUpdate(
- Compiler compiler,
- PartialClassElement before,
- PartialClassElement after);
-
- void addAddedFunctionUpdate(
- Compiler compiler,
- PartialFunctionElement element,
- /* ScopeContainerElement */ container);
-
- void addRemovedFunctionUpdate(
- Compiler compiler,
- PartialFunctionElement element);
-
- void addRemovedFieldUpdate(
- Compiler compiler,
- FieldElementX element);
-
- void addRemovedClassUpdate(
- Compiler compiler,
- PartialClassElement element);
-
- void addAddedFieldUpdate(
- Compiler compiler,
- FieldElementX element,
- /* ScopeContainerElement */ container);
-
- void addAddedClassUpdate(
- Compiler compiler,
- PartialClassElement element,
- LibraryElementX library);
-
- bool uriHasUpdate(Uri uri);
-
- bool allowClassHeaderModified(PartialClassElement after);
-
- bool allowSignatureChanged(
- PartialFunctionElement before,
- PartialFunctionElement after);
-
- bool allowNonInstanceMemberModified(PartialFunctionElement after);
-
- bool allowRemovedElement(PartialElement element);
-
- bool allowAddedElement(PartialElement element);
-}
-
-/// Represents an update (aka patch) of [before] to [after]. We use the word
-/// "update" to avoid confusion with the compiler feature of "patch" methods.
-abstract class Update {
- final Compiler compiler;
-
- PartialElement get before;
-
- PartialElement get after;
-
- Update(this.compiler);
-
- /// Applies the update to [before] and returns that element.
- Element apply(IncrementalBackend backend);
-
- bool get isRemoval => false;
-
- /// Called before any patches are applied to capture any state that is needed
- /// later.
- void captureState() {
- }
-}
-
-/// Represents an update of a function element.
-class FunctionUpdate extends Update with ReuseFunctionElement {
- final PartialFunctionElement before;
-
- final PartialFunctionElement after;
-
- FunctionUpdate(Compiler compiler, this.before, this.after)
- : super(compiler);
-
- PartialFunctionElement apply(IncrementalBackend backend) {
- patchElement();
- reuseElement();
- return before;
- }
-
- /// Destructively change the tokens in [before] to match those of [after].
- void patchElement() {
- before.beginToken = after.beginToken;
- before.endToken = after.endToken;
- before.getOrSet = after.getOrSet;
- }
-}
-
-abstract class ReuseFunctionElement {
- Compiler get compiler;
-
- PartialFunctionElement get before;
-
- /// Reset various caches and remove this element from the compiler's internal
- /// state.
- void reuseElement() {
- compiler.forgetElement(before);
- before.reuseElement();
- }
-}
-
-abstract class RemovalUpdate extends Update {
- ElementX get element;
-
- RemovalUpdate(Compiler compiler)
- : super(compiler);
-
- bool get isRemoval => true;
-
- void removeFromEnclosing() {
- // TODO(ahe): Need to recompute duplicated elements logic again. Simplest
- // solution is probably to remove all elements from enclosing scope and add
- // them back.
- if (element.isTopLevel) {
- removeFromLibrary(element.library);
- } else {
- removeFromEnclosingClass(element.enclosingClass);
- }
- }
-
- void removeFromEnclosingClass(PartialClassElement cls) {
- cls.localMembersCache = null;
- cls.localMembersReversed = cls.localMembersReversed.copyWithout(element);
- cls.localScope.contents.remove(element.name);
- }
-
- void removeFromLibrary(LibraryElementX library) {
- library.localMembers = library.localMembers.copyWithout(element);
- library.localScope.contents.remove(element.name);
- }
-}
-
-abstract class RemovedFunctionUpdate extends RemovalUpdate
- with ReuseFunctionElement {
- final PartialFunctionElement element;
-
- bool wasStateCaptured = false;
-
- RemovedFunctionUpdate(Compiler compiler, this.element)
- : super(compiler);
-
- PartialFunctionElement get before => element;
-
- PartialFunctionElement get after => null;
-
- void captureState() {
- if (wasStateCaptured) throw "captureState was called twice.";
- wasStateCaptured = true;
- }
-
- PartialFunctionElement apply(IncrementalBackend backend) {
- if (!wasStateCaptured) throw "captureState must be called before apply.";
- removeFromEnclosing();
- backend.removeFunction(element);
- reuseElement();
- return null;
- }
-}
-
-abstract class RemovedClassUpdate extends RemovalUpdate {
- final PartialClassElement element;
-
- bool wasStateCaptured = false;
-
- RemovedClassUpdate(Compiler compiler, this.element)
- : super(compiler);
-
- PartialClassElement get before => element;
-
- PartialClassElement get after => null;
-
- void captureState() {
- if (wasStateCaptured) throw "captureState was called twice.";
- wasStateCaptured = true;
- }
-
- PartialClassElement apply(IncrementalBackend backend) {
- if (!wasStateCaptured) {
- throw new StateError("captureState must be called before apply.");
- }
-
- removeFromEnclosing();
-
- element.forEachLocalMember((ElementX member) {
- compiler.forgetElement(member);
- member.reuseElement();
- });
-
- compiler.forgetElement(element);
- element.reuseElement();
-
- return null;
- }
-}
-
-abstract class RemovedFieldUpdate extends RemovalUpdate {
- final FieldElementX element;
-
- bool wasStateCaptured = false;
-
- RemovedFieldUpdate(Compiler compiler, this.element)
- : super(compiler);
-
- PartialFieldList get before => element.declarationSite;
-
- PartialFieldList get after => null;
-
- void captureState() {
- if (wasStateCaptured) throw "captureState was called twice.";
- wasStateCaptured = true;
- }
-
- FieldElementX apply(IncrementalBackend backend) {
- if (!wasStateCaptured) {
- throw new StateError("captureState must be called before apply.");
- }
-
- removeFromEnclosing();
- backend.removeField(element);
-
- return element;
- }
-}
-
-abstract class AddedFunctionUpdate extends Update {
- final PartialFunctionElement element;
-
- final /* ScopeContainerElement */ container;
-
- AddedFunctionUpdate(Compiler compiler, this.element, this.container)
- : super(compiler) {
- if (container == null) {
- throw "container is null";
- }
- }
-
- PartialFunctionElement get before => null;
-
- PartialFunctionElement get after => element;
-
- PartialFunctionElement apply(IncrementalBackend backend) {
- Element enclosing = container;
- if (enclosing.isLibrary) {
- // TODO(ahe): Reuse compilation unit of element instead?
- enclosing = enclosing.compilationUnit;
- }
- PartialFunctionElement copy = element.copyWithEnclosing(enclosing);
- container.addMember(copy, compiler.reporter);
- return copy;
- }
-}
-
-abstract class AddedClassUpdate extends Update {
- final PartialClassElement element;
-
- final LibraryElementX library;
-
- AddedClassUpdate(Compiler compiler, this.element, this.library)
- : super(compiler);
-
- PartialClassElement get before => null;
-
- PartialClassElement get after => element;
-
- PartialClassElement apply(IncrementalBackend backend) {
- // TODO(ahe): Reuse compilation unit of element instead?
- CompilationUnitElementX compilationUnit = library.compilationUnit;
- PartialClassElement copy = element.copyWithEnclosing(compilationUnit);
- compilationUnit.addMember(copy, compiler.reporter);
- return copy;
- }
-}
-
-abstract class AddedFieldUpdate extends Update {
- final FieldElementX element;
-
- final /* ScopeContainerElement */ container;
-
- AddedFieldUpdate(Compiler compiler, this.element, this.container)
- : super(compiler);
-
- PartialFieldList get before => null;
-
- PartialFieldList get after => element.declarationSite;
-
- FieldElementX apply(IncrementalBackend backend) {
- Element enclosing = container;
- if (enclosing.isLibrary) {
- // TODO(ahe): Reuse compilation unit of element instead?
- enclosing = enclosing.compilationUnit;
- }
- FieldElementX copy = element.copyWithEnclosing(enclosing);
- container.addMember(copy, compiler.reporter);
- return copy;
- }
-}
-
-abstract class ClassUpdate extends Update {
- final PartialClassElement before;
-
- final PartialClassElement after;
-
- ClassUpdate(Compiler compiler, this.before, this.after)
- : super(compiler);
-
- PartialClassElement apply(IncrementalBackend backend) {
- patchElement();
- reuseElement();
- return before;
- }
-
- /// Destructively change the tokens in [before] to match those of [after].
- void patchElement() {
- before.cachedNode = after.cachedNode;
- before.beginToken = after.beginToken;
- before.endToken = after.endToken;
- }
-
- void reuseElement() {
- before.supertype = null;
- before.interfaces = null;
- before.supertypeLoadState = STATE_NOT_STARTED;
- before.resolutionState = STATE_NOT_STARTED;
- before.isProxy = false;
- before.hasIncompleteHierarchy = false;
- before.backendMembers = const Link<Element>();
- before.allSupertypesAndSelf = null;
- }
-}
-
-/// Returns all qualified names in [element] with less than four identifiers. A
-/// qualified name is an identifier followed by a sequence of dots and
-/// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the
-/// fourth identifier).
-///
-/// The longest possible name that can be resolved is three identifiers, for
-/// example, "prefix.MyClass.staticMethod". Since four or more identifiers
-/// cannot resolve to anything statically, they're not included in the returned
-/// value of this method.
-Set<String> qualifiedNamesIn(PartialElement element) {
- Token beginToken = element.beginToken;
- Token endToken = element.endToken;
- Token token = beginToken;
- if (element is PartialClassElement) {
- ClassNode node = element.cachedNode;
- if (node != null) {
- NodeList body = node.body;
- if (body != null) {
- endToken = body.beginToken;
- }
- }
- }
- Set<String> names = new Set<String>();
- do {
- if (token.isIdentifier()) {
- String name = token.value;
- // [name] is a single "identifier".
- names.add(name);
- if (identical('.', token.next.stringValue) &&
- token.next.next.isIdentifier()) {
- token = token.next.next;
- name += '.${token.value}';
- // [name] is "idenfifier.idenfifier".
- names.add(name);
-
- if (identical('.', token.next.stringValue) &&
- token.next.next.isIdentifier()) {
- token = token.next.next;
- name += '.${token.value}';
- // [name] is "idenfifier.idenfifier.idenfifier".
- names.add(name);
-
- while (identical('.', token.next.stringValue) &&
- token.next.next.isIdentifier()) {
- // Skip remaining identifiers, they cannot statically resolve to
- // anything, and must be dynamic sends.
- token = token.next.next;
- }
- }
- }
- }
- token = token.next;
- } while (token.kind != EOF_TOKEN && token != endToken);
- return names;
-}
-
-/// Returns true if one of the qualified names in names (as computed by
-/// [qualifiedNamesIn]) could be a static reference to [element].
-bool canNamesResolveStaticallyTo(
- Set<String> names,
- Element element,
- /* ScopeContainerElement */ container) {
- if (names.contains(element.name)) return true;
- if (container != null && container.isClass) {
- // [names] contains C.m, where C is the name of [container], and m is the
- // name of [element].
- if (names.contains("${container.name}.${element.name}")) return true;
- }
- // TODO(ahe): Check for prefixes as well.
- return false;
-}
-
-DeclarationSite declarationSite(Element element) {
- return element is ElementX ? element.declarationSite : null;
-}
« no previous file with comments | « pkg/fletchc/lib/incremental/fletchc_incremental.dart ('k') | pkg/fletchc/lib/incremental/scope_information_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698