| Index: pkg/analyzer/lib/src/dart/element/builder.dart
|
| diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
|
| index 3534a2aed4bd99f023e0d9ebeded4d3af1869668..df8f470bd3b63fc4e5ab07658bc6d494080ed499 100644
|
| --- a/pkg/analyzer/lib/src/dart/element/builder.dart
|
| +++ b/pkg/analyzer/lib/src/dart/element/builder.dart
|
| @@ -9,12 +9,54 @@ import 'dart:collection';
|
| import 'package:analyzer/dart/ast/ast.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/src/dart/element/element.dart';
|
| +import 'package:analyzer/src/dart/element/type.dart';
|
| import 'package:analyzer/src/generated/engine.dart';
|
| import 'package:analyzer/src/generated/error.dart';
|
| +import 'package:analyzer/src/generated/java_engine.dart';
|
| +import 'package:analyzer/src/generated/resolver.dart';
|
| import 'package:analyzer/src/generated/scanner.dart';
|
| import 'package:analyzer/src/generated/sdk.dart';
|
| import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/generated/utilities_dart.dart';
|
| +
|
| +/**
|
| + * A `CompilationUnitBuilder` builds an element model for a single compilation
|
| + * unit.
|
| + */
|
| +class CompilationUnitBuilder {
|
| + /**
|
| + * Build the compilation unit element for the given [source] based on the
|
| + * compilation [unit] associated with the source. Throw an AnalysisException
|
| + * if the element could not be built. [librarySource] is the source for the
|
| + * containing library.
|
| + */
|
| + CompilationUnitElementImpl buildCompilationUnit(
|
| + Source source, CompilationUnit unit, Source librarySource) {
|
| + return PerformanceStatistics.resolve.makeCurrentWhile(() {
|
| + if (unit == null) {
|
| + return null;
|
| + }
|
| + ElementHolder holder = new ElementHolder();
|
| + ElementBuilder builder = new ElementBuilder(holder);
|
| + unit.accept(builder);
|
| + CompilationUnitElementImpl element =
|
| + new CompilationUnitElementImpl(source.shortName);
|
| + element.accessors = holder.accessors;
|
| + element.enums = holder.enums;
|
| + element.functions = holder.functions;
|
| + element.source = source;
|
| + element.librarySource = librarySource;
|
| + element.typeAliases = holder.typeAliases;
|
| + element.types = holder.types;
|
| + element.topLevelVariables = holder.topLevelVariables;
|
| + unit.element = element;
|
| + holder.validate();
|
| + return element;
|
| + });
|
| + }
|
| +}
|
|
|
| /**
|
| * Instances of the class `DirectiveElementBuilder` build elements for top
|
| @@ -230,6 +272,1048 @@ class DirectiveElementBuilder extends SimpleAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * Instances of the class `ElementBuilder` traverse an AST structure and build the element
|
| + * model representing the AST structure.
|
| + */
|
| +class ElementBuilder extends RecursiveAstVisitor<Object> {
|
| + /**
|
| + * The element holder associated with the element that is currently being built.
|
| + */
|
| + ElementHolder _currentHolder;
|
| +
|
| + /**
|
| + * A flag indicating whether a variable declaration is in the context of a field declaration.
|
| + */
|
| + bool _inFieldContext = false;
|
| +
|
| + /**
|
| + * A flag indicating whether a variable declaration is within the body of a method or function.
|
| + */
|
| + bool _inFunction = false;
|
| +
|
| + /**
|
| + * A collection holding the elements defined in a class that need to have
|
| + * their function type fixed to take into account type parameters of the
|
| + * enclosing class, or `null` if we are not currently processing nodes within
|
| + * a class.
|
| + */
|
| + List<ExecutableElementImpl> _functionTypesToFix = null;
|
| +
|
| + /**
|
| + * A table mapping field names to field elements for the fields defined in the current class, or
|
| + * `null` if we are not in the scope of a class.
|
| + */
|
| + HashMap<String, FieldElement> _fieldMap;
|
| +
|
| + /**
|
| + * Initialize a newly created element builder to build the elements for a compilation unit.
|
| + *
|
| + * @param initialHolder the element holder associated with the compilation unit being built
|
| + */
|
| + ElementBuilder(ElementHolder initialHolder) {
|
| + _currentHolder = initialHolder;
|
| + }
|
| +
|
| + @override
|
| + Object visitBlock(Block node) {
|
| + bool wasInField = _inFieldContext;
|
| + _inFieldContext = false;
|
| + try {
|
| + node.visitChildren(this);
|
| + } finally {
|
| + _inFieldContext = wasInField;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCatchClause(CatchClause node) {
|
| + SimpleIdentifier exceptionParameter = node.exceptionParameter;
|
| + if (exceptionParameter != null) {
|
| + // exception
|
| + LocalVariableElementImpl exception =
|
| + new LocalVariableElementImpl.forNode(exceptionParameter);
|
| + if (node.exceptionType == null) {
|
| + exception.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addLocalVariable(exception);
|
| + exceptionParameter.staticElement = exception;
|
| + // stack trace
|
| + SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
|
| + if (stackTraceParameter != null) {
|
| + LocalVariableElementImpl stackTrace =
|
| + new LocalVariableElementImpl.forNode(stackTraceParameter);
|
| + _currentHolder.addLocalVariable(stackTrace);
|
| + stackTraceParameter.staticElement = stackTrace;
|
| + }
|
| + }
|
| + return super.visitCatchClause(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitClassDeclaration(ClassDeclaration node) {
|
| + ElementHolder holder = new ElementHolder();
|
| + _functionTypesToFix = new List<ExecutableElementImpl>();
|
| + //
|
| + // Process field declarations before constructors and methods so that field
|
| + // formal parameters can be correctly resolved to their fields.
|
| + //
|
| + ElementHolder previousHolder = _currentHolder;
|
| + _currentHolder = holder;
|
| + try {
|
| + List<ClassMember> nonFields = new List<ClassMember>();
|
| + node.visitChildren(
|
| + new _ElementBuilder_visitClassDeclaration(this, nonFields));
|
| + _buildFieldMap(holder.fieldsWithoutFlushing);
|
| + int count = nonFields.length;
|
| + for (int i = 0; i < count; i++) {
|
| + nonFields[i].accept(this);
|
| + }
|
| + } finally {
|
| + _currentHolder = previousHolder;
|
| + }
|
| + SimpleIdentifier className = node.name;
|
| + ClassElementImpl element = new ClassElementImpl.forNode(className);
|
| + List<TypeParameterElement> typeParameters = holder.typeParameters;
|
| + List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
|
| + InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
|
| + interfaceType.typeArguments = typeArguments;
|
| + element.type = interfaceType;
|
| + element.typeParameters = typeParameters;
|
| + _setDoc(element, node);
|
| + element.abstract = node.isAbstract;
|
| + element.accessors = holder.accessors;
|
| + List<ConstructorElement> constructors = holder.constructors;
|
| + if (constructors.isEmpty) {
|
| + constructors = _createDefaultConstructors(element);
|
| + }
|
| + element.constructors = constructors;
|
| + element.fields = holder.fields;
|
| + element.methods = holder.methods;
|
| + // Function types must be initialized after the enclosing element has been
|
| + // set, for them to pick up the type parameters.
|
| + for (ExecutableElementImpl e in _functionTypesToFix) {
|
| + e.type = new FunctionTypeImpl(e);
|
| + }
|
| + _functionTypesToFix = null;
|
| + _currentHolder.addType(element);
|
| + className.staticElement = element;
|
| + _fieldMap = null;
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Implementation of this method should be synchronized with
|
| + * [visitClassDeclaration].
|
| + */
|
| + void visitClassDeclarationIncrementally(ClassDeclaration node) {
|
| + //
|
| + // Process field declarations before constructors and methods so that field
|
| + // formal parameters can be correctly resolved to their fields.
|
| + //
|
| + ClassElement classElement = node.element;
|
| + _buildFieldMap(classElement.fields);
|
| + }
|
| +
|
| + @override
|
| + Object visitClassTypeAlias(ClassTypeAlias node) {
|
| + ElementHolder holder = new ElementHolder();
|
| + _visitChildren(holder, node);
|
| + SimpleIdentifier className = node.name;
|
| + ClassElementImpl element = new ClassElementImpl.forNode(className);
|
| + element.abstract = node.abstractKeyword != null;
|
| + element.mixinApplication = true;
|
| + List<TypeParameterElement> typeParameters = holder.typeParameters;
|
| + element.typeParameters = typeParameters;
|
| + List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
|
| + InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
|
| + interfaceType.typeArguments = typeArguments;
|
| + element.type = interfaceType;
|
| + _setDoc(element, node);
|
| + _currentHolder.addType(element);
|
| + className.staticElement = element;
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + ElementHolder holder = new ElementHolder();
|
| + bool wasInFunction = _inFunction;
|
| + _inFunction = true;
|
| + try {
|
| + _visitChildren(holder, node);
|
| + } finally {
|
| + _inFunction = wasInFunction;
|
| + }
|
| + FunctionBody body = node.body;
|
| + SimpleIdentifier constructorName = node.name;
|
| + ConstructorElementImpl element =
|
| + new ConstructorElementImpl.forNode(constructorName);
|
| + _setDoc(element, node);
|
| + if (node.externalKeyword != null) {
|
| + element.external = true;
|
| + }
|
| + if (node.factoryKeyword != null) {
|
| + element.factory = true;
|
| + }
|
| + element.functions = holder.functions;
|
| + element.labels = holder.labels;
|
| + element.localVariables = holder.localVariables;
|
| + element.parameters = holder.parameters;
|
| + element.const2 = node.constKeyword != null;
|
| + if (body.isAsynchronous) {
|
| + element.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + element.generator = true;
|
| + }
|
| + _currentHolder.addConstructor(element);
|
| + node.element = element;
|
| + if (constructorName == null) {
|
| + Identifier returnType = node.returnType;
|
| + if (returnType != null) {
|
| + element.nameOffset = returnType.offset;
|
| + element.nameEnd = returnType.end;
|
| + }
|
| + } else {
|
| + constructorName.staticElement = element;
|
| + element.periodOffset = node.period.offset;
|
| + element.nameEnd = constructorName.end;
|
| + }
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitDeclaredIdentifier(DeclaredIdentifier node) {
|
| + SimpleIdentifier variableName = node.identifier;
|
| + LocalVariableElementImpl element =
|
| + new LocalVariableElementImpl.forNode(variableName);
|
| + ForEachStatement statement = node.parent as ForEachStatement;
|
| + int declarationEnd = node.offset + node.length;
|
| + int statementEnd = statement.offset + statement.length;
|
| + element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1);
|
| + element.const3 = node.isConst;
|
| + element.final2 = node.isFinal;
|
| + if (node.type == null) {
|
| + element.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addLocalVariable(element);
|
| + variableName.staticElement = element;
|
| + return super.visitDeclaredIdentifier(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitDefaultFormalParameter(DefaultFormalParameter node) {
|
| + ElementHolder holder = new ElementHolder();
|
| + NormalFormalParameter normalParameter = node.parameter;
|
| + SimpleIdentifier parameterName = normalParameter.identifier;
|
| + ParameterElementImpl parameter;
|
| + if (normalParameter is FieldFormalParameter) {
|
| + parameter = new DefaultFieldFormalParameterElementImpl(parameterName);
|
| + FieldElement field =
|
| + _fieldMap == null ? null : _fieldMap[parameterName.name];
|
| + if (field != null) {
|
| + (parameter as DefaultFieldFormalParameterElementImpl).field = field;
|
| + }
|
| + } else {
|
| + parameter = new DefaultParameterElementImpl(parameterName);
|
| + }
|
| + parameter.const3 = node.isConst;
|
| + parameter.final2 = node.isFinal;
|
| + parameter.parameterKind = node.kind;
|
| + // set initializer, default value range
|
| + Expression defaultValue = node.defaultValue;
|
| + if (defaultValue != null) {
|
| + _visit(holder, defaultValue);
|
| + FunctionElementImpl initializer =
|
| + new FunctionElementImpl.forOffset(defaultValue.beginToken.offset);
|
| + initializer.functions = holder.functions;
|
| + initializer.labels = holder.labels;
|
| + initializer.localVariables = holder.localVariables;
|
| + initializer.parameters = holder.parameters;
|
| + initializer.synthetic = true;
|
| + parameter.initializer = initializer;
|
| + parameter.defaultValueCode = defaultValue.toSource();
|
| + }
|
| + // visible range
|
| + _setParameterVisibleRange(node, parameter);
|
| + if (normalParameter is SimpleFormalParameter &&
|
| + normalParameter.type == null) {
|
| + parameter.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addParameter(parameter);
|
| + parameterName.staticElement = parameter;
|
| + normalParameter.accept(this);
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitEnumDeclaration(EnumDeclaration node) {
|
| + SimpleIdentifier enumName = node.name;
|
| + ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
|
| + enumElement.enum2 = true;
|
| + _setDoc(enumElement, node);
|
| + InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
|
| + enumElement.type = enumType;
|
| + // The equivalent code for enums in the spec shows a single constructor,
|
| + // but that constructor is not callable (since it is a compile-time error
|
| + // to subclass, mix-in, implement, or explicitly instantiate an enum). So
|
| + // we represent this as having no constructors.
|
| + enumElement.constructors = ConstructorElement.EMPTY_LIST;
|
| + _currentHolder.addEnum(enumElement);
|
| + enumName.staticElement = enumElement;
|
| + return super.visitEnumDeclaration(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitFieldDeclaration(FieldDeclaration node) {
|
| + bool wasInField = _inFieldContext;
|
| + _inFieldContext = true;
|
| + try {
|
| + node.visitChildren(this);
|
| + } finally {
|
| + _inFieldContext = wasInField;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFieldFormalParameter(FieldFormalParameter node) {
|
| + if (node.parent is! DefaultFormalParameter) {
|
| + SimpleIdentifier parameterName = node.identifier;
|
| + FieldElement field =
|
| + _fieldMap == null ? null : _fieldMap[parameterName.name];
|
| + FieldFormalParameterElementImpl parameter =
|
| + new FieldFormalParameterElementImpl(parameterName);
|
| + parameter.const3 = node.isConst;
|
| + parameter.final2 = node.isFinal;
|
| + parameter.parameterKind = node.kind;
|
| + if (field != null) {
|
| + parameter.field = field;
|
| + }
|
| + _currentHolder.addParameter(parameter);
|
| + parameterName.staticElement = parameter;
|
| + }
|
| + //
|
| + // The children of this parameter include any parameters defined on the type
|
| + // of this parameter.
|
| + //
|
| + ElementHolder holder = new ElementHolder();
|
| + _visitChildren(holder, node);
|
| + ParameterElementImpl element = node.element;
|
| + element.parameters = holder.parameters;
|
| + element.typeParameters = holder.typeParameters;
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionDeclaration(FunctionDeclaration node) {
|
| + FunctionExpression expression = node.functionExpression;
|
| + if (expression != null) {
|
| + ElementHolder holder = new ElementHolder();
|
| + bool wasInFunction = _inFunction;
|
| + _inFunction = true;
|
| + try {
|
| + _visitChildren(holder, node);
|
| + } finally {
|
| + _inFunction = wasInFunction;
|
| + }
|
| + FunctionBody body = expression.body;
|
| + Token property = node.propertyKeyword;
|
| + if (property == null || _inFunction) {
|
| + SimpleIdentifier functionName = node.name;
|
| + FunctionElementImpl element =
|
| + new FunctionElementImpl.forNode(functionName);
|
| + _setDoc(element, node);
|
| + if (node.externalKeyword != null) {
|
| + element.external = true;
|
| + }
|
| + element.functions = holder.functions;
|
| + element.labels = holder.labels;
|
| + element.localVariables = holder.localVariables;
|
| + element.parameters = holder.parameters;
|
| + element.typeParameters = holder.typeParameters;
|
| + if (body.isAsynchronous) {
|
| + element.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + element.generator = true;
|
| + }
|
| + if (_inFunction) {
|
| + Block enclosingBlock = node.getAncestor((node) => node is Block);
|
| + if (enclosingBlock != null) {
|
| + int functionEnd = node.offset + node.length;
|
| + int blockEnd = enclosingBlock.offset + enclosingBlock.length;
|
| + element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
|
| + }
|
| + }
|
| + if (node.returnType == null) {
|
| + element.hasImplicitReturnType = true;
|
| + }
|
| + _currentHolder.addFunction(element);
|
| + expression.element = element;
|
| + functionName.staticElement = element;
|
| + } else {
|
| + SimpleIdentifier propertyNameNode = node.name;
|
| + if (propertyNameNode == null) {
|
| + // TODO(brianwilkerson) Report this internal error.
|
| + return null;
|
| + }
|
| + String propertyName = propertyNameNode.name;
|
| + TopLevelVariableElementImpl variable = _currentHolder
|
| + .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl;
|
| + if (variable == null) {
|
| + variable = new TopLevelVariableElementImpl(node.name.name, -1);
|
| + variable.final2 = true;
|
| + variable.synthetic = true;
|
| + _currentHolder.addTopLevelVariable(variable);
|
| + }
|
| + if (node.isGetter) {
|
| + PropertyAccessorElementImpl getter =
|
| + new PropertyAccessorElementImpl.forNode(propertyNameNode);
|
| + _setDoc(getter, node);
|
| + if (node.externalKeyword != null) {
|
| + getter.external = true;
|
| + }
|
| + getter.functions = holder.functions;
|
| + getter.labels = holder.labels;
|
| + getter.localVariables = holder.localVariables;
|
| + if (body.isAsynchronous) {
|
| + getter.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + getter.generator = true;
|
| + }
|
| + getter.variable = variable;
|
| + getter.getter = true;
|
| + getter.static = true;
|
| + variable.getter = getter;
|
| + if (node.returnType == null) {
|
| + getter.hasImplicitReturnType = true;
|
| + }
|
| + _currentHolder.addAccessor(getter);
|
| + expression.element = getter;
|
| + propertyNameNode.staticElement = getter;
|
| + } else {
|
| + PropertyAccessorElementImpl setter =
|
| + new PropertyAccessorElementImpl.forNode(propertyNameNode);
|
| + _setDoc(setter, node);
|
| + if (node.externalKeyword != null) {
|
| + setter.external = true;
|
| + }
|
| + setter.functions = holder.functions;
|
| + setter.labels = holder.labels;
|
| + setter.localVariables = holder.localVariables;
|
| + setter.parameters = holder.parameters;
|
| + if (body.isAsynchronous) {
|
| + setter.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + setter.generator = true;
|
| + }
|
| + setter.variable = variable;
|
| + setter.setter = true;
|
| + setter.static = true;
|
| + if (node.returnType == null) {
|
| + setter.hasImplicitReturnType = true;
|
| + }
|
| + variable.setter = setter;
|
| + variable.final2 = false;
|
| + _currentHolder.addAccessor(setter);
|
| + expression.element = setter;
|
| + propertyNameNode.staticElement = setter;
|
| + }
|
| + }
|
| + holder.validate();
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionExpression(FunctionExpression node) {
|
| + if (node.parent is FunctionDeclaration) {
|
| + // visitFunctionDeclaration has already created the element for the
|
| + // declaration. We just need to visit children.
|
| + return super.visitFunctionExpression(node);
|
| + }
|
| + ElementHolder holder = new ElementHolder();
|
| + bool wasInFunction = _inFunction;
|
| + _inFunction = true;
|
| + try {
|
| + _visitChildren(holder, node);
|
| + } finally {
|
| + _inFunction = wasInFunction;
|
| + }
|
| + FunctionBody body = node.body;
|
| + FunctionElementImpl element =
|
| + new FunctionElementImpl.forOffset(node.beginToken.offset);
|
| + element.functions = holder.functions;
|
| + element.labels = holder.labels;
|
| + element.localVariables = holder.localVariables;
|
| + element.parameters = holder.parameters;
|
| + element.typeParameters = holder.typeParameters;
|
| + if (body.isAsynchronous) {
|
| + element.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + element.generator = true;
|
| + }
|
| + if (_inFunction) {
|
| + Block enclosingBlock = node.getAncestor((node) => node is Block);
|
| + if (enclosingBlock != null) {
|
| + int functionEnd = node.offset + node.length;
|
| + int blockEnd = enclosingBlock.offset + enclosingBlock.length;
|
| + element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
|
| + }
|
| + }
|
| + if (_functionTypesToFix != null) {
|
| + _functionTypesToFix.add(element);
|
| + } else {
|
| + element.type = new FunctionTypeImpl(element);
|
| + }
|
| + element.hasImplicitReturnType = true;
|
| + _currentHolder.addFunction(element);
|
| + node.element = element;
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + ElementHolder holder = new ElementHolder();
|
| + _visitChildren(holder, node);
|
| + SimpleIdentifier aliasName = node.name;
|
| + List<ParameterElement> parameters = holder.parameters;
|
| + List<TypeParameterElement> typeParameters = holder.typeParameters;
|
| + FunctionTypeAliasElementImpl element =
|
| + new FunctionTypeAliasElementImpl.forNode(aliasName);
|
| + _setDoc(element, node);
|
| + element.parameters = parameters;
|
| + element.typeParameters = typeParameters;
|
| + _createTypeParameterTypes(typeParameters);
|
| + element.type = new FunctionTypeImpl.forTypedef(element);
|
| + _currentHolder.addTypeAlias(element);
|
| + aliasName.staticElement = element;
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
|
| + if (node.parent is! DefaultFormalParameter) {
|
| + SimpleIdentifier parameterName = node.identifier;
|
| + ParameterElementImpl parameter =
|
| + new ParameterElementImpl.forNode(parameterName);
|
| + parameter.parameterKind = node.kind;
|
| + _setParameterVisibleRange(node, parameter);
|
| + _currentHolder.addParameter(parameter);
|
| + parameterName.staticElement = parameter;
|
| + }
|
| + //
|
| + // The children of this parameter include any parameters defined on the type
|
| + //of this parameter.
|
| + //
|
| + ElementHolder holder = new ElementHolder();
|
| + _visitChildren(holder, node);
|
| + ParameterElementImpl element = node.element;
|
| + element.parameters = holder.parameters;
|
| + element.typeParameters = holder.typeParameters;
|
| + holder.validate();
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitLabeledStatement(LabeledStatement node) {
|
| + bool onSwitchStatement = node.statement is SwitchStatement;
|
| + for (Label label in node.labels) {
|
| + SimpleIdentifier labelName = label.label;
|
| + LabelElementImpl element =
|
| + new LabelElementImpl(labelName, onSwitchStatement, false);
|
| + _currentHolder.addLabel(element);
|
| + labelName.staticElement = element;
|
| + }
|
| + return super.visitLabeledStatement(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitMethodDeclaration(MethodDeclaration node) {
|
| + try {
|
| + ElementHolder holder = new ElementHolder();
|
| + bool wasInFunction = _inFunction;
|
| + _inFunction = true;
|
| + try {
|
| + _visitChildren(holder, node);
|
| + } finally {
|
| + _inFunction = wasInFunction;
|
| + }
|
| + bool isStatic = node.isStatic;
|
| + Token property = node.propertyKeyword;
|
| + FunctionBody body = node.body;
|
| + if (property == null) {
|
| + SimpleIdentifier methodName = node.name;
|
| + String nameOfMethod = methodName.name;
|
| + if (nameOfMethod == TokenType.MINUS.lexeme &&
|
| + node.parameters.parameters.length == 0) {
|
| + nameOfMethod = "unary-";
|
| + }
|
| + MethodElementImpl element =
|
| + new MethodElementImpl(nameOfMethod, methodName.offset);
|
| + _setDoc(element, node);
|
| + element.abstract = node.isAbstract;
|
| + if (node.externalKeyword != null) {
|
| + element.external = true;
|
| + }
|
| + element.functions = holder.functions;
|
| + element.labels = holder.labels;
|
| + element.localVariables = holder.localVariables;
|
| + element.parameters = holder.parameters;
|
| + element.static = isStatic;
|
| + element.typeParameters = holder.typeParameters;
|
| + if (body.isAsynchronous) {
|
| + element.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + element.generator = true;
|
| + }
|
| + if (node.returnType == null) {
|
| + element.hasImplicitReturnType = true;
|
| + }
|
| + _currentHolder.addMethod(element);
|
| + methodName.staticElement = element;
|
| + } else {
|
| + SimpleIdentifier propertyNameNode = node.name;
|
| + String propertyName = propertyNameNode.name;
|
| + FieldElementImpl field =
|
| + _currentHolder.getField(propertyName) as FieldElementImpl;
|
| + if (field == null) {
|
| + field = new FieldElementImpl(node.name.name, -1);
|
| + field.final2 = true;
|
| + field.static = isStatic;
|
| + field.synthetic = true;
|
| + _currentHolder.addField(field);
|
| + }
|
| + if (node.isGetter) {
|
| + PropertyAccessorElementImpl getter =
|
| + new PropertyAccessorElementImpl.forNode(propertyNameNode);
|
| + _setDoc(getter, node);
|
| + if (node.externalKeyword != null) {
|
| + getter.external = true;
|
| + }
|
| + getter.functions = holder.functions;
|
| + getter.labels = holder.labels;
|
| + getter.localVariables = holder.localVariables;
|
| + if (body.isAsynchronous) {
|
| + getter.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + getter.generator = true;
|
| + }
|
| + getter.variable = field;
|
| + getter.abstract = node.isAbstract;
|
| + getter.getter = true;
|
| + getter.static = isStatic;
|
| + field.getter = getter;
|
| + if (node.returnType == null) {
|
| + getter.hasImplicitReturnType = true;
|
| + }
|
| + _currentHolder.addAccessor(getter);
|
| + propertyNameNode.staticElement = getter;
|
| + } else {
|
| + PropertyAccessorElementImpl setter =
|
| + new PropertyAccessorElementImpl.forNode(propertyNameNode);
|
| + _setDoc(setter, node);
|
| + if (node.externalKeyword != null) {
|
| + setter.external = true;
|
| + }
|
| + setter.functions = holder.functions;
|
| + setter.labels = holder.labels;
|
| + setter.localVariables = holder.localVariables;
|
| + setter.parameters = holder.parameters;
|
| + if (body.isAsynchronous) {
|
| + setter.asynchronous = true;
|
| + }
|
| + if (body.isGenerator) {
|
| + setter.generator = true;
|
| + }
|
| + setter.variable = field;
|
| + setter.abstract = node.isAbstract;
|
| + setter.setter = true;
|
| + setter.static = isStatic;
|
| + if (node.returnType == null) {
|
| + setter.hasImplicitReturnType = true;
|
| + }
|
| + field.setter = setter;
|
| + field.final2 = false;
|
| + _currentHolder.addAccessor(setter);
|
| + propertyNameNode.staticElement = setter;
|
| + }
|
| + }
|
| + holder.validate();
|
| + } catch (exception, stackTrace) {
|
| + if (node.name.staticElement == null) {
|
| + ClassDeclaration classNode =
|
| + node.getAncestor((node) => node is ClassDeclaration);
|
| + StringBuffer buffer = new StringBuffer();
|
| + buffer.write("The element for the method ");
|
| + buffer.write(node.name);
|
| + buffer.write(" in ");
|
| + buffer.write(classNode.name);
|
| + buffer.write(" was not set while trying to build the element model.");
|
| + AnalysisEngine.instance.logger.logError(
|
| + buffer.toString(), new CaughtException(exception, stackTrace));
|
| + } else {
|
| + String message =
|
| + "Exception caught in ElementBuilder.visitMethodDeclaration()";
|
| + AnalysisEngine.instance.logger
|
| + .logError(message, new CaughtException(exception, stackTrace));
|
| + }
|
| + } finally {
|
| + if (node.name.staticElement == null) {
|
| + ClassDeclaration classNode =
|
| + node.getAncestor((node) => node is ClassDeclaration);
|
| + StringBuffer buffer = new StringBuffer();
|
| + buffer.write("The element for the method ");
|
| + buffer.write(node.name);
|
| + buffer.write(" in ");
|
| + buffer.write(classNode.name);
|
| + buffer.write(" was not set while trying to resolve types.");
|
| + AnalysisEngine.instance.logger.logError(
|
| + buffer.toString(),
|
| + new CaughtException(
|
| + new AnalysisException(buffer.toString()), null));
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + if (node.parent is! DefaultFormalParameter) {
|
| + SimpleIdentifier parameterName = node.identifier;
|
| + ParameterElementImpl parameter =
|
| + new ParameterElementImpl.forNode(parameterName);
|
| + parameter.const3 = node.isConst;
|
| + parameter.final2 = node.isFinal;
|
| + parameter.parameterKind = node.kind;
|
| + _setParameterVisibleRange(node, parameter);
|
| + if (node.type == null) {
|
| + parameter.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addParameter(parameter);
|
| + parameterName.staticElement = parameter;
|
| + }
|
| + return super.visitSimpleFormalParameter(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchCase(SwitchCase node) {
|
| + for (Label label in node.labels) {
|
| + SimpleIdentifier labelName = label.label;
|
| + LabelElementImpl element = new LabelElementImpl(labelName, false, true);
|
| + _currentHolder.addLabel(element);
|
| + labelName.staticElement = element;
|
| + }
|
| + return super.visitSwitchCase(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchDefault(SwitchDefault node) {
|
| + for (Label label in node.labels) {
|
| + SimpleIdentifier labelName = label.label;
|
| + LabelElementImpl element = new LabelElementImpl(labelName, false, true);
|
| + _currentHolder.addLabel(element);
|
| + labelName.staticElement = element;
|
| + }
|
| + return super.visitSwitchDefault(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeParameter(TypeParameter node) {
|
| + SimpleIdentifier parameterName = node.name;
|
| + TypeParameterElementImpl typeParameter =
|
| + new TypeParameterElementImpl.forNode(parameterName);
|
| + TypeParameterTypeImpl typeParameterType =
|
| + new TypeParameterTypeImpl(typeParameter);
|
| + typeParameter.type = typeParameterType;
|
| + _currentHolder.addTypeParameter(typeParameter);
|
| + parameterName.staticElement = typeParameter;
|
| + return super.visitTypeParameter(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclaration(VariableDeclaration node) {
|
| + bool isConst = node.isConst;
|
| + bool isFinal = node.isFinal;
|
| + bool hasInitializer = node.initializer != null;
|
| + VariableElementImpl element;
|
| + if (_inFieldContext) {
|
| + SimpleIdentifier fieldName = node.name;
|
| + FieldElementImpl field;
|
| + if ((isConst || isFinal) && hasInitializer) {
|
| + field = new ConstFieldElementImpl.forNode(fieldName);
|
| + } else {
|
| + field = new FieldElementImpl.forNode(fieldName);
|
| + }
|
| + element = field;
|
| + if (node.parent.parent is FieldDeclaration) {
|
| + _setDoc(element, node.parent.parent);
|
| + }
|
| + if ((node.parent as VariableDeclarationList).type == null) {
|
| + field.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addField(field);
|
| + fieldName.staticElement = field;
|
| + } else if (_inFunction) {
|
| + SimpleIdentifier variableName = node.name;
|
| + LocalVariableElementImpl variable;
|
| + if (isConst && hasInitializer) {
|
| + variable = new ConstLocalVariableElementImpl.forNode(variableName);
|
| + } else {
|
| + variable = new LocalVariableElementImpl.forNode(variableName);
|
| + }
|
| + element = variable;
|
| + Block enclosingBlock = node.getAncestor((node) => node is Block);
|
| + // TODO(brianwilkerson) This isn't right for variables declared in a for
|
| + // loop.
|
| + variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
|
| + if ((node.parent as VariableDeclarationList).type == null) {
|
| + variable.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addLocalVariable(variable);
|
| + variableName.staticElement = element;
|
| + } else {
|
| + SimpleIdentifier variableName = node.name;
|
| + TopLevelVariableElementImpl variable;
|
| + if (isConst && hasInitializer) {
|
| + variable = new ConstTopLevelVariableElementImpl.forNode(variableName);
|
| + } else {
|
| + variable = new TopLevelVariableElementImpl.forNode(variableName);
|
| + }
|
| + element = variable;
|
| + if (node.parent.parent is TopLevelVariableDeclaration) {
|
| + _setDoc(element, node.parent.parent);
|
| + }
|
| + if ((node.parent as VariableDeclarationList).type == null) {
|
| + variable.hasImplicitType = true;
|
| + }
|
| + _currentHolder.addTopLevelVariable(variable);
|
| + variableName.staticElement = element;
|
| + }
|
| + element.const3 = isConst;
|
| + element.final2 = isFinal;
|
| + if (hasInitializer) {
|
| + ElementHolder holder = new ElementHolder();
|
| + bool wasInFieldContext = _inFieldContext;
|
| + _inFieldContext = false;
|
| + try {
|
| + _visit(holder, node.initializer);
|
| + } finally {
|
| + _inFieldContext = wasInFieldContext;
|
| + }
|
| + FunctionElementImpl initializer =
|
| + new FunctionElementImpl.forOffset(node.initializer.beginToken.offset);
|
| + initializer.functions = holder.functions;
|
| + initializer.labels = holder.labels;
|
| + initializer.localVariables = holder.localVariables;
|
| + initializer.synthetic = true;
|
| + element.initializer = initializer;
|
| + holder.validate();
|
| + }
|
| + if (element is PropertyInducingElementImpl) {
|
| + if (_inFieldContext) {
|
| + (element as FieldElementImpl).static =
|
| + (node.parent.parent as FieldDeclaration).isStatic;
|
| + }
|
| + PropertyAccessorElementImpl getter =
|
| + new PropertyAccessorElementImpl.forVariable(element);
|
| + getter.getter = true;
|
| + if (element.hasImplicitType) {
|
| + getter.hasImplicitReturnType = true;
|
| + }
|
| + _currentHolder.addAccessor(getter);
|
| + element.getter = getter;
|
| + if (!isConst && !isFinal) {
|
| + PropertyAccessorElementImpl setter =
|
| + new PropertyAccessorElementImpl.forVariable(element);
|
| + setter.setter = true;
|
| + ParameterElementImpl parameter =
|
| + new ParameterElementImpl("_${element.name}", element.nameOffset);
|
| + parameter.synthetic = true;
|
| + parameter.parameterKind = ParameterKind.REQUIRED;
|
| + setter.parameters = <ParameterElement>[parameter];
|
| + _currentHolder.addAccessor(setter);
|
| + element.setter = setter;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Build the table mapping field names to field elements for the fields defined in the current
|
| + * class.
|
| + *
|
| + * @param fields the field elements defined in the current class
|
| + */
|
| + void _buildFieldMap(List<FieldElement> fields) {
|
| + _fieldMap = new HashMap<String, FieldElement>();
|
| + int count = fields.length;
|
| + for (int i = 0; i < count; i++) {
|
| + FieldElement field = fields[i];
|
| + _fieldMap[field.name] = field;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Creates the [ConstructorElement]s array with the single default constructor element.
|
| + *
|
| + * @param interfaceType the interface type for which to create a default constructor
|
| + * @return the [ConstructorElement]s array with the single default constructor element
|
| + */
|
| + List<ConstructorElement> _createDefaultConstructors(
|
| + ClassElementImpl definingClass) {
|
| + ConstructorElementImpl constructor =
|
| + new ConstructorElementImpl.forNode(null);
|
| + constructor.synthetic = true;
|
| + constructor.returnType = definingClass.type;
|
| + constructor.enclosingElement = definingClass;
|
| + constructor.type = new FunctionTypeImpl(constructor);
|
| + return <ConstructorElement>[constructor];
|
| + }
|
| +
|
| + /**
|
| + * Create the types associated with the given type parameters, setting the type of each type
|
| + * parameter, and return an array of types corresponding to the given parameters.
|
| + *
|
| + * @param typeParameters the type parameters for which types are to be created
|
| + * @return an array of types corresponding to the given parameters
|
| + */
|
| + List<DartType> _createTypeParameterTypes(
|
| + List<TypeParameterElement> typeParameters) {
|
| + int typeParameterCount = typeParameters.length;
|
| + List<DartType> typeArguments = new List<DartType>(typeParameterCount);
|
| + for (int i = 0; i < typeParameterCount; i++) {
|
| + TypeParameterElementImpl typeParameter =
|
| + typeParameters[i] as TypeParameterElementImpl;
|
| + TypeParameterTypeImpl typeParameterType =
|
| + new TypeParameterTypeImpl(typeParameter);
|
| + typeParameter.type = typeParameterType;
|
| + typeArguments[i] = typeParameterType;
|
| + }
|
| + return typeArguments;
|
| + }
|
| +
|
| + /**
|
| + * Return the body of the function that contains the given parameter, or `null` if no
|
| + * function body could be found.
|
| + *
|
| + * @param node the parameter contained in the function whose body is to be returned
|
| + * @return the body of the function that contains the given parameter
|
| + */
|
| + FunctionBody _getFunctionBody(FormalParameter node) {
|
| + AstNode parent = node.parent;
|
| + while (parent != null) {
|
| + if (parent is ConstructorDeclaration) {
|
| + return parent.body;
|
| + } else if (parent is FunctionExpression) {
|
| + return parent.body;
|
| + } else if (parent is MethodDeclaration) {
|
| + return parent.body;
|
| + }
|
| + parent = parent.parent;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * If the given [node] has a documentation comment, remember its content
|
| + * and range into the given [element].
|
| + */
|
| + void _setDoc(ElementImpl element, AnnotatedNode node) {
|
| + Comment comment = node.documentationComment;
|
| + if (comment != null && comment.isDocumentation) {
|
| + element.documentationComment =
|
| + comment.tokens.map((Token t) => t.lexeme).join('\n');
|
| + element.setDocRange(comment.offset, comment.length);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Sets the visible source range for formal parameter.
|
| + */
|
| + void _setParameterVisibleRange(
|
| + FormalParameter node, ParameterElementImpl element) {
|
| + FunctionBody body = _getFunctionBody(node);
|
| + if (body != null) {
|
| + element.setVisibleRange(body.offset, body.length);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Make the given holder be the current holder while visiting the given node.
|
| + *
|
| + * @param holder the holder that will gather elements that are built while visiting the children
|
| + * @param node the node to be visited
|
| + */
|
| + void _visit(ElementHolder holder, AstNode node) {
|
| + if (node != null) {
|
| + ElementHolder previousHolder = _currentHolder;
|
| + _currentHolder = holder;
|
| + try {
|
| + node.accept(this);
|
| + } finally {
|
| + _currentHolder = previousHolder;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Make the given holder be the current holder while visiting the children of the given node.
|
| + *
|
| + * @param holder the holder that will gather elements that are built while visiting the children
|
| + * @param node the node whose children are to be visited
|
| + */
|
| + void _visitChildren(ElementHolder holder, AstNode node) {
|
| + if (node != null) {
|
| + ElementHolder previousHolder = _currentHolder;
|
| + _currentHolder = holder;
|
| + try {
|
| + node.visitChildren(this);
|
| + } finally {
|
| + _currentHolder = previousHolder;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> {
|
| + final ElementBuilder builder;
|
| +
|
| + List<ClassMember> nonFields;
|
| +
|
| + _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super();
|
| +
|
| + @override
|
| + Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + nonFields.add(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitMethodDeclaration(MethodDeclaration node) {
|
| + nonFields.add(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitNode(AstNode node) => node.accept(builder);
|
| +}
|
| +
|
| +/**
|
| * Instances of the class [_NamespaceCombinatorBuilder] can be used to visit
|
| * [Combinator] AST nodes and generate [NamespaceCombinator] elements.
|
| */
|
|
|