| Index: pkg/analysis_server/lib/src/services/correction/namespace.dart
|
| diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fc0fd35b4a0e9c477a50766e26c86154e114d5aa
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
|
| @@ -0,0 +1,189 @@
|
| +// 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 services.src.correction.namespace;
|
| +
|
| +import 'package:analyzer/src/generated/ast.dart';
|
| +import 'package:analyzer/src/generated/element.dart';
|
| +import 'package:analyzer/src/generated/resolver.dart';
|
| +
|
| +
|
| +/**
|
| + * Returns the namespace of the given [ExportElement].
|
| + */
|
| +Map<String, Element> getExportNamespaceForDirective(ExportElement exp) {
|
| + Namespace namespace =
|
| + new NamespaceBuilder().createExportNamespaceForDirective(exp);
|
| + return namespace.definedNames;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Returns the export namespace of the given [LibraryElement].
|
| + */
|
| +Map<String, Element> getExportNamespaceForLibrary(LibraryElement library) {
|
| + Namespace namespace =
|
| + new NamespaceBuilder().createExportNamespaceForLibrary(library);
|
| + return namespace.definedNames;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Returns the [Element] exported from the given [LibraryElement].
|
| + */
|
| +Element getExportedElement(LibraryElement library, String name) {
|
| + if (library == null) {
|
| + return null;
|
| + }
|
| + return getExportNamespaceForLibrary(library)[name];
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Returns the [ImportElement] that is referenced by [prefixNode] with
|
| + * an [PrefixElement], maybe `null`.
|
| + */
|
| +ImportElement getImportElement(SimpleIdentifier prefixNode) {
|
| + if (prefixNode.parent is ImportDirective) {
|
| + ImportDirective importDirective = prefixNode.parent;
|
| + return importDirective.element;
|
| + }
|
| + ImportElementInfo info = internal_getImportElementInfo(prefixNode);
|
| + return info != null ? info.element : null;
|
| +}
|
| +
|
| +/**
|
| + * Return the [ImportElement] that declared [prefix] and imports [element].
|
| + *
|
| + * [libraryElement] - the [LibraryElement] where reference is.
|
| + * [prefix] - the import prefix, maybe `null`.
|
| + * [element] - the referenced element.
|
| + * [importElementsMap] - the cache of [Element]s imported by [ImportElement]s.
|
| + */
|
| +ImportElement internal_getImportElement(LibraryElement libraryElement,
|
| + String prefix, Element element, Map<ImportElement,
|
| + Set<Element>> importElementsMap) {
|
| + // validate Element
|
| + if (element == null) {
|
| + return null;
|
| + }
|
| + if (element.enclosingElement is! CompilationUnitElement) {
|
| + return null;
|
| + }
|
| + LibraryElement usedLibrary = element.library;
|
| + // find ImportElement that imports used library with used prefix
|
| + List<ImportElement> candidates = null;
|
| + for (ImportElement importElement in libraryElement.imports) {
|
| + // required library
|
| + if (importElement.importedLibrary != usedLibrary) {
|
| + continue;
|
| + }
|
| + // required prefix
|
| + PrefixElement prefixElement = importElement.prefix;
|
| + if (prefix == null) {
|
| + if (prefixElement != null) {
|
| + continue;
|
| + }
|
| + } else {
|
| + if (prefixElement == null) {
|
| + continue;
|
| + }
|
| + if (prefix != prefixElement.name) {
|
| + continue;
|
| + }
|
| + }
|
| + // no combinators => only possible candidate
|
| + if (importElement.combinators.length == 0) {
|
| + return importElement;
|
| + }
|
| + // OK, we have candidate
|
| + if (candidates == null) {
|
| + candidates = [];
|
| + }
|
| + candidates.add(importElement);
|
| + }
|
| + // no candidates, probably element is defined in this library
|
| + if (candidates == null) {
|
| + return null;
|
| + }
|
| + // one candidate
|
| + if (candidates.length == 1) {
|
| + return candidates[0];
|
| + }
|
| + // ensure that each ImportElement has set of elements
|
| + for (ImportElement importElement in candidates) {
|
| + if (importElementsMap.containsKey(importElement)) {
|
| + continue;
|
| + }
|
| + Namespace namespace =
|
| + new NamespaceBuilder().createImportNamespaceForDirective(importElement);
|
| + Set<Element> elements = new Set.from(namespace.definedNames.values);
|
| + importElementsMap[importElement] = elements;
|
| + }
|
| + // use import namespace to choose correct one
|
| + for (ImportElement importElement in importElementsMap.keys) {
|
| + Set<Element> elements = importElementsMap[importElement];
|
| + if (elements.contains(element)) {
|
| + return importElement;
|
| + }
|
| + }
|
| + // not found
|
| + return null;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Returns the [ImportElementInfo] with the [ImportElement] that is referenced
|
| + * by [prefixNode] with a [PrefixElement], maybe `null`.
|
| + */
|
| +ImportElementInfo internal_getImportElementInfo(SimpleIdentifier prefixNode) {
|
| + ImportElementInfo info = new ImportElementInfo();
|
| + // prepare environment
|
| + AstNode parent = prefixNode.parent;
|
| + CompilationUnit unit =
|
| + prefixNode.getAncestor((node) => node is CompilationUnit);
|
| + LibraryElement libraryElement = unit.element.library;
|
| + // prepare used element
|
| + Element usedElement = null;
|
| + if (parent is PrefixedIdentifier) {
|
| + PrefixedIdentifier prefixed = parent;
|
| + if (prefixed.prefix == prefixNode) {
|
| + usedElement = prefixed.staticElement;
|
| + info.periodEnd = prefixed.period.end;
|
| + }
|
| + }
|
| + if (parent is MethodInvocation) {
|
| + MethodInvocation invocation = parent;
|
| + if (invocation.target == prefixNode) {
|
| + usedElement = invocation.methodName.staticElement;
|
| + info.periodEnd = invocation.period.end;
|
| + }
|
| + }
|
| + // we need used Element
|
| + if (usedElement == null) {
|
| + return null;
|
| + }
|
| + // find ImportElement
|
| + String prefix = prefixNode.name;
|
| + Map<ImportElement, Set<Element>> importElementsMap = {};
|
| + info.element = internal_getImportElement(
|
| + libraryElement,
|
| + prefix,
|
| + usedElement,
|
| + importElementsMap);
|
| + if (info.element == null) {
|
| + return null;
|
| + }
|
| + return info;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Information about [ImportElement] and place where it is referenced using
|
| + * [PrefixElement].
|
| + */
|
| +class ImportElementInfo {
|
| + ImportElement element;
|
| + int periodEnd;
|
| +}
|
|
|