diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/InjectedTypesResolverUtility.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/InjectedTypesResolverUtility.java new file mode 100644 index 0000000000..45c5e46f3a --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/InjectedTypesResolverUtility.java @@ -0,0 +1,146 @@ +/** + * 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.AnnotationDefinition.BIND; +import static org.eclipse.n4js.AnnotationDefinition.BINDER; +import static org.eclipse.n4js.AnnotationDefinition.GENERATE_INJECTOR; +import static org.eclipse.n4js.AnnotationDefinition.INJECT; +import static org.eclipse.n4js.AnnotationDefinition.PROVIDES; +import static org.eclipse.n4js.AnnotationDefinition.USE_BINDER; +import static org.eclipse.n4js.AnnotationDefinition.WITH_PARENT_INJECTOR; +import static org.eclipse.n4js.tooling.organizeImports.DIUtility.getProvidedType; +import static org.eclipse.n4js.tooling.organizeImports.DIUtility.isProviderType; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.filterNull; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.last; +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.IteratorExtensions.filter; +import static org.eclipse.xtext.xbase.lib.IteratorExtensions.toIterable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.n4js.n4JS.Annotation; +import org.eclipse.n4js.n4JS.FormalParameter; +import org.eclipse.n4js.n4JS.N4ClassifierDefinition; +import org.eclipse.n4js.n4JS.N4FieldDeclaration; +import org.eclipse.n4js.n4JS.N4MethodDeclaration; +import org.eclipse.n4js.n4JS.Script; +import org.eclipse.n4js.n4JS.TypeRefAnnotationArgument; +import org.eclipse.n4js.ts.typeRefs.TypeRef; +import org.eclipse.n4js.ts.types.TClass; +import org.eclipse.n4js.ts.types.TFormalParameter; +import org.eclipse.n4js.ts.types.TMethod; +import org.eclipse.n4js.ts.types.Type; + +/** + * Utility for computing dependencies for N4JS DI mechanisms. + */ +public class InjectedTypesResolverUtility { + + /** + * Search through {@link Script} to find all {@link N4ClassifierDefinition}s. From found entries builds collection + * of {@link Type}s used with DI annotations. + */ + public static List findAllInjected(Script script) { + List injections = new ArrayList<>(); + + for (N4ClassifierDefinition cl : toIterable(filter(script.eAllContents(), N4ClassifierDefinition.class))) { + + // If has owned injected ctor with formal params, then use params types + for (TFormalParameter fp : getOwnedInjectedCtorParams(cl)) { + injections.add(getDeclaredTypeFromTypeRef(fp.getTypeRef())); + } + + // Injected fields. + for (N4FieldDeclaration fd : cl.getOwnedFields()) { + if (INJECT.hasAnnotation(fd)) { + injections.add(getDeclaredTypeFromTypeRef(fd.getDeclaredTypeRef())); + } + } + + // Binder specific + if (BINDER.hasOwnedAnnotation(cl)) { + // Binder's @Bind dependencies. + for (Annotation an : BIND.getAllOwnedAnnotations(cl)) { + // Since bind has only two arguments, both are TypeRefs. + injections.add(getDeclaredTypeFromTypeRef((TypeRef) an.getArgs().get(0).value())); + injections.add(getDeclaredTypeFromTypeRef((TypeRef) last(an.getArgs()).value())); + } + + // Binder's @Provides dependencies. + for (N4MethodDeclaration m : cl.getOwnedMethods()) { + if (PROVIDES.hasAnnotation(m)) { + injections.add(getDeclaredTypeFromTypeRef(m.getDeclaredReturnTypeRef())); + + for (FormalParameter fp : m.getFpars()) { + injections.add(getDeclaredTypeFromTypeRef(fp.getDeclaredTypeRef())); + } + } + } + } + + // DIComponent specific + if (GENERATE_INJECTOR.hasOwnedAnnotation(cl)) { + if (WITH_PARENT_INJECTOR.hasOwnedAnnotation(cl)) { + var ann = WITH_PARENT_INJECTOR.getOwnedAnnotation(cl); + if (ann != null) { + injections + .add(((TypeRefAnnotationArgument) ann.getArgs().get(0)).getTypeRef().getDeclaredType()); + } + } + + if (USE_BINDER.hasOwnedAnnotation(cl)) { + Iterable anns = USE_BINDER.getAllOwnedAnnotations(cl); + if (anns != null) { + var argsTypes = map( + filterNull(map(anns, a -> ((TypeRefAnnotationArgument) a.getArgs().get(0)))), + arg -> arg.getTypeRef().getDeclaredType()); + + for (Type at : argsTypes) { + injections.add(at); + } + } + } + } + } + return toList(filterNull(injections)); + } + + private static List getOwnedInjectedCtorParams(N4ClassifierDefinition cd) { + if (cd != null && cd.getDefinedType() instanceof TClass) { + TMethod ctor = ((TClass) cd.getDefinedType()).getOwnedCtor(); + if (null != ctor) { + if (INJECT.hasAnnotation(ctor)) + return ctor.getFpars(); + } + } + return Collections.emptyList(); + } + + /** + * resolves declared type from type ref. If declared type is N4Provider (can be nested) resolves to (nested) + * provided type. + */ + private static Type getDeclaredTypeFromTypeRef(TypeRef typeRef) { + if (isProviderType(typeRef)) { + Type providedType = getProvidedType(typeRef); + if (null != providedType) { + return providedType; + } + } else { + return typeRef.getDeclaredType(); + } + return null; + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/InjectedTypesResolverUtility.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/InjectedTypesResolverUtility.xtend deleted file mode 100644 index 974eb29826..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/InjectedTypesResolverUtility.xtend +++ /dev/null @@ -1,114 +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.Collection -import org.eclipse.n4js.n4JS.N4ClassifierDefinition -import org.eclipse.n4js.n4JS.Script -import org.eclipse.n4js.n4JS.TypeRefAnnotationArgument -import org.eclipse.n4js.ts.typeRefs.TypeRef -import org.eclipse.n4js.ts.types.TClass -import org.eclipse.n4js.ts.types.Type - -import static org.eclipse.n4js.AnnotationDefinition.* - -import static extension org.eclipse.n4js.tooling.organizeImports.DIUtility.* - -/** - * Utility for computing dependencies for N4JS DI mechanisms. - */ -class InjectedTypesResolverUtility { - - /** - * Search through {@link Script} to find all {@link N4ClassifierDefinition}s. - * From found entries builds collection of {@link Type}s used with DI annotations. - */ - public static def Collection findAllInjected(Script script) { - val injections = newArrayList; - - script.eAllContents.filter(N4ClassifierDefinition).forEach [ cl | - - // If has owned injected ctor with formal params, then use params types - cl.getOwnedInjectedCtorParams.forEach[ - injections.add(getDeclaredTypeFromTypeRef(it.typeRef)) - ]; - // Injected fields. - cl.ownedFields.forEach [ f | - if (INJECT.hasAnnotation(f)) { - injections.add(getDeclaredTypeFromTypeRef(f.declaredTypeRef)); - } - ] - - //Binder specific - if(BINDER.hasOwnedAnnotation(cl)){ - // Binder's @Bind dependencies. - BIND.getAllOwnedAnnotations(cl).forEach [ an | - // Since bind has only two arguments, both are TypeRefs. - injections.add(getDeclaredTypeFromTypeRef(an.args.head.value as TypeRef)); - injections.add(getDeclaredTypeFromTypeRef(an.args.last.value as TypeRef)); - ] - - // Binder's @Provides dependencies. - cl.ownedMethods.forEach [ m | - if (PROVIDES.hasAnnotation(m)) { - injections.add(getDeclaredTypeFromTypeRef(m.declaredReturnTypeRef)); - m.fpars.forEach[injections.add(getDeclaredTypeFromTypeRef(it.declaredTypeRef))]; - } - ]; - } - - //DIComponent specific - if(GENERATE_INJECTOR.hasOwnedAnnotation(cl)){ - if(WITH_PARENT_INJECTOR.hasOwnedAnnotation(cl)){ - var ann = WITH_PARENT_INJECTOR.getOwnedAnnotation(cl) - if(ann !== null){ - injections.add((ann.args.head as TypeRefAnnotationArgument).typeRef.declaredType) - } - } - - if(USE_BINDER.hasOwnedAnnotation(cl)){ - var anns = USE_BINDER.getAllOwnedAnnotations(cl) - if(anns !== null){ - var argsTypes = anns.map[(args.head as TypeRefAnnotationArgument)].filterNull.map[typeRef.declaredType]; - argsTypes.forEach[injections.add(it)]; - } - } - } - - ]; - return injections.filterNull.toList; - } - - private static def getOwnedInjectedCtorParams(N4ClassifierDefinition it) { - if (it?.definedType instanceof TClass) { - val ctor = (definedType as TClass).ownedCtor; - if (null !== ctor) { - if (INJECT.hasAnnotation(ctor)) return ctor.fpars; - } - } - return emptyList; - } - - /** - * resolves declared type from type ref. If declared type is - * N4Provider (can be nested) resolves to (nested) provided type. - */ - private static def getDeclaredTypeFromTypeRef(TypeRef typeRef) { - if (typeRef.providerType) { - val providedType = typeRef.providedType; - if (null !== providedType) { - return providedType; - } - } else { - typeRef.declaredType; - } - } -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RecordingImportState.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RecordingImportState.java new file mode 100644 index 0000000000..765c95191b --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RecordingImportState.java @@ -0,0 +1,176 @@ +/** + * 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.xtext.xbase.lib.IterableExtensions.exists; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.findFirst; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.n4js.n4JS.ImportDeclaration; +import org.eclipse.n4js.n4JS.ImportSpecifier; +import org.eclipse.n4js.n4JS.NamedImportSpecifier; +import org.eclipse.n4js.n4JS.NamespaceImportSpecifier; +import org.eclipse.n4js.ts.types.TModule; +import org.eclipse.xtext.xbase.lib.Pair; + +/** + * Register holding results of analyzing {@link ImportDeclaration}s and contained {@link ImportSpecifier}s. + */ +@SuppressWarnings("javadoc") +public class RecordingImportState { + + public List>> duplicatedImportDeclarations = new ArrayList<>(); + + public List unusedImports = new ArrayList<>(); + public List brokenImports = new ArrayList<>(); + + /* TODO refactor nested collections into specialized types */ + public List, List>> duplicateImportsOfSameElement = new ArrayList<>(); + public List>> localNameCollision = new ArrayList<>(); + + public List allUsedTypeNameToSpecifierTuples = new ArrayList<>(); + + public void registerDuplicatesOfImportDeclaration(ImportDeclaration declaration, + List duplicates) { + duplicatedImportDeclarations.add(Pair.of(declaration, duplicates)); + } + + public boolean isDuplicatingImportDeclaration(ImportDeclaration importDeclaration) { + return exists(duplicatedImportDeclarations, + dupePair -> dupePair.getKey().getModule() == importDeclaration.getModule() && + dupePair.getValue().contains(importDeclaration)); + } + + public void registerUnusedImport(ImportSpecifier specifier) { + unusedImports.add(specifier); + } + + public void registerBrokenImport(ImportSpecifier specifier) { + brokenImports.add(specifier); + } + + /** + * Removes any information stored in the register. + */ + public void cleanup() { + // clean own + unusedImports.clear(); + brokenImports.clear(); + allUsedTypeNameToSpecifierTuples.clear(); + + localNameCollision.clear(); + duplicatedImportDeclarations.clear(); + duplicateImportsOfSameElement.clear(); + + // cut ref: + allUsedTypeNameToSpecifierTuples = null; + } + + public void registerAllUsedTypeNameToSpecifierTuples(List pairs) { + allUsedTypeNameToSpecifierTuples = pairs; + } + + // remove all known unused imports from the passed in list. + public void removeDuplicatedImportsOfSameelement(List declarations, Adapter nodelessMarker) { + for (Pair, List> e : duplicateImportsOfSameElement) { + for (ImportProvidedElement e2 : e.getValue()) { + List l = new ArrayList<>(); + l.add(e2.getImportSpecifier()); + removeFrom(l, declarations, nodelessMarker); + } + } + } + + public void removeLocalNameCollisions(List declarations, Adapter nodelessMarker) { + for (Pair> e : localNameCollision) { + for (ImportProvidedElement e2 : e.getValue()) { + List l = new ArrayList<>(); + l.add(e2.getImportSpecifier()); + removeFrom(l, declarations, nodelessMarker); + } + } + } + + public void removeDuplicatedImportDeclarations(List declarations) { + for (Pair> decl2dupes : duplicatedImportDeclarations) { + declarations.removeAll(decl2dupes.getValue()); + } + } + + public void removeUnusedImports(List declarations, Adapter nodelessMarker) { + removeFrom(unusedImports, declarations, nodelessMarker); + } + + public void removeBrokenImports(List declarations, Adapter nodelessMarker) { + removeFrom(brokenImports, declarations, nodelessMarker); + } + + private void removeFrom(List tobeRemoved, List declarations, + Adapter nodelessMarker) { + + // remove from declarations + for (ImportSpecifier it : tobeRemoved) { + if (it instanceof NamespaceImportSpecifier) { + declarations.remove(it.eContainer()); + + } else if (it instanceof NamedImportSpecifier) { + ImportDeclaration imp = (ImportDeclaration) it.eContainer(); + if (imp != null) { + if (imp.getImportSpecifiers() != null) { + imp.getImportSpecifiers().remove(it); + // mark as modified to rebuild whole node. + imp.eAdapters().add(nodelessMarker); + } + if (imp.getImportSpecifiers() == null || imp.getImportSpecifiers().isEmpty()) { + declarations.remove(imp); + } + } + } + } + } + + /** + * Returns set of names, for which there are broken import specifiers. Happens after broken imports are removed, + * which makes name (usually IdRef/TypeRef) refer to ImportSpecifier, which is being removed from document. + * Providing list of broken names, allows organize imports to fix those. + */ + public Set calcRemovedImportedNames() { + Set ret = new HashSet<>(); + for (ImportProvidedElement e : allUsedTypeNameToSpecifierTuples) { + if (e.isUsed() && e.getImportSpecifier().eContainer() == null) { + ret.add(e.getLocalName()); + } + } + return ret; + } + + public void registerDuplicateImportsOfSameElement(String name, TModule module, + List elements) { + duplicateImportsOfSameElement.add(Pair.of(Pair.of(name, module), elements)); + } + + public void registerLocalNameCollision(String string, List elements) { + Pair> key = findFirst(localNameCollision, + it -> Objects.equals(it.getKey(), string)); + if (key != null) { + key.getValue().addAll(elements); + } else { + localNameCollision.add(Pair.of(string, elements)); + } + } + +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RecordingImportState.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RecordingImportState.xtend deleted file mode 100644 index 7a5334426a..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RecordingImportState.xtend +++ /dev/null @@ -1,161 +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.List -import java.util.Set -import org.eclipse.emf.common.notify.Adapter -import org.eclipse.n4js.n4JS.ImportDeclaration -import org.eclipse.n4js.n4JS.ImportSpecifier -import org.eclipse.n4js.n4JS.NamedImportSpecifier -import org.eclipse.n4js.n4JS.NamespaceImportSpecifier -import org.eclipse.n4js.ts.types.TModule - -/** - * Register holding results of analyzing {@link ImportDeclaration}s - * and contained {@link ImportSpecifier}s. - */ -class RecordingImportState { - - public List>> duplicatedImportDeclarations = newArrayList(); - - public List unusedImports = newArrayList(); - public List brokenImports = newArrayList(); - - /*TODO refactor nested collections into specialized types */ - public List, List>> duplicateImportsOfSameElement = newArrayList(); - public List>> localNameCollision = newArrayList(); - - public List allUsedTypeNameToSpecifierTuples = newArrayList(); - - def registerDuplicatesOfImportDeclaration(ImportDeclaration declaration, List duplicates) { - duplicatedImportDeclarations.add(declaration -> duplicates); - } - - def boolean isDuplicatingImportDeclaration(ImportDeclaration importDeclaration){ - duplicatedImportDeclarations.exists[dupePair| - dupePair.key.module === importDeclaration.module && - dupePair.value.contains(importDeclaration) - ] - } - - def registerUnusedImport(ImportSpecifier specifier) { - unusedImports.add(specifier); - } - - def registerBrokenImport(ImportSpecifier specifier) { - brokenImports.add(specifier); - } - - /** - * Removes any information stored in the register. - */ - def cleanup() { - - // clean own - #[unusedImports, brokenImports, allUsedTypeNameToSpecifierTuples].forEach[clear] - - localNameCollision.clear - duplicatedImportDeclarations.clear - duplicateImportsOfSameElement.clear - - // cut ref: - allUsedTypeNameToSpecifierTuples = null; - } - - def registerAllUsedTypeNameToSpecifierTuples(List pairs) { - allUsedTypeNameToSpecifierTuples = pairs - } - - // remove all known unused imports from the passed in list. - def removeDuplicatedImportsOfSameelement(List declarations, Adapter nodelessMarker ) { - duplicateImportsOfSameElement.forEach[e| - e.value.forEach[e2| - newArrayList(e2.importSpecifier).removeFrom(declarations, nodelessMarker) - ] - ] - } - - def removeLocalNameCollisions(List declarations, Adapter nodelessMarker ) { - localNameCollision.forEach[e| - e.value.forEach[e2| - newArrayList(e2.importSpecifier).removeFrom(declarations, nodelessMarker) - ] - ] - return - } - - def removeDuplicatedImportDeclarations(List declarations) { - duplicatedImportDeclarations.forEach[decl2dupes| - declarations.removeAll(decl2dupes.value) - ] - } - - def removeUnusedImports(List declarations, Adapter nodelessMarker ) { - unusedImports.removeFrom(declarations, nodelessMarker) - } - - def removeBrokenImports(List declarations, Adapter nodelessMarker ) { - brokenImports.removeFrom(declarations, nodelessMarker ) - } - - private def removeFrom(List tobeRemoved, List declarations, Adapter nodelessMarker ) { - //remove from declarations - tobeRemoved.forEach [ - switch (it) { - NamespaceImportSpecifier: - declarations.remove(it.eContainer) - NamedImportSpecifier: { - val imp = it.eContainer as ImportDeclaration - if (imp !== null) { - if (imp.importSpecifiers !== null) { - imp.importSpecifiers.remove(it); - // mark as modified to rebuild whole node. - imp.eAdapters.add(nodelessMarker) - } - if (imp.importSpecifiers === null || imp.importSpecifiers.empty) { - declarations.remove(imp) - } - } - } - } - ] - } - - /** - * Returns set of names, for which there are broken import specifiers. Happens after broken - * imports are removed, which makes name (usually IdRef/TypeRef) refer to ImportSpecifier, which - * is being removed from document. Providing list of broken names, allows organize imports to fix those. - */ - def Set calcRemovedImportedNames() { - var ret = newHashSet() - for (e : allUsedTypeNameToSpecifierTuples) { - if (e.used && e.importSpecifier.eContainer === null) { - ret.add(e.getLocalName()) - } - } - return ret - } - - def registerDuplicateImportsOfSameElement(String name, TModule module, List elements) { - duplicateImportsOfSameElement.add((name->module)->elements); - } - - def registerLocalNameCollision(String string, List elements) { - val key = localNameCollision.findFirst[it.key == string]; - if(key !== null){ - key.value.addAll(elements) - }else{ - localNameCollision.add(string -> elements.toList) - } - } - -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RefNameUtil.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RefNameUtil.java new file mode 100644 index 0000000000..5c47b39bfd --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RefNameUtil.java @@ -0,0 +1,76 @@ +/** + * 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.xtext.xbase.lib.IterableExtensions.filter; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.join; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.map; + +import org.eclipse.n4js.n4JS.IdentifierRef; +import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef; +import org.eclipse.n4js.ts.types.TypingStrategy; +import org.eclipse.xtext.nodemodel.ICompositeNode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; + +/** + * Utility to find actual name that was used for given reference. + */ +class RefNameUtil { + + /** + * Finds name that is used as identifier. + */ + public static String findIdentifierName(IdentifierRef ref) { + return join(map(filter(NodeModelUtils.findActualNodeFor(ref).getLeafNodes(), n -> !n.isHidden()), + n -> n.getText())); + } + + /** + * Finds the name in the ParameterizedTypeRef. + * + * @return null if no connection to AST + */ + public static String findTypeName(ParameterizedTypeRef ref) { + ICompositeNode astNode = NodeModelUtils.findActualNodeFor(ref); + if (astNode != null) { + int prefixLen = 0; + int suffixLen = 0; + String nodeText = join(map(filter(astNode.getLeafNodes(), n -> !n.isHidden()), n -> n.getText())); + + if (!ref.getDefinedTypingStrategy().equals(TypingStrategy.NOMINAL)) { + String typingLiteral = ref.getDefinedTypingStrategy().getLiteral(); + if (nodeText.startsWith(typingLiteral)) { + // handle things like + // foo2 : ~r~ /* ~r~ */ A + // nodeText does not contain whitespace or comments, so it is like + // ~r~A + // drop typing strategy literal value and return just + // A + prefixLen = ref.getDefinedTypingStrategy().getLiteral().length(); + } + } + + // handle A? + if (ref.isFollowedByQuestionMark() && nodeText.endsWith("?")) { + suffixLen = 1; + } + + // handle A+ + if (ref.isDynamic() && nodeText.endsWith("+")) { + suffixLen = 1; + } + + return nodeText.substring(prefixLen, nodeText.length() - suffixLen); + } else { + return null; + } + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RefNameUtil.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RefNameUtil.xtend deleted file mode 100644 index 0d7de932a5..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/tooling/organizeImports/RefNameUtil.xtend +++ /dev/null @@ -1,68 +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 org.eclipse.n4js.n4JS.IdentifierRef -import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef -import org.eclipse.n4js.ts.types.TypingStrategy -import org.eclipse.xtext.nodemodel.util.NodeModelUtils - -/** - * Utility to find actual name that was used for given reference. - */ -class RefNameUtil { - /** - * Finds name that is used as identifier. - */ - def public static String findIdentifierName(IdentifierRef ref) { - NodeModelUtils.findActualNodeFor(ref).leafNodes.filter[!hidden].map[text].join - } - - /** - * Finds the name in the ParameterizedTypeRef. - * @return null if no connection to AST - */ - def public static String findTypeName(ParameterizedTypeRef ref) { - val astNode = NodeModelUtils.findActualNodeFor(ref) - if (astNode !== null) { - var prefixLen = 0 - var suffixLen = 0 - val nodeText = astNode.leafNodes.filter[!hidden].map[text].join - - if(!ref.definedTypingStrategy.equals(TypingStrategy.NOMINAL)){ - val typingLiteral = ref.definedTypingStrategy.literal - if(nodeText.startsWith(typingLiteral)){ - // handle things like - // foo2 : ~r~ /* ~r~ */ A - // nodeText does not contain whitespace or comments, so it is like - // ~r~A - // drop typing strategy literal value and return just - // A - prefixLen = ref.definedTypingStrategy.literal.length - } - } - - // handle A? - if(ref.isFollowedByQuestionMark && nodeText.endsWith('?')) { - suffixLen = 1; - } - - //handle A+ - if(ref.dynamic && nodeText.endsWith('+')) { - suffixLen = 1; - } - - return nodeText.substring(prefixLen, nodeText.length - suffixLen) - } else { - null - } - } -}