blob: dfd827b374926a30e8dad26d60ecf83ebd0916eb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.correction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
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.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
public class DefaultModulepathFixProcessor extends DefaultClasspathFixProcessor {
public static String MODULE_SEARCH= "Module/:"; //$NON-NLS-1$
@Override
public ClasspathFixProposal[] getFixImportProposals(IJavaProject project, String missingType) throws CoreException {
ArrayList<DefaultClasspathFixProposal> res= new ArrayList<>();
if (missingType.startsWith(MODULE_SEARCH)) {
collectModuleProposals(project, missingType.substring(MODULE_SEARCH.length()), res);
}
return res.toArray(new ClasspathFixProposal[res.size()]);
}
private void collectModuleProposals(IJavaProject project, String name, Collection<DefaultClasspathFixProposal> proposals) throws CoreException {
IModuleDescription currentModuleDescription= null;
if (JavaModelUtil.is9OrHigher(project)) {
currentModuleDescription= project.getModuleDescription();
if (currentModuleDescription != null && !currentModuleDescription.exists()) {
currentModuleDescription= null;
}
}
if (currentModuleDescription == null) {
return;
}
IJavaSearchScope scope= SearchEngine.createWorkspaceScope();
ArrayList<IModuleDescription> res= new ArrayList<>();
SearchRequestor requestor= new SearchRequestor() {
@Override
public void acceptSearchMatch(SearchMatch match) throws CoreException {
Object element= match.getElement();
if (element instanceof IModuleDescription) {
IModuleDescription moduleDesc= (IModuleDescription) element;
if (moduleDesc.exists() || moduleDesc.isAutoModule()) {
res.add(moduleDesc);
}
}
}
};
SearchPattern searchPattern= SearchPattern.createPattern(name, IJavaSearchConstants.MODULE, IJavaSearchConstants.DECLARATIONS,
SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
SearchParticipant[] participants= new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
try {
new SearchEngine().search(searchPattern, participants, scope, requestor, null);
} catch (CoreException e) {
//do nothing
} catch (OperationCanceledException e) {
//do nothing
}
if (res.isEmpty()) {
return;
}
HashMap<IClasspathEntry, IModuleDescription> classPathEntryToModuleMap= new HashMap<>();
HashSet<IClasspathEntry> classpaths= new HashSet<>();
HashSet<String> typesWithModule= new HashSet<>();
for (int i= 0; i < res.size(); i++) {
IModuleDescription curr= res.get(i);
if (curr != null) {
IPackageFragmentRoot root= (IPackageFragmentRoot) curr.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
try {
IClasspathEntry entry= root.getRawClasspathEntry();
if (entry == null) {
continue;
}
String moduleName= curr.getElementName();
if (classpaths.add(entry) && moduleName != null) {
classPathEntryToModuleMap.put(entry, curr);
typesWithModule.add(moduleName);
} else {
Object typeNameMatch= classPathEntryToModuleMap.get(entry);
if (typeNameMatch != null) {
if (moduleName != null) {
if (typesWithModule.contains(moduleName)) {
typesWithModule.remove(typeNameMatch);
}
}
}
}
} catch (JavaModelException e) {
// ignore
}
}
}
HashSet<Object> addedClaspaths= new HashSet<>();
for (int i= 0; i < res.size(); i++) {
IModuleDescription curr= res.get(i);
if (curr != null) {
IPackageFragmentRoot root= (IPackageFragmentRoot) curr.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
try {
IClasspathEntry entry= root.getRawClasspathEntry();
if (entry == null) {
continue;
}
String moduleName= curr.getElementName();
boolean isModule= false;
if (moduleName != null && typesWithModule.contains(moduleName)) {
isModule= true;
}
IJavaProject other= root.getJavaProject();
int entryKind= entry.getEntryKind();
if ((entry.isExported() || entryKind == IClasspathEntry.CPE_SOURCE) && addedClaspaths.add(other)) {
IClasspathEntry newEntry= null;
if (isModule) {
IClasspathAttribute[] extraAttributes= new IClasspathAttribute[] {
JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true") //$NON-NLS-1$
};
newEntry= JavaCore.newProjectEntry(other.getPath(), null, true, extraAttributes, false);
} else {
newEntry= JavaCore.newProjectEntry(other.getPath());
}
Change change= ClasspathFixProposal.newAddClasspathChange(project, newEntry);
if (change != null) {
String[] args= { BasicElementLabels.getResourceName(other.getElementName()), BasicElementLabels.getResourceName(project.getElementName()) };
String label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_addcp_project_description, args);
String desc= label;
DefaultClasspathFixProposal proposal= new DefaultClasspathFixProposal(label, change, desc, IProposalRelevance.ADD_PROJECT_TO_BUILDPATH);
proposals.add(proposal);
}
}
if (entryKind == IClasspathEntry.CPE_CONTAINER) {
IPath entryPath= entry.getPath();
if (isNonProjectSpecificContainer(entryPath)) {
addLibraryProposal(project, root, entry, addedClaspaths, proposals, null);
} else {
try {
IClasspathContainer classpathContainer= JavaCore.getClasspathContainer(entryPath, root.getJavaProject());
if (classpathContainer != null) {
IClasspathEntry entryInContainer= JavaModelUtil.findEntryInContainer(classpathContainer, root.getPath());
if (entryInContainer != null) {
addLibraryProposal(project, root, entryInContainer, addedClaspaths, proposals, null);
}
}
} catch (CoreException e) {
// ignore
}
}
} else if ((entryKind == IClasspathEntry.CPE_LIBRARY || entryKind == IClasspathEntry.CPE_VARIABLE)) {
addLibraryProposal(project, root, entry, addedClaspaths, proposals, null);
}
} catch (JavaModelException e) {
// ignore
}
}
}
}
}