Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(583)

Unified Diff: pkg/analysis_server/lib/src/services/correction/namespace.dart

Issue 481173002: When user renames 'prefix' in 'prefix.Class' she actually wants to rename ImportElement. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tweak for test - reference ambiguous prefix name. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;
+}

Powered by Google App Engine
This is Rietveld 408576698