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

Unified Diff: pkg/analyzer/lib/src/generated/incremental_resolver.dart

Issue 757743004: Update errors during incremental resolution. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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/generated/incremental_resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 38393f0372c9dd0e5412d8e5552eaffa6b62f68b..f73c3acf98b9db49f7eee7bab25a960857cf734c 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -7,8 +7,11 @@ library engine.incremental_resolver;
import 'dart:collection';
import 'dart:math' as math;
+import 'package:analyzer/src/generated/error_verifier.dart';
+
import 'ast.dart';
import 'element.dart';
+import 'engine.dart';
import 'error.dart';
import 'java_engine.dart';
import 'parser.dart';
@@ -18,165 +21,6 @@ import 'source.dart';
/**
- * Attempts to update [oldUnit] to the state that would correspond to [newCode].
- * Returns `true` if success, or `false` otherwise.
- * The [oldUnit] might be damaged.
- */
-bool poorMansIncrementalResolution(TypeProvider typeProvider,
- CompilationUnit oldUnit, String newCode) {
- try {
- CompilationUnit newUnit = _parseUnit(newCode);
- _TokenPair firstPair =
- _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken);
- _TokenPair lastPair =
- _findLastDifferentToken(oldUnit.endToken, newUnit.endToken);
- if (firstPair != null && lastPair != null) {
- // Prepare the "old" token range.
- Token oldBeginToken;
- Token oldEndToken;
- if (firstPair.oldToken.offset < lastPair.oldToken.offset) {
- oldBeginToken = firstPair.oldToken;
- oldEndToken = lastPair.oldToken;
- } else {
- oldBeginToken = lastPair.oldToken;
- oldEndToken = firstPair.oldToken;
- }
- // Prepare the "old" token tange.
- Token newBeginToken;
- Token newEndToken;
- if (firstPair.newToken.offset < lastPair.newToken.offset) {
- newBeginToken = firstPair.newToken;
- newEndToken = lastPair.newToken;
- } else {
- newBeginToken = lastPair.newToken;
- newEndToken = firstPair.newToken;
- }
- // Find nodes covering the "old" and "new" token ranges.
- AstNode oldNode =
- _findNodeWithTokens(oldUnit, oldBeginToken, oldEndToken);
- AstNode newNode =
- _findNodeWithTokens(newUnit, newBeginToken, newEndToken);
- // Try to find the smallest common node, a FunctionBody currently.
- {
- List<AstNode> oldParents = _getParents(oldNode);
- List<AstNode> newParents = _getParents(newNode);
- int length = math.min(oldParents.length, newParents.length);
- bool found = false;
- for (int i = 0; i < length; i++) {
- AstNode oldParent = oldParents[i];
- AstNode newParent = newParents[i];
- if (oldParent is FunctionBody && newParent is FunctionBody) {
- oldNode = oldParent;
- newNode = newParent;
- found = true;
- break;
- }
- }
- if (!found) {
- return false;
- }
- }
- // replace node
- NodeReplacer.replace(oldNode, newNode);
- // update token references
- oldNode.beginToken.previous.setNext(newNode.beginToken);
- oldNode.endToken.setNext(oldNode.endToken.next);
- // perform incremental resolution
- // TODO(scheglov) update errors
- AnalysisErrorListener errorListener = new BooleanErrorListener();
- CompilationUnitElement oldUnitElement = oldUnit.element;
- IncrementalResolver incrementalResolver = new IncrementalResolver(
- errorListener,
- typeProvider,
- oldUnitElement.library,
- oldUnitElement,
- oldUnitElement.source,
- oldNode.offset,
- oldNode.length,
- newNode.length);
- incrementalResolver.resolve(newNode);
- return true;
- }
- } catch (e) {
- // TODO(scheglov) find a way to log these exceptions
- }
- return false;
-}
-
-
-bool _equalToken(Token oldToken, Token newToken, int delta) {
- if (oldToken.type != newToken.type) {
- return false;
- }
- if (newToken.offset - oldToken.offset != delta) {
- return false;
- }
- return oldToken.lexeme == newToken.lexeme;
-}
-
-
-_TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
-// print('first ------------');
- while (oldToken.type != TokenType.EOF && newToken.type != TokenType.EOF) {
-// print('old: $oldToken @ ${oldToken.offset}');
-// print('new: $newToken @ ${newToken.offset}');
- if (!_equalToken(oldToken, newToken, 0)) {
- return new _TokenPair(oldToken, newToken);
- }
- oldToken = oldToken.next;
- newToken = newToken.next;
- }
- return null;
-}
-
-
-_TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
-// print('last ------------');
- int delta = newToken.offset - oldToken.offset;
- while (oldToken.previous != oldToken && newToken.previous != newToken) {
-// print('old: $oldToken @ ${oldToken.offset}');
-// print('new: $newToken @ ${newToken.offset}');
- if (!_equalToken(oldToken, newToken, delta)) {
- return new _TokenPair(oldToken.next, newToken.next);
- }
- oldToken.offset += delta;
- oldToken = oldToken.previous;
- newToken = newToken.previous;
- }
- return null;
-}
-
-
-AstNode _findNodeWithTokens(AstNode root, Token first, Token last) {
- int offset = first.offset;
- int end = last.end;
- NodeLocator nodeLocator = new NodeLocator.con2(offset, end);
- return nodeLocator.searchWithin(root);
-}
-
-
-List<AstNode> _getParents(AstNode node) {
- List<AstNode> parents = <AstNode>[];
- while (node != null) {
- parents.insert(0, node);
- node = node.parent;
- }
- return parents;
-}
-
-
-CompilationUnit _parseUnit(String code) {
- // TODO(scheglov) remember and update errors
- var errorListener = new BooleanErrorListener();
- var reader = new CharSequenceReader(code);
- var scanner = new Scanner(null, reader, errorListener);
- var token = scanner.tokenize();
- var parser = new Parser(null, errorListener);
- return parser.parseCompilationUnit(token);
-}
-
-
-/**
* Instances of the class [DeclarationMatcher] determine whether the element
* model defined by a given AST structure matches an existing element model.
*/
@@ -782,12 +626,6 @@ class DeclarationMatcher extends RecursiveAstVisitor {
*/
class IncrementalResolver {
/**
- * The error listener that will be informed of any errors that are found
- * during resolution.
- */
- final AnalysisErrorListener _errorListener;
-
- /**
* The object used to access the types from the core library.
*/
final TypeProvider _typeProvider;
@@ -822,14 +660,19 @@ class IncrementalResolver {
*/
final int _updateNewLength;
+ ResolutionContext _resolutionContext;
+
+ List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS;
+ List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS;
+ List<AnalysisError> _hints = AnalysisError.NO_ERRORS;
+
/**
* Initialize a newly created incremental resolver to resolve a node in the
- * given source in the given library, reporting errors to the given error
- * listener.
+ * given source in the given library.
*/
- IncrementalResolver(this._errorListener, this._typeProvider,
- this._definingLibrary, this._definingUnit, this._source, this._updateOffset,
- this._updateOldLength, this._updateNewLength);
+ IncrementalResolver(this._typeProvider, this._definingLibrary,
+ this._definingUnit, this._source, this._updateOffset, this._updateOldLength,
+ this._updateNewLength);
/**
* Resolve [node], reporting any errors or warnings to the given listener.
@@ -847,13 +690,11 @@ class IncrementalResolver {
throw new AnalysisException("Cannot resolve node: element model changed");
}
_updateElements(rootNode);
- // resolve root in scope
- ResolutionContext context =
- ResolutionContextBuilder.contextFor(rootNode, _errorListener);
- Scope scope = context.scope;
- _resolveTypes(rootNode, scope);
- _resolveVariables(rootNode, scope);
- _resolveReferences(rootNode, context);
+ // resolve
+ _resolveReferences(rootNode);
+ // verify
+ _verify(rootNode);
+ _generateHints(rootNode);
}
/**
@@ -917,6 +758,16 @@ class IncrementalResolver {
throw new AnalysisException("Cannot resolve node: no resolvable node");
}
+ void _generateHints(AstNode node) {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
+ AnalysisContext analysisContext = _definingLibrary.context;
+ HintGenerator hintGenerator =
+ new HintGenerator(<CompilationUnit>[unit], analysisContext, errorListener);
+ hintGenerator.generateForLibrary();
+ _hints = errorListener.getErrorsForSource(_source);
+ }
+
/**
* Return the element defined by [node], or `null` if the node does not
* define an element.
@@ -930,35 +781,45 @@ class IncrementalResolver {
return null;
}
- void _resolveReferences(AstNode node, ResolutionContext context) {
- ResolverVisitor visitor = new ResolverVisitor.con3(
- _definingLibrary,
- _source,
- _typeProvider,
- context.scope,
- _errorListener);
- visitor.enclosingClass = context.enclosingClass;
- node.accept(visitor);
- }
-
- void _resolveTypes(AstNode node, Scope scope) {
- TypeResolverVisitor visitor = new TypeResolverVisitor.con3(
- _definingLibrary,
- _source,
- _typeProvider,
- scope,
- _errorListener);
- node.accept(visitor);
- }
-
- void _resolveVariables(AstNode node, Scope scope) {
- VariableResolverVisitor visitor = new VariableResolverVisitor.con2(
- _definingLibrary,
- _source,
- _typeProvider,
- scope,
- _errorListener);
- node.accept(visitor);
+ _resolveReferences(AstNode node) {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ // prepare context
+ _resolutionContext =
+ ResolutionContextBuilder.contextFor(node, errorListener);
+ Scope scope = _resolutionContext.scope;
+ // resolve types
+ {
+ TypeResolverVisitor visitor = new TypeResolverVisitor.con3(
+ _definingLibrary,
+ _source,
+ _typeProvider,
+ scope,
+ errorListener);
+ node.accept(visitor);
+ }
+ // resolve variables
+ {
+ VariableResolverVisitor visitor = new VariableResolverVisitor.con2(
+ _definingLibrary,
+ _source,
+ _typeProvider,
+ scope,
+ errorListener);
+ node.accept(visitor);
+ }
+ // resolve references
+ {
+ ResolverVisitor visitor = new ResolverVisitor.con3(
+ _definingLibrary,
+ _source,
+ _typeProvider,
+ _resolutionContext.scope,
+ errorListener);
+ visitor.enclosingClass = _resolutionContext.enclosingClass;
+ node.accept(visitor);
+ }
+ // remember errors
+ _resolveErrors = errorListener.getErrorsForSource(_source);
}
void _updateElements(AstNode node) {
@@ -986,6 +847,272 @@ class IncrementalResolver {
oldElement.localVariables = newElement.localVariables;
}
}
+
+ void _verify(AstNode node) {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
+ ErrorVerifier errorVerifier = new ErrorVerifier(
+ errorReporter,
+ _definingLibrary,
+ _typeProvider,
+ new InheritanceManager(_definingLibrary));
+ if (_resolutionContext.enclosingClassDeclaration != null) {
+ errorVerifier.initClassDeclaration(
+ _resolutionContext.enclosingClassDeclaration);
+ }
+ node.accept(errorVerifier);
+ _verifyErrors = errorListener.getErrorsForSource(_source);
+ }
+}
+
+
+class PoorMansIncrementalResolver {
+ final TypeProvider _typeProvider;
+ final Source _unitSource;
+ final Source _librarySource;
+ final DartEntry _entry;
+
+ int _updateOffset;
+ int _updateDelta;
+ int _updateEndOld;
+ int _updateEndNew;
+
+ List<AnalysisError> _newScanErrors = <AnalysisError>[];
+ List<AnalysisError> _newParseErrors = <AnalysisError>[];
+ List<AnalysisError> _newResolveErrors = <AnalysisError>[];
+ List<AnalysisError> _newVerifyErrors = <AnalysisError>[];
+ List<AnalysisError> _newHints = <AnalysisError>[];
+
+ PoorMansIncrementalResolver(this._typeProvider, this._unitSource,
+ this._librarySource, this._entry);
+
+ /**
+ * Attempts to update [oldUnit] to the state corresponding to [newCode].
+ * Returns `true` if success, or `false` otherwise.
+ * The [oldUnit] might be damaged.
+ */
+ bool resolve(CompilationUnit oldUnit, String newCode) {
+ try {
+ CompilationUnit newUnit = _parseUnit(newCode);
+ _TokenPair firstPair =
+ _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken);
+ _TokenPair lastPair =
+ _findLastDifferentToken(oldUnit.endToken, newUnit.endToken);
+ if (firstPair != null && lastPair != null) {
+ // Prepare the "old" token range.
+ Token oldBeginToken;
+ Token oldEndToken;
+ if (firstPair.oldToken.offset < lastPair.oldToken.offset) {
+ oldBeginToken = firstPair.oldToken;
+ oldEndToken = lastPair.oldToken;
+ } else {
+ oldBeginToken = lastPair.oldToken;
+ oldEndToken = firstPair.oldToken;
+ }
+ // Prepare the "old" token tange.
+ Token newBeginToken;
+ Token newEndToken;
+ if (firstPair.newToken.offset < lastPair.newToken.offset) {
+ newBeginToken = firstPair.newToken;
+ newEndToken = lastPair.newToken;
+ } else {
+ newBeginToken = lastPair.newToken;
+ newEndToken = firstPair.newToken;
+ }
+ // Find nodes covering the "old" and "new" token ranges.
+ AstNode oldNode =
+ _findNodeWithTokens(oldUnit, oldBeginToken, oldEndToken);
+ AstNode newNode =
+ _findNodeWithTokens(newUnit, newBeginToken, newEndToken);
+ // Try to find the smallest common node, a FunctionBody currently.
+ {
+ List<AstNode> oldParents = _getParents(oldNode);
+ List<AstNode> newParents = _getParents(newNode);
+ int length = math.min(oldParents.length, newParents.length);
+ bool found = false;
+ for (int i = 0; i < length; i++) {
+ AstNode oldParent = oldParents[i];
+ AstNode newParent = newParents[i];
+ if (oldParent is FunctionBody && newParent is FunctionBody) {
+ oldNode = oldParent;
+ newNode = newParent;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ // replace node
+ NodeReplacer.replace(oldNode, newNode);
+ // update token references
+ oldNode.beginToken.previous.setNext(newNode.beginToken);
+ oldNode.endToken.setNext(oldNode.endToken.next);
+ // prepare update range
+ _updateOffset = oldNode.offset;
+ _updateDelta = lastPair.delta;
+ _updateEndOld = oldNode.end;
+ _updateEndNew = newNode.end;
+ // perform incremental resolution
+ CompilationUnitElement oldUnitElement = oldUnit.element;
+ IncrementalResolver incrementalResolver = new IncrementalResolver(
+ _typeProvider,
+ oldUnitElement.library,
+ oldUnitElement,
+ oldUnitElement.source,
+ _updateOffset,
+ oldNode.length,
+ newNode.length + _updateDelta);
+ incrementalResolver.resolve(newNode);
+ _newResolveErrors = incrementalResolver._resolveErrors;
+ _newVerifyErrors = incrementalResolver._verifyErrors;
+ _newHints = incrementalResolver._hints;
+ _updateEntry();
+ return true;
+ }
+ } catch (e, st) {
+ // TODO(scheglov) find a way to log these exceptions
+ print(e);
+ print(st);
+ }
+ return false;
+ }
+
+ CompilationUnit _parseUnit(String code) {
+ Token token = _scan(code);
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ Parser parser = new Parser(_unitSource, errorListener);
+ CompilationUnit unit = parser.parseCompilationUnit(token);
+ _newParseErrors = errorListener.errors;
+ return unit;
+ }
+
+ Token _scan(String code) {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ CharSequenceReader reader = new CharSequenceReader(code);
+ Scanner scanner = new Scanner(_unitSource, reader, errorListener);
+ Token token = scanner.tokenize();
+ _newScanErrors = errorListener.errors;
+ return token;
+ }
+
+ void _updateEntry() {
+ {
+ List<AnalysisError> oldErrors = _entry.getValue(DartEntry.SCAN_ERRORS);
+ List<AnalysisError> errors = _updateErrors(oldErrors, _newScanErrors);
Brian Wilkerson 2014/11/25 14:53:58 Given that we're scanning and parsing the whole fi
scheglov 2014/11/25 18:54:11 Good idea! Done.
+ _entry.setValue(DartEntry.SCAN_ERRORS, errors);
+ }
+ {
+ List<AnalysisError> oldErrors = _entry.getValue(DartEntry.PARSE_ERRORS);
+ List<AnalysisError> errors = _updateErrors(oldErrors, _newParseErrors);
+ _entry.setValue(DartEntry.PARSE_ERRORS, errors);
+ }
+ {
+ List<AnalysisError> oldErrors =
+ _entry.getValueInLibrary(DartEntry.RESOLUTION_ERRORS, _librarySource);
+ List<AnalysisError> errors = _updateErrors(oldErrors, _newResolveErrors);
+ _entry.setValueInLibrary(
+ DartEntry.RESOLUTION_ERRORS,
+ _librarySource,
+ errors);
+ }
+ {
+ List<AnalysisError> oldErrors =
+ _entry.getValueInLibrary(DartEntry.VERIFICATION_ERRORS, _librarySource);
+ List<AnalysisError> errors = _updateErrors(oldErrors, _newVerifyErrors);
+ _entry.setValueInLibrary(
+ DartEntry.VERIFICATION_ERRORS,
+ _librarySource,
+ errors);
+ }
+ {
+ List<AnalysisError> oldErrors =
+ _entry.getValueInLibrary(DartEntry.HINTS, _librarySource);
+ List<AnalysisError> errors = _updateErrors(oldErrors, _newHints);
+ _entry.setValueInLibrary(DartEntry.HINTS, _librarySource, errors);
+ }
+ }
+
+ List<AnalysisError> _updateErrors(List<AnalysisError> oldErrors,
+ List<AnalysisError> newErrors) {
+ List<AnalysisError> errors = new List<AnalysisError>();
+ // add updated old errors
+ for (AnalysisError error in oldErrors) {
+ int errorOffset = error.offset;
+ if (errorOffset < _updateOffset) {
+ errors.add(error);
+ } else if (errorOffset > _updateEndOld) {
+ error.offset += _updateDelta;
+ errors.add(error);
+ }
+ }
+ // add new errors
+ for (AnalysisError error in newErrors) {
+ int errorOffset = error.offset;
+ if (errorOffset > _updateOffset && errorOffset < _updateEndNew) {
+ errors.add(error);
+ }
+ }
+ // done
+ return errors;
+ }
+
+ static bool _equalToken(Token oldToken, Token newToken, int delta) {
+ if (oldToken.type != newToken.type) {
+ return false;
+ }
+ if (newToken.offset - oldToken.offset != delta) {
+ return false;
+ }
+ return oldToken.lexeme == newToken.lexeme;
+ }
+
+ static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
+ // print('first ------------');
+ while (oldToken.type != TokenType.EOF && newToken.type != TokenType.EOF) {
+ // print('old: $oldToken @ ${oldToken.offset}');
+ // print('new: $newToken @ ${newToken.offset}');
+ if (!_equalToken(oldToken, newToken, 0)) {
+ return new _TokenPair(oldToken, newToken, 0);
+ }
+ oldToken = oldToken.next;
+ newToken = newToken.next;
+ }
+ return null;
+ }
+
+ static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
+ // print('last ------------');
+ int delta = newToken.offset - oldToken.offset;
+ while (oldToken.previous != oldToken && newToken.previous != newToken) {
+ // print('old: $oldToken @ ${oldToken.offset}');
+ // print('new: $newToken @ ${newToken.offset}');
+ if (!_equalToken(oldToken, newToken, delta)) {
+ return new _TokenPair(oldToken.next, newToken.next, delta);
+ }
+ oldToken.offset += delta;
+ oldToken = oldToken.previous;
+ newToken = newToken.previous;
+ }
+ return null;
+ }
+
+ static AstNode _findNodeWithTokens(AstNode root, Token first, Token last) {
+ int offset = first.offset;
+ int end = last.end;
+ NodeLocator nodeLocator = new NodeLocator.con2(offset, end);
+ return nodeLocator.searchWithin(root);
+ }
+
+ static List<AstNode> _getParents(AstNode node) {
+ List<AstNode> parents = <AstNode>[];
+ while (node != null) {
+ parents.insert(0, node);
+ node = node.parent;
+ }
+ return parents;
+ }
}
@@ -993,6 +1120,7 @@ class IncrementalResolver {
* The context to resolve an [AstNode] in.
*/
class ResolutionContext {
+ ClassDeclaration enclosingClassDeclaration;
ClassElement enclosingClass;
Scope scope;
}
@@ -1010,7 +1138,13 @@ class ResolutionContextBuilder {
final AnalysisErrorListener _errorListener;
/**
- * The class containing the AST nodes being visited, or `null` if we are not
+ * The class containing the enclosing [ClassDeclaration], or `null` if we are
+ * not in the scope of a class.
+ */
+ ClassDeclaration _enclosingClassDeclaration;
+
+ /**
+ * The class containing the enclosing [ClassElement], or `null` if we are not
* in the scope of a class.
*/
ClassElement _enclosingClass;
@@ -1055,6 +1189,7 @@ class ResolutionContextBuilder {
}
Scope scope = _scopeForAstNode(parent);
if (node is ClassDeclaration) {
+ _enclosingClassDeclaration = node;
_enclosingClass = node.element;
if (_enclosingClass == null) {
throw new AnalysisException(
@@ -1138,6 +1273,7 @@ class ResolutionContextBuilder {
// prepare context
ResolutionContext context = new ResolutionContext();
context.scope = scope;
+ context.enclosingClassDeclaration = builder._enclosingClassDeclaration;
context.enclosingClass = builder._enclosingClass;
return context;
}
@@ -1273,5 +1409,6 @@ class _ElementsRestorer extends RecursiveAstVisitor {
class _TokenPair {
final Token oldToken;
final Token newToken;
- _TokenPair(this.oldToken, this.newToken);
+ final int delta;
+ _TokenPair(this.oldToken, this.newToken, this.delta);
}
« no previous file with comments | « pkg/analyzer/lib/src/generated/error_verifier.dart ('k') | pkg/analyzer/test/generated/incremental_resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698