Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoracuccuru2012-10-01 09:01:18 +0000
committeracuccuru2012-10-01 09:01:18 +0000
commit0488d055795a6308b48942ab42e39ca51e68111e (patch)
tree220a7fa9c59447b728861bf752d5c5c07d171605 /incoming
parent10da17448feac9b2be9be0c56477da3be6140e69 (diff)
downloadorg.eclipse.papyrus-0488d055795a6308b48942ab42e39ca51e68111e.tar.gz
org.eclipse.papyrus-0488d055795a6308b48942ab42e39ca51e68111e.tar.xz
org.eclipse.papyrus-0488d055795a6308b48942ab42e39ca51e68111e.zip
390801: Papyrus shall provide name resolution utils
https://bugs.eclipse.org/bugs/show_bug.cgi?id=390801
Diffstat (limited to 'incoming')
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/.classpath7
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/.project28
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/META-INF/MANIFEST.MF13
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/OSGI-INF/l10n/bundle.properties3
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/about.html28
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/build.properties5
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/plugin.pdoc4
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/Activator.java63
-rw-r--r--incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/NameResolutionUtils.java321
10 files changed, 479 insertions, 0 deletions
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/.classpath b/incoming/org.eclipse.papyrus.uml.naming.utils/.classpath
new file mode 100644
index 00000000000..2d1a4302f04
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/.project b/incoming/org.eclipse.papyrus.uml.naming.utils/.project
new file mode 100644
index 00000000000..77c5f0bf6e6
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.uml.naming.utils</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/.settings/org.eclipse.jdt.core.prefs b/incoming/org.eclipse.papyrus.uml.naming.utils/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..44217f8c068
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/META-INF/MANIFEST.MF b/incoming/org.eclipse.papyrus.uml.naming.utils/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..84a85eadf6c
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Bundle-SymbolicName: org.eclipse.papyrus.uml.naming.utils
+Bundle-Version: 0.10.0.qualifier
+Bundle-Activator: org.eclipse.papyrus.uml.naming.utils.Activator
+Bundle-Vendor: %Bundle-Vendor
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.uml2.uml;bundle-version="4.0.0"
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.papyrus.uml.naming.utils
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/OSGI-INF/l10n/bundle.properties b/incoming/org.eclipse.papyrus.uml.naming.utils/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 00000000000..4540cd68d19
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,3 @@
+#Properties file for org.eclipse.papyrus.uml.naming.utils
+Bundle-Vendor = Eclipse Modeling Project
+Bundle-Name = Naming Utils (Incubation) \ No newline at end of file
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/about.html b/incoming/org.eclipse.papyrus.uml.naming.utils/about.html
new file mode 100644
index 00000000000..82d49bf5f81
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/build.properties b/incoming/org.eclipse.papyrus.uml.naming.utils/build.properties
new file mode 100644
index 00000000000..5d7848ab179
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/l10n/bundle.properties
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/plugin.pdoc b/incoming/org.eclipse.papyrus.uml.naming.utils/plugin.pdoc
new file mode 100644
index 00000000000..df7d4308f8e
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/plugin.pdoc
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<doc:Documentation xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:doc="http://www.eclipse.org/papyrus/documentation/plugin/documentation" description="UML utils related to name resolution.">
+ <referent firstName="Arnaud" lastName="Cuccuru" eMail="arnaud.cuccuru@cea.fr" currentCompany="CEA LIST"/>
+</doc:Documentation>
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/Activator.java b/incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/Activator.java
new file mode 100644
index 00000000000..17a4f8c21c4
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/Activator.java
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.naming.utils;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.uml.naming.utils"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/NameResolutionUtils.java b/incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/NameResolutionUtils.java
new file mode 100644
index 00000000000..f7497427f9d
--- /dev/null
+++ b/incoming/org.eclipse.papyrus.uml.naming.utils/src/org/eclipse/papyrus/uml/naming/utils/NameResolutionUtils.java
@@ -0,0 +1,321 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.naming.utils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Model;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.Namespace;
+import org.eclipse.uml2.uml.resource.UMLResource;
+
+public class NameResolutionUtils {
+
+ protected final String qualifiedNameSeparator = "::";
+
+ /**
+ * From a given (potentially qualified) name and a scope, retrieves a list of NamedElement, filter by the filter metaclass (which can be null).
+ * If there are more than one element in the returned list, the name is ambiguous
+ * If the list is empty, the name does not correspond to any available named element in the context of the model resource set
+ *
+ * @param name, the potentially/partially qualified name of the NamedElement to be resolved
+ * @param scope, the namespace defining the scope for the name resolution
+ * @param filter, the potential "filter" metaclass (can be null)
+ * @return the list of NamedElement found by applying the resolution process
+ */
+ public List<NamedElement> getNamedElements(String name, Element scope, EClass filter) {
+ List<NamedElement> resolvedNamedElements = new ArrayList<NamedElement>() ;
+ // In practice, a scope can only be a Namespace
+ if (! (scope instanceof Namespace))
+ return resolvedNamedElements ;
+
+ // extracts name fragments for the given (potentially qualified) name
+ List<String> nameFragments = computeNameFragments(name) ;
+ // tries to resolve the name
+ resolvedNamedElements.addAll(getNamedElements(nameFragments, (Namespace)scope, filter)) ;
+
+ // If no named elements have been found, tries to restart the process on the enclosing namespace of the scope, if any
+ if (resolvedNamedElements.isEmpty()) {
+ Namespace enclosingNamespace = ((Namespace)scope).getNamespace() ;
+ while (resolvedNamedElements.isEmpty() && enclosingNamespace != null) {
+ resolvedNamedElements.addAll(getNamedElements(nameFragments, enclosingNamespace, filter)) ;
+ enclosingNamespace = enclosingNamespace.getNamespace() ;
+ }
+ }
+
+ // If no named elements have been found, tries to evaluate the name using the root context model has a root of the qualified name
+ if (resolvedNamedElements.isEmpty()) {
+ Namespace model = scope.getModel() ;
+ if (model.getName().equals(nameFragments.get(0))) {
+ if (nameFragments.size() == 1) {
+ if (filter != null) {
+ if (filter.isSuperTypeOf(model.eClass()))
+ resolvedNamedElements.add(model) ;
+ }
+ else {
+ resolvedNamedElements.add(model) ;
+ }
+ }
+ else {
+ List<String> remainingNameFragments = nameFragments.subList(1, nameFragments.size()) ;
+ resolvedNamedElements.addAll(getNamedElements(remainingNameFragments, model, filter)) ;
+ }
+ }
+ }
+
+ // If no named elements have been found, tries to evaluate the name as a fully qualified name
+ // This requires analysis of available UML resources in the context of scope resource set
+ if (resolvedNamedElements.isEmpty()) {
+ List<Resource> resources = scope.eResource().getResourceSet().getResources() ;
+ for (Resource resource : resources) {
+ if (resource != scope.eResource() && resource instanceof UMLResource) {
+ UMLResource umlResource = (UMLResource)resource ;
+ Model root = null ;
+ for (Iterator<EObject> i = umlResource.getAllContents() ; i.hasNext() && root == null ; ) {
+ EObject next = i.next() ;
+ if (next instanceof Model)
+ root = (Model)next ;
+ }
+ if (root != null) {
+ if (root.getName().equals(nameFragments.get(0))) {
+ if (nameFragments.size() == 1) {
+ if (filter != null) {
+ if (filter.isSuperTypeOf(root.eClass()))
+ resolvedNamedElements.add(root) ;
+ }
+ else {
+ resolvedNamedElements.add(root) ;
+ }
+ }
+ else {
+ List<String> remainingNameFragments = nameFragments.subList(1, nameFragments.size()) ;
+ resolvedNamedElements.addAll(getNamedElements(remainingNameFragments, root, filter)) ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return resolvedNamedElements ;
+ }
+
+ /**
+ * From a given list of name fragments representing a (potentially qualified name),
+ * retrieves a list of NamedElement.
+ * The basic principle of the algorithm is to try to match the first element of nameFragments with
+ * members of the scope.
+ * When a match is found, this method is called a recursively on a sublist of a nameFragments
+ * (i.e., the first element is omitted) and on the matched member.
+ * The stop condition for recursivity is that the size of nameFragments is 1.
+ *
+ * @param nameFragments, the potentially/partially qualified name of the NamedElement to be resolved
+ * @param scope, the namespace defining the scope for the name resolution
+ * @param clazz, the potential "filter" metaclass (can be null)
+ * @return the list of NamedElement found by applying the resolution process
+ */
+ protected List<NamedElement> getNamedElements(List<String> nameFragments, Namespace scope, EClass clazz) {
+ List<NamedElement> resolvedNamedElements = new ArrayList<NamedElement>() ;
+ // Tries to match the first name fragment with members of the scope
+ for (NamedElement member : scope.getMembers()) {
+ List<String> memberNames = scope.getNamesOfMember(member) ;
+ String firstNameFragment = nameFragments.get(0) ;
+ // iterates other names given to the current member in the context of this scope
+ for (String memberName : memberNames) {
+ if (memberName.equals(firstNameFragment)) {
+ // the first fragment matches with this member
+ if (nameFragments.size() == 1) { // Stop condition for recursivity
+ if (clazz != null) {
+ if (clazz.isSuperTypeOf(member.eClass()))
+ resolvedNamedElements.add(member) ;
+ }
+ else {
+ resolvedNamedElements.add(member) ;
+ }
+ }
+ else {
+ if (member instanceof Namespace) { // Recursive call on the sublist and the matching member
+ List<String> remainingNameFragments = nameFragments.subList(1, nameFragments.size()) ;
+ resolvedNamedElements.addAll(getNamedElements(remainingNameFragments, (Namespace)member, clazz)) ;
+ }
+ }
+ }
+ }
+ }
+ return resolvedNamedElements ;
+ }
+
+ /**
+ * Computes a List<String> containing the various "name fragments" of parameter "name".
+ * The string "name" is simply splitted according to qualifiedNameSeparator ("::").
+ *
+ * @param name The name to be "fragmented"
+ * @return The list of name fragments
+ */
+ protected List<String> computeNameFragments(String name) {
+ String[] nameFragmentsArray = name.split(qualifiedNameSeparator) ;
+ List<String> nameFragments = new ArrayList<String>() ;
+ for (int i = 0 ; i < nameFragmentsArray.length ; i++) {
+ nameFragments.add(nameFragmentsArray[i]) ;
+ }
+ return nameFragments ;
+ }
+
+ /**
+ * Computes the shortest qualified names for a named element, in the context of a scope.
+ * The shortest qualified names are the shortest name in terms of qualification depth which unambiguously
+ * resolve to the researched element.
+ * In the case where the returned list is empty, there is no unambiguous name that could be found,
+ * including the fully qualified name of the element. This typically means that there are problems in the
+ * context model in terms of organization of element imports and package imports and named element
+ * definitions, or conflict in loaded UML resources.
+ * In the case where the list contains more than one name, all these names are all valid, all have the same
+ * qualification depth, and can be used indifferently.
+ *
+ * @param element, the named element for which we try to determine the shortest qualified name
+ * @param scope, the scope in which we try to determine the shortest qualified name for element
+ * @return the shortest qualified names for element
+ */
+ public List<String> getShortestQualifiedNames(NamedElement element, Element scope) {
+ List<String> shortestNames = new ArrayList<String>() ;
+ // In practice, a scope can only be a Namespace
+ if (! (scope instanceof Namespace)) {
+ return shortestNames ;
+ }
+ // Tries to compute
+ shortestNames.addAll(getShortestQualifiedNamesOmittingFullyQualifiedName(element, (Namespace)scope)) ;
+
+ // if no short name have been found, returns the fully qualified name, if it is itself unambiguous
+ if(shortestNames.isEmpty()) {
+ String fullyQualifiedNameOfElement = element.getQualifiedName() ;
+ if (fullyQualifiedNameOfElement != null && ! (fullyQualifiedNameOfElement.length() == 0)) {
+ shortestNames.add(fullyQualifiedNameOfElement) ;
+ shortestNames.removeAll(findAmbiguousNames(shortestNames, element, (Namespace)scope)) ;
+ }
+ }
+ return shortestNames ;
+ }
+
+ /**
+ * Computes the shortest qualified names for a named element in the context of a scope, omitting
+ * fully qualified name of the named element (The fully qualified name is handled as a special case of
+ * getShortestQualifiedName, in the case where this method was not able to produce a non-ambiguous qualified
+ * name).
+ * The basic principle is the following (each step is applied if the previous one did not succeed.
+ * "Evaluates" means assuring that computed names are not ambiguous):
+ * 1. if element and scope are the same, directly evaluates the name of the element.
+ * 2. if element is a member of scope, evaluates member names for this element,
+ * 3. Iterate over enclosing namespaces of scope, and if element is a member of an enclosing namespace,
+ * evaluate member names for element in the context of this enclosing namespace
+ * 4. Recursively call this method using the enclosing namespace of element as the reasearched named element,
+ * build partially qualified names from the obtained list, and evaluate the computed names
+ *
+ * @param element, the named element for which we try to determine the shortest qualified name
+ * @param scope, the scope in which we try to determine the shortest qualified name for element
+ * @return the shortest qualified names for element (omitting the fully qualified name element)
+ */
+ protected List<String> getShortestQualifiedNamesOmittingFullyQualifiedName(NamedElement element, Namespace scope) {
+ boolean continueResearch = true ;
+ List<String> shortestNames = new ArrayList<String>() ;
+ // if element and scope are the same, the shortest name is the name of the element
+ if (element == scope) {
+ shortestNames.add(element.getName()) ;
+ shortestNames.removeAll(findAmbiguousNames(shortestNames, element, scope)) ;
+ if (! shortestNames.isEmpty())
+ continueResearch = false ;
+ }
+ // if element is part of the scope members, the shortest names are the names given to this member in the context of this scope
+ if (continueResearch && scope.getMembers().contains(element)) {
+ shortestNames.addAll(scope.getNamesOfMember(element)) ;
+ shortestNames.removeAll(findAmbiguousNames(shortestNames, element, scope)) ;
+ if (! shortestNames.isEmpty())
+ continueResearch = false ;
+ }
+ if (continueResearch) {
+ // tries to find element in the enclosing namespaces of scope
+ Namespace enclosingNamespaceOfScope = scope.getNamespace() ;
+ while (enclosingNamespaceOfScope != null && shortestNames.isEmpty()) {
+ if (enclosingNamespaceOfScope.getMembers().contains(element)) {
+ shortestNames.addAll(enclosingNamespaceOfScope.getNamesOfMember(element)) ;
+ shortestNames.removeAll(findAmbiguousNames(shortestNames, element, scope)) ;
+ }
+ enclosingNamespaceOfScope = enclosingNamespaceOfScope.getNamespace() ;
+ }
+ if (shortestNames.isEmpty()) {
+ // tries to find the shortest name for the enclosing namespace in the context of scope
+ Namespace enclosingNamespaceOfElement = element.getNamespace() ;
+ if (enclosingNamespaceOfElement != null) {
+ List<String> shortestNamesForEnclosingNamespace = new ArrayList<String>() ;
+ shortestNamesForEnclosingNamespace.addAll(getShortestQualifiedNames(enclosingNamespaceOfElement, scope)) ;
+ // creates the list of shortest name from the list of shortest names for the enclosing namespace
+ for (String shortestNameForEnclosing : shortestNamesForEnclosingNamespace) {
+ List<String> memberNames = enclosingNamespaceOfElement.getNamesOfMember(element) ;
+ for (String memberName : memberNames) {
+ shortestNames.add(shortestNameForEnclosing + qualifiedNameSeparator + memberName) ;
+ }
+ }
+ shortestNames.removeAll(findAmbiguousNames(shortestNames, element, scope)) ;
+ }
+ }
+ }
+ return shortestNames ;
+ }
+
+ /**
+ * From a list of names, select the names which do not unambiguously resolve to researchedElement,
+ * in the context of scope
+ *
+ * @param names, the list of names to evaluate
+ * @param researchedElement, the element that must be resolved from the names
+ * @param scope, the scope in which evaluation happens
+ * @return the list of names which are ambiguous
+ */
+ protected List<String> findAmbiguousNames(List<String> names, NamedElement researchedElement, Namespace scope) {
+ List<String> ambiguousNames = new ArrayList<String>() ;
+ for (String name : names) {
+ if (isQualifiedNameAmbiguous(name, researchedElement, scope))
+ ambiguousNames.add("" + name) ;
+ }
+ return ambiguousNames ;
+ }
+
+
+ /**
+ * Determines if a given name is ambiguous. From a given scope where evaluation of the name happens,
+ * a name is ambiguous if:
+ * - The given name resolves to multiple elements,
+ * - Or the name resolves to one element which is not the researched element.
+ * This method relies on getNamedElements(String, Element, EClass), using researchedElement.eClass() as a filter.
+ *
+ * @param name
+ * @param researchedElement
+ * @param scope
+ * @return
+ */
+ protected boolean isQualifiedNameAmbiguous(String name, NamedElement researchedElement, Namespace scope) {
+ List<NamedElement> resolvedElements = getNamedElements(name, scope, researchedElement.eClass());
+ if (resolvedElements.size() > 1)
+ return true ;
+ if (resolvedElements.get(0) != researchedElement)
+ return true ;
+ return false ;
+ }
+}

Back to the top