diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/ScriptDependencyResolver.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/ScriptDependencyResolver.java
new file mode 100644
index 0000000000..74c1fc2659
--- /dev/null
+++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/ScriptDependencyResolver.java
@@ -0,0 +1,423 @@
+/**
+ * Copyright (c) 2016 NumberFour AG.
+ * 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:
+ * NumberFour AG - Initial API and implementation
+ */
+package org.eclipse.n4js.tooling.organizeImports;
+
+import static org.eclipse.n4js.tooling.organizeImports.InjectedTypesResolverUtility.findAllInjected;
+import static org.eclipse.n4js.tooling.organizeImports.RefNameUtil.findTypeName;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.exists;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.filter;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.filterNull;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.findFirst;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.isNullOrEmpty;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.map;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.toList;
+import static org.eclipse.xtext.xbase.lib.IterableExtensions.toMap;
+import static org.eclipse.xtext.xbase.lib.IteratorExtensions.filter;
+import static org.eclipse.xtext.xbase.lib.IteratorExtensions.toInvertedMap;
+import static org.eclipse.xtext.xbase.lib.IteratorExtensions.toList;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Function;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.n4js.AnnotationDefinition;
+import org.eclipse.n4js.n4JS.AnnotableElement;
+import org.eclipse.n4js.n4JS.IdentifierRef;
+import org.eclipse.n4js.n4JS.ImportDeclaration;
+import org.eclipse.n4js.n4JS.N4ClassDeclaration;
+import org.eclipse.n4js.n4JS.N4InterfaceDeclaration;
+import org.eclipse.n4js.n4JS.N4TypeDeclaration;
+import org.eclipse.n4js.n4JS.NamedImportSpecifier;
+import org.eclipse.n4js.n4JS.NamespaceImportSpecifier;
+import org.eclipse.n4js.n4JS.Script;
+import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef;
+import org.eclipse.n4js.ts.typeRefs.TypeRef;
+import org.eclipse.n4js.ts.types.IdentifiableElement;
+import org.eclipse.n4js.ts.types.ModuleNamespaceVirtualType;
+import org.eclipse.n4js.ts.types.TAnnotableElement;
+import org.eclipse.n4js.ts.types.TClass;
+import org.eclipse.n4js.ts.types.TDynamicElement;
+import org.eclipse.n4js.ts.types.TExportableElement;
+import org.eclipse.n4js.ts.types.TFunction;
+import org.eclipse.n4js.ts.types.TInterface;
+import org.eclipse.n4js.ts.types.TModule;
+import org.eclipse.n4js.ts.types.TVariable;
+import org.eclipse.n4js.ts.types.Type;
+import org.eclipse.n4js.utils.ResourceType;
+import org.eclipse.xtext.EcoreUtil2;
+
+/**
+ * Static analysis for {@link Script} dependencies. Analyzes all identifiers in the {@link Script}, and on (on demand)
+ * {@link Type}s or {@link TypeRef}s. During analysis identifiers from {@link NamedImportSpecifier} and
+ * {@link NamespaceImportSpecifier} are taken into account. Note that if result analysis does not contain descriptions
+ * matching some of the imports, it means those imports are not used, and can be removed from script, or ignored during
+ * compilation.
+ *
+ * Result of analysis is list of {@link ScriptDependency} instances describing what {@link EObject}s should be imported.
+ *
+ * Note:
+ * - declarations marked with "@ProvidedByRuntime" are ignored (they are never in the result)
+ * - declarations marked with "@Global" are not ignored (can show up in the result)
+ *
+ */
+@SuppressWarnings("unused")
+public class ScriptDependencyResolver {
+
+ /**
+ * Resolves dependencies only from {@link IdentifierRef}s, no {@link Type}s or {@link TypeRef}s are taken into
+ * account.
+ */
+ public static List usedDependencies(Script script) {
+ if (null == script) {
+ return Collections.emptyList();
+ }
+ return allRequiredExternalDeclaration(script, Collections.emptySet(), Collections.emptySet());
+ }
+
+ /**
+ * Resolves dependencies from {@link IdentifierRef}s and {@link Type}s that are injected into local type
+ * declarations.
+ */
+ public static List usedDependenciesWithInejctedTypes(Script script) {
+ if (null == script) {
+ return Collections.emptyList();
+ }
+ return allRequiredExternalDeclaration(script, findAllInjected(script), Collections.emptySet());
+ }
+
+ /**
+ * Resolves dependencies from {@link IdentifierRef}s and all {@link TypeRef}s.
+ */
+ public static List usedDependenciesTypeRefs(Script script) {
+ if (null == script) {
+ return Collections.emptyList();
+ }
+ return allRequiredExternalDeclaration(script, Collections.emptySet(),
+ toList(filter(script.eAllContents(), TypeRef.class)));
+ }
+
+ /**
+ * Looks through all {@link IdentifierRef} for external dependencies (from different module than currently analyzed
+ * script containing module). Additionally looks through all types used as super types and implemented interfaces.
+ * Not used types (see {@link #shouldBeImported}) are removed from external dependencies.
+ *
+ * @param script
+ * to be analyzed
+ * @param typesToBeIncluded
+ * force specific collection of {@link Type}s to be considered for as dependencies
+ * @param typeRefsToBeIncluded
+ * force specific collection of {@link TypeRef}s to be considered for as dependencies
+ */
+ private static List allRequiredExternalDeclaration(Script script,
+ Collection typesToBeIncluded,
+ Collection typeRefsToBeIncluded) {
+
+ List indirectlyImported = toList(filter(script.eAllContents(), N4TypeDeclaration.class));
+ List identifierRefs = toList(filter(script.eAllContents(), IdentifierRef.class));
+
+ List potentialDependencies = new ArrayList<>();
+ potentialDependencies.addAll(indirectlyImported);
+ potentialDependencies.addAll(identifierRefs);
+ potentialDependencies.addAll(typesToBeIncluded);
+ potentialDependencies.addAll(typeRefsToBeIncluded);
+
+ List namedImportSpecifiers = toList(
+ filter(filter(script.eAllContents(), NamedImportSpecifier.class),
+ nis -> nis.getImportedElement() != null));
+ Map usedNamespaceSpecifiers = toInvertedMap(
+ filter(script.eAllContents(), NamespaceImportSpecifier.class), x -> false);
+
+ TModule baseModule = script.getModule();
+
+ Set sortedDeps = new TreeSet<>(Comparator.comparing(dep -> dep.localName));
+ for (EObject eo : potentialDependencies) {
+ Map nisByName = toMap(namedImportSpecifiers,
+ nis -> nis.getImportedElement().getName());
+
+ Iterable deps = handle(eo, nisByName, usedNamespaceSpecifiers,
+ eo2 -> shouldBeImported(baseModule, eo2));
+
+ for (ScriptDependency dep : deps) {
+ if (dep != null) {
+ sortedDeps.add(dep);
+ }
+ }
+ }
+
+ return new ArrayList<>(sortedDeps);
+ }
+
+ /**
+ * Checks if a given EObject should be imported.
+ *
+ *
+ * Evaluates to true if:
+ * - provided EO is not from the module provided at creation time (that module is assumed to be one for which we
+ * analyze dependencies)
+ * - provided EO is not from built in types
+ * - (in case of AST elements) is not annotated with {@link AnnotationDefinition#PROVIDED_BY_RUNTIME}
+ * - (in case of TS elements) providedByRuntime evaluates to false
+ *
+ *
+ * @returns true if given EO should be imported
+ */
+ public static boolean shouldBeImported(TModule baseModule, EObject eo) {
+ if (eo instanceof ModuleNamespaceVirtualType
+ || eo instanceof TDynamicElement) {
+ return true;
+ }
+
+ EObject containingModule = EcoreUtil.getRootContainer(eo);
+ if (containingModule instanceof TModule) {
+ if (AnnotationDefinition.PROVIDED_BY_RUNTIME.hasAnnotation((TModule) containingModule)
+ || (ResourceType.getResourceType(containingModule) == ResourceType.DTS
+ && AnnotationDefinition.GLOBAL.hasAnnotation((TModule) containingModule))) {
+ return false;
+ }
+ }
+
+ if (eo instanceof AnnotableElement) {
+ if (AnnotationDefinition.PROVIDED_BY_RUNTIME.hasAnnotation((AnnotableElement) eo)) {
+ return false;
+ }
+ } else if (eo instanceof TAnnotableElement) {
+ if (AnnotationDefinition.PROVIDED_BY_RUNTIME.hasAnnotation((TAnnotableElement) eo)) {
+ return false;
+ } else if (eo instanceof Type) {
+ // TODO is this dead code
+ if (((Type) eo).isProvidedByRuntime()) {
+ return false;
+ }
+ } else if (eo instanceof TVariable) {
+ // TODO is this dead code
+ if (((TVariable) eo).isProvidedByRuntime()) {
+ return false;
+ }
+ }
+ }
+
+ // ignore built-in things as n4scheme:/console.n4jsd:
+ // in non platform realm check if URI describes file,
+ // in eclipse platform realm check if URI describes platform resource
+ Resource res = eo.eResource();
+ return res != null && res.getURI() != null //
+ && ((res.getURI().isFile() || res.getURI().isPlatformResource())) //
+ // and check if modules/files are different
+ && (!res.getURI().toString().equals(baseModule.eResource().getURI().toString()));
+ }
+
+ private static boolean isNamespaceDependencyHandlingNeeded(
+ Map usedNamespaceSpecifiers, TModule targMod) {
+
+ return exists(usedNamespaceSpecifiers.keySet(),
+ is -> ((ImportDeclaration) is.eContainer()).getModule() == targMod);
+ }
+
+ private static ScriptDependency createScriptDependency(Type type,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers) {
+ if (nameToNamedImportSpecifiers.containsKey(type.getName())) {
+ NamedImportSpecifier nis = nameToNamedImportSpecifiers.get(type.getName());
+ TExportableElement identifiableElement = nis.getImportedElement();
+ TModule module = EcoreUtil2.getContainerOfType(identifiableElement, TModule.class);
+ return new ScriptDependency(nis.getAlias() != null ? nis.getAlias() : identifiableElement.getName(),
+ identifiableElement.getName(), identifiableElement, module);
+ } else if (isNamespaceDependencyHandlingNeeded(usedNamespaceSpecifiers, type.getContainingModule())) {
+ return createDependencyOnNamespace(usedNamespaceSpecifiers, type.getContainingModule());
+ } else {
+ // add dependency, looks like something that is @Global but not @ProvidedByRuntime
+ return new ScriptDependency(type.getName(), type.getName(), type, type.getContainingModule());
+ }
+ }
+
+ private static ScriptDependency createDependencyOnNamespace(
+ Map usedNamespaceSpecifiers, TModule targMod) {
+ NamespaceImportSpecifier is = findFirst(usedNamespaceSpecifiers.keySet(),
+ nis -> ((ImportDeclaration) nis.eContainer()).getModule() == targMod);
+ boolean used = usedNamespaceSpecifiers.get(is);
+ if (!used) {
+ // add dependency on the namespace
+ usedNamespaceSpecifiers.put(is, true);
+ return new ScriptDependency(is.getAlias(),
+ // For namespace imports, the actual name is intentionally null.
+ null,
+ // For namespace imports, this is ModuleNamespaceVirtualType, but intentionally null
+ null,
+ targMod);
+ } else {
+ // namespace was already used
+ return null;
+ }
+ }
+
+ private static Iterable handle(EObject tClass,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+ if (tClass instanceof TClass
+ && compare != null) {
+ return handle((TClass) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ } else if (tClass instanceof TInterface
+ && compare != null) {
+ return handle((TInterface) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ } else if (tClass instanceof N4ClassDeclaration
+ && compare != null) {
+ return handle((N4ClassDeclaration) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ } else if (tClass instanceof N4InterfaceDeclaration
+ && compare != null) {
+ return handle((N4InterfaceDeclaration) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers,
+ compare);
+ } else if (tClass instanceof TFunction
+ && compare != null) {
+ return handle((TFunction) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ } else if (tClass instanceof ParameterizedTypeRef
+ && compare != null) {
+ return handle((ParameterizedTypeRef) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ } else if (tClass instanceof IdentifierRef
+ && compare != null) {
+ return handle((IdentifierRef) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ } else if (tClass instanceof TypeRef
+ && compare != null) {
+ return handle((TypeRef) tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ }
+ return new ArrayList<>();
+ }
+
+ private static Iterable handle(TypeRef eo,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ return new ArrayList<>();
+ }
+
+ private static Iterable handle(Void eo,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ return new ArrayList<>();
+ }
+
+ private static Iterable handle(TFunction tFunction,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+ // TODO is there nothing to do?
+
+ return new ArrayList<>();
+ }
+
+ private static Iterable handle(N4ClassDeclaration eo,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ TClass tClass = (TClass) eo.getDefinedType();
+ return handle(tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ }
+
+ private static Iterable handle(N4InterfaceDeclaration eo,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ TInterface tInterface = (TInterface) eo.getDefinedType();
+ return handle(tInterface, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare);
+ }
+
+ private static Iterable handle(ParameterizedTypeRef eo,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ // added check for container instance, as polyfill tests were crashing when
+ // eo.declared type was TVariable and its container TClass
+ if (eo.getDeclaredType() != null && eo.getDeclaredType().eContainer() instanceof TModule &&
+ compare.apply(eo.getDeclaredType())) {
+ String typeName = findTypeName(eo);
+ if (typeName != null) { // null means not typed in script (e.g. TypesComputer)-> no import necessary
+ TModule module = EcoreUtil2.getContainerOfType(eo.getDeclaredType(), TModule.class);
+ return List.of(
+ new ScriptDependency(typeName, eo.getDeclaredType().getName(), eo.getDeclaredType(), module));
+ }
+ }
+ return new ArrayList<>();
+ }
+
+ /**
+ * Resolves dependency from identifier reference.
+ */
+ private static Iterable handle(IdentifierRef idRef,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ IdentifiableElement targetElem = idRef.getId();
+ if (targetElem == null) {
+ // broken identifier ref? smoke tests?
+ return new ArrayList<>();
+ }
+
+ if (compare.apply(targetElem)) {
+ TModule containingModule = EcoreUtil2.getContainerOfType(targetElem, TModule.class);
+ return List.of(
+ new ScriptDependency(RefNameUtil.findIdentifierName(idRef), targetElem.getName(), targetElem,
+ containingModule));
+ } else if (targetElem instanceof ModuleNamespaceVirtualType) {
+ TModule targMod = ((ModuleNamespaceVirtualType) targetElem).getModule();
+
+ if (isNamespaceDependencyHandlingNeeded(usedNamespaceSpecifiers, targMod)) {
+ return List.of(createDependencyOnNamespace(usedNamespaceSpecifiers, targMod));
+ }
+ }
+ return new ArrayList<>();
+ }
+
+ private static Iterable handle(TClass tClass,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ List deps = new ArrayList<>();
+
+ deps.add(tClass);
+
+ EList interfaces = tClass.getImplementedInterfaceRefs();
+ if (!isNullOrEmpty(interfaces))
+ deps.addAll(toList(filterNull(map(interfaces, i -> i.getDeclaredType()))));
+
+ ParameterizedTypeRef superClass = tClass.getSuperClassRef();
+ if (superClass != null)
+ deps.add(superClass.getDeclaredType());
+
+ return map(filter(deps, it -> compare.apply(it)),
+ it -> createScriptDependency(it, nameToNamedImportSpecifiers, usedNamespaceSpecifiers));
+ }
+
+ private static Iterable handle(TInterface tInterface,
+ Map nameToNamedImportSpecifiers,
+ Map usedNamespaceSpecifiers, Function compare) {
+
+ List deps = new ArrayList<>();
+
+ deps.add(tInterface);
+
+ EList rs = tInterface.getSuperInterfaceRefs();
+ if (!isNullOrEmpty(rs))
+ deps.addAll(toList(filterNull(map(rs, it -> it.getDeclaredType()))));
+
+ return map(filter(deps, d -> compare.apply(d)),
+ it -> createScriptDependency(it, nameToNamedImportSpecifiers, usedNamespaceSpecifiers));
+ }
+
+}
diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/ScriptDependencyResolver.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/ScriptDependencyResolver.xtend
deleted file mode 100644
index 2117f81e99..0000000000
--- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/ScriptDependencyResolver.xtend
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * Copyright (c) 2016 NumberFour AG.
- * 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:
- * NumberFour AG - Initial API and implementation
- */
-package org.eclipse.n4js.tooling.organizeImports
-
-import java.util.ArrayList
-import java.util.Collection
-import java.util.Collections
-import java.util.List
-import java.util.Map
-import org.eclipse.emf.ecore.EObject
-import org.eclipse.emf.ecore.util.EcoreUtil
-import org.eclipse.n4js.AnnotationDefinition
-import org.eclipse.n4js.n4JS.AnnotableElement
-import org.eclipse.n4js.n4JS.IdentifierRef
-import org.eclipse.n4js.n4JS.ImportDeclaration
-import org.eclipse.n4js.n4JS.N4ClassDeclaration
-import org.eclipse.n4js.n4JS.N4InterfaceDeclaration
-import org.eclipse.n4js.n4JS.N4TypeDeclaration
-import org.eclipse.n4js.n4JS.NamedImportSpecifier
-import org.eclipse.n4js.n4JS.NamespaceImportSpecifier
-import org.eclipse.n4js.n4JS.Script
-import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef
-import org.eclipse.n4js.ts.typeRefs.TypeRef
-import org.eclipse.n4js.ts.types.ModuleNamespaceVirtualType
-import org.eclipse.n4js.ts.types.TAnnotableElement
-import org.eclipse.n4js.ts.types.TClass
-import org.eclipse.n4js.ts.types.TDynamicElement
-import org.eclipse.n4js.ts.types.TFunction
-import org.eclipse.n4js.ts.types.TInterface
-import org.eclipse.n4js.ts.types.TModule
-import org.eclipse.n4js.ts.types.TVariable
-import org.eclipse.n4js.ts.types.Type
-import org.eclipse.n4js.utils.ResourceType
-import org.eclipse.xtext.EcoreUtil2
-
-import static extension org.eclipse.n4js.tooling.organizeImports.InjectedTypesResolverUtility.*
-import static extension org.eclipse.n4js.tooling.organizeImports.RefNameUtil.*
-
-/**
- * Static analysis for {@link Script} dependencies. Analyzes all identifiers in the {@link Script},
- * and on (on demand) {@link Type}s or {@link TypeRef}s. During analysis identifiers from {@link NamedImportSpecifier}
- * and {@link NamespaceImportSpecifier} are taken into account. Note that if result analysis does not contain descriptions matching
- * some of the imports, it means those imports are not used, and can be removed from script, or ignored during compilation.
- *
- * Result of analysis is list of {@link ScriptDependency} instances describing what {@link EObject}s should be imported.
- *
- * Note:
- * - declarations marked with "@ProvidedByRuntime" are ignored (they are never in the result)
- * - declarations marked with "@Global" are not ignored (can show up in the result)
- *
- */
-class ScriptDependencyResolver {
-
- /**
- * Resolves dependencies only from {@link IdentifierRef}s, no {@link Type}s or {@link TypeRef}s
- * are taken into account.
- */
- def public static List usedDependencies(Script script) {
- if (null === script) return emptyList
- allRequiredExternalDeclaration(script, Collections.EMPTY_SET, Collections.EMPTY_SET)
- }
-
- /**
- * Resolves dependencies from {@link IdentifierRef}s and {@link Type}s that are
- * injected into local type declarations.
- */
- def public static List usedDependenciesWithInejctedTypes(Script script) {
- if (null === script) return emptyList
- allRequiredExternalDeclaration(script, script.findAllInjected, Collections.EMPTY_SET)
- }
-
- /**
- * Resolves dependencies from {@link IdentifierRef}s and all {@link TypeRef}s.
- */
- def public static List usedDependenciesTypeRefs(Script script) {
- if (null === script) return emptyList
- allRequiredExternalDeclaration(script, Collections.EMPTY_SET, script.eAllContents.filter(TypeRef).toList)
- }
-
- /**
- * Looks through all {@link IdentifierRef} for external dependencies
- * (from different module than currently analyzed script containing module).
- * Additionally looks through all types used as super types and implemented interfaces.
- * Not used types (see {@link #shouldBeImported}) are removed from external dependencies.
- *
- * @param script to be analyzed
- * @param typesToBeIncluded force specific collection of {@link Type}s to be considered for as dependencies
- * @param typeRefsToBeIncluded force specific collection of {@link TypeRef}s to be considered for as dependencies
- */
- def private static List allRequiredExternalDeclaration(Script script, Collection typesToBeIncluded,
- Collection typeRefsToBeIncluded) {
-
- val indirectlyImported = script.eAllContents.filter(N4TypeDeclaration).toList
- val identifierRefs = script.eAllContents.filter(IdentifierRef).toList
-
- val potentialDependencies = newArrayList
- potentialDependencies += indirectlyImported
- potentialDependencies += identifierRefs
- potentialDependencies += typesToBeIncluded
- potentialDependencies += typeRefsToBeIncluded
-
- val namedImportSpecifiers = script.eAllContents.filter(NamedImportSpecifier).
- filter[it.importedElement !== null].toList
- val usedNamespaceSpecifiers = script.eAllContents.filter(NamespaceImportSpecifier).toInvertedMap[false]
-
- val baseModule = script.module;
- var depsImportedWithName = potentialDependencies.map [
- handle(namedImportSpecifiers.toMap[importedElement.name], usedNamespaceSpecifiers,
- [ EObject eo | shouldBeImported(baseModule, eo) ])
- ].flatten.filterNull.toSet.toList.sortBy[localName]
-
- return depsImportedWithName
- }
-
- /**
- * Checks if a given EObject should be imported.
- *
- *
- * Evaluates to true if:
- * - provided EO is not from the module provided at creation time (that module is assumed to be one for which we analyze dependencies)
- * - provided EO is not from built in types
- * - (in case of AST elements) is not annotated with {@link AnnotationDefinition.PROVIDED_BY_RUNTIME)
- * - (in case of TS elements) providedByRuntime evaluates to false
- *
- *
- * @returns true if given EO should be imported
- */
- def public static boolean shouldBeImported(TModule baseModule, EObject eo) {
- if (eo instanceof ModuleNamespaceVirtualType
- || eo instanceof TDynamicElement) {
- return true;
- }
-
- val containingModule = EcoreUtil.getRootContainer(eo);
- if (containingModule instanceof TModule) {
- if (AnnotationDefinition.PROVIDED_BY_RUNTIME.hasAnnotation(containingModule)
- || (ResourceType.getResourceType(containingModule) === ResourceType.DTS && AnnotationDefinition.GLOBAL.hasAnnotation(containingModule))) {
- return false;
- }
- }
-
- if (eo instanceof AnnotableElement) {
- if (AnnotationDefinition.PROVIDED_BY_RUNTIME.hasAnnotation(eo)) {
- return false;
- }
- } else if (eo instanceof TAnnotableElement) {
- if (AnnotationDefinition.PROVIDED_BY_RUNTIME.hasAnnotation(eo)) {
- return false;
- } else if (eo instanceof Type) {
- // TODO is this dead code
- if (eo.providedByRuntime) {
- return false;
- }
- } else if (eo instanceof TVariable) {
- // TODO is this dead code
- if (eo.providedByRuntime) {
- return false;
- }
- }
- }
-
- // ignore built-in things as n4scheme:/console.n4jsd:
- // in non platform realm check if URI describes file,
- // in eclipse platform realm check if URI describes platform resource
- return eo.eResource?.getURI !== null //
- && ((eo.eResource.getURI.file || eo.eResource.getURI.platformResource)) //
- // and check if modules/files are different
- && (! eo.eResource.getURI.toString.equals(baseModule.eResource.getURI.toString))
- }
-
- def private static boolean isNamespaceDependencyHandlingNeeded(
- Map usedNamespaceSpecifiers, TModule targMod) {
-
- return usedNamespaceSpecifiers.keySet.exists[is|(is.eContainer as ImportDeclaration).module === targMod]
- }
-
- def private static createScriptDependency(Type type, Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers) {
- if (nameToNamedImportSpecifiers.containsKey(type.name)) {
- val nis = nameToNamedImportSpecifiers.get(type.name);
- val identifiableElement = nis.importedElement;
- val module = EcoreUtil2.getContainerOfType(identifiableElement, TModule);
- new ScriptDependency(nis.alias ?: identifiableElement.name, identifiableElement.name, identifiableElement, module);
- } else if (isNamespaceDependencyHandlingNeeded(usedNamespaceSpecifiers, type.containingModule)) {
- createDependencyOnNamespace(usedNamespaceSpecifiers, type.containingModule)
- } else {
- // add dependency, looks like something that is @Global but not @ProvidedByRuntime
- new ScriptDependency(type.name, type.name, type, type.containingModule)
- }
- }
-
- def private static ScriptDependency createDependencyOnNamespace(
- Map usedNamespaceSpecifiers, TModule targMod) {
- val is = usedNamespaceSpecifiers.keySet.findFirst [ is |
- (is.eContainer as ImportDeclaration).module === targMod
- ]
- val used = usedNamespaceSpecifiers.get(is)
- if (!used) {
- // add dependency on the namespace
- usedNamespaceSpecifiers.put(is, true)
- new ScriptDependency(is.alias, null, // For namespace imports, the actual name is intentionally null.
- null, // For namespace imports, this is ModuleNamespaceVirtualType, but intentionally null
- targMod)
- } else {
- // namespace was already used
- null
- }
- }
-
- def private static dispatch Iterable handle(EObject eo,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- return newArrayList()
- }
-
- def private static dispatch Iterable handle(TypeRef eo,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- return newArrayList()
- }
-
- def private static dispatch Iterable handle(Void eo,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- return newArrayList()
- }
-
- def private static dispatch Iterable handle(TFunction tFunction,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
- // TODO is there nothing to do?
-
- return newArrayList()
- }
-
- def private static dispatch Iterable handle(N4ClassDeclaration eo,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- val tClass = eo.definedType as TClass
- handle(tClass, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare)
- }
-
- def private static dispatch Iterable handle(N4InterfaceDeclaration eo,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- val tInterface = eo.definedType as TInterface
- handle(tInterface, nameToNamedImportSpecifiers, usedNamespaceSpecifiers, compare)
- }
-
- def private static dispatch Iterable handle(ParameterizedTypeRef eo,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- // added check for container instance, as polyfill tests were crashing when
- // eo.declared type was TVariable and its container TClass
- if (eo.declaredType !== null && eo.declaredType.eContainer instanceof TModule &&
- compare.apply(eo.declaredType)) {
- val typeName = eo.findTypeName
- if (typeName !== null) { // null means not typed in script (e.g. TypesComputer)-> no import necessary
- val module = EcoreUtil2.getContainerOfType(eo.declaredType, TModule);
- return newArrayList(
- new ScriptDependency(typeName, eo.declaredType.name, eo.declaredType, module))
- }
- }
- return newArrayList()
- }
-
- /**
- * Resolves dependency from identifier reference.
- */
- def private static dispatch Iterable handle(IdentifierRef idRef,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- val targetElem = idRef.id;
- if(targetElem === null){
- //broken identifier ref? smoke tests?
- return newArrayList()
- }
-
- if (compare.apply(targetElem)) {
- val containingModule = EcoreUtil2.getContainerOfType(targetElem, TModule);
- return newArrayList(
- new ScriptDependency(idRef.findIdentifierName, targetElem.name, targetElem, containingModule))
- } else if (targetElem instanceof ModuleNamespaceVirtualType) {
- val targMod = targetElem.module
-
- if (isNamespaceDependencyHandlingNeeded(usedNamespaceSpecifiers, targMod)) {
- return newArrayList(createDependencyOnNamespace(usedNamespaceSpecifiers, targMod))
- }
- }
- return newArrayList()
- }
-
- def private static dispatch Iterable handle(TClass tClass,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- val deps = new ArrayList()
-
- deps.add(tClass)
-
- val interfaces = tClass.implementedInterfaceRefs
- if (!interfaces.nullOrEmpty) deps.addAll(interfaces.map[declaredType].filterNull)
-
- val superClass = tClass.superClassRef
- if (superClass !== null) deps.add(superClass.declaredType)
-
- deps.filter[compare.apply(it)].map[createScriptDependency(nameToNamedImportSpecifiers, usedNamespaceSpecifiers)]
- }
-
- def private static dispatch Iterable handle(TInterface tInterface,
- Map nameToNamedImportSpecifiers,
- Map usedNamespaceSpecifiers, (EObject)=>boolean compare) {
-
- val deps = new ArrayList()
-
- deps.add(tInterface)
-
- val rs = tInterface.superInterfaceRefs
- if (!rs.nullOrEmpty) deps.addAll(rs.map[declaredType].filterNull)
-
- deps.filter[compare.apply(it)].map[createScriptDependency(nameToNamedImportSpecifiers, usedNamespaceSpecifiers)]
- }
-
-}