blob: 5ef12b55cf6d3922571e2c683ba036e77700c4d3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 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.dltk.internal.corext.refactoring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IMember;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
public class RefactoringScopeFactory {
/*
* Adds to <code> projects </code> ImodelProject objects for all projects directly or indirectly referencing focus. @param projects ImodelProjects will be added to this set
*/
private static void addReferencingProjects(IScriptProject focus, Set<IScriptProject> projects) throws ModelException {
IProject[] referencingProjects= focus.getProject().getReferencingProjects();
for (int i= 0; i < referencingProjects.length; i++) {
IScriptProject candidate= DLTKCore.create(referencingProjects[i]);
if (candidate == null || projects.contains(candidate) || !candidate.exists())
continue; // break cycle
IBuildpathEntry entry= getReferencingClassPathEntry(candidate, focus);
if (entry != null) {
projects.add(candidate);
if (entry.isExported())
addReferencingProjects(candidate, projects);
}
}
}
private static void addRelatedReferencing(IScriptProject focus, Set<IScriptProject> projects) throws CoreException {
IProject[] referencingProjects= focus.getProject().getReferencingProjects();
for (int i= 0; i < referencingProjects.length; i++) {
IScriptProject candidate= DLTKCore.create(referencingProjects[i]);
if (candidate == null || projects.contains(candidate) || !candidate.exists())
continue; // break cycle
IBuildpathEntry entry= getReferencingClassPathEntry(candidate, focus);
if (entry != null) {
projects.add(candidate);
if (entry.isExported()) {
addRelatedReferencing(candidate, projects);
addRelatedReferenced(candidate, projects);
}
}
}
}
private static void addRelatedReferenced(IScriptProject focus, Set<IScriptProject> projects) throws CoreException {
IProject[] referencedProjects= focus.getProject().getReferencedProjects();
for (int i= 0; i < referencedProjects.length; i++) {
IScriptProject candidate= DLTKCore.create(referencedProjects[i]);
if (candidate == null || projects.contains(candidate) || !candidate.exists())
continue; // break cycle
IBuildpathEntry entry= getReferencingClassPathEntry(focus, candidate);
if (entry != null) {
projects.add(candidate);
if (entry.isExported()) {
addRelatedReferenced(candidate, projects);
addRelatedReferencing(candidate, projects);
}
}
}
}
/**
* Creates a new search scope with all compilation units possibly referencing <code>modelElement</code>,
* considering the visibility of the element, references only from source
*
* @param modelElement the model element
* @return the search scope
* @throws ModelException if an error occurs
*/
public static IDLTKSearchScope create(IModelElement modelElement) throws ModelException {
return RefactoringScopeFactory.create(modelElement, true, true);
}
/**
* Creates a new search scope with all compilation units possibly referencing <code>modelElement</code>,
* references only from source
*
* @param modelElement the model element
* @param considerVisibility consider visibility of modelElement iff <code>true</code>
* @return the search scope
* @throws ModelException if an error occurs
*/
public static IDLTKSearchScope create(IModelElement modelElement, boolean considerVisibility) throws ModelException {
return RefactoringScopeFactory.create(modelElement, considerVisibility, true);
}
/**
* Creates a new search scope with all compilation units possibly referencing <code>modelElement</code>.
*
* @param modelElement the model element
* @param considerVisibility consider visibility of modelElement iff <code>true</code>
* @param sourceReferencesOnly consider references in source only (no references in binary)
* @return the search scope
* @throws ModelException if an error occurs
*/
public static IDLTKSearchScope create(IModelElement modelElement, boolean considerVisibility, boolean sourceReferencesOnly) throws ModelException {
if (considerVisibility & modelElement instanceof IMember) {
/*IMember member= (IMember) modelElement;
if (JdtFlags.isPrivate(member)) {
if (member.getCompilationUnit() != null)
return SearchEngine.createmodelSearchScope(new ImodelElement[] { member.getCompilationUnit()});
else
return SearchEngine.createmodelSearchScope(new ImodelElement[] { member});
}*/
// Removed code that does some optimizations regarding package visible members. The problem is that
// there can be a package fragment with the same name in a different source folder or project. So we
// have to treat package visible members like public or protected members.
}
IScriptProject modelProject= modelElement.getScriptProject();
return SearchEngine.createSearchScope(getAllScopeElements(modelProject, sourceReferencesOnly), false,
modelProject.getLanguageToolkit());
}
/**
* Creates a new search scope comprising <code>members</code>.
*
* @param members the members
* @return the search scope
* @throws modelModelException if an error occurs
*/
public static IDLTKSearchScope create(IMember[] members) throws ModelException {
return create(members, true);
}
/**
* Creates a new search scope comprising <code>members</code>.
*
* @param members the members
* @param sourceReferencesOnly consider references in source only (no references in binary)
* @return the search scope
* @throws modelModelException if an error occurs
*/
public static IDLTKSearchScope create(IMember[] members, boolean sourceReferencesOnly) throws ModelException {
/*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);*/
return create(members[0], true, sourceReferencesOnly);
}
/**
* Creates a new search scope with all projects possibly referenced
* from the given <code>modelElements</code>.
*
* @param modelElements the model elements
* @return the search scope
*/
public static IDLTKSearchScope createReferencedScope(IModelElement[] modelElements) {
Set<IScriptProject> projects= new HashSet<IScriptProject>();
for (int i= 0; i < modelElements.length; i++) {
projects.add(modelElements[i].getScriptProject());
}
IScriptProject[] prj= projects.toArray(new IScriptProject[projects.size()]);
return SearchEngine.createSearchScope(prj, true,
prj.length > 0 ? prj[0].getLanguageToolkit() : null);
}
/**
* Creates a new search scope with all projects possibly referenced
* from the given <code>modelElements</code>.
*
* @param modelElements the model elements
* @param includeMask the include mask
* @return the search scope
*/
public static IDLTKSearchScope createReferencedScope(IModelElement[] modelElements, int includeMask) {
Set<IScriptProject> projects= new HashSet<IScriptProject>();
for (int i= 0; i < modelElements.length; i++) {
projects.add(modelElements[i].getScriptProject());
}
IScriptProject[] prj= projects.toArray(new IScriptProject[projects.size()]);
return SearchEngine.createSearchScope(prj, true,
prj.length > 0 ? prj[0].getLanguageToolkit() : null);
}
/**
* Creates a new search scope containing all projects which reference or are referenced by the specified project.
*
* @param project the project
* @param includeMask the include mask
* @return the search scope
* @throws CoreException if a referenced project could not be determined
*/
public static IDLTKSearchScope createRelatedProjectsScope(IScriptProject project, int includeMask) throws CoreException {
IScriptProject[] projects= getRelatedProjects(project);
return SearchEngine.createSearchScope(projects, true,
projects.length > 0 ? projects[0].getLanguageToolkit() : null);
}
/*
* @param projects a collection of ImodelProject
* @return Array of IPackageFragmentRoot, one element for each packageFragmentRoot which lies within a project in <code> projects </code> .
*/
private static IProjectFragment[] getAllScopeElements(IScriptProject project, boolean onlySourceRoots) throws ModelException {
Collection<IScriptProject> referencingProjects= getReferencingProjects(project);
List<IProjectFragment> result= new ArrayList<IProjectFragment>();
for (IScriptProject scriptProject : referencingProjects) {
IProjectFragment[] roots= scriptProject.getProjectFragments();
// Add all package fragment roots except archives
for (int i= 0; i < roots.length; i++) {
IProjectFragment root= roots[i];
if (!onlySourceRoots || root.getKind() == IProjectFragment.K_SOURCE)
result.add(root);
}
}
return result.toArray(new IProjectFragment[result.size()]);
}
/*
* Finds, if possible, a classpathEntry in one given project such that this classpath entry references another given project. If more than one entry exists for the referenced project and at least one is exported, then an exported entry will be returned.
*/
private static IBuildpathEntry getReferencingClassPathEntry(IScriptProject referencingProject, IScriptProject referencedProject) throws ModelException {
IBuildpathEntry result= null;
IPath path= referencedProject.getProject().getFullPath();
IBuildpathEntry[] classpath= referencingProject.getResolvedBuildpath(true);
for (int i= 0; i < classpath.length; i++) {
IBuildpathEntry entry= classpath[i];
if (entry.getEntryKind() == IBuildpathEntry.BPE_PROJECT && path.equals(entry.getPath())) {
if (entry.isExported())
return entry;
// Consider it as a candidate. May be there is another entry that is
// exported.
result= entry;
}
}
return result;
}
private static IScriptProject[] getRelatedProjects(IScriptProject focus) throws CoreException {
final Set<IScriptProject> projects= new HashSet<IScriptProject>();
addRelatedReferencing(focus, projects);
addRelatedReferenced(focus, projects);
projects.add(focus);
return projects.toArray(new IScriptProject[projects.size()]);
}
private static Collection<IScriptProject> getReferencingProjects(IScriptProject focus) throws ModelException {
Set<IScriptProject> projects= new HashSet<IScriptProject>();
addReferencingProjects(focus, projects);
projects.add(focus);
return projects;
}
/*private static int getVisibility(IMember member) throws ModelException {
if (JdtFlags.isPrivate(member))
return 0;
if (JdtFlags.isPackageVisible(member))
return 1;
if (JdtFlags.isProtected(member))
return 2;
return 4;
}*/
private RefactoringScopeFactory() {
// no instances
}
}