| 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 37d3801802d4117ec8622ce8aa97b24cf5432cdf..cca604ad642f46dd8e2a5591b244b38223038cb7 100644
|
| --- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
|
| @@ -9,9 +9,7 @@ import 'dart:math' as math;
|
|
|
| import 'package:analyzer/dart/ast/ast.dart';
|
| import 'package:analyzer/dart/ast/token.dart';
|
| -import 'package:analyzer/dart/ast/visitor.dart';
|
| import 'package:analyzer/dart/element/element.dart';
|
| -import 'package:analyzer/dart/element/type.dart';
|
| import 'package:analyzer/dart/element/visitor.dart';
|
| import 'package:analyzer/src/context/cache.dart';
|
| import 'package:analyzer/src/dart/ast/token.dart';
|
| @@ -50,812 +48,6 @@ void set test_resolveApiChanges(bool 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 library 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 enum containing the AST nodes being visited, or `null` if we are not
|
| - * in the scope of an enum.
|
| - */
|
| - EnumElementImpl _enclosingEnum;
|
| -
|
| - /**
|
| - * 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 {
|
| - logger.log("mismatched");
|
| - return DeclarationMatchKind.MISMATCH;
|
| - } finally {
|
| - logger.exit();
|
| - }
|
| - // no API changes
|
| - if (_removedElements.isEmpty && _addedElements.isEmpty) {
|
| - logger.log("no API changes");
|
| - 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);
|
| - }
|
| - }
|
| - // matches, set the element
|
| - node.name.staticElement = element;
|
| - }
|
| -
|
| - @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(_enclosingEnum.fields, name);
|
| - _processElement(element);
|
| - }
|
| -
|
| - @override
|
| - visitEnumDeclaration(EnumDeclaration node) {
|
| - String name = node.name.name;
|
| - ClassElement element = _findElement(_enclosingUnit.enums, name);
|
| - _enclosingEnum = 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.toList();
|
| - methods.add(newElement);
|
| - _enclosingClass.methods = methods;
|
| - } else {
|
| - List<PropertyAccessorElement> accessors =
|
| - _enclosingClass.accessors.toList();
|
| - 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;
|
| - Element variable = element;
|
| - if (variable is VariableElementImpl) {
|
| - variable.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 ||
|
| - element.enclosingElement is ConstructorElement) {
|
| - _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);
|
| - DartType parameterType = element.type;
|
| - if (node.type == null && node.parameters == null) {
|
| - FieldFormalParameterElement parameterElement = element;
|
| - if (!parameterElement.hasImplicitType) {
|
| - _assertTrue(parameterType == null || parameterType.isDynamic);
|
| - }
|
| - if (parameterElement.field != null) {
|
| - _assertEquals(node.identifier.name, element.name);
|
| - }
|
| - } else {
|
| - if (node.parameters != null) {
|
| - _assertTrue(parameterType is FunctionType);
|
| - FunctionType parameterFunctionType = parameterType;
|
| - _assertSameType(node.type, parameterFunctionType.returnType);
|
| - } else {
|
| - _assertSameType(node.type, parameterType);
|
| - }
|
| - }
|
| - _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> nodeAnnotations = node.metadata;
|
| - List<ElementAnnotation> elementAnnotations = element.metadata;
|
| - int length = nodeAnnotations.length;
|
| - _assertEquals(elementAnnotations.length, length);
|
| - for (int i = 0; i < length; i++) {
|
| - _assertSameAnnotation(nodeAnnotations[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;
|
| -}
|
| -
|
| -/**
|
| * The [Delta] implementation used by incremental resolver.
|
| * It keeps Dart results that are either don't change or are updated.
|
| */
|
| @@ -1062,30 +254,27 @@ class IncrementalResolver {
|
| _updateDelta = updateEndNew - updateEndOld;
|
|
|
| /**
|
| - * Resolve [node], reporting any errors or warnings to the given listener.
|
| + * Resolve [body], reporting any errors or warnings to the given listener.
|
| *
|
| - * [node] - the root of the AST structure to be resolved.
|
| + * [body] - the root of the AST structure to be resolved.
|
| *
|
| * Returns `true` if resolution was successful.
|
| */
|
| - bool resolve(AstNode node) {
|
| + bool resolve(BlockFunctionBody body) {
|
| logger.enter('resolve: $_definingUnit');
|
| try {
|
| - AstNode rootNode = _findResolutionRoot(node);
|
| - _prepareResolutionContext(rootNode);
|
| + Declaration executable = _findResolutionRoot(body);
|
| + _prepareResolutionContext(executable);
|
| // update elements
|
| _updateCache();
|
| _updateElementNameOffsets();
|
| - _buildElements(rootNode);
|
| - if (!_canBeIncrementallyResolved(rootNode)) {
|
| - return false;
|
| - }
|
| + _buildElements(executable, body);
|
| // resolve
|
| - _resolveReferences(rootNode);
|
| - _computeConstants(rootNode);
|
| + _resolveReferences(executable);
|
| + _computeConstants(executable);
|
| _resolveErrors = errorListener.getErrorsForSource(_source);
|
| // verify
|
| - _verify(rootNode);
|
| + _verify(executable);
|
| _context.invalidateLibraryHints(_librarySource);
|
| // update entry errors
|
| _updateEntry();
|
| @@ -1096,69 +285,26 @@ class IncrementalResolver {
|
| }
|
| }
|
|
|
| - void _buildElements(AstNode node) {
|
| + void _buildElements(Declaration executable, AstNode node) {
|
| LoggingTimer timer = logger.startTimer();
|
| try {
|
| ElementHolder holder = new ElementHolder();
|
| ElementBuilder builder = new ElementBuilder(holder, _definingUnit);
|
| - if (_resolutionContext.enclosingClassDeclaration != null) {
|
| - builder.visitClassDeclarationIncrementally(
|
| - _resolutionContext.enclosingClassDeclaration);
|
| - }
|
| + builder.initForFunctionBodyIncrementalResolution();
|
| node.accept(builder);
|
| + // Move local elements into the ExecutableElementImpl.
|
| + ExecutableElementImpl executableElement =
|
| + executable.element as ExecutableElementImpl;
|
| + executableElement.localVariables = holder.localVariables;
|
| + executableElement.functions = holder.functions;
|
| + executableElement.labels = holder.labels;
|
| + holder.validate();
|
| } 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) {
|
| @@ -1187,9 +333,11 @@ class IncrementalResolver {
|
| *
|
| * Throws [AnalysisException] if there is no such node.
|
| */
|
| - AstNode _findResolutionRoot(AstNode node) {
|
| + Declaration _findResolutionRoot(AstNode node) {
|
| while (node != null) {
|
| - if (_canBeResolved(node)) {
|
| + if (node is ConstructorDeclaration ||
|
| + node is FunctionDeclaration ||
|
| + node is MethodDeclaration) {
|
| return node;
|
| }
|
| node = node.parent;
|
| @@ -1197,19 +345,6 @@ class IncrementalResolver {
|
| 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 =
|
| @@ -1532,13 +667,7 @@ class PoorMansIncrementalResolver {
|
| newParent is ConstructorDeclaration ||
|
| oldParent is MethodDeclaration &&
|
| newParent is MethodDeclaration) {
|
| - Element oldElement = (oldParent as Declaration).element;
|
| - if (new DeclarationMatcher().matches(newParent, oldElement) ==
|
| - DeclarationMatchKind.MATCH) {
|
| - oldNode = oldParent;
|
| - newNode = newParent;
|
| - found = true;
|
| - } else {
|
| + if (oldParents.length == i || newParents.length == i) {
|
| return false;
|
| }
|
| } else if (oldParent is FunctionBody && newParent is FunctionBody) {
|
| @@ -2072,13 +1201,6 @@ class ResolutionContextBuilder {
|
| }
|
|
|
| /**
|
| - * 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 {}
|
| -
|
| -/**
|
| * Adjusts the location of each Element that moved.
|
| *
|
| * Since `==` and `hashCode` of a local variable or function Element are based
|
| @@ -2173,60 +1295,6 @@ class _ElementOffsetUpdater extends GeneralizingElementVisitor {
|
| }
|
| }
|
|
|
| -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.
|
| */
|
|
|