blob: 383961132be36ed500dde09b305fd74c854a7457 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2008 Technical University Berlin, Germany.
*
* 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
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.ext;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
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.core.hierarchy.TypeHierarchy;
import org.eclipse.objectteams.otdt.core.compiler.OTNameUtils;
import org.eclipse.objectteams.otdt.core.ext.IMarkableJavaElement;
/**
* Partial implementation of {@link IMarkableJavaElement}, as a shared base
* for concrete subclasses.
*
* @author stephan
* @since 1.2.5
*/
public abstract class AbstractMarkable implements IMarkableJavaElement {
final static String PDE_PLUGIN_NATURE_ID = "org.eclipse.pde.PluginNature"; //$NON-NLS-1$ // avoid importing org.eclipse.pde.core
/**
* Fetch the member and super types of type and add them to the given sets.
* Works recursively.
*
* @param members all members, direct and indirect, including inherited members.
* @param supers all super types of this and its members.
* @param type focus type
* @param currentProject the project of the current Markable, use this first when searching types.
* @param projects where to search for super types which are given by their name
* @param monitor
* @throws JavaModelException
*/
void addSuperAndMemberTypes(Set<IType> members, Set<IType> supers, IType type, IJavaProject currentProject, IJavaProject[] projects, IProgressMonitor monitor)
throws JavaModelException
{
if (!type.exists())
return; // mh?
IType superType = null;
String superclassName = type.getSuperclassName();
String packageName = null;
String typeName = null;
if (superclassName != null) {
superclassName = superclassName.replace('$', '.');
if (superclassName.indexOf('.') != -1) {
// qualified, find the type directly:
superType = currentProject.findType(superclassName);
} else {
// resolve it now:
String[][] resolvedSuperName = type.resolveType(superclassName);
if (resolvedSuperName != null && resolvedSuperName.length == 1) {
packageName = resolvedSuperName[0][0];
typeName = resolvedSuperName[0][1];
if (!(packageName.equals("java.lang") && typeName.equals("Object"))) //$NON-NLS-1$ //$NON-NLS-2$
{
superType = currentProject.findType(packageName, typeName, (IProgressMonitor)null);
if (superType == null)
for (IJavaProject prj : projects)
if ((superType = prj.findType(packageName, typeName, (IProgressMonitor)null)) != null)
break;
}
}
}
}
if (superType != null && !superType.isAnonymous()) {
supers.add(superType);
if (!members.contains(superType)) // avoid super-member-loop
addSuperAndMemberTypes(members, supers, superType, currentProject, projects, monitor);
}
for (IType member : type.getTypes()) {
if (member.isInterface()) continue; // not currently bindable
if ( Flags.isRole(member.getFlags())
&& OTNameUtils.isTopConfined(member.getElementName())) continue; // confineds are not bound base
members.add(member);
if (!supers.contains(member)) // avoid super-member-loop
addSuperAndMemberTypes(members, supers, member, currentProject, projects, monitor);
}
}
/**
* Get all direct and indirect subtypes of all types in 'types'.
* @param types
* @param monitor
* @return
* @throws JavaModelException
*/
Set<IType> getSubTypes(Set<IType> types, IProgressMonitor monitor) throws JavaModelException {
monitor.beginTask(OTCoreExtMessages.AbstractMarkable_baseClassHierarchy_progress, types.size());
IJavaSearchScope workspaceScope = SearchEngine.createWorkspaceScope();
Set<IType> subTypes = new HashSet<IType>(13);
for (IType type: types) {
TypeHierarchy hier = new TypeHierarchy(type, null, workspaceScope, true);
hier.refresh(monitor);
for(IType subType : hier.getAllSubtypes(type))
subTypes.add(subType);
monitor.worked(1);
}
monitor.done();
return subTypes;
}
/** Fetch
* - directly dependent projects from a resource, or
* - all workspace OT projects if resource == null
*/
IJavaProject[] getProjects(IResource resource) {
/*
* Should we ever want to restrict the set of projects to those that have a direct
* dependency on the "current" project, we'd need to perform these steps:
*
* PDE scenarii:
* - determine the current plugin:
* - root = getJavaElement().getAncestor(PACKAGE_FRAGMENT_ROOT)
* - traverse getJavaElement().getJavaProject().getResolvedClasspath(true)
* - match javaProject.getPackageFragmentRoots(cpEntry) against root
* - when found extract pluginName = cpEntry.extraAttributes[o.e.ot.originBaseBundle*]
* - for each candidate project
* - fetch the AspectBindingReader
* (See org.eclipse.objectteams.otdt.internal.compiler.adaptor.ResourceProjectAdaptor.getAspectBindingReader(IProject))
* - check if an aspect binding exists towards pluginName
* This appears to be quite heavy weight, will only pay off if
* - number of OT-plugins is large
* - looking at a class from a non-WS plugin
*
* Plain-Java scenarii:
* - have no dependency information other than project dependencies, see next.
*
* Dependencies between workspace projects are already leveraged in calculateProjectsToSearch()
*/
IJavaProject[] projects = null;
if (resource != null) {
IProject project = resource.getProject();
projects = getProjectsToSearch(project);
} else {
IWorkspace ws = ResourcesPlugin.getWorkspace();
ArrayList<IJavaProject> projectList = new ArrayList<IJavaProject>();
for (IProject prj : ws.getRoot().getProjects())
if (isOTProject(prj) && prj.isOpen())
projectList.add(JavaCore.create(prj));
projects = projectList.toArray(new IJavaProject[projectList.size()]);
}
return projects;
}
private IJavaProject[] getProjectsToSearch(IProject baseProject)
{
Set<IJavaProject> result = new HashSet<IJavaProject>();
calculateProjectsToSearch(baseProject, result, true);
return result.toArray(new IJavaProject[result.size()]);
}
private boolean isOTProject(IProject project)
{
try
{
return project.hasNature(JavaCore.OTJ_NATURE_ID);
}
catch (CoreException ex)
{
return false;
}
}
private boolean isPluginProject(IProject project)
{
try
{
return project.hasNature(PDE_PLUGIN_NATURE_ID);
}
catch (CoreException ex)
{
return false;
}
}
private void calculateProjectsToSearch(IProject currentProject, Set<IJavaProject> allProjectsFound, boolean descend)
{
if (isOTProject(currentProject))
allProjectsFound.add(JavaCore.create(currentProject));
if (!descend)
return;
// don't search indirect dependencies of plug-in projects because aspectBindings must be declared directly:
descend = !isPluginProject(currentProject);
for(IProject referencingProject : currentProject.getReferencingProjects())
calculateProjectsToSearch(referencingProject, allProjectsFound, descend);
}
}