| Index: pkg/analyzer/lib/src/generated/resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
|
| index 6d39b3b2ca74c894261b2269e019d3bbe5d9c590..239522b70d60a296032bbb8643df73d4246c8e3c 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -1386,7 +1386,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> {
|
| @override
|
| Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
| if (node.constKeyword != null) {
|
| - _validateInitializers(node);
|
| + _validateConstructorInitializers(node);
|
| + _validateFieldInitializers(node.parent as ClassDeclaration, node);
|
| }
|
| _validateDefaultValues(node.parameters);
|
| return super.visitConstructorDeclaration(node);
|
| @@ -1651,6 +1652,31 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * Validates that the expressions of the given initializers (of a constant constructor) are all
|
| + * compile time constants.
|
| + *
|
| + * @param constructor the constant constructor declaration to validate
|
| + */
|
| + void _validateConstructorInitializers(ConstructorDeclaration constructor) {
|
| + List<ParameterElement> parameterElements = constructor.parameters.parameterElements;
|
| + NodeList<ConstructorInitializer> initializers = constructor.initializers;
|
| + for (ConstructorInitializer initializer in initializers) {
|
| + if (initializer is ConstructorFieldInitializer) {
|
| + ConstructorFieldInitializer fieldInitializer = initializer;
|
| + _validateInitializerExpression(parameterElements, fieldInitializer.expression);
|
| + }
|
| + if (initializer is RedirectingConstructorInvocation) {
|
| + RedirectingConstructorInvocation invocation = initializer;
|
| + _validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
|
| + }
|
| + if (initializer is SuperConstructorInvocation) {
|
| + SuperConstructorInvocation invocation = initializer;
|
| + _validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Validate that the default value associated with each of the parameters in the given list is a
|
| * compile time constant.
|
| *
|
| @@ -1677,6 +1703,34 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * Validates that the expressions of any field initializers in the class declaration are all
|
| + * compile time constants. Since this is only required if the class has a constant constructor,
|
| + * the error is reported at the constructor site.
|
| + *
|
| + * @param classDeclaration the class which should be validated
|
| + * @param errorSite the site at which errors should be reported.
|
| + */
|
| + void _validateFieldInitializers(ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) {
|
| + NodeList<ClassMember> members = classDeclaration.members;
|
| + for (ClassMember member in members) {
|
| + if (member is FieldDeclaration) {
|
| + FieldDeclaration fieldDeclaration = member;
|
| + if (!fieldDeclaration.isStatic) {
|
| + for (VariableDeclaration variableDeclaration in fieldDeclaration.fields.variables) {
|
| + Expression initializer = variableDeclaration.initializer;
|
| + if (initializer != null) {
|
| + EvaluationResultImpl result = initializer.accept(new ConstantVisitor.con1(_typeProvider));
|
| + if (result is! ValidResult) {
|
| + _errorReporter.reportErrorForNode(CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST, errorSite, [variableDeclaration.name.name]);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Validates that the given expression is a compile time constant.
|
| *
|
| * @param parameterElements the elements of parameters of constant constructor, they are
|
| @@ -1708,31 +1762,6 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| - * Validates that the expressions of the given initializers (of a constant constructor) are all
|
| - * compile time constants.
|
| - *
|
| - * @param constructor the constant constructor declaration to validate
|
| - */
|
| - void _validateInitializers(ConstructorDeclaration constructor) {
|
| - List<ParameterElement> parameterElements = constructor.parameters.parameterElements;
|
| - NodeList<ConstructorInitializer> initializers = constructor.initializers;
|
| - for (ConstructorInitializer initializer in initializers) {
|
| - if (initializer is ConstructorFieldInitializer) {
|
| - ConstructorFieldInitializer fieldInitializer = initializer;
|
| - _validateInitializerExpression(parameterElements, fieldInitializer.expression);
|
| - }
|
| - if (initializer is RedirectingConstructorInvocation) {
|
| - RedirectingConstructorInvocation invocation = initializer;
|
| - _validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
|
| - }
|
| - if (initializer is SuperConstructorInvocation) {
|
| - SuperConstructorInvocation invocation = initializer;
|
| - _validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| * Validate that if the passed instance creation is 'const' then all its arguments are constant
|
| * expressions.
|
| *
|
| @@ -3859,7 +3888,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> {
|
| }
|
| }
|
| holder.validate();
|
| - } on JavaException catch (ex) {
|
| + } catch (ex) {
|
| if (node.name.staticElement == null) {
|
| ClassDeclaration classNode = node.getAncestor((node) => node is ClassDeclaration);
|
| JavaStringBuilder builder = new JavaStringBuilder();
|
| @@ -15286,7 +15315,7 @@ class LibraryImportScope extends Scope {
|
| * @param errorListener the listener that is to be informed when an error is encountered
|
| */
|
| LibraryImportScope(this._definingLibrary, this.errorListener) {
|
| - _createImportedNamespaces(_definingLibrary);
|
| + _createImportedNamespaces();
|
| }
|
|
|
| @override
|
| @@ -15302,7 +15331,8 @@ class LibraryImportScope extends Scope {
|
| if (foundElement != null) {
|
| return foundElement;
|
| }
|
| - for (Namespace nameSpace in _importedNamespaces) {
|
| + for (int i = 0; i < _importedNamespaces.length; i++) {
|
| + Namespace nameSpace = _importedNamespaces[i];
|
| Element element = nameSpace.get(name);
|
| if (element != null) {
|
| if (foundElement == null) {
|
| @@ -15321,7 +15351,7 @@ class LibraryImportScope extends Scope {
|
| int count = conflictingMembers.length;
|
| List<String> libraryNames = new List<String>(count);
|
| for (int i = 0; i < count; i++) {
|
| - libraryNames[i] = _getLibraryName(conflictingMembers[i], "");
|
| + libraryNames[i] = _getLibraryName(conflictingMembers[i]);
|
| }
|
| libraryNames.sort();
|
| errorListener.onError(new AnalysisError.con2(getSource(identifier), identifier.offset, identifier.length, StaticWarningCode.AMBIGUOUS_IMPORT, [
|
| @@ -15342,9 +15372,9 @@ class LibraryImportScope extends Scope {
|
| * @param definingLibrary the element representing the library that imports the libraries for
|
| * which namespaces will be created
|
| */
|
| - void _createImportedNamespaces(LibraryElement definingLibrary) {
|
| + void _createImportedNamespaces() {
|
| NamespaceBuilder builder = new NamespaceBuilder();
|
| - List<ImportElement> imports = definingLibrary.imports;
|
| + List<ImportElement> imports = _definingLibrary.imports;
|
| int count = imports.length;
|
| _importedNamespaces = new List<Namespace>(count);
|
| for (int i = 0; i < count; i++) {
|
| @@ -15356,18 +15386,47 @@ class LibraryImportScope extends Scope {
|
| * Returns the name of the library that defines given element.
|
| *
|
| * @param element the element to get library name
|
| - * @param def the default name to use
|
| * @return the name of the library that defines given element
|
| */
|
| - String _getLibraryName(Element element, String def) {
|
| + String _getLibraryName(Element element) {
|
| if (element == null) {
|
| - return def;
|
| + return StringUtilities.EMPTY;
|
| }
|
| LibraryElement library = element.library;
|
| if (library == null) {
|
| - return def;
|
| + return StringUtilities.EMPTY;
|
| + }
|
| + List<ImportElement> imports = _definingLibrary.imports;
|
| + int count = imports.length;
|
| + for (int i = 0; i < count; i++) {
|
| + if (identical(imports[i].importedLibrary, library)) {
|
| + return library.definingCompilationUnit.displayName;
|
| + }
|
| + }
|
| + List<String> indirectSources = new List<String>();
|
| + for (int i = 0; i < count; i++) {
|
| + LibraryElement importedLibrary = imports[i].importedLibrary;
|
| + for (LibraryElement exportedLibrary in importedLibrary.exportedLibraries) {
|
| + if (identical(exportedLibrary, library)) {
|
| + indirectSources.add(importedLibrary.definingCompilationUnit.displayName);
|
| + }
|
| + }
|
| + }
|
| + int indirectCount = indirectSources.length;
|
| + JavaStringBuilder builder = new JavaStringBuilder();
|
| + builder.append(library.definingCompilationUnit.displayName);
|
| + if (indirectCount > 0) {
|
| + builder.append(" (via ");
|
| + if (indirectCount > 1) {
|
| + List<String> indirectNames = new List.from(indirectSources);
|
| + indirectNames.sort();
|
| + builder.append(StringUtilities.printListOfQuotedNames(indirectNames));
|
| + } else {
|
| + builder.append(indirectSources[0]);
|
| + }
|
| + builder.append(")");
|
| }
|
| - return library.definingCompilationUnit.displayName;
|
| + return builder.toString();
|
| }
|
|
|
| /**
|
| @@ -15393,8 +15452,8 @@ class LibraryImportScope extends Scope {
|
| }
|
| }
|
| if (sdkElement != null && to > 0) {
|
| - String sdkLibName = _getLibraryName(sdkElement, "");
|
| - String otherLibName = _getLibraryName(conflictingMembers[0], "");
|
| + String sdkLibName = _getLibraryName(sdkElement);
|
| + String otherLibName = _getLibraryName(conflictingMembers[0]);
|
| errorListener.onError(new AnalysisError.con2(getSource(identifier), identifier.offset, identifier.length, StaticWarningCode.CONFLICTING_DART_IMPORT, [name, sdkLibName, otherLibName]));
|
| }
|
| if (to == length) {
|
| @@ -22976,8 +23035,22 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
| super.visitConstructorDeclaration(node);
|
| ExecutableElementImpl element = node.element as ExecutableElementImpl;
|
| - if (element != null) {
|
| - // TODO(brianwilkerson) Figure out how the element could ever be null.
|
| + if (element == null) {
|
| + ClassDeclaration classNode = node.getAncestor((node) => node is ClassDeclaration);
|
| + JavaStringBuilder builder = new JavaStringBuilder();
|
| + builder.append("The element for the constructor ");
|
| + builder.append(node.name == null ? "<unnamed>" : node.name.name);
|
| + builder.append(" in ");
|
| + if (classNode == null) {
|
| + builder.append("<unknown class>");
|
| + } else {
|
| + builder.append(classNode.name.name);
|
| + }
|
| + builder.append(" in ");
|
| + builder.append(source.fullName);
|
| + builder.append(" was not set while trying to resolve types.");
|
| + AnalysisEngine.instance.logger.logError2(builder.toString(), new AnalysisException());
|
| + } else {
|
| ClassElement definingClass = element.enclosingElement as ClassElement;
|
| element.returnType = definingClass.type;
|
| FunctionTypeImpl type = new FunctionTypeImpl.con1(element);
|
| @@ -23036,6 +23109,15 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| Object visitFunctionDeclaration(FunctionDeclaration node) {
|
| super.visitFunctionDeclaration(node);
|
| ExecutableElementImpl element = node.element as ExecutableElementImpl;
|
| + if (element == null) {
|
| + JavaStringBuilder builder = new JavaStringBuilder();
|
| + builder.append("The element for the top-level function ");
|
| + builder.append(node.name);
|
| + builder.append(" in ");
|
| + builder.append(source.fullName);
|
| + builder.append(" was not set while trying to resolve types.");
|
| + AnalysisEngine.instance.logger.logError2(builder.toString(), new AnalysisException());
|
| + }
|
| element.returnType = _computeReturnType(node.returnType);
|
| FunctionTypeImpl type = new FunctionTypeImpl.con1(element);
|
| ClassElement definingClass = element.getAncestor((element) => element is ClassElement);
|
| @@ -23071,18 +23153,17 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| ExecutableElementImpl element = node.element as ExecutableElementImpl;
|
| if (element == null) {
|
| ClassDeclaration classNode = node.getAncestor((node) => node is ClassDeclaration);
|
| - ClassElement classElement = classNode.element;
|
| JavaStringBuilder builder = new JavaStringBuilder();
|
| builder.append("The element for the method ");
|
| - builder.append(node.name);
|
| + builder.append(node.name.name);
|
| builder.append(" in ");
|
| - builder.append(classNode.name);
|
| - builder.append(" in ");
|
| - if (classElement != null) {
|
| - builder.append(classElement.source.fullName);
|
| + if (classNode == null) {
|
| + builder.append("<unknown class>");
|
| } else {
|
| - builder.append("<element from class also not resolved>");
|
| + builder.append(classNode.name.name);
|
| }
|
| + builder.append(" in ");
|
| + builder.append(source.fullName);
|
| builder.append(" was not set while trying to resolve types.");
|
| AnalysisEngine.instance.logger.logError2(builder.toString(), new AnalysisException());
|
| }
|
|
|