|
From: <caw...@us...> - 2007-08-24 17:02:43
|
Revision: 3071
http://rubyeclipse.svn.sourceforge.net/rubyeclipse/?rev=3071&view=rev
Author: cawilliams
Date: 2007-08-24 10:02:38 -0700 (Fri, 24 Aug 2007)
Log Message:
-----------
an initial cut at #4846 - Create a Call Hierarchy View
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IMethod.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/Openable.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyMethod.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java
Added Paths:
-----------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/HierarchyScope.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IMethod.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IMethod.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IMethod.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -45,4 +45,6 @@
public int getNumberOfParameters() throws RubyModelException;
+ public boolean isPrivate() throws RubyModelException;
+
}
\ No newline at end of file
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -210,4 +210,25 @@
*/
ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws RubyModelException;
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type, all of its supertypes, and all its subtypes in the workspace,
+ * considering types in the working copies with the given owner.
+ * In other words, the owner's working copies will take
+ * precedence over their original compilation units in the workspace.
+ * <p>
+ * Note that if a working copy is empty, it will be as if the original compilation
+ * unit had been deleted.
+ * <p>
+ *
+ * @param owner the owner of working copies that take precedence over their original compilation units
+ * @param monitor the given progress monitor
+ * @return a type hierarchy for this type containing
+ * this type, all of its supertypes, and all its subtypes in the workspace
+ * @exception RubyModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ * @since 3.0
+ */
+ ITypeHierarchy newTypeHierarchy(WorkingCopyOwner owner, IProgressMonitor monitor) throws RubyModelException;
+
}
\ No newline at end of file
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -3,6 +3,7 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.WorkingCopyOwner;
import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
@@ -142,7 +143,7 @@
/**
* Searches for matches of a given search pattern. Search patterns can be created using helper
- * methods (from a String pattern or a Java element) and encapsulate the description of what is
+ * methods (from a String pattern or a Ruby element) and encapsulate the description of what is
* being searched (for example, search method declarations in a case sensitive way).
*
* @param pattern the pattern to search
@@ -160,4 +161,17 @@
this.basicEngine.search(pattern, participants, scope, requestor, monitor);
}
+ /**
+ * Returns a Ruby search scope limited to the hierarchy of the given type.
+ * The Ruby elements resulting from a search with this scope will
+ * be types in this hierarchy, or members of the types in this hierarchy.
+ *
+ * @param type the focus of the hierarchy scope
+ * @return a new hierarchy scope
+ * @exception RubyModelException if the hierarchy could not be computed on the given type
+ */
+ public static IRubySearchScope createHierarchyScope(IType type) throws RubyModelException {
+ return BasicSearchEngine.createHierarchyScope(type);
+ }
+
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -926,5 +926,9 @@
return null;
}
+ public boolean isPrivate() throws RubyModelException {
+ return false;
+ }
+
}
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/Openable.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/Openable.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/Openable.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -102,7 +102,7 @@
IBuffer buffer = getBufferManager().getBuffer(this);
if (buffer == null) {
// try to (re)open a buffer
- buffer = openBuffer(null);
+ buffer = openBuffer(null, info);
}
return buffer;
}
@@ -113,8 +113,9 @@
* Opens a buffer on the contents of this element, and returns the buffer,
* or returns <code>null</code> if opening fails. By default, do nothing -
* subclasses that have buffers must override as required.
+ * @param info
*/
- protected IBuffer openBuffer(IProgressMonitor pm) {
+ protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws RubyModelException {
return null;
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyMethod.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyMethod.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyMethod.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -135,5 +135,9 @@
}
return method;
}
+
+ public boolean isPrivate() throws RubyModelException {
+ return getVisibility() == PRIVATE;
+ }
}
\ No newline at end of file
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -328,6 +328,20 @@
}
/**
+ * @see IType#newTypeHierarchy(WorkingCopyOwner, IProgressMonitor)
+ */
+ public ITypeHierarchy newTypeHierarchy(
+ WorkingCopyOwner owner,
+ IProgressMonitor monitor)
+ throws RubyModelException {
+
+ IRubyScript[] workingCopies = RubyModelManager.getRubyModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
+ CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
+ op.runOperation(monitor);
+ return op.getResult();
+ }
+
+ /**
* @see IType
*/
public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws RubyModelException {
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java 2007-08-24 17:02:19 UTC (rev 3070)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -561,4 +561,18 @@
}
return buffer.toString();
}
+
+ /**
+ * @see SearchEngine#createHierarchyScope(IType) for detailed comment.
+ */
+ public static IRubySearchScope createHierarchyScope(IType type) throws RubyModelException {
+ return createHierarchyScope(type, DefaultWorkingCopyOwner.PRIMARY);
+ }
+
+ /**
+ * @see SearchEngine#createHierarchyScope(IType,WorkingCopyOwner) for detailed comment.
+ */
+ public static IRubySearchScope createHierarchyScope(IType type, WorkingCopyOwner owner) throws RubyModelException {
+ return new HierarchyScope(type, owner);
+ }
}
Added: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/HierarchyScope.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/HierarchyScope.java (rev 0)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/HierarchyScope.java 2007-08-24 17:02:38 UTC (rev 3071)
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.rubypeople.rdt.internal.core.search;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.rubypeople.rdt.core.ILoadpathEntry;
+import org.rubypeople.rdt.core.IMember;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IRubyElementDelta;
+import org.rubypeople.rdt.core.IRubyModel;
+import org.rubypeople.rdt.core.IRubyProject;
+import org.rubypeople.rdt.core.ISourceFolderRoot;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.ITypeHierarchy;
+import org.rubypeople.rdt.core.RubyCore;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.core.WorkingCopyOwner;
+import org.rubypeople.rdt.core.search.IRubySearchScope;
+import org.rubypeople.rdt.internal.core.RubyElement;
+import org.rubypeople.rdt.internal.core.RubyModelManager;
+import org.rubypeople.rdt.internal.core.RubyProject;
+import org.rubypeople.rdt.internal.core.hierarchy.TypeHierarchy;
+
+/**
+ * Scope limited to the subtype and supertype hierarchy of a given type.
+ */
+public class HierarchyScope implements IRubySearchScope {
+
+ public IType focusType;
+ private String focusPath;
+ private WorkingCopyOwner owner;
+
+ private ITypeHierarchy hierarchy;
+ private IType[] types;
+ private HashSet resourcePaths;
+ private IPath[] enclosingProjectsAndJars;
+
+ protected IResource[] elements;
+ protected int elementCount;
+
+ public boolean needsRefresh;
+
+ /* (non-Rubydoc)
+ * Adds the given resource to this search scope.
+ */
+ public void add(IResource element) {
+ if (this.elementCount == this.elements.length) {
+ System.arraycopy(
+ this.elements,
+ 0,
+ this.elements = new IResource[this.elementCount * 2],
+ 0,
+ this.elementCount);
+ }
+ elements[elementCount++] = element;
+ }
+
+ /* (non-Rubydoc)
+ * Creates a new hiearchy scope for the given type.
+ */
+ public HierarchyScope(IType type, WorkingCopyOwner owner) throws RubyModelException {
+ this.focusType = type;
+ this.owner = owner;
+
+ this.enclosingProjectsAndJars = this.computeProjectsAndJars(type);
+
+ // resource path
+ ISourceFolderRoot root = (ISourceFolderRoot)type.getSourceFolder().getParent();
+ this.focusPath = type.getPath().toString();
+
+ this.needsRefresh = true;
+
+ //disabled for now as this could be expensive
+ //RubyModelManager.getRubyModelManager().rememberScope(this);
+ }
+ private void buildResourceVector() {
+ HashMap resources = new HashMap();
+ HashMap paths = new HashMap();
+ this.types = this.hierarchy.getAllTypes();
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+ for (int i = 0; i < this.types.length; i++) {
+ IType type = this.types[i];
+ IResource resource = type.getResource();
+ if (resource != null && resources.get(resource) == null) {
+ resources.put(resource, resource);
+ add(resource);
+ }
+ ISourceFolderRoot root =
+ (ISourceFolderRoot) type.getSourceFolder().getParent();
+
+ // type is a project
+ paths.put(type.getRubyProject().getProject().getFullPath(), type);
+
+ }
+ this.enclosingProjectsAndJars = new IPath[paths.size()];
+ int i = 0;
+ for (Iterator iter = paths.keySet().iterator(); iter.hasNext();) {
+ this.enclosingProjectsAndJars[i++] = (IPath) iter.next();
+ }
+ }
+ /*
+ * Computes the paths of projects and jars that the hierarchy on the given type could contain.
+ * This is a super set of the project and jar paths once the hierarchy is computed.
+ */
+ private IPath[] computeProjectsAndJars(IType type) throws RubyModelException {
+ HashSet set = new HashSet();
+ ISourceFolderRoot root = (ISourceFolderRoot)type.getSourceFolder().getParent();
+ if (root.isArchive()) {
+ // add the root
+ set.add(root.getPath());
+ // add all projects that reference this archive and their dependents
+ IPath rootPath = root.getPath();
+ IRubyModel model = RubyModelManager.getRubyModelManager().getRubyModel();
+ IRubyProject[] projects = model.getRubyProjects();
+ HashSet visited = new HashSet();
+ for (int i = 0; i < projects.length; i++) {
+ RubyProject project = (RubyProject) projects[i];
+ ILoadpathEntry[] classpath = project.getResolvedLoadpath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+ for (int j = 0; j < classpath.length; j++) {
+ if (rootPath.equals(classpath[j].getPath())) {
+ // add the project and its binary pkg fragment roots
+ ISourceFolderRoot[] roots = project.getAllSourceFolderRoots();
+ set.add(project.getPath());
+ // add the dependent projects
+ this.computeDependents(project, set, visited);
+ break;
+ }
+ }
+ }
+ } else {
+ // add all the project's pkg fragment roots
+ IRubyProject project = (IRubyProject)root.getParent();
+ ISourceFolderRoot[] roots = project.getAllSourceFolderRoots();
+ for (int i = 0; i < roots.length; i++) {
+ ISourceFolderRoot pkgFragmentRoot = roots[i];
+ set.add(pkgFragmentRoot.getParent().getPath());
+ }
+ // add the dependent projects
+ this.computeDependents(project, set, new HashSet());
+ }
+ IPath[] result = new IPath[set.size()];
+ set.toArray(result);
+ return result;
+ }
+ private void computeDependents(IRubyProject project, HashSet set, HashSet visited) {
+ if (visited.contains(project)) return;
+ visited.add(project);
+ IProject[] dependents = project.getProject().getReferencingProjects();
+ for (int i = 0; i < dependents.length; i++) {
+ try {
+ IRubyProject dependent = RubyCore.create(dependents[i]);
+ ISourceFolderRoot[] roots = dependent.getSourceFolderRoots();
+ set.add(dependent.getPath());
+ for (int j = 0; j < roots.length; j++) {
+ ISourceFolderRoot pkgFragmentRoot = roots[j];
+ if (pkgFragmentRoot.isArchive()) {
+ set.add(pkgFragmentRoot.getPath());
+ }
+ }
+ this.computeDependents(dependent, set, visited);
+ } catch (RubyModelException e) {
+ // project is not a java project
+ }
+ }
+ }
+ /* (non-Rubydoc)
+ * @see IRubySearchScope#encloses(String)
+ */
+ public boolean encloses(String resourcePath) {
+ if (this.hierarchy == null) {
+ if (resourcePath.equals(this.focusPath)) {
+ return true;
+ } else {
+ if (this.needsRefresh) {
+ try {
+ this.initialize();
+ } catch (RubyModelException e) {
+ return false;
+ }
+ } else {
+ // the scope is used only to find enclosing projects and jars
+ // clients is responsible for filtering out elements not in the hierarchy (see SearchEngine)
+ return true;
+ }
+ }
+ }
+ if (this.needsRefresh) {
+ try {
+ this.refresh();
+ } catch(RubyModelException e) {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < this.elementCount; i++) {
+ if (resourcePath.startsWith(this.elements[i].getFullPath().toString())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ /* (non-Rubydoc)
+ * @see IRubySearchScope#encloses(IRubyElement)
+ */
+ public boolean encloses(IRubyElement element) {
+ if (this.hierarchy == null) {
+ if (this.focusType.equals(element.getAncestor(IRubyElement.TYPE))) {
+ return true;
+ } else {
+ if (this.needsRefresh) {
+ try {
+ this.initialize();
+ } catch (RubyModelException e) {
+ return false;
+ }
+ } else {
+ // the scope is used only to find enclosing projects and jars
+ // clients is responsible for filtering out elements not in the hierarchy (see SearchEngine)
+ return true;
+ }
+ }
+ }
+ if (this.needsRefresh) {
+ try {
+ this.refresh();
+ } catch(RubyModelException e) {
+ return false;
+ }
+ }
+ IType type = null;
+ if (element instanceof IType) {
+ type = (IType) element;
+ } else if (element instanceof IMember) {
+ type = ((IMember) element).getDeclaringType();
+ }
+ if (type != null) {
+ if (this.hierarchy.contains(type)) {
+ return true;
+ } else {
+ // be flexible: look at original element (see bug 14106 Declarations in Hierarchy does not find declarations in hierarchy)
+ IType original;
+ if ((original = (IType)type.getPrimaryElement()) != null) {
+ return this.hierarchy.contains(original);
+ }
+ }
+ }
+ return false;
+ }
+ /* (non-Rubydoc)
+ * @see IRubySearchScope#enclosingProjectsAndJars()
+ * @deprecated
+ */
+ public IPath[] enclosingProjectsAndJars() {
+ if (this.needsRefresh) {
+ try {
+ this.refresh();
+ } catch(RubyModelException e) {
+ return new IPath[0];
+ }
+ }
+ return this.enclosingProjectsAndJars;
+ }
+ protected void initialize() throws RubyModelException {
+ this.resourcePaths = new HashSet();
+ this.elements = new IResource[5];
+ this.elementCount = 0;
+ this.needsRefresh = false;
+ if (this.hierarchy == null) {
+ this.hierarchy = this.focusType.newTypeHierarchy(this.owner, null);
+ } else {
+ this.hierarchy.refresh(null);
+ }
+ this.buildResourceVector();
+ }
+ /*
+ * @see AbstractSearchScope#processDelta(IRubyElementDelta)
+ */
+ public void processDelta(IRubyElementDelta delta) {
+ if (this.needsRefresh) return;
+ this.needsRefresh = this.hierarchy == null ? false : ((TypeHierarchy)this.hierarchy).isAffected(delta);
+ }
+ protected void refresh() throws RubyModelException {
+ if (this.hierarchy != null) {
+ this.initialize();
+ }
+ }
+ public String toString() {
+ return "HierarchyScope on " + ((RubyElement)this.focusType).toStringWithAncestors(); //$NON-NLS-1$
+ }
+
+}
Property changes on: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/HierarchyScope.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|