| Index: analyzer/lib/src/generated/incremental_resolver.dart
|
| diff --git a/analyzer/lib/src/generated/incremental_resolver.dart b/analyzer/lib/src/generated/incremental_resolver.dart
|
| deleted file mode 100644
|
| index 78481ce117eb96306a99b92cb3058f6ec03c3a8a..0000000000000000000000000000000000000000
|
| --- a/analyzer/lib/src/generated/incremental_resolver.dart
|
| +++ /dev/null
|
| @@ -1,1988 +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 engine.incremental_resolver;
|
| -
|
| -import 'dart:collection';
|
| -import 'dart:math' as math;
|
| -
|
| -import 'package:analyzer/src/context/cache.dart'
|
| - show CacheEntry, TargetedResult;
|
| -import 'package:analyzer/src/generated/constant.dart';
|
| -import 'package:analyzer/src/task/dart.dart'
|
| - show
|
| - HINTS,
|
| - PARSE_ERRORS,
|
| - RESOLVE_REFERENCES_ERRORS,
|
| - RESOLVE_TYPE_NAMES_ERRORS,
|
| - SCAN_ERRORS,
|
| - USED_IMPORTED_ELEMENTS,
|
| - USED_LOCAL_ELEMENTS,
|
| - VARIABLE_REFERENCE_ERRORS,
|
| - VERIFY_ERRORS;
|
| -import 'package:analyzer/task/dart.dart'
|
| - show DART_ERRORS, LibrarySpecificUnit, PARSED_UNIT, TOKEN_STREAM;
|
| -import 'package:analyzer/task/general.dart' show CONTENT;
|
| -import 'package:analyzer/task/model.dart' show ResultDescriptor;
|
| -
|
| -import 'ast.dart';
|
| -import 'element.dart';
|
| -import 'engine.dart';
|
| -import 'error.dart';
|
| -import 'error_verifier.dart';
|
| -import 'incremental_logger.dart' show logger, LoggingTimer;
|
| -import 'java_engine.dart';
|
| -import 'parser.dart';
|
| -import 'resolver.dart';
|
| -import 'scanner.dart';
|
| -import 'source.dart';
|
| -import 'utilities_dart.dart';
|
| -
|
| -/**
|
| - * If `true`, an attempt to resolve API-changing modifications is made.
|
| - */
|
| -bool _resolveApiChanges = false;
|
| -
|
| -/**
|
| - * This method is used to enable/disable API-changing modifications resolution.
|
| - */
|
| -void set test_resolveApiChanges(bool value) {
|
| - _resolveApiChanges = value;
|
| -}
|
| -
|
| -/**
|
| - * Instances of the class [DeclarationMatcher] determine whether the element
|
| - * model defined by a given AST structure matches an existing element model.
|
| - */
|
| -class DeclarationMatcher extends RecursiveAstVisitor {
|
| - /**
|
| - * The libary containing the AST nodes being visited.
|
| - */
|
| - LibraryElement _enclosingLibrary;
|
| -
|
| - /**
|
| - * The compilation unit containing the AST nodes being visited.
|
| - */
|
| - CompilationUnitElement _enclosingUnit;
|
| -
|
| - /**
|
| - * The function type alias containing the AST nodes being visited, or `null` if we are not
|
| - * in the scope of a function type alias.
|
| - */
|
| - FunctionTypeAliasElement _enclosingAlias;
|
| -
|
| - /**
|
| - * The class containing the AST nodes being visited, or `null` if we are not
|
| - * in the scope of a class.
|
| - */
|
| - ClassElementImpl _enclosingClass;
|
| -
|
| - /**
|
| - * The parameter containing the AST nodes being visited, or `null` if we are not in the
|
| - * scope of a parameter.
|
| - */
|
| - ParameterElement _enclosingParameter;
|
| -
|
| - FieldDeclaration _enclosingFieldNode = null;
|
| - bool _inTopLevelVariableDeclaration = false;
|
| -
|
| - /**
|
| - * Is `true` if the current class declaration has a constructor.
|
| - */
|
| - bool _hasConstructor = false;
|
| -
|
| - /**
|
| - * A set containing all of the elements in the element model that were defined by the old AST node
|
| - * corresponding to the AST node being visited.
|
| - */
|
| - HashSet<Element> _allElements = new HashSet<Element>();
|
| -
|
| - /**
|
| - * A set containing all of the elements were defined in the old element model,
|
| - * but are not defined in the new element model.
|
| - */
|
| - HashSet<Element> _removedElements = new HashSet<Element>();
|
| -
|
| - /**
|
| - * A set containing all of the elements are defined in the new element model,
|
| - * but were not defined in the old element model.
|
| - */
|
| - HashSet<Element> _addedElements = new HashSet<Element>();
|
| -
|
| - /**
|
| - * Determines how elements model corresponding to the given [node] differs
|
| - * from the [element].
|
| - */
|
| - DeclarationMatchKind matches(AstNode node, Element element) {
|
| - logger.enter('match $element @ ${element.nameOffset}');
|
| - try {
|
| - _captureEnclosingElements(element);
|
| - _gatherElements(element);
|
| - node.accept(this);
|
| - } on _DeclarationMismatchException {
|
| - return DeclarationMatchKind.MISMATCH;
|
| - } finally {
|
| - logger.exit();
|
| - }
|
| - // no API changes
|
| - if (_removedElements.isEmpty && _addedElements.isEmpty) {
|
| - return DeclarationMatchKind.MATCH;
|
| - }
|
| - // simple API change
|
| - logger.log('_removedElements: $_removedElements');
|
| - logger.log('_addedElements: $_addedElements');
|
| - _removedElements.forEach(_removeElement);
|
| - if (_removedElements.length <= 1 && _addedElements.length == 1) {
|
| - return DeclarationMatchKind.MISMATCH_OK;
|
| - }
|
| - // something more complex
|
| - return DeclarationMatchKind.MISMATCH;
|
| - }
|
| -
|
| - @override
|
| - visitBlockFunctionBody(BlockFunctionBody node) {
|
| - // ignore bodies
|
| - }
|
| -
|
| - @override
|
| - visitClassDeclaration(ClassDeclaration node) {
|
| - String name = node.name.name;
|
| - ClassElement element = _findElement(_enclosingUnit.types, name);
|
| - _enclosingClass = element;
|
| - _processElement(element);
|
| - _assertSameAnnotations(node, element);
|
| - _assertSameTypeParameters(node.typeParameters, element.typeParameters);
|
| - // check for missing clauses
|
| - if (node.extendsClause == null) {
|
| - _assertTrue(element.supertype.name == 'Object');
|
| - }
|
| - if (node.implementsClause == null) {
|
| - _assertTrue(element.interfaces.isEmpty);
|
| - }
|
| - if (node.withClause == null) {
|
| - _assertTrue(element.mixins.isEmpty);
|
| - }
|
| - // process clauses and members
|
| - _hasConstructor = false;
|
| - super.visitClassDeclaration(node);
|
| - // process default constructor
|
| - if (!_hasConstructor) {
|
| - ConstructorElement constructor = element.unnamedConstructor;
|
| - _processElement(constructor);
|
| - if (!constructor.isSynthetic) {
|
| - _assertEquals(constructor.parameters.length, 0);
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitClassTypeAlias(ClassTypeAlias node) {
|
| - String name = node.name.name;
|
| - ClassElement element = _findElement(_enclosingUnit.types, name);
|
| - _enclosingClass = element;
|
| - _processElement(element);
|
| - _assertSameTypeParameters(node.typeParameters, element.typeParameters);
|
| - super.visitClassTypeAlias(node);
|
| - }
|
| -
|
| - @override
|
| - visitCompilationUnit(CompilationUnit node) {
|
| - _processElement(_enclosingUnit);
|
| - super.visitCompilationUnit(node);
|
| - }
|
| -
|
| - @override
|
| - visitConstructorDeclaration(ConstructorDeclaration node) {
|
| - _hasConstructor = true;
|
| - SimpleIdentifier constructorName = node.name;
|
| - ConstructorElementImpl element = constructorName == null
|
| - ? _enclosingClass.unnamedConstructor
|
| - : _enclosingClass.getNamedConstructor(constructorName.name);
|
| - _processElement(element);
|
| - _assertEquals(node.constKeyword != null, element.isConst);
|
| - _assertEquals(node.factoryKeyword != null, element.isFactory);
|
| - _assertCompatibleParameters(node.parameters, element.parameters);
|
| - // matches, update the existing element
|
| - ExecutableElement newElement = node.element;
|
| - node.element = element;
|
| - _setLocalElements(element, newElement);
|
| - }
|
| -
|
| - @override
|
| - visitEnumConstantDeclaration(EnumConstantDeclaration node) {
|
| - String name = node.name.name;
|
| - FieldElement element = _findElement(_enclosingClass.fields, name);
|
| - _processElement(element);
|
| - }
|
| -
|
| - @override
|
| - visitEnumDeclaration(EnumDeclaration node) {
|
| - String name = node.name.name;
|
| - ClassElement element = _findElement(_enclosingUnit.enums, name);
|
| - _enclosingClass = element;
|
| - _processElement(element);
|
| - _assertTrue(element.isEnum);
|
| - super.visitEnumDeclaration(node);
|
| - }
|
| -
|
| - @override
|
| - visitExportDirective(ExportDirective node) {
|
| - String uri = _getStringValue(node.uri);
|
| - if (uri != null) {
|
| - ExportElement element =
|
| - _findUriReferencedElement(_enclosingLibrary.exports, uri);
|
| - _processElement(element);
|
| - _assertCombinators(node.combinators, element.combinators);
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
| - // ignore bodies
|
| - }
|
| -
|
| - @override
|
| - visitExtendsClause(ExtendsClause node) {
|
| - _assertSameType(node.superclass, _enclosingClass.supertype);
|
| - }
|
| -
|
| - @override
|
| - visitFieldDeclaration(FieldDeclaration node) {
|
| - _enclosingFieldNode = node;
|
| - try {
|
| - super.visitFieldDeclaration(node);
|
| - } finally {
|
| - _enclosingFieldNode = null;
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitFunctionDeclaration(FunctionDeclaration node) {
|
| - // prepare element name
|
| - String name = node.name.name;
|
| - if (node.isSetter) {
|
| - name += '=';
|
| - }
|
| - // prepare element
|
| - Token property = node.propertyKeyword;
|
| - ExecutableElementImpl element;
|
| - if (property == null) {
|
| - element = _findElement(_enclosingUnit.functions, name);
|
| - } else {
|
| - element = _findElement(_enclosingUnit.accessors, name);
|
| - }
|
| - // process element
|
| - _processElement(element);
|
| - _assertSameAnnotations(node, element);
|
| - _assertFalse(element.isSynthetic);
|
| - _assertSameType(node.returnType, element.returnType);
|
| - _assertCompatibleParameters(
|
| - node.functionExpression.parameters, element.parameters);
|
| - _assertBody(node.functionExpression.body, element);
|
| - // matches, update the existing element
|
| - ExecutableElement newElement = node.element;
|
| - node.name.staticElement = element;
|
| - node.functionExpression.element = element;
|
| - _setLocalElements(element, newElement);
|
| - }
|
| -
|
| - @override
|
| - visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| - String name = node.name.name;
|
| - FunctionTypeAliasElement element =
|
| - _findElement(_enclosingUnit.functionTypeAliases, name);
|
| - _processElement(element);
|
| - _assertSameTypeParameters(node.typeParameters, element.typeParameters);
|
| - _assertSameType(node.returnType, element.returnType);
|
| - _assertCompatibleParameters(node.parameters, element.parameters);
|
| - }
|
| -
|
| - @override
|
| - visitImplementsClause(ImplementsClause node) {
|
| - List<TypeName> nodes = node.interfaces;
|
| - List<InterfaceType> types = _enclosingClass.interfaces;
|
| - _assertSameTypes(nodes, types);
|
| - }
|
| -
|
| - @override
|
| - visitImportDirective(ImportDirective node) {
|
| - String uri = _getStringValue(node.uri);
|
| - if (uri != null) {
|
| - ImportElement element =
|
| - _findUriReferencedElement(_enclosingLibrary.imports, uri);
|
| - _processElement(element);
|
| - // match the prefix
|
| - SimpleIdentifier prefixNode = node.prefix;
|
| - PrefixElement prefixElement = element.prefix;
|
| - if (prefixNode == null) {
|
| - _assertNull(prefixElement);
|
| - } else {
|
| - _assertNotNull(prefixElement);
|
| - _assertEquals(prefixNode.name, prefixElement.name);
|
| - }
|
| - // match combinators
|
| - _assertCombinators(node.combinators, element.combinators);
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitMethodDeclaration(MethodDeclaration node) {
|
| - // prepare element name
|
| - String name = node.name.name;
|
| - if (name == TokenType.MINUS.lexeme &&
|
| - node.parameters.parameters.length == 0) {
|
| - name = "unary-";
|
| - }
|
| - if (node.isSetter) {
|
| - name += '=';
|
| - }
|
| - // prepare element
|
| - Token property = node.propertyKeyword;
|
| - ExecutableElementImpl element;
|
| - if (property == null) {
|
| - element = _findElement(_enclosingClass.methods, name);
|
| - } else {
|
| - element = _findElement(_enclosingClass.accessors, name);
|
| - }
|
| - // process element
|
| - ExecutableElement newElement = node.element;
|
| - try {
|
| - _assertNotNull(element);
|
| - _assertSameAnnotations(node, element);
|
| - _assertEquals(node.isStatic, element.isStatic);
|
| - _assertSameType(node.returnType, element.returnType);
|
| - _assertCompatibleParameters(node.parameters, element.parameters);
|
| - _assertBody(node.body, element);
|
| - _removedElements.remove(element);
|
| - // matches, update the existing element
|
| - node.name.staticElement = element;
|
| - _setLocalElements(element, newElement);
|
| - } on _DeclarationMismatchException {
|
| - _removeElement(element);
|
| - // add new element
|
| - if (newElement != null) {
|
| - _addedElements.add(newElement);
|
| - if (newElement is MethodElement) {
|
| - List<MethodElement> methods = _enclosingClass.methods;
|
| - methods.add(newElement);
|
| - _enclosingClass.methods = methods;
|
| - } else {
|
| - List<PropertyAccessorElement> accessors = _enclosingClass.accessors;
|
| - accessors.add(newElement);
|
| - _enclosingClass.accessors = accessors;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitPartDirective(PartDirective node) {
|
| - String uri = _getStringValue(node.uri);
|
| - if (uri != null) {
|
| - CompilationUnitElement element =
|
| - _findUriReferencedElement(_enclosingLibrary.parts, uri);
|
| - _processElement(element);
|
| - }
|
| - super.visitPartDirective(node);
|
| - }
|
| -
|
| - @override
|
| - visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
| - _inTopLevelVariableDeclaration = true;
|
| - try {
|
| - super.visitTopLevelVariableDeclaration(node);
|
| - } finally {
|
| - _inTopLevelVariableDeclaration = false;
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitVariableDeclaration(VariableDeclaration node) {
|
| - // prepare variable
|
| - String name = node.name.name;
|
| - PropertyInducingElement element;
|
| - if (_inTopLevelVariableDeclaration) {
|
| - element = _findElement(_enclosingUnit.topLevelVariables, name);
|
| - } else {
|
| - element = _findElement(_enclosingClass.fields, name);
|
| - }
|
| - // verify
|
| - PropertyInducingElement newElement = node.name.staticElement;
|
| - _processElement(element);
|
| - _assertSameAnnotations(node, element);
|
| - _assertEquals(node.isConst, element.isConst);
|
| - _assertEquals(node.isFinal, element.isFinal);
|
| - if (_enclosingFieldNode != null) {
|
| - _assertEquals(_enclosingFieldNode.isStatic, element.isStatic);
|
| - }
|
| - _assertSameType(
|
| - (node.parent as VariableDeclarationList).type, element.type);
|
| - // matches, restore the existing element
|
| - node.name.staticElement = element;
|
| - if (element is VariableElementImpl) {
|
| - (element as VariableElementImpl).initializer = newElement.initializer;
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitWithClause(WithClause node) {
|
| - List<TypeName> nodes = node.mixinTypes;
|
| - List<InterfaceType> types = _enclosingClass.mixins;
|
| - _assertSameTypes(nodes, types);
|
| - }
|
| -
|
| - /**
|
| - * Assert that the given [body] is compatible with the given [element].
|
| - * It should not be empty if the [element] is not an abstract class member.
|
| - * If it is present, it should have the same async / generator modifiers.
|
| - */
|
| - void _assertBody(FunctionBody body, ExecutableElementImpl element) {
|
| - if (body is EmptyFunctionBody) {
|
| - _assertTrue(element.isAbstract);
|
| - } else {
|
| - _assertFalse(element.isAbstract);
|
| - _assertEquals(body.isSynchronous, element.isSynchronous);
|
| - _assertEquals(body.isGenerator, element.isGenerator);
|
| - }
|
| - }
|
| -
|
| - void _assertCombinators(List<Combinator> nodeCombinators,
|
| - List<NamespaceCombinator> elementCombinators) {
|
| - // prepare shown/hidden names in the element
|
| - Set<String> showNames = new Set<String>();
|
| - Set<String> hideNames = new Set<String>();
|
| - for (NamespaceCombinator combinator in elementCombinators) {
|
| - if (combinator is ShowElementCombinator) {
|
| - showNames.addAll(combinator.shownNames);
|
| - } else if (combinator is HideElementCombinator) {
|
| - hideNames.addAll(combinator.hiddenNames);
|
| - }
|
| - }
|
| - // match combinators with the node
|
| - for (Combinator combinator in nodeCombinators) {
|
| - if (combinator is ShowCombinator) {
|
| - for (SimpleIdentifier nameNode in combinator.shownNames) {
|
| - String name = nameNode.name;
|
| - _assertTrue(showNames.remove(name));
|
| - }
|
| - } else if (combinator is HideCombinator) {
|
| - for (SimpleIdentifier nameNode in combinator.hiddenNames) {
|
| - String name = nameNode.name;
|
| - _assertTrue(hideNames.remove(name));
|
| - }
|
| - }
|
| - }
|
| - _assertTrue(showNames.isEmpty);
|
| - _assertTrue(hideNames.isEmpty);
|
| - }
|
| -
|
| - void _assertCompatibleParameter(
|
| - FormalParameter node, ParameterElement element) {
|
| - _assertEquals(node.kind, element.parameterKind);
|
| - if (node.kind == ParameterKind.NAMED) {
|
| - _assertEquals(node.identifier.name, element.name);
|
| - }
|
| - // check parameter type specific properties
|
| - if (node is DefaultFormalParameter) {
|
| - Expression nodeDefault = node.defaultValue;
|
| - if (nodeDefault == null) {
|
| - _assertNull(element.defaultValueCode);
|
| - } else {
|
| - _assertEquals(nodeDefault.toSource(), element.defaultValueCode);
|
| - }
|
| - _assertCompatibleParameter(node.parameter, element);
|
| - } else if (node is FieldFormalParameter) {
|
| - _assertTrue(element.isInitializingFormal);
|
| - _assertCompatibleParameters(node.parameters, element.parameters);
|
| - } else if (node is FunctionTypedFormalParameter) {
|
| - _assertFalse(element.isInitializingFormal);
|
| - _assertTrue(element.type is FunctionType);
|
| - FunctionType elementType = element.type;
|
| - _assertCompatibleParameters(node.parameters, element.parameters);
|
| - _assertSameType(node.returnType, elementType.returnType);
|
| - } else if (node is SimpleFormalParameter) {
|
| - _assertFalse(element.isInitializingFormal);
|
| - _assertSameType(node.type, element.type);
|
| - }
|
| - }
|
| -
|
| - void _assertCompatibleParameters(
|
| - FormalParameterList nodes, List<ParameterElement> elements) {
|
| - if (nodes == null) {
|
| - return _assertEquals(elements.length, 0);
|
| - }
|
| - List<FormalParameter> parameters = nodes.parameters;
|
| - int length = parameters.length;
|
| - _assertEquals(length, elements.length);
|
| - for (int i = 0; i < length; i++) {
|
| - _assertCompatibleParameter(parameters[i], elements[i]);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Asserts that there is an import with the same prefix as the given
|
| - * [prefixNode], which exposes the given [element].
|
| - */
|
| - void _assertElementVisibleWithPrefix(
|
| - SimpleIdentifier prefixNode, Element element) {
|
| - if (prefixNode == null) {
|
| - return;
|
| - }
|
| - String prefixName = prefixNode.name;
|
| - for (ImportElement import in _enclosingLibrary.imports) {
|
| - if (import.prefix != null && import.prefix.name == prefixName) {
|
| - Namespace namespace =
|
| - new NamespaceBuilder().createImportNamespaceForDirective(import);
|
| - Iterable<Element> visibleElements = namespace.definedNames.values;
|
| - if (visibleElements.contains(element)) {
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - _assertTrue(false);
|
| - }
|
| -
|
| - void _assertEquals(Object a, Object b) {
|
| - if (a != b) {
|
| - throw new _DeclarationMismatchException();
|
| - }
|
| - }
|
| -
|
| - void _assertFalse(bool condition) {
|
| - if (condition) {
|
| - throw new _DeclarationMismatchException();
|
| - }
|
| - }
|
| -
|
| - void _assertNotNull(Object object) {
|
| - if (object == null) {
|
| - throw new _DeclarationMismatchException();
|
| - }
|
| - }
|
| -
|
| - void _assertNull(Object object) {
|
| - if (object != null) {
|
| - throw new _DeclarationMismatchException();
|
| - }
|
| - }
|
| -
|
| - void _assertSameAnnotation(Annotation node, ElementAnnotation annotation) {
|
| - Element element = annotation.element;
|
| - if (element is ConstructorElement) {
|
| - _assertTrue(node.name is SimpleIdentifier);
|
| - _assertNull(node.constructorName);
|
| - TypeName nodeType = new TypeName(node.name, null);
|
| - _assertSameType(nodeType, element.returnType);
|
| - // TODO(scheglov) validate arguments
|
| - }
|
| - if (element is PropertyAccessorElement) {
|
| - _assertTrue(node.name is SimpleIdentifier);
|
| - String nodeName = node.name.name;
|
| - String elementName = element.displayName;
|
| - _assertEquals(nodeName, elementName);
|
| - }
|
| - }
|
| -
|
| - void _assertSameAnnotations(AnnotatedNode node, Element element) {
|
| - List<Annotation> nodeAnnotaitons = node.metadata;
|
| - List<ElementAnnotation> elementAnnotations = element.metadata;
|
| - int length = nodeAnnotaitons.length;
|
| - _assertEquals(elementAnnotations.length, length);
|
| - for (int i = 0; i < length; i++) {
|
| - _assertSameAnnotation(nodeAnnotaitons[i], elementAnnotations[i]);
|
| - }
|
| - }
|
| -
|
| - void _assertSameType(TypeName node, DartType type) {
|
| - // no type == dynamic
|
| - if (node == null) {
|
| - return _assertTrue(type == null || type.isDynamic);
|
| - }
|
| - if (type == null) {
|
| - return _assertTrue(false);
|
| - }
|
| - // prepare name
|
| - SimpleIdentifier prefixIdentifier = null;
|
| - Identifier nameIdentifier = node.name;
|
| - if (nameIdentifier is PrefixedIdentifier) {
|
| - PrefixedIdentifier prefixedIdentifier = nameIdentifier;
|
| - prefixIdentifier = prefixedIdentifier.prefix;
|
| - nameIdentifier = prefixedIdentifier.identifier;
|
| - }
|
| - String nodeName = nameIdentifier.name;
|
| - // check specific type kinds
|
| - if (type is ParameterizedType) {
|
| - _assertEquals(nodeName, type.name);
|
| - _assertElementVisibleWithPrefix(prefixIdentifier, type.element);
|
| - // check arguments
|
| - TypeArgumentList nodeArgumentList = node.typeArguments;
|
| - List<DartType> typeArguments = type.typeArguments;
|
| - if (nodeArgumentList == null) {
|
| - // Node doesn't have type arguments, so all type arguments of the
|
| - // element must be "dynamic".
|
| - for (DartType typeArgument in typeArguments) {
|
| - _assertTrue(typeArgument.isDynamic);
|
| - }
|
| - } else {
|
| - List<TypeName> nodeArguments = nodeArgumentList.arguments;
|
| - _assertSameTypes(nodeArguments, typeArguments);
|
| - }
|
| - } else if (type is TypeParameterType) {
|
| - _assertEquals(nodeName, type.name);
|
| - // TODO(scheglov) it should be possible to rename type parameters
|
| - } else if (type.isVoid) {
|
| - _assertEquals(nodeName, 'void');
|
| - } else if (type.isDynamic) {
|
| - _assertEquals(nodeName, 'dynamic');
|
| - } else {
|
| - // TODO(scheglov) support other types
|
| - logger.log('node: $node type: $type type.type: ${type.runtimeType}');
|
| - _assertTrue(false);
|
| - }
|
| - }
|
| -
|
| - void _assertSameTypeParameter(
|
| - TypeParameter node, TypeParameterElement element) {
|
| - _assertSameType(node.bound, element.bound);
|
| - }
|
| -
|
| - void _assertSameTypeParameters(
|
| - TypeParameterList nodesList, List<TypeParameterElement> elements) {
|
| - if (nodesList == null) {
|
| - return _assertEquals(elements.length, 0);
|
| - }
|
| - List<TypeParameter> nodes = nodesList.typeParameters;
|
| - int length = nodes.length;
|
| - _assertEquals(length, elements.length);
|
| - for (int i = 0; i < length; i++) {
|
| - _assertSameTypeParameter(nodes[i], elements[i]);
|
| - }
|
| - }
|
| -
|
| - void _assertSameTypes(List<TypeName> nodes, List<DartType> types) {
|
| - int length = nodes.length;
|
| - _assertEquals(length, types.length);
|
| - for (int i = 0; i < length; i++) {
|
| - _assertSameType(nodes[i], types[i]);
|
| - }
|
| - }
|
| -
|
| - void _assertTrue(bool condition) {
|
| - if (!condition) {
|
| - throw new _DeclarationMismatchException();
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Given that the comparison is to begin with the given [element], capture
|
| - * the enclosing elements that might be used while performing the comparison.
|
| - */
|
| - void _captureEnclosingElements(Element element) {
|
| - Element parent =
|
| - element is CompilationUnitElement ? element : element.enclosingElement;
|
| - while (parent != null) {
|
| - if (parent is CompilationUnitElement) {
|
| - _enclosingUnit = parent;
|
| - _enclosingLibrary = element.library;
|
| - } else if (parent is ClassElement) {
|
| - if (_enclosingClass == null) {
|
| - _enclosingClass = parent;
|
| - }
|
| - } else if (parent is FunctionTypeAliasElement) {
|
| - if (_enclosingAlias == null) {
|
| - _enclosingAlias = parent;
|
| - }
|
| - } else if (parent is ParameterElement) {
|
| - if (_enclosingParameter == null) {
|
| - _enclosingParameter = parent;
|
| - }
|
| - }
|
| - parent = parent.enclosingElement;
|
| - }
|
| - }
|
| -
|
| - void _gatherElements(Element element) {
|
| - _ElementsGatherer gatherer = new _ElementsGatherer(this);
|
| - element.accept(gatherer);
|
| - // TODO(scheglov) what if a change in a directive?
|
| - if (identical(element, _enclosingLibrary.definingCompilationUnit)) {
|
| - gatherer.addElements(_enclosingLibrary.imports);
|
| - gatherer.addElements(_enclosingLibrary.exports);
|
| - gatherer.addElements(_enclosingLibrary.parts);
|
| - }
|
| - }
|
| -
|
| - void _processElement(Element element) {
|
| - _assertNotNull(element);
|
| - if (!_allElements.contains(element)) {
|
| - throw new _DeclarationMismatchException();
|
| - }
|
| - _removedElements.remove(element);
|
| - }
|
| -
|
| - void _removeElement(Element element) {
|
| - if (element != null) {
|
| - Element enclosingElement = element.enclosingElement;
|
| - if (element is MethodElement) {
|
| - ClassElement classElement = enclosingElement;
|
| - _removeIdenticalElement(classElement.methods, element);
|
| - } else if (element is PropertyAccessorElement) {
|
| - if (enclosingElement is ClassElement) {
|
| - _removeIdenticalElement(enclosingElement.accessors, element);
|
| - }
|
| - if (enclosingElement is CompilationUnitElement) {
|
| - _removeIdenticalElement(enclosingElement.accessors, element);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Return the [Element] in [elements] with the given [name].
|
| - */
|
| - static Element _findElement(List<Element> elements, String name) {
|
| - for (Element element in elements) {
|
| - if (element.name == name) {
|
| - return element;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Return the [UriReferencedElement] from [elements] with the given [uri], or
|
| - * `null` if there is no such element.
|
| - */
|
| - static UriReferencedElement _findUriReferencedElement(
|
| - List<UriReferencedElement> elements, String uri) {
|
| - for (UriReferencedElement element in elements) {
|
| - if (element.uri == uri) {
|
| - return element;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Return the value of [literal], or `null` if the string is not a constant
|
| - * string without any string interpolation.
|
| - */
|
| - static String _getStringValue(StringLiteral literal) {
|
| - if (literal is StringInterpolation) {
|
| - return null;
|
| - }
|
| - return literal.stringValue;
|
| - }
|
| -
|
| - /**
|
| - * Removes the first element identical to the given [element] from [elements].
|
| - */
|
| - static void _removeIdenticalElement(List elements, Object element) {
|
| - int length = elements.length;
|
| - for (int i = 0; i < length; i++) {
|
| - if (identical(elements[i], element)) {
|
| - elements.removeAt(i);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -
|
| - static void _setLocalElements(
|
| - ExecutableElementImpl to, ExecutableElement from) {
|
| - if (from != null) {
|
| - to.functions = from.functions;
|
| - to.labels = from.labels;
|
| - to.localVariables = from.localVariables;
|
| - to.parameters = from.parameters;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Describes how declarations match an existing elements model.
|
| - */
|
| -class DeclarationMatchKind {
|
| - /**
|
| - * Complete match, no API changes.
|
| - */
|
| - static const MATCH = const DeclarationMatchKind('MATCH');
|
| -
|
| - /**
|
| - * Has API changes that we might be able to resolve incrementally.
|
| - */
|
| - static const MISMATCH_OK = const DeclarationMatchKind('MISMATCH_OK');
|
| -
|
| - /**
|
| - * Has API changes that we cannot resolve incrementally.
|
| - */
|
| - static const MISMATCH = const DeclarationMatchKind('MISMATCH');
|
| -
|
| - final String name;
|
| -
|
| - const DeclarationMatchKind(this.name);
|
| -
|
| - @override
|
| - String toString() => name;
|
| -}
|
| -
|
| -/**
|
| - * Instances of the class [IncrementalResolver] resolve the smallest portion of
|
| - * an AST structure that we currently know how to resolve.
|
| - */
|
| -class IncrementalResolver {
|
| - /**
|
| - * The element of the compilation unit being resolved.
|
| - */
|
| - final CompilationUnitElementImpl _definingUnit;
|
| -
|
| - /**
|
| - * The context the compilation unit being resolved in.
|
| - */
|
| - AnalysisContext _context;
|
| -
|
| - /**
|
| - * The object used to access the types from the core library.
|
| - */
|
| - TypeProvider _typeProvider;
|
| -
|
| - /**
|
| - * The element for the library containing the compilation unit being resolved.
|
| - */
|
| - LibraryElementImpl _definingLibrary;
|
| -
|
| - /**
|
| - * The [DartEntry] corresponding to the source being resolved.
|
| - */
|
| - DartEntry oldEntry;
|
| -
|
| - /**
|
| - * The [CacheEntry] corresponding to the source being resolved.
|
| - */
|
| - CacheEntry newSourceEntry;
|
| -
|
| - /**
|
| - * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved.
|
| - */
|
| - CacheEntry newUnitEntry;
|
| -
|
| - /**
|
| - * The source representing the compilation unit being visited.
|
| - */
|
| - Source _source;
|
| -
|
| - /**
|
| - * The source representing the library of the compilation unit being visited.
|
| - */
|
| - Source _librarySource;
|
| -
|
| - /**
|
| - * The offset of the changed contents.
|
| - */
|
| - final int _updateOffset;
|
| -
|
| - /**
|
| - * The end of the changed contents in the old unit.
|
| - */
|
| - final int _updateEndOld;
|
| -
|
| - /**
|
| - * The end of the changed contents in the new unit.
|
| - */
|
| - final int _updateEndNew;
|
| -
|
| - int _updateDelta;
|
| -
|
| - RecordingErrorListener errorListener = new RecordingErrorListener();
|
| - ResolutionContext _resolutionContext;
|
| -
|
| - List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS;
|
| - List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS;
|
| -
|
| - /**
|
| - * Initialize a newly created incremental resolver to resolve a node in the
|
| - * given source in the given library.
|
| - */
|
| - IncrementalResolver(this.oldEntry, this.newSourceEntry, this.newUnitEntry,
|
| - this._definingUnit, this._updateOffset, this._updateEndOld,
|
| - this._updateEndNew) {
|
| - _updateDelta = _updateEndNew - _updateEndOld;
|
| - _definingLibrary = _definingUnit.library;
|
| - _librarySource = _definingLibrary.source;
|
| - _source = _definingUnit.source;
|
| - _context = _definingUnit.context;
|
| - _typeProvider = _context.typeProvider;
|
| - }
|
| -
|
| - /**
|
| - * Resolve [node], reporting any errors or warnings to the given listener.
|
| - *
|
| - * [node] - the root of the AST structure to be resolved.
|
| - *
|
| - * Returns `true` if resolution was successful.
|
| - */
|
| - bool resolve(AstNode node) {
|
| - logger.enter('resolve: $_definingUnit');
|
| - try {
|
| - AstNode rootNode = _findResolutionRoot(node);
|
| - _prepareResolutionContext(rootNode);
|
| - // update elements
|
| - _updateElementNameOffsets();
|
| - _buildElements(rootNode);
|
| - if (!_canBeIncrementallyResolved(rootNode)) {
|
| - return false;
|
| - }
|
| - // resolve
|
| - _resolveReferences(rootNode);
|
| - _computeConstants(rootNode);
|
| - _resolveErrors = errorListener.getErrorsForSource(_source);
|
| - // verify
|
| - _verify(rootNode);
|
| - _context.invalidateLibraryHints(_librarySource);
|
| - // update entry errors
|
| - _updateEntry();
|
| - // notify unit
|
| - _definingUnit.afterIncrementalResolution();
|
| - // OK
|
| - return true;
|
| - } finally {
|
| - logger.exit();
|
| - }
|
| - }
|
| -
|
| - void _buildElements(AstNode node) {
|
| - LoggingTimer timer = logger.startTimer();
|
| - try {
|
| - ElementHolder holder = new ElementHolder();
|
| - ElementBuilder builder = new ElementBuilder(holder);
|
| - if (_resolutionContext.enclosingClassDeclaration != null) {
|
| - builder.visitClassDeclarationIncrementally(
|
| - _resolutionContext.enclosingClassDeclaration);
|
| - }
|
| - node.accept(builder);
|
| - } finally {
|
| - timer.stop('build elements');
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Return `true` if [node] does not have element model changes, or these
|
| - * changes can be incrementally propagated.
|
| - */
|
| - bool _canBeIncrementallyResolved(AstNode node) {
|
| - // If we are replacing the whole declaration, this means that its signature
|
| - // is changed. It might be an API change, or not.
|
| - //
|
| - // If, for example, a required parameter is changed, it is not an API
|
| - // change, but we want to find the existing corresponding Element in the
|
| - // enclosing one, set it for the node and update as needed.
|
| - //
|
| - // If, for example, the name of a method is changed, it is an API change,
|
| - // we need to know the old Element and the new Element. Again, we need to
|
| - // check the whole enclosing Element.
|
| - if (node is Declaration) {
|
| - node = node.parent;
|
| - }
|
| - Element element = _getElement(node);
|
| - DeclarationMatcher matcher = new DeclarationMatcher();
|
| - DeclarationMatchKind matchKind = matcher.matches(node, element);
|
| - if (matchKind == DeclarationMatchKind.MATCH) {
|
| - return true;
|
| - }
|
| - // mismatch that cannot be incrementally fixed
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Return `true` if the given node can be resolved independently of any other
|
| - * nodes.
|
| - *
|
| - * *Note*: This method needs to be kept in sync with
|
| - * [ScopeBuilder.ContextBuilder].
|
| - *
|
| - * [node] - the node being tested.
|
| - */
|
| - bool _canBeResolved(AstNode node) => node is ClassDeclaration ||
|
| - node is ClassTypeAlias ||
|
| - node is CompilationUnit ||
|
| - node is ConstructorDeclaration ||
|
| - node is FunctionDeclaration ||
|
| - node is FunctionTypeAlias ||
|
| - node is MethodDeclaration ||
|
| - node is TopLevelVariableDeclaration;
|
| -
|
| - /**
|
| - * Compute a value for all of the constants in the given [node].
|
| - */
|
| - void _computeConstants(AstNode node) {
|
| - // compute values
|
| - {
|
| - CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
|
| - ConstantValueComputer computer = new ConstantValueComputer(
|
| - _context, _typeProvider, _context.declaredVariables);
|
| - computer.add(unit, _source, _librarySource);
|
| - computer.computeValues();
|
| - }
|
| - // validate
|
| - {
|
| - ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
|
| - ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter,
|
| - _definingLibrary, _typeProvider, _context.declaredVariables);
|
| - node.accept(constantVerifier);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Starting at [node], find the smallest AST node that can be resolved
|
| - * independently of any other nodes. Return the node that was found.
|
| - *
|
| - * [node] - the node at which the search is to begin
|
| - *
|
| - * Throws [AnalysisException] if there is no such node.
|
| - */
|
| - AstNode _findResolutionRoot(AstNode node) {
|
| - while (node != null) {
|
| - if (_canBeResolved(node)) {
|
| - return node;
|
| - }
|
| - node = node.parent;
|
| - }
|
| - throw new AnalysisException("Cannot resolve node: no resolvable node");
|
| - }
|
| -
|
| - /**
|
| - * Return the element defined by [node], or `null` if the node does not
|
| - * define an element.
|
| - */
|
| - Element _getElement(AstNode node) {
|
| - if (node is Declaration) {
|
| - return node.element;
|
| - } else if (node is CompilationUnit) {
|
| - return node.element;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void _prepareResolutionContext(AstNode node) {
|
| - if (_resolutionContext == null) {
|
| - _resolutionContext =
|
| - ResolutionContextBuilder.contextFor(node, errorListener);
|
| - }
|
| - }
|
| -
|
| - _resolveReferences(AstNode node) {
|
| - LoggingTimer timer = logger.startTimer();
|
| - try {
|
| - _prepareResolutionContext(node);
|
| - Scope scope = _resolutionContext.scope;
|
| - // resolve types
|
| - {
|
| - TypeResolverVisitor visitor = new TypeResolverVisitor(
|
| - _definingLibrary, _source, _typeProvider, errorListener,
|
| - nameScope: scope);
|
| - node.accept(visitor);
|
| - }
|
| - // resolve variables
|
| - {
|
| - VariableResolverVisitor visitor = new VariableResolverVisitor(
|
| - _definingLibrary, _source, _typeProvider, errorListener,
|
| - nameScope: scope);
|
| - node.accept(visitor);
|
| - }
|
| - // resolve references
|
| - {
|
| - ResolverVisitor visitor = new ResolverVisitor(
|
| - _definingLibrary, _source, _typeProvider, errorListener,
|
| - nameScope: scope);
|
| - if (_resolutionContext.enclosingClassDeclaration != null) {
|
| - visitor.visitClassDeclarationIncrementally(
|
| - _resolutionContext.enclosingClassDeclaration);
|
| - }
|
| - if (node is Comment) {
|
| - visitor.resolveOnlyCommentInFunctionBody = true;
|
| - node = node.parent;
|
| - }
|
| - visitor.initForIncrementalResolution();
|
| - node.accept(visitor);
|
| - }
|
| - } finally {
|
| - timer.stop('resolve references');
|
| - }
|
| - }
|
| -
|
| - void _shiftEntryErrors() {
|
| - if (oldEntry != null) {
|
| - _shiftEntryErrors_OLD();
|
| - } else {
|
| - _shiftEntryErrors_NEW();
|
| - }
|
| - }
|
| -
|
| - void _shiftEntryErrors_NEW() {
|
| - _shiftErrors_NEW(HINTS);
|
| - _shiftErrors_NEW(RESOLVE_REFERENCES_ERRORS);
|
| - _shiftErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS);
|
| - _shiftErrors_NEW(VARIABLE_REFERENCE_ERRORS);
|
| - _shiftErrors_NEW(VERIFY_ERRORS);
|
| - }
|
| -
|
| - void _shiftEntryErrors_OLD() {
|
| - _shiftErrors_OLD(DartEntry.RESOLUTION_ERRORS);
|
| - _shiftErrors_OLD(DartEntry.VERIFICATION_ERRORS);
|
| - _shiftErrors_OLD(DartEntry.HINTS);
|
| - _shiftErrors_OLD(DartEntry.LINTS);
|
| - }
|
| -
|
| - void _shiftErrors(List<AnalysisError> errors) {
|
| - for (AnalysisError error in errors) {
|
| - int errorOffset = error.offset;
|
| - if (errorOffset > _updateOffset) {
|
| - error.offset += _updateDelta;
|
| - }
|
| - }
|
| - }
|
| -
|
| - void _shiftErrors_NEW(ResultDescriptor<List<AnalysisError>> descriptor) {
|
| - List<AnalysisError> errors = newUnitEntry.getValue(descriptor);
|
| - _shiftErrors(errors);
|
| - }
|
| -
|
| - void _shiftErrors_OLD(DataDescriptor<List<AnalysisError>> descriptor) {
|
| - List<AnalysisError> errors =
|
| - oldEntry.getValueInLibrary(descriptor, _librarySource);
|
| - _shiftErrors(errors);
|
| - }
|
| -
|
| - void _updateElementNameOffsets() {
|
| - LoggingTimer timer = logger.startTimer();
|
| - try {
|
| - _definingUnit
|
| - .accept(new _ElementNameOffsetUpdater(_updateOffset, _updateDelta));
|
| - } finally {
|
| - timer.stop('update element offsets');
|
| - }
|
| - }
|
| -
|
| - void _updateEntry() {
|
| - if (oldEntry != null) {
|
| - _updateEntry_OLD();
|
| - } else {
|
| - _updateEntry_NEW();
|
| - }
|
| - }
|
| -
|
| - void _updateEntry_NEW() {
|
| - _updateErrors_NEW(RESOLVE_REFERENCES_ERRORS, _resolveErrors);
|
| - _updateErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS, []);
|
| - _updateErrors_NEW(VARIABLE_REFERENCE_ERRORS, []);
|
| - _updateErrors_NEW(VERIFY_ERRORS, _verifyErrors);
|
| - // invalidate results we don't update incrementally
|
| - newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID);
|
| - newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID);
|
| - newUnitEntry.setState(HINTS, CacheState.INVALID);
|
| - }
|
| -
|
| - void _updateEntry_OLD() {
|
| - _updateErrors_OLD(DartEntry.RESOLUTION_ERRORS, _resolveErrors);
|
| - _updateErrors_OLD(DartEntry.VERIFICATION_ERRORS, _verifyErrors);
|
| - }
|
| -
|
| - 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;
|
| - }
|
| -
|
| - void _updateErrors_NEW(ResultDescriptor<List<AnalysisError>> descriptor,
|
| - List<AnalysisError> newErrors) {
|
| - List<AnalysisError> oldErrors = newUnitEntry.getValue(descriptor);
|
| - List<AnalysisError> errors = _updateErrors(oldErrors, newErrors);
|
| - newUnitEntry.setValueIncremental(descriptor, errors);
|
| - }
|
| -
|
| - void _updateErrors_OLD(DataDescriptor<List<AnalysisError>> descriptor,
|
| - List<AnalysisError> newErrors) {
|
| - List<AnalysisError> oldErrors =
|
| - oldEntry.getValueInLibrary(descriptor, _librarySource);
|
| - List<AnalysisError> errors = _updateErrors(oldErrors, newErrors);
|
| - oldEntry.setValueInLibrary(descriptor, _librarySource, errors);
|
| - }
|
| -
|
| - void _verify(AstNode node) {
|
| - LoggingTimer timer = logger.startTimer();
|
| - try {
|
| - 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.visitClassDeclarationIncrementally(
|
| - _resolutionContext.enclosingClassDeclaration);
|
| - }
|
| - node.accept(errorVerifier);
|
| - _verifyErrors = errorListener.getErrorsForSource(_source);
|
| - } finally {
|
| - timer.stop('verify');
|
| - }
|
| - }
|
| -}
|
| -
|
| -class PoorMansIncrementalResolver {
|
| - final TypeProvider _typeProvider;
|
| - final Source _unitSource;
|
| -
|
| - /**
|
| - * The [DartEntry] corresponding to the source being resolved.
|
| - */
|
| - DartEntry _oldEntry;
|
| -
|
| - /**
|
| - * The [CacheEntry] corresponding to the source being resolved.
|
| - */
|
| - CacheEntry _newSourceEntry;
|
| -
|
| - /**
|
| - * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved.
|
| - */
|
| - CacheEntry _newUnitEntry;
|
| -
|
| - final CompilationUnit _oldUnit;
|
| - final AnalysisOptions _options;
|
| - CompilationUnitElement _unitElement;
|
| -
|
| - int _updateOffset;
|
| - int _updateDelta;
|
| - int _updateEndOld;
|
| - int _updateEndNew;
|
| -
|
| - List<AnalysisError> _newScanErrors = <AnalysisError>[];
|
| - List<AnalysisError> _newParseErrors = <AnalysisError>[];
|
| -
|
| - PoorMansIncrementalResolver(this._typeProvider, this._unitSource,
|
| - this._oldEntry, this._newSourceEntry, this._newUnitEntry, this._oldUnit,
|
| - bool resolveApiChanges, this._options) {
|
| - _resolveApiChanges = resolveApiChanges;
|
| - }
|
| -
|
| - /**
|
| - * Attempts to update [_oldUnit] to the state corresponding to [newCode].
|
| - * Returns `true` if success, or `false` otherwise.
|
| - * The [_oldUnit] might be damaged.
|
| - */
|
| - bool resolve(String newCode) {
|
| - logger.enter('diff/resolve $_unitSource');
|
| - try {
|
| - // prepare old unit
|
| - if (!_areCurlyBracketsBalanced(_oldUnit.beginToken)) {
|
| - logger.log('Unbalanced number of curly brackets in the old unit.');
|
| - return false;
|
| - }
|
| - _unitElement = _oldUnit.element;
|
| - // prepare new unit
|
| - CompilationUnit newUnit = _parseUnit(newCode);
|
| - if (!_areCurlyBracketsBalanced(newUnit.beginToken)) {
|
| - logger.log('Unbalanced number of curly brackets in the new unit.');
|
| - return false;
|
| - }
|
| - // find difference
|
| - _TokenPair firstPair =
|
| - _findFirstDifferentToken(_oldUnit.beginToken, newUnit.beginToken);
|
| - _TokenPair lastPair =
|
| - _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken);
|
| - if (firstPair != null && lastPair != null) {
|
| - int firstOffsetOld = firstPair.oldToken.offset;
|
| - int firstOffsetNew = firstPair.newToken.offset;
|
| - int lastOffsetOld = lastPair.oldToken.end;
|
| - int lastOffsetNew = lastPair.newToken.end;
|
| - int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld);
|
| - int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld);
|
| - int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew);
|
| - int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew);
|
| - // check for a whitespace only change
|
| - if (identical(lastPair.oldToken, firstPair.oldToken) &&
|
| - identical(lastPair.newToken, firstPair.newToken)) {
|
| - _updateOffset = beginOffsetOld - 1;
|
| - _updateEndOld = endOffsetOld;
|
| - _updateEndNew = endOffsetNew;
|
| - _updateDelta = newUnit.length - _oldUnit.length;
|
| - // A Dart documentation comment change.
|
| - if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) {
|
| - bool success = _resolveCommentDoc(newUnit, firstPair);
|
| - logger.log('Documentation comment resolved: $success');
|
| - return success;
|
| - }
|
| - // A pure whitespace change.
|
| - if (firstPair.kind == _TokenDifferenceKind.OFFSET) {
|
| - logger.log('Whitespace change.');
|
| - _shiftTokens(firstPair.oldToken);
|
| - {
|
| - IncrementalResolver incrementalResolver = new IncrementalResolver(
|
| - _oldEntry, _newSourceEntry, _newUnitEntry, _unitElement,
|
| - _updateOffset, _updateEndOld, _updateEndNew);
|
| - incrementalResolver._updateElementNameOffsets();
|
| - incrementalResolver._shiftEntryErrors();
|
| - }
|
| - _updateEntry();
|
| - logger.log('Success.');
|
| - return true;
|
| - }
|
| - // fall-through, end-of-line comment
|
| - }
|
| - // Find nodes covering the "old" and "new" token ranges.
|
| - AstNode oldNode =
|
| - _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld - 1);
|
| - AstNode newNode =
|
| - _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew - 1);
|
| - logger.log(() => 'oldNode: $oldNode');
|
| - logger.log(() => 'newNode: $newNode');
|
| - // 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 ConstructorInitializer ||
|
| - newParent is ConstructorInitializer) {
|
| - logger.log('Failure: changes in constant constructor initializers'
|
| - ' may cause external changes in constant objects.');
|
| - return false;
|
| - }
|
| - if (oldParent is FunctionDeclaration &&
|
| - newParent is FunctionDeclaration ||
|
| - oldParent is MethodDeclaration &&
|
| - newParent is MethodDeclaration ||
|
| - oldParent is ConstructorDeclaration &&
|
| - newParent is ConstructorDeclaration) {
|
| - Element oldElement = (oldParent as Declaration).element;
|
| - if (new DeclarationMatcher().matches(newParent, oldElement) ==
|
| - DeclarationMatchKind.MATCH) {
|
| - oldNode = oldParent;
|
| - newNode = newParent;
|
| - found = true;
|
| - }
|
| - }
|
| - if (oldParent is FunctionBody && newParent is FunctionBody) {
|
| - oldNode = oldParent;
|
| - newNode = newParent;
|
| - found = true;
|
| - break;
|
| - }
|
| - }
|
| - if (!found) {
|
| - logger.log('Failure: no enclosing function body or executable.');
|
| - return false;
|
| - }
|
| - // fail if a comment change outside the bodies
|
| - if (firstPair.kind == _TokenDifferenceKind.COMMENT) {
|
| - if (beginOffsetOld <= oldNode.offset ||
|
| - beginOffsetNew <= newNode.offset) {
|
| - logger.log('Failure: comment outside a function body.');
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| - logger.log(() => 'oldNode: $oldNode');
|
| - logger.log(() => 'newNode: $newNode');
|
| - // prepare update range
|
| - _updateOffset = oldNode.offset;
|
| - _updateEndOld = oldNode.end;
|
| - _updateEndNew = newNode.end;
|
| - _updateDelta = _updateEndNew - _updateEndOld;
|
| - // replace node
|
| - NodeReplacer.replace(oldNode, newNode);
|
| - // update token references
|
| - {
|
| - Token oldBeginToken = _getBeginTokenNotComment(oldNode);
|
| - Token newBeginToken = _getBeginTokenNotComment(newNode);
|
| - if (oldBeginToken.previous.type == TokenType.EOF) {
|
| - _oldUnit.beginToken = newBeginToken;
|
| - } else {
|
| - oldBeginToken.previous.setNext(newBeginToken);
|
| - }
|
| - newNode.endToken.setNext(oldNode.endToken.next);
|
| - _shiftTokens(oldNode.endToken.next);
|
| - }
|
| - // perform incremental resolution
|
| - IncrementalResolver incrementalResolver = new IncrementalResolver(
|
| - _oldEntry, _newSourceEntry, _newUnitEntry, _unitElement,
|
| - _updateOffset, _updateEndOld, _updateEndNew);
|
| - bool success = incrementalResolver.resolve(newNode);
|
| - // check if success
|
| - if (!success) {
|
| - logger.log('Failure: element model changed.');
|
| - return false;
|
| - }
|
| - // update DartEntry
|
| - _updateEntry();
|
| - logger.log('Success.');
|
| - return true;
|
| - }
|
| - } catch (e, st) {
|
| - logger.log(e);
|
| - logger.log(st);
|
| - logger.log('Failure: exception.');
|
| - } finally {
|
| - logger.exit();
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - CompilationUnit _parseUnit(String code) {
|
| - LoggingTimer timer = logger.startTimer();
|
| - try {
|
| - Token token = _scan(code);
|
| - RecordingErrorListener errorListener = new RecordingErrorListener();
|
| - Parser parser = new Parser(_unitSource, errorListener);
|
| - AnalysisOptions options = _unitElement.context.analysisOptions;
|
| - parser.parseGenericMethods = options.enableGenericMethods;
|
| - CompilationUnit unit = parser.parseCompilationUnit(token);
|
| - _newParseErrors = errorListener.errors;
|
| - return unit;
|
| - } finally {
|
| - timer.stop('parse');
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Attempts to resolve a documentation comment change.
|
| - * Returns `true` if success.
|
| - */
|
| - bool _resolveCommentDoc(CompilationUnit newUnit, _TokenPair firstPair) {
|
| - Token oldToken = firstPair.oldToken;
|
| - Token newToken = firstPair.newToken;
|
| - CommentToken oldComments = oldToken.precedingComments;
|
| - CommentToken newComments = newToken.precedingComments;
|
| - if (oldComments == null || newComments == null) {
|
| - return false;
|
| - }
|
| - // find nodes
|
| - int offset = oldComments.offset;
|
| - logger.log('offset: $offset');
|
| - Comment oldComment = _findNodeCovering(_oldUnit, offset, offset);
|
| - Comment newComment = _findNodeCovering(newUnit, offset, offset);
|
| - logger.log('oldComment.beginToken: ${oldComment.beginToken}');
|
| - logger.log('newComment.beginToken: ${newComment.beginToken}');
|
| - _updateOffset = oldToken.offset - 1;
|
| - // update token references
|
| - _shiftTokens(firstPair.oldToken);
|
| - _setPrecedingComments(oldToken, newComment.tokens.first);
|
| - // replace node
|
| - NodeReplacer.replace(oldComment, newComment);
|
| - // update elements
|
| - IncrementalResolver incrementalResolver = new IncrementalResolver(_oldEntry,
|
| - _newSourceEntry, _newUnitEntry, _unitElement, _updateOffset,
|
| - _updateEndOld, _updateEndNew);
|
| - incrementalResolver._updateElementNameOffsets();
|
| - incrementalResolver._shiftEntryErrors();
|
| - _updateEntry();
|
| - // resolve references in the comment
|
| - incrementalResolver._resolveReferences(newComment);
|
| - // OK
|
| - return true;
|
| - }
|
| -
|
| - 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;
|
| - }
|
| -
|
| - /**
|
| - * Set the given [comment] as a "precedingComments" for [token].
|
| - */
|
| - void _setPrecedingComments(Token token, CommentToken comment) {
|
| - if (token is BeginTokenWithComment) {
|
| - token.precedingComments = comment;
|
| - } else if (token is KeywordTokenWithComment) {
|
| - token.precedingComments = comment;
|
| - } else if (token is StringTokenWithComment) {
|
| - token.precedingComments = comment;
|
| - } else if (token is TokenWithComment) {
|
| - token.precedingComments = comment;
|
| - } else {
|
| - Type parentType = token != null ? token.runtimeType : null;
|
| - throw new AnalysisException('Uknown parent token type: $parentType');
|
| - }
|
| - }
|
| -
|
| - void _shiftTokens(Token token) {
|
| - while (token != null) {
|
| - if (token.offset > _updateOffset) {
|
| - token.offset += _updateDelta;
|
| - }
|
| - // comments
|
| - _shiftTokens(token.precedingComments);
|
| - if (token is DocumentationCommentToken) {
|
| - for (Token reference in token.references) {
|
| - _shiftTokens(reference);
|
| - }
|
| - }
|
| - // next
|
| - if (token.type == TokenType.EOF) {
|
| - break;
|
| - }
|
| - token = token.next;
|
| - }
|
| - }
|
| -
|
| - void _updateEntry() {
|
| - if (_oldEntry != null) {
|
| - _updateEntry_OLD();
|
| - } else {
|
| - _updateEntry_NEW();
|
| - }
|
| - }
|
| -
|
| - void _updateEntry_NEW() {
|
| - _newSourceEntry.setState(DART_ERRORS, CacheState.INVALID);
|
| - // scan results
|
| - _newSourceEntry.setState(SCAN_ERRORS, CacheState.INVALID);
|
| - List<TargetedResult> scanDeps =
|
| - <TargetedResult>[new TargetedResult(_unitSource, CONTENT)];
|
| - _newSourceEntry.setValue(SCAN_ERRORS, _newScanErrors, scanDeps);
|
| - // parse results
|
| - List<TargetedResult> parseDeps =
|
| - <TargetedResult>[new TargetedResult(_unitSource, TOKEN_STREAM)];
|
| - _newSourceEntry.setState(PARSE_ERRORS, CacheState.INVALID);
|
| - _newSourceEntry.setValue(PARSE_ERRORS, _newParseErrors, parseDeps);
|
| - _newSourceEntry.setValue(PARSED_UNIT, _oldUnit, parseDeps);
|
| - }
|
| -
|
| - void _updateEntry_OLD() {
|
| - _oldEntry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors);
|
| - _oldEntry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors);
|
| - }
|
| -
|
| - /**
|
| - * Checks if [token] has a balanced number of open and closed curly brackets.
|
| - */
|
| - static bool _areCurlyBracketsBalanced(Token token) {
|
| - int numOpen = _getTokenCount(token, TokenType.OPEN_CURLY_BRACKET);
|
| - int numOpen2 =
|
| - _getTokenCount(token, TokenType.STRING_INTERPOLATION_EXPRESSION);
|
| - int numClosed = _getTokenCount(token, TokenType.CLOSE_CURLY_BRACKET);
|
| - return numOpen + numOpen2 == numClosed;
|
| - }
|
| -
|
| - static _TokenDifferenceKind _compareToken(
|
| - Token oldToken, Token newToken, int delta, bool forComment) {
|
| - while (true) {
|
| - if (oldToken == null && newToken == null) {
|
| - return null;
|
| - }
|
| - if (oldToken == null || newToken == null) {
|
| - return _TokenDifferenceKind.CONTENT;
|
| - }
|
| - if (oldToken.type != newToken.type) {
|
| - return _TokenDifferenceKind.CONTENT;
|
| - }
|
| - if (oldToken.lexeme != newToken.lexeme) {
|
| - return _TokenDifferenceKind.CONTENT;
|
| - }
|
| - if (newToken.offset - oldToken.offset != delta) {
|
| - return _TokenDifferenceKind.OFFSET;
|
| - }
|
| - // continue if comment tokens are being checked
|
| - if (!forComment) {
|
| - break;
|
| - }
|
| - oldToken = oldToken.next;
|
| - newToken = newToken.next;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
|
| - while (true) {
|
| - if (oldToken.type == TokenType.EOF && newToken.type == TokenType.EOF) {
|
| - return null;
|
| - }
|
| - if (oldToken.type == TokenType.EOF || newToken.type == TokenType.EOF) {
|
| - return new _TokenPair(_TokenDifferenceKind.CONTENT, oldToken, newToken);
|
| - }
|
| - // compare comments
|
| - {
|
| - Token oldComment = oldToken.precedingComments;
|
| - Token newComment = newToken.precedingComments;
|
| - if (_compareToken(oldComment, newComment, 0, true) != null) {
|
| - _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
|
| - if (oldComment is DocumentationCommentToken ||
|
| - newComment is DocumentationCommentToken) {
|
| - diffKind = _TokenDifferenceKind.COMMENT_DOC;
|
| - }
|
| - return new _TokenPair(diffKind, oldToken, newToken);
|
| - }
|
| - }
|
| - // compare tokens
|
| - _TokenDifferenceKind diffKind =
|
| - _compareToken(oldToken, newToken, 0, false);
|
| - if (diffKind != null) {
|
| - return new _TokenPair(diffKind, oldToken, newToken);
|
| - }
|
| - // next tokens
|
| - oldToken = oldToken.next;
|
| - newToken = newToken.next;
|
| - }
|
| - // no difference
|
| - return null;
|
| - }
|
| -
|
| - static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
|
| - int delta = newToken.offset - oldToken.offset;
|
| - while (oldToken.previous != oldToken && newToken.previous != newToken) {
|
| - // compare tokens
|
| - _TokenDifferenceKind diffKind =
|
| - _compareToken(oldToken, newToken, delta, false);
|
| - if (diffKind != null) {
|
| - return new _TokenPair(diffKind, oldToken.next, newToken.next);
|
| - }
|
| - // compare comments
|
| - {
|
| - Token oldComment = oldToken.precedingComments;
|
| - Token newComment = newToken.precedingComments;
|
| - if (_compareToken(oldComment, newComment, delta, true) != null) {
|
| - _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
|
| - if (oldComment is DocumentationCommentToken ||
|
| - newComment is DocumentationCommentToken) {
|
| - diffKind = _TokenDifferenceKind.COMMENT_DOC;
|
| - }
|
| - return new _TokenPair(diffKind, oldToken, newToken);
|
| - }
|
| - }
|
| - // next tokens
|
| - oldToken = oldToken.previous;
|
| - newToken = newToken.previous;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - static AstNode _findNodeCovering(AstNode root, int offset, int end) {
|
| - NodeLocator nodeLocator = new NodeLocator(offset, end);
|
| - return nodeLocator.searchWithin(root);
|
| - }
|
| -
|
| - static Token _getBeginTokenNotComment(AstNode node) {
|
| - Token oldBeginToken = node.beginToken;
|
| - if (oldBeginToken is CommentToken) {
|
| - oldBeginToken = (oldBeginToken as CommentToken).parent;
|
| - }
|
| - return oldBeginToken;
|
| - }
|
| -
|
| - static List<AstNode> _getParents(AstNode node) {
|
| - List<AstNode> parents = <AstNode>[];
|
| - while (node != null) {
|
| - parents.insert(0, node);
|
| - node = node.parent;
|
| - }
|
| - return parents;
|
| - }
|
| -
|
| - /**
|
| - * Returns number of tokens with the given [type].
|
| - */
|
| - static int _getTokenCount(Token token, TokenType type) {
|
| - int count = 0;
|
| - while (token.type != TokenType.EOF) {
|
| - if (token.type == type) {
|
| - count++;
|
| - }
|
| - token = token.next;
|
| - }
|
| - return count;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * The context to resolve an [AstNode] in.
|
| - */
|
| -class ResolutionContext {
|
| - CompilationUnitElement enclosingUnit;
|
| - ClassDeclaration enclosingClassDeclaration;
|
| - ClassElement enclosingClass;
|
| - Scope scope;
|
| -}
|
| -
|
| -/**
|
| - * Instances of the class [ResolutionContextBuilder] build the context for a
|
| - * given node in an AST structure. At the moment, this class only handles
|
| - * top-level and class-level declarations.
|
| - */
|
| -class ResolutionContextBuilder {
|
| - /**
|
| - * The listener to which analysis errors will be reported.
|
| - */
|
| - final AnalysisErrorListener _errorListener;
|
| -
|
| - /**
|
| - * The class containing the enclosing [CompilationUnitElement].
|
| - */
|
| - CompilationUnitElement _enclosingUnit;
|
| -
|
| - /**
|
| - * 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;
|
| -
|
| - /**
|
| - * Initialize a newly created scope builder to generate a scope that will
|
| - * report errors to the given listener.
|
| - */
|
| - ResolutionContextBuilder(this._errorListener);
|
| -
|
| - Scope _scopeFor(AstNode node) {
|
| - if (node is CompilationUnit) {
|
| - return _scopeForAstNode(node);
|
| - }
|
| - AstNode parent = node.parent;
|
| - if (parent == null) {
|
| - throw new AnalysisException(
|
| - "Cannot create scope: node is not part of a CompilationUnit");
|
| - }
|
| - return _scopeForAstNode(parent);
|
| - }
|
| -
|
| - /**
|
| - * Return the scope in which the given AST structure should be resolved.
|
| - *
|
| - * *Note:* This method needs to be kept in sync with
|
| - * [IncrementalResolver.canBeResolved].
|
| - *
|
| - * [node] - the root of the AST structure to be resolved.
|
| - *
|
| - * Throws [AnalysisException] if the AST structure has not been resolved or
|
| - * is not part of a [CompilationUnit]
|
| - */
|
| - Scope _scopeForAstNode(AstNode node) {
|
| - if (node is CompilationUnit) {
|
| - return _scopeForCompilationUnit(node);
|
| - }
|
| - AstNode parent = node.parent;
|
| - if (parent == null) {
|
| - throw new AnalysisException(
|
| - "Cannot create scope: node is not part of a CompilationUnit");
|
| - }
|
| - Scope scope = _scopeForAstNode(parent);
|
| - if (node is ClassDeclaration) {
|
| - _enclosingClassDeclaration = node;
|
| - _enclosingClass = node.element;
|
| - if (_enclosingClass == null) {
|
| - throw new AnalysisException(
|
| - "Cannot build a scope for an unresolved class");
|
| - }
|
| - scope = new ClassScope(
|
| - new TypeParameterScope(scope, _enclosingClass), _enclosingClass);
|
| - } else if (node is ClassTypeAlias) {
|
| - ClassElement element = node.element;
|
| - if (element == null) {
|
| - throw new AnalysisException(
|
| - "Cannot build a scope for an unresolved class type alias");
|
| - }
|
| - scope = new ClassScope(new TypeParameterScope(scope, element), element);
|
| - } else if (node is ConstructorDeclaration) {
|
| - ConstructorElement element = node.element;
|
| - if (element == null) {
|
| - throw new AnalysisException(
|
| - "Cannot build a scope for an unresolved constructor");
|
| - }
|
| - FunctionScope functionScope = new FunctionScope(scope, element);
|
| - functionScope.defineParameters();
|
| - scope = functionScope;
|
| - } else if (node is FunctionDeclaration) {
|
| - ExecutableElement element = node.element;
|
| - if (element == null) {
|
| - throw new AnalysisException(
|
| - "Cannot build a scope for an unresolved function");
|
| - }
|
| - FunctionScope functionScope = new FunctionScope(scope, element);
|
| - functionScope.defineParameters();
|
| - scope = functionScope;
|
| - } else if (node is FunctionTypeAlias) {
|
| - scope = new FunctionTypeScope(scope, node.element);
|
| - } else if (node is MethodDeclaration) {
|
| - ExecutableElement element = node.element;
|
| - if (element == null) {
|
| - throw new AnalysisException(
|
| - "Cannot build a scope for an unresolved method");
|
| - }
|
| - FunctionScope functionScope = new FunctionScope(scope, element);
|
| - functionScope.defineParameters();
|
| - scope = functionScope;
|
| - }
|
| - return scope;
|
| - }
|
| -
|
| - Scope _scopeForCompilationUnit(CompilationUnit node) {
|
| - _enclosingUnit = node.element;
|
| - if (_enclosingUnit == null) {
|
| - throw new AnalysisException(
|
| - "Cannot create scope: compilation unit is not resolved");
|
| - }
|
| - LibraryElement libraryElement = _enclosingUnit.library;
|
| - if (libraryElement == null) {
|
| - throw new AnalysisException(
|
| - "Cannot create scope: compilation unit is not part of a library");
|
| - }
|
| - return new LibraryScope(libraryElement, _errorListener);
|
| - }
|
| -
|
| - /**
|
| - * Return the context in which the given AST structure should be resolved.
|
| - *
|
| - * [node] - the root of the AST structure to be resolved.
|
| - * [errorListener] - the listener to which analysis errors will be reported.
|
| - *
|
| - * Throws [AnalysisException] if the AST structure has not been resolved or
|
| - * is not part of a [CompilationUnit]
|
| - */
|
| - static ResolutionContext contextFor(
|
| - AstNode node, AnalysisErrorListener errorListener) {
|
| - if (node == null) {
|
| - throw new AnalysisException("Cannot create context: node is null");
|
| - }
|
| - // build scope
|
| - ResolutionContextBuilder builder =
|
| - new ResolutionContextBuilder(errorListener);
|
| - Scope scope = builder._scopeFor(node);
|
| - // prepare context
|
| - ResolutionContext context = new ResolutionContext();
|
| - context.scope = scope;
|
| - context.enclosingUnit = builder._enclosingUnit;
|
| - context.enclosingClassDeclaration = builder._enclosingClassDeclaration;
|
| - context.enclosingClass = builder._enclosingClass;
|
| - return context;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Instances of the class [_DeclarationMismatchException] represent an exception
|
| - * that is thrown when the element model defined by a given AST structure does
|
| - * not match an existing element model.
|
| - */
|
| -class _DeclarationMismatchException {}
|
| -
|
| -class _ElementNameOffsetUpdater extends GeneralizingElementVisitor {
|
| - final int updateOffset;
|
| - final int updateDelta;
|
| -
|
| - _ElementNameOffsetUpdater(this.updateOffset, this.updateDelta);
|
| -
|
| - @override
|
| - visitElement(Element element) {
|
| - int nameOffset = element.nameOffset;
|
| - if (nameOffset > updateOffset) {
|
| - (element as ElementImpl).nameOffset = nameOffset + updateDelta;
|
| - }
|
| - super.visitElement(element);
|
| - }
|
| -}
|
| -
|
| -class _ElementsGatherer extends GeneralizingElementVisitor {
|
| - final DeclarationMatcher matcher;
|
| -
|
| - _ElementsGatherer(this.matcher);
|
| -
|
| - void addElements(List<Element> elements) {
|
| - for (Element element in elements) {
|
| - if (!element.isSynthetic) {
|
| - _addElement(element);
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - visitElement(Element element) {
|
| - _addElement(element);
|
| - super.visitElement(element);
|
| - }
|
| -
|
| - @override
|
| - visitExecutableElement(ExecutableElement element) {
|
| - _addElement(element);
|
| - }
|
| -
|
| - @override
|
| - visitParameterElement(ParameterElement element) {}
|
| -
|
| - @override
|
| - visitPropertyAccessorElement(PropertyAccessorElement element) {
|
| - if (!element.isSynthetic) {
|
| - _addElement(element);
|
| - }
|
| - // Don't visit children (such as synthetic setter parameters).
|
| - }
|
| -
|
| - @override
|
| - visitPropertyInducingElement(PropertyInducingElement element) {
|
| - if (!element.isSynthetic) {
|
| - _addElement(element);
|
| - }
|
| - // Don't visit children (such as property accessors).
|
| - }
|
| -
|
| - @override
|
| - visitTypeParameterElement(TypeParameterElement element) {}
|
| -
|
| - void _addElement(Element element) {
|
| - if (element != null) {
|
| - matcher._allElements.add(element);
|
| - matcher._removedElements.add(element);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Describes how two [Token]s are different.
|
| - */
|
| -class _TokenDifferenceKind {
|
| - static const COMMENT = const _TokenDifferenceKind('COMMENT');
|
| - static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC');
|
| - static const CONTENT = const _TokenDifferenceKind('CONTENT');
|
| - static const OFFSET = const _TokenDifferenceKind('OFFSET');
|
| -
|
| - final String name;
|
| -
|
| - const _TokenDifferenceKind(this.name);
|
| -
|
| - @override
|
| - String toString() => name;
|
| -}
|
| -
|
| -class _TokenPair {
|
| - final _TokenDifferenceKind kind;
|
| - final Token oldToken;
|
| - final Token newToken;
|
| - _TokenPair(this.kind, this.oldToken, this.newToken);
|
| -}
|
|
|