| /** |
| * Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Florian Pirchner - Initial implementation |
| * |
| * generated by Xtext 2.11.0 |
| */ |
| package org.eclipse.osbp.xtext.oxtype.ui.imports; |
| |
| import static com.google.common.collect.Lists.newArrayList; |
| import static org.eclipse.xtext.util.Strings.notNull; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.apache.log4j.Logger; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.compiler.IProblem; |
| import org.eclipse.jdt.core.search.IJavaSearchConstants; |
| import org.eclipse.jdt.core.search.IJavaSearchScope; |
| import org.eclipse.jdt.core.search.SearchEngine; |
| import org.eclipse.jdt.core.search.SearchPattern; |
| import org.eclipse.jdt.internal.compiler.env.AccessRestriction; |
| import org.eclipse.jdt.internal.core.search.BasicSearchEngine; |
| import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor; |
| import org.eclipse.osbp.xtext.oxtype.imports.EObjectJvmLinkUsage; |
| import org.eclipse.osbp.xtext.oxtype.imports.EObjectUsage; |
| import org.eclipse.osbp.xtext.oxtype.imports.EObjectUsages; |
| import org.eclipse.osbp.xtext.oxtype.imports.IUnresolvedEObjectResolver; |
| import org.eclipse.xtext.common.types.JvmDeclaredType; |
| import org.eclipse.xtext.common.types.JvmType; |
| import org.eclipse.xtext.common.types.TypesPackage; |
| import org.eclipse.xtext.common.types.access.jdt.IJavaProjectProvider; |
| import org.eclipse.xtext.common.types.util.TypeReferences; |
| import org.eclipse.xtext.naming.IQualifiedNameProvider; |
| import org.eclipse.xtext.naming.QualifiedName; |
| import org.eclipse.xtext.resource.IEObjectDescription; |
| import org.eclipse.xtext.resource.XtextResource; |
| import org.eclipse.xtext.scoping.IScope; |
| import org.eclipse.xtext.scoping.IScopeProvider; |
| import org.eclipse.xtext.util.IAcceptor; |
| import org.eclipse.xtext.xbase.conversion.XbaseQualifiedNameValueConverter; |
| |
| import com.google.common.collect.LinkedHashMultimap; |
| import com.google.common.collect.Multimap; |
| import com.google.inject.Inject; |
| |
| @SuppressWarnings("restriction") |
| public class InteractiveUnresolvedEClassResolver implements IUnresolvedEObjectResolver { |
| |
| @SuppressWarnings("unused") |
| private static final Logger LOG = Logger.getLogger(InteractiveUnresolvedEClassResolver.class); |
| |
| @Inject |
| private EObjectChooser typeChooser; |
| |
| @Inject |
| private IJavaProjectProvider projectProvider; |
| |
| @Inject |
| private IScopeProvider scopeProvider; |
| |
| @Inject |
| private IQualifiedNameProvider nameProvider; |
| |
| @Inject |
| private TypeReferences typeRefs; |
| |
| @Inject |
| XbaseQualifiedNameValueConverter valueConverter; |
| |
| // @Inject |
| // private ISimilarityMatcher similarityMatcher; |
| |
| public void resolve(EObjectUsages typeUsages, XtextResource resource) { |
| if (resource == null) |
| return; |
| |
| // in the first step, handle all unresolved EObject imports "import |
| // ns" |
| Multimap<String, EObjectUsage> name2EObjectUsage = LinkedHashMultimap.create(); |
| for (EObjectUsage unresolved : typeUsages.getUnresolvedEObjects()) { |
| name2EObjectUsage.put(unresolved.getUniqueKeyUnresolved(), unresolved); |
| } |
| for (String key : name2EObjectUsage.keySet()) { |
| Iterable<EObjectUsage> usages = name2EObjectUsage.get(key); |
| EObject resolvedType = resolve(usages, resource); |
| if (resolvedType != null && !resolvedType.eIsProxy()) { |
| for (EObjectUsage usage : usages) { |
| usage.resolve(resolvedType, nameProvider.getFullyQualifiedName(resolvedType), typeUsages); |
| } |
| } |
| } |
| |
| // in the second step, handle all the JvmHelperLinks for |
| // "import org.my.foo.Bar" |
| Multimap<String, EObjectJvmLinkUsage> name2typeUsage = LinkedHashMultimap.create(); |
| for (EObjectJvmLinkUsage unresolved : typeUsages.getUnresolvedJvmTypes()) { |
| QualifiedName text = unresolved.getTypeQualifiedName(); |
| if (text != null) { |
| name2typeUsage.put(text.toString(), unresolved); |
| } |
| } |
| for (String name : name2typeUsage.keySet()) { |
| Iterable<EObjectJvmLinkUsage> usages = name2typeUsage.get(name); |
| JvmType resolvedType = resolveJvmLinks(name, usages, resource); |
| if (resolvedType != null) { |
| EObjectJvmLinkUsage first = usages.iterator().next(); |
| for (EObjectJvmLinkUsage usage : usages) |
| typeUsages.addResolvedJvmLink(first.getParent(), resolvedType, usage.getTextRegion(), |
| usage.getContext(), usage.getCrossReferenceString()); |
| } |
| } |
| } |
| |
| protected EObject resolve(Iterable<EObjectUsage> usages, XtextResource resource) { |
| |
| EObjectUsage first = usages.iterator().next(); |
| |
| if (first.getReference().getEReferenceType().getEPackage() == TypesPackage.eINSTANCE) { |
| return resolveOrphanedJvmTypes(usages, resource, first); |
| } else { |
| return resolveEObject(usages, resource, first); |
| } |
| } |
| |
| private EObject resolveEObject(Iterable<EObjectUsage> usages, XtextResource resource, EObjectUsage first) { |
| IScope scope = scopeProvider.getScope(first.getContext(), first.getReference()); |
| |
| String name = valueConverter.toValue(first.getCrossReferenceString(), null); |
| List<EObject> candidateTypes = new ArrayList<EObject>(); |
| for (IEObjectDescription desc : scope.getAllElements()) { |
| // for later use maybe |
| // if (similarityMatcher.isSimilar(name, desc.getQualifiedName() |
| // .getLastSegment())) { |
| if (name.equals(desc.getQualifiedName().getLastSegment())) { |
| EObject result = desc.getEObjectOrProxy(); |
| if (result.eIsProxy()) { |
| result = EcoreUtil.resolve(desc.getEObjectOrProxy(), resource); |
| } |
| candidateTypes.add(result); |
| } |
| } |
| if (candidateTypes.isEmpty()) { |
| return null; |
| } else if (candidateTypes.size() == 1) { |
| return candidateTypes.get(0); |
| } else { |
| return typeChooser.choose(candidateTypes, usages, resource); |
| } |
| } |
| |
| protected JvmType resolveJvmLinks(String name, Iterable<EObjectJvmLinkUsage> usages, XtextResource resource) { |
| |
| EObjectJvmLinkUsage first = usages.iterator().next(); |
| IScope scope = scopeProvider.getScope(first.getContext(), first.getReference()); |
| |
| EObjectUsage resolvedParent = first.getParent(); |
| if (!resolvedParent.isResolved()) { |
| throw new IllegalStateException("Parent EObjectUsage must be resolved!"); |
| } |
| |
| // construct the qualified name of the JvmType |
| QualifiedName typeFQN = resolvedParent.getTypeQualifiedName().skipLast(1) |
| .append(first.getCrossReferenceString()); |
| |
| IEObjectDescription desc = scope.getSingleElement(typeFQN); |
| if (desc == null) { |
| return null; |
| } |
| EObject result = desc.getEObjectOrProxy(); |
| if (result.eIsProxy()) { |
| result = EcoreUtil.resolve(desc.getEObjectOrProxy(), resource); |
| } |
| return (JvmType) result; |
| } |
| |
| protected EObject resolveOrphanedJvmTypes(Iterable<EObjectUsage> usages, XtextResource resource, |
| EObjectUsage first) { |
| try { |
| IJavaSearchScope javaSearchScope = getJavaSearchScope(resource); |
| final List<EObject> candidateTypes = newArrayList(); |
| EObject context = first.getContext(); |
| findJvmCandidateTypes(context, first.getCrossReferenceString(), javaSearchScope, |
| new IAcceptor<JvmDeclaredType>() { |
| public void accept(JvmDeclaredType t) { |
| candidateTypes.add(t); |
| } |
| }); |
| if (candidateTypes.isEmpty()) |
| return null; |
| else if (candidateTypes.size() == 1) |
| return candidateTypes.get(0); |
| else |
| return typeChooser.choose(candidateTypes, usages, resource); |
| } catch (JavaModelException e) { |
| LOG.error("Error searching for type named '" + notNull(first.getCrossReferenceString()) + "'", e); |
| } |
| return null; |
| } |
| |
| protected IJavaSearchScope getJavaSearchScope(XtextResource resource) { |
| IJavaProject javaProject = projectProvider.getJavaProject(resource.getResourceSet()); |
| IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[] { javaProject }); |
| return searchScope; |
| } |
| |
| protected String getQualifiedTypeName(char[] packageName, char[][] enclosingTypeNames, char[] simpleTypeName) { |
| StringBuilder fqName = new StringBuilder(packageName.length + simpleTypeName.length + 1); |
| if (packageName.length != 0) { |
| fqName.append(packageName); |
| fqName.append('.'); |
| } |
| for (char[] enclosingType : enclosingTypeNames) { |
| fqName.append(enclosingType); |
| fqName.append('.'); |
| } |
| fqName.append(simpleTypeName); |
| String fqNameAsString = fqName.toString(); |
| return fqNameAsString; |
| } |
| |
| protected void findJvmCandidateTypes(final EObject context, final String typeSimpleName, |
| IJavaSearchScope searchScope, final IAcceptor<JvmDeclaredType> acceptor) throws JavaModelException { |
| BasicSearchEngine searchEngine = new BasicSearchEngine(); |
| searchEngine.searchAllTypeNames(null, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, |
| typeSimpleName.toCharArray(), SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, |
| IJavaSearchConstants.TYPE, searchScope, new IRestrictedAccessTypeRequestor() { |
| public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, |
| char[][] enclosingTypeNames, String path, AccessRestriction access) { |
| final String qualifiedTypeName = getQualifiedTypeName(packageName, enclosingTypeNames, |
| simpleTypeName); |
| if (access == null |
| || (access.getProblemId() != IProblem.ForbiddenReference && !access.ignoreIfBetter())) { |
| JvmType importType = typeRefs.findDeclaredType(qualifiedTypeName, context.eResource()); |
| if (importType instanceof JvmDeclaredType) { |
| acceptor.accept((JvmDeclaredType) importType); |
| } |
| } |
| } |
| }, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, new NullProgressMonitor()); |
| } |
| } |