package org.eclipse.jdt.internal.corext.refactoring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
public class RefactoringScopeFactory {
private static void addReferencingProjects(IJavaProject focus, Set<IJavaProject> projects) throws JavaModelException {
IProject[] referencingProjects= focus.getProject().getReferencingProjects();
for (int i= 0; i < referencingProjects.length; i++) {
IJavaProject candidate= JavaCore.create(referencingProjects[i]);
if (candidate == null || projects.contains(candidate) || !candidate.exists())
continue;
IClasspathEntry entry= getReferencingClassPathEntry(candidate, focus);
if (entry != null) {
projects.add(candidate);
if (entry.isExported())
addReferencingProjects(candidate, projects);
}
}
}
private static void addRelatedReferencing(IJavaProject focus, Set<IJavaProject> projects) throws CoreException {
IProject[] referencingProjects= focus.getProject().getReferencingProjects();
for (int i= 0; i < referencingProjects.length; i++) {
IJavaProject candidate= JavaCore.create(referencingProjects[i]);
if (candidate == null || projects.contains(candidate) || !candidate.exists())
continue;
IClasspathEntry entry= getReferencingClassPathEntry(candidate, focus);
if (entry != null) {
projects.add(candidate);
if (entry.isExported()) {
addRelatedReferencing(candidate, projects);
addRelatedReferenced(candidate, projects);
}
}
}
}
private static void addRelatedReferenced(IJavaProject focus, Set<IJavaProject> projects) throws CoreException {
IProject[] referencedProjects= focus.getProject().getReferencedProjects();
for (int i= 0; i < referencedProjects.length; i++) {
IJavaProject candidate= JavaCore.create(referencedProjects[i]);
if (candidate == null || projects.contains(candidate) || !candidate.exists())
continue;
IClasspathEntry entry= getReferencingClassPathEntry(focus, candidate);
if (entry != null) {
projects.add(candidate);
if (entry.isExported()) {
addRelatedReferenced(candidate, projects);
addRelatedReferencing(candidate, projects);
}
}
}
}
public static IJavaSearchScope create(IJavaElement javaElement) throws JavaModelException {
return RefactoringScopeFactory.create(javaElement, true, true);
}
public static IJavaSearchScope create(IJavaElement javaElement, boolean considerVisibility) throws JavaModelException {
return RefactoringScopeFactory.create(javaElement, considerVisibility, true);
}
public static IJavaSearchScope create(IJavaElement javaElement, boolean considerVisibility, boolean sourceReferencesOnly) throws JavaModelException {
if (considerVisibility && javaElement instanceof IMember) {
IMember member= (IMember) javaElement;
if (JdtFlags.isPrivate(member)) {
if (member.getCompilationUnit() != null)
return SearchEngine.createJavaSearchScope(new IJavaElement[] { member.getCompilationUnit()});
else
return SearchEngine.createJavaSearchScope(new IJavaElement[] { member});
}
}
IJavaProject javaProject= javaElement.getJavaProject();
return SearchEngine.createJavaSearchScope(getAllScopeElements(javaProject, sourceReferencesOnly), false);
}
public static IJavaSearchScope create(IMember[] members) throws JavaModelException {
return create(members, true);
}
public static IJavaSearchScope create(IMember[] members, boolean sourceReferencesOnly) throws JavaModelException {
Assert.isTrue(members != null && members.length > 0);
IMember candidate= members[0];
int visibility= getVisibility(candidate);
for (int i= 1; i < members.length; i++) {
int mv= getVisibility(members[i]);
if (mv > visibility) {
visibility= mv;
candidate= members[i];
}
}
return create(candidate, true, sourceReferencesOnly);
}
public static IJavaSearchScope createReferencedScope(IJavaElement[] javaElements) {
Set<IJavaProject> projects= new HashSet<>();
for (int i= 0; i < javaElements.length; i++) {
projects.add(javaElements[i].getJavaProject());
}
IJavaProject[] prj= projects.toArray(new IJavaProject[projects.size()]);
return SearchEngine.createJavaSearchScope(prj, true);
}
public static IJavaSearchScope createReferencedScope(IJavaElement[] javaElements, int includeMask) {
Set<IJavaProject> projects= new HashSet<>();
for (int i= 0; i < javaElements.length; i++) {
projects.add(javaElements[i].getJavaProject());
}
IJavaProject[] prj= projects.toArray(new IJavaProject[projects.size()]);
return SearchEngine.createJavaSearchScope(prj, includeMask);
}
public static IJavaSearchScope createRelatedProjectsScope(IJavaProject project, int includeMask) throws CoreException {
IJavaProject[] projects= getRelatedProjects(project);
return SearchEngine.createJavaSearchScope(projects, includeMask);
}
private static IPackageFragmentRoot[] getAllScopeElements(IJavaProject project, boolean onlySourceRoots) throws JavaModelException {
Collection<IJavaProject> referencingProjects= getReferencingProjects(project);
List<IPackageFragmentRoot> result= new ArrayList<>();
for (Iterator<IJavaProject> it= referencingProjects.iterator(); it.hasNext();) {
IJavaProject javaProject= it.next();
IPackageFragmentRoot[] roots= javaProject.getPackageFragmentRoots();
for (int i= 0; i < roots.length; i++) {
IPackageFragmentRoot root= roots[i];
if (!onlySourceRoots || root.getKind() == IPackageFragmentRoot.K_SOURCE)
result.add(root);
}
}
return result.toArray(new IPackageFragmentRoot[result.size()]);
}
private static IClasspathEntry getReferencingClassPathEntry(IJavaProject referencingProject, IJavaProject referencedProject) throws JavaModelException {
IClasspathEntry result= null;
IPath path= referencedProject.getProject().getFullPath();
IClasspathEntry[] classpath= referencingProject.getResolvedClasspath(true);
for (int i= 0; i < classpath.length; i++) {
IClasspathEntry entry= classpath[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && path.equals(entry.getPath())) {
if (entry.isExported())
return entry;
result= entry;
}
}
return result;
}
private static IJavaProject[] getRelatedProjects(IJavaProject focus) throws CoreException {
final Set<IJavaProject> projects= new HashSet<>();
addRelatedReferencing(focus, projects);
addRelatedReferenced(focus, projects);
projects.add(focus);
return projects.toArray(new IJavaProject[projects.size()]);
}
private static Collection<IJavaProject> getReferencingProjects(IJavaProject focus) throws JavaModelException {
Set<IJavaProject> projects= new HashSet<>();
addReferencingProjects(focus, projects);
projects.add(focus);
return projects;
}
private static int getVisibility(IMember member) throws JavaModelException {
if (JdtFlags.isPrivate(member))
return 0;
if (JdtFlags.isPackageVisible(member))
return 1;
if (JdtFlags.isProtected(member))
return 2;
return 4;
}
private RefactoringScopeFactory() {
}
}