|
From: <caw...@us...> - 2007-04-13 18:50:02
|
Revision: 2311
http://svn.sourceforge.net/rubyeclipse/?rev=2311&view=rev
Author: cawilliams
Date: 2007-04-13 11:50:01 -0700 (Fri, 13 Apr 2007)
Log Message:
-----------
Ha ha! I finally got this stuff working! I can actually look up constant and type names very quickly. Rock on!
Modified Paths:
--------------
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/Flags.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchDocument.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/DeltaProcessor.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyModelManager.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolderRoot.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/IndexManager.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexer.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexerRequestor.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldPattern.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/PatternLocator.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/TypeDeclarationLocator.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/TypeDeclarationPattern.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/processing/JobManager.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/CharOperation.java
Added Paths:
-----------
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/CollectingSearchRequestor.java
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/Flags.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/Flags.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/Flags.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -16,6 +16,8 @@
* @since 3.0
*/
public static final int AccDefault = 0;
+
+ public static final int AccModule = 0x0001;
/**
* Returns whether the given integer includes the <code>private</code> modifier.
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -32,4 +32,22 @@
* so as to better narrow down the search.
*/
int ALL_OCCURRENCES= 3;
+
+ /**
+ * When searching for field matches, it will exclusively find read accesses, as
+ * opposed to write accesses. Note that some expressions are considered both
+ * as field read/write accesses: for example, x++; x+= 1;
+ *
+ * @since 2.0
+ */
+ int READ_ACCESSES = 4;
+
+ /**
+ * When searching for field matches, it will exclusively find write accesses, as
+ * opposed to read accesses. Note that some expressions are considered both
+ * as field read/write accesses: for example, x++; x+= 1;
+ *
+ * @since 2.0
+ */
+ int WRITE_ACCESSES = 5;
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchDocument.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchDocument.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchDocument.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -70,6 +70,18 @@
}
return this.script;
}
+
+ /**
+ * Returns the path to the original document to publicly mention in index
+ * or search results. This path is a string that uniquely identifies the document.
+ * Most of the time it is a workspace-relative path, but it can also be a file system path,
+ * or a path inside a zip file.
+ *
+ * @return the path to the document
+ */
+ public final String getPath() {
+ return this.documentPath;
+ }
private List<IRubyElement> getChildrenOfType(IParent parent, int type) {
List<IRubyElement> elements = new ArrayList<IRubyElement>();
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -3,6 +3,7 @@
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.internal.core.search.indexing.IIndexConstants;
import org.rubypeople.rdt.internal.core.search.matching.ConstructorPattern;
+import org.rubypeople.rdt.internal.core.search.matching.FieldPattern;
import org.rubypeople.rdt.internal.core.search.matching.InternalSearchPattern;
import org.rubypeople.rdt.internal.core.search.matching.MethodPattern;
import org.rubypeople.rdt.internal.core.search.matching.OrPattern;
@@ -251,6 +252,12 @@
return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.TYPE_SUFFIX);
case IRubyElement.METHOD:
return createMethodOrConstructorPattern(stringPattern, limitTo, matchRule, false/*not a constructor*/);
+ case IRubyElement.FIELD:
+ case IRubyElement.CONSTANT:
+ case IRubyElement.GLOBAL:
+ case IRubyElement.CLASS_VAR:
+ case IRubyElement.INSTANCE_VAR:
+ return createFieldPattern(stringPattern, limitTo, matchRule);
default:
break;
}
@@ -258,6 +265,55 @@
}
/**
+ * Field pattern are formed by [declaringType.]name[ type]
+ * e.g. java.lang.String.serialVersionUID long
+ * field*
+ */
+ private static SearchPattern createFieldPattern(String patternString, int limitTo, int matchRule) {
+ String fieldName = patternString;
+ if (fieldName == null) return null;
+
+ char[] fieldNameChars = fieldName.toCharArray();
+ if (fieldNameChars.length == 1 && fieldNameChars[0] == '*') fieldNameChars = null;
+
+ char[] declaringTypeQualification = null, declaringTypeSimpleName = null;
+ char[] typeQualification = null, typeSimpleName = null;
+
+ // Create field pattern
+ boolean findDeclarations = false;
+ boolean readAccess = false;
+ boolean writeAccess = false;
+ switch (limitTo) {
+ case IRubySearchConstants.DECLARATIONS :
+ findDeclarations = true;
+ break;
+ case IRubySearchConstants.REFERENCES :
+ readAccess = true;
+ writeAccess = true;
+ break;
+ case IRubySearchConstants.READ_ACCESSES :
+ readAccess = true;
+ break;
+ case IRubySearchConstants.WRITE_ACCESSES :
+ writeAccess = true;
+ break;
+ case IRubySearchConstants.ALL_OCCURRENCES :
+ findDeclarations = true;
+ readAccess = true;
+ writeAccess = true;
+ break;
+ }
+ return new FieldPattern(
+ findDeclarations,
+ readAccess,
+ writeAccess,
+ fieldNameChars,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ matchRule);
+ }
+
+ /**
* Returns whether the given name matches the given pattern.
* <p>
* This method should be re-implemented in subclasses that need to define how
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -11,6 +11,7 @@
import java.util.Set;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.jruby.ast.ClassNode;
import org.jruby.ast.ClassVarAsgnNode;
@@ -43,6 +44,7 @@
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.search.IRubySearchConstants;
import org.rubypeople.rdt.core.search.IRubySearchScope;
+import org.rubypeople.rdt.core.search.SearchMatch;
import org.rubypeople.rdt.core.search.SearchParticipant;
import org.rubypeople.rdt.core.search.SearchPattern;
import org.rubypeople.rdt.internal.core.RubyElement;
@@ -50,6 +52,7 @@
import org.rubypeople.rdt.internal.core.RubyType;
import org.rubypeople.rdt.internal.core.parser.RubyParser;
import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
+import org.rubypeople.rdt.internal.core.search.CollectingSearchRequestor;
import org.rubypeople.rdt.internal.core.util.ASTUtil;
import org.rubypeople.rdt.internal.ti.DefaultTypeInferrer;
import org.rubypeople.rdt.internal.ti.ITypeGuess;
@@ -139,11 +142,24 @@
}
private void suggestGlobals() {
- Set<String> globals = BasicSearchEngine.getGlobalNames(fContext.getScript());
- for (String name : globals) {
+ BasicSearchEngine engine = new BasicSearchEngine();
+ SearchParticipant[] participants = new SearchParticipant[] { BasicSearchEngine.getDefaultSearchParticipant() };
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.GLOBAL, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript().getRubyProject()});
+ CollectingSearchRequestor requestor = new CollectingSearchRequestor();
+ try {
+ engine.search(pattern, participants, scope, requestor, null);
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ for (SearchMatch match: requestor.getResults()) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ String name = element.getElementName();
if (!fContext.prefixStartsWith(name))
continue;
CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.FIELD_REF, name);
+ proposal.setType(name);
fRequestor.accept(proposal);
}
}
@@ -153,9 +169,16 @@
SearchParticipant[] participants = new SearchParticipant[] { BasicSearchEngine.getDefaultSearchParticipant() };
SearchPattern pattern = SearchPattern.createPattern(IRubyElement.TYPE, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript().getRubyProject()});
- engine.search(pattern, participants, scope, requestor, null);
- Set<String> types = BasicSearchEngine.getTypeNames(fContext.getScript());
- for (String name : types) {
+ CollectingSearchRequestor requestor = new CollectingSearchRequestor();
+ try {
+ engine.search(pattern, participants, scope, requestor, null);
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ for (SearchMatch match: requestor.getResults()) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ String name = element.getElementName();
if (!fContext.prefixStartsWith(name))
continue;
CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.TYPE_REF, name);
@@ -171,11 +194,25 @@
}
private void suggestConstantNames() {
- Set<String> types = BasicSearchEngine.getConstantNames(fContext.getScript());
- for (String name : types) {
+ BasicSearchEngine engine = new BasicSearchEngine();
+ SearchParticipant[] participants = new SearchParticipant[] { BasicSearchEngine.getDefaultSearchParticipant() };
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.CONSTANT, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript()});
+ CollectingSearchRequestor requestor = new CollectingSearchRequestor();
+ try {
+ engine.search(pattern, participants, scope, requestor, null);
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ for (SearchMatch match: requestor.getResults()) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ String name = element.getElementName();
+ // TODO Skip if not starting with an uppercase?
if (!fContext.prefixStartsWith(name))
continue;
CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.FIELD_REF, name);
+ proposal.setType(name);
fRequestor.accept(proposal);
}
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/DeltaProcessor.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/DeltaProcessor.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/DeltaProcessor.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -9,6 +9,7 @@
import java.util.Map;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
@@ -30,10 +31,13 @@
import org.rubypeople.rdt.core.IRubyModel;
import org.rubypeople.rdt.core.IRubyProject;
import org.rubypeople.rdt.core.IRubyScript;
+import org.rubypeople.rdt.core.ISourceFolder;
import org.rubypeople.rdt.core.ISourceFolderRoot;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.core.builder.RubyBuilder;
+import org.rubypeople.rdt.internal.core.search.indexing.IndexManager;
+import org.rubypeople.rdt.internal.core.util.CharOperation;
import org.rubypeople.rdt.internal.core.util.Util;
public class DeltaProcessor {
@@ -177,6 +181,8 @@
* is.
*/
public int overridenEventType = -1;
+
+ private SourceParser sourceElementParserCache;
public DeltaProcessor(DeltaProcessingState state, RubyModelManager manager) {
this.state = state;
@@ -1298,117 +1304,6 @@
return (ArrayList)this.state.otherRoots.get(path);
}
- /*
- * Update the current delta (ie. add/remove/change the given element) and
- * update the correponding index. Returns whether the children of the given
- * delta must be processed. @throws a RubyModelException if the delta
- * doesn't correspond to a ruby element of the given type.
- */
- public boolean updateCurrentDeltaAndIndex(IResourceDelta delta, int elementType, RootInfo rootInfo) {
- Openable element;
- switch (delta.getKind()) {
- case IResourceDelta.ADDED:
- IResource deltaRes = delta.getResource();
- element = createElement(deltaRes, elementType, rootInfo);
- if (element == null) {
- // resource might be containing shared roots (see bug 19058)
- this.state.updateRoots(deltaRes.getFullPath(), delta, this);
- return rootInfo != null && rootInfo.inclusionPatterns != null;
- }
- elementAdded(element, delta, rootInfo);
- return elementType == IRubyElement.SOURCE_FOLDER;
- case IResourceDelta.REMOVED:
- deltaRes = delta.getResource();
- element = createElement(deltaRes, elementType, rootInfo);
- if (element == null) {
- // resource might be containing shared roots (see bug 19058)
- this.state.updateRoots(deltaRes.getFullPath(), delta, this);
- return rootInfo != null && rootInfo.inclusionPatterns != null;
- }
- elementRemoved(element, delta, rootInfo);
-
- if (deltaRes.getType() == IResource.PROJECT) {
- // reset the corresponding project built state, since cannot
- // reuse if added back
- if (RubyBuilder.DEBUG)
- System.out.println("Clearing last state for removed project : " + deltaRes); //$NON-NLS-1$
- this.manager.setLastBuiltState((IProject)deltaRes, null /*no state*/);
-
- // clean up previous session containers (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89850)
- this.manager.previousSessionContainers.remove(element);
- }
- return elementType == IRubyElement.SOURCE_FOLDER;
- case IResourceDelta.CHANGED:
- int flags = delta.getFlags();
- if ((flags & IResourceDelta.CONTENT) != 0 || (flags & IResourceDelta.ENCODING) != 0) {
- // content or encoding has changed
- element = createElement(delta.getResource(), elementType, rootInfo);
- if (element == null) return false;
- contentChanged(element);
- } else if (elementType == IRubyElement.RUBY_PROJECT) {
- if ((flags & IResourceDelta.OPEN) != 0) {
- // project has been opened or closed
- IProject res = (IProject) delta.getResource();
- element = createElement(res, elementType, rootInfo);
- if (element == null) { return false; }
- if (res.isOpen()) {
- if (RubyProject.hasRubyNature(res)) {
- addToParentInfo(element);
- currentDelta().opened(element);
- this.state.updateRoots(element.getPath(), delta, this);
-
- // refresh src folder roots and caches of the project (and its dependents)
- this.rootsToRefresh.add((IRubyProject)element);
- this.projectCachesToReset.add((IRubyProject)element);
-
-// this.manager.indexManager.indexAll(res);
- }
- } else {
- RubyModel javaModel = this.manager.getRubyModel();
- boolean wasJavaProject = javaModel.findRubyProject(res) != null;
- if (wasJavaProject) {
- close(element);
- removeFromParentInfo(element);
- currentDelta().closed(element);
- }
- }
- return false; // when a project is open/closed don't
- // process children
- }
- if ((flags & IResourceDelta.DESCRIPTION) != 0) {
- IProject res = (IProject) delta.getResource();
- RubyModel javaModel = this.manager.getRubyModel();
- boolean wasJavaProject = javaModel.findRubyProject(res) != null;
- boolean isJavaProject = RubyProject.hasRubyNature(res);
- if (wasJavaProject != isJavaProject) {
- // project's nature has been added or removed
- element = this.createElement(res, elementType, rootInfo);
- if (element == null) return false; // note its
- // resources are
- // still visible as
- // roots to other
- // projects
- if (isJavaProject) {
- elementAdded(element, delta, rootInfo);
- } else {
- elementRemoved(element, delta, rootInfo);
- // reset the corresponding project built state,
- // since cannot reuse if added back
- if (RubyBuilder.DEBUG)
- System.out
- .println("Clearing last state for project losing Ruby nature: " + res); //$NON-NLS-1$
-
- }
- return false; // when a project's nature is
- // added/removed don't process children
- }
- }
- }
- return true;
- }
- return true;
- }
-
/*
* Closes the given element, which removes it from the cache of open
* elements.
@@ -1879,5 +1774,245 @@
}
}
}
+
+ private void updateIndex(Openable element, IResourceDelta delta) {
+
+ IndexManager indexManager = this.manager.getIndexManager();
+ if (indexManager == null)
+ return;
+
+ switch (element.getElementType()) {
+ case IRubyElement.RUBY_PROJECT :
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ indexManager.indexAll(element.getRubyProject().getProject());
+ break;
+ case IResourceDelta.REMOVED :
+ indexManager.removeIndexFamily(element.getRubyProject().getProject().getFullPath());
+ // NB: Discarding index jobs belonging to this project was done during PRE_DELETE
+ break;
+ // NB: Update of index if project is opened, closed, or its java nature is added or removed
+ // is done in updateCurrentDeltaAndIndex
+ }
+ break;
+ case IRubyElement.SOURCE_FOLDER_ROOT :
+ if (element instanceof ExternalSourceFolderRoot) {
+ ExternalSourceFolderRoot root = (ExternalSourceFolderRoot)element;
+ // index jar file only once (if the root is in its declaring project)
+ IPath jarPath = root.getPath();
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED:
+ // index the new jar
+ indexManager.indexLibrary(jarPath, root.getRubyProject().getProject());
+ break;
+ case IResourceDelta.CHANGED:
+ // first remove the index so that it is forced to be re-indexed
+ indexManager.removeIndex(jarPath);
+ // then index the jar
+ indexManager.indexLibrary(jarPath, root.getRubyProject().getProject());
+ break;
+ case IResourceDelta.REMOVED:
+ // the jar was physically removed: remove the index
+ indexManager.discardJobs(jarPath.toString());
+ indexManager.removeIndex(jarPath);
+ break;
+ }
+ break;
+ }
+ int kind = delta.getKind();
+ if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
+ SourceFolderRoot root = (SourceFolderRoot)element;
+ this.updateRootIndex(root, CharOperation.NO_STRINGS, delta);
+ break;
+ }
+ // don't break as packages of the package fragment root can be indexed below
+ case IRubyElement.SOURCE_FOLDER :
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED:
+ case IResourceDelta.REMOVED:
+ ISourceFolder pkg = null;
+ if (element instanceof ISourceFolderRoot) {
+ SourceFolderRoot root = (SourceFolderRoot)element;
+ pkg = root.getSourceFolder(CharOperation.NO_STRINGS);
+ } else {
+ pkg = (ISourceFolder)element;
+ }
+ RootInfo rootInfo = rootInfo(pkg.getParent().getPath(), delta.getKind());
+ boolean isSource =
+ rootInfo == null // if null, defaults to source
+ || rootInfo.entryKind == ILoadpathEntry.CPE_SOURCE;
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ IResourceDelta child = children[i];
+ IResource resource = child.getResource();
+ // TODO (philippe) Why do this? Every child is added anyway as the delta is walked
+ if (resource instanceof IFile) {
+ String name = resource.getName();
+ if (isSource) {
+ if (org.rubypeople.rdt.internal.core.util.Util.isRubyLikeFileName(name)) {
+ Openable cu = (Openable)pkg.getRubyScript(name);
+ this.updateIndex(cu, child);
+ }
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case IRubyElement.SCRIPT :
+ IFile file = (IFile) delta.getResource();
+ switch (delta.getKind()) {
+ case IResourceDelta.CHANGED :
+ // no need to index if the content has not changed
+ int flags = delta.getFlags();
+ if ((flags & IResourceDelta.CONTENT) == 0 && (flags & IResourceDelta.ENCODING) == 0)
+ break;
+ case IResourceDelta.ADDED :
+ indexManager.addSource(file, file.getProject().getFullPath(), getSourceElementParser(element));
+ // Clean file from secondary types cache but do not update indexing secondary type cache as it will be updated through indexing itself
+ this.manager.secondaryTypesRemoving(file, false);
+ break;
+ case IResourceDelta.REMOVED :
+ indexManager.remove(Util.relativePath(file.getFullPath(), 1/*remove project segment*/), file.getProject().getFullPath());
+ // Clean file from secondary types cache and update indexing secondary type cache as indexing cannot remove secondary types from cache
+ this.manager.secondaryTypesRemoving(file, true);
+ break;
+ }
+ }
+ }
+ private SourceParser getSourceElementParser(Openable element) {
+ if (this.sourceElementParserCache == null)
+ this.sourceElementParserCache = this.manager.getIndexManager().getSourceElementParser(element.getRubyProject(), null/*requestor will be set by indexer*/);
+ return this.sourceElementParserCache;
+ }
+
+ /*
+ * Updates the index of the given root (assuming it's an addition or a removal).
+ * This is done recusively, pkg being the current package.
+ */
+ private void updateRootIndex(SourceFolderRoot root, String[] pkgName, IResourceDelta delta) {
+ Openable pkg = root.getSourceFolder(pkgName);
+ this.updateIndex(pkg, delta);
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ IResourceDelta child = children[i];
+ IResource resource = child.getResource();
+ if (resource instanceof IFolder) {
+ String[] subpkgName = Util.arrayConcat(pkgName, resource.getName());
+ this.updateRootIndex(root, subpkgName, child);
+ }
+ }
+ }
+
+ /*
+ * Update the current delta (ie. add/remove/change the given element) and update the correponding index.
+ * Returns whether the children of the given delta must be processed.
+ * @throws a JavaModelException if the delta doesn't correspond to a java element of the given type.
+ */
+ public boolean updateCurrentDeltaAndIndex(IResourceDelta delta, int elementType, RootInfo rootInfo) {
+ Openable element;
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ IResource deltaRes = delta.getResource();
+ element = createElement(deltaRes, elementType, rootInfo);
+ if (element == null) {
+ // resource might be containing shared roots (see bug 19058)
+ this.state.updateRoots(deltaRes.getFullPath(), delta, this);
+ return rootInfo != null && rootInfo.inclusionPatterns != null;
+ }
+ updateIndex(element, delta);
+ elementAdded(element, delta, rootInfo);
+ return elementType == IRubyElement.SOURCE_FOLDER;
+ case IResourceDelta.REMOVED :
+ deltaRes = delta.getResource();
+ element = createElement(deltaRes, elementType, rootInfo);
+ if (element == null) {
+ // resource might be containing shared roots (see bug 19058)
+ this.state.updateRoots(deltaRes.getFullPath(), delta, this);
+ return rootInfo != null && rootInfo.inclusionPatterns != null;
+ }
+ updateIndex(element, delta);
+ elementRemoved(element, delta, rootInfo);
+
+ if (deltaRes.getType() == IResource.PROJECT){
+ // reset the corresponding project built state, since cannot reuse if added back
+ if (RubyBuilder.DEBUG)
+ System.out.println("Clearing last state for removed project : " + deltaRes); //$NON-NLS-1$
+ this.manager.setLastBuiltState((IProject)deltaRes, null /*no state*/);
+
+ // clean up previous session containers (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89850)
+ this.manager.previousSessionContainers.remove(element);
+ }
+ return elementType == IRubyElement.SOURCE_FOLDER;
+ case IResourceDelta.CHANGED :
+ int flags = delta.getFlags();
+ if ((flags & IResourceDelta.CONTENT) != 0 || (flags & IResourceDelta.ENCODING) != 0) {
+ // content or encoding has changed
+ element = createElement(delta.getResource(), elementType, rootInfo);
+ if (element == null) return false;
+ updateIndex(element, delta);
+ contentChanged(element);
+ } else if (elementType == IRubyElement.RUBY_PROJECT) {
+ if ((flags & IResourceDelta.OPEN) != 0) {
+ // project has been opened or closed
+ IProject res = (IProject)delta.getResource();
+ element = createElement(res, elementType, rootInfo);
+ if (element == null) {
+ // resource might be containing shared roots (see bug 19058)
+ this.state.updateRoots(res.getFullPath(), delta, this);
+ return false;
+ }
+ if (res.isOpen()) {
+ if (RubyProject.hasRubyNature(res)) {
+ addToParentInfo(element);
+ currentDelta().opened(element);
+ this.state.updateRoots(element.getPath(), delta, this);
+
+ // refresh pkg fragment roots and caches of the project (and its dependents)
+ this.rootsToRefresh.add((IRubyProject)element);
+ this.projectCachesToReset.add((IRubyProject)element);
+
+ this.manager.getIndexManager().indexAll(res);
+ }
+ } else {
+ boolean wasJavaProject = this.state.findRubyProject(res.getName()) != null;
+ if (wasJavaProject) {
+ close(element);
+ removeFromParentInfo(element);
+ currentDelta().closed(element);
+ this.manager.getIndexManager().discardJobs(element.getElementName());
+ this.manager.getIndexManager().removeIndexFamily(res.getFullPath());
+ }
+ }
+ return false; // when a project is open/closed don't process children
+ }
+ if ((flags & IResourceDelta.DESCRIPTION) != 0) {
+ IProject res = (IProject)delta.getResource();
+ boolean wasJavaProject = this.state.findRubyProject(res.getName()) != null;
+ boolean isJavaProject = RubyProject.hasRubyNature(res);
+ if (wasJavaProject != isJavaProject) {
+ // project's nature has been added or removed
+ element = this.createElement(res, elementType, rootInfo);
+ if (element == null) return false; // note its resources are still visible as roots to other projects
+ if (isJavaProject) {
+ elementAdded(element, delta, rootInfo);
+ this.manager.getIndexManager().indexAll(res);
+ } else {
+ elementRemoved(element, delta, rootInfo);
+ this.manager.getIndexManager().discardJobs(element.getElementName());
+ this.manager.getIndexManager().removeIndexFamily(res.getFullPath());
+ // reset the corresponding project built state, since cannot reuse if added back
+ if (RubyBuilder.DEBUG)
+ System.out.println("Clearing last state for project loosing Java nature: " + res); //$NON-NLS-1$
+ this.manager.setLastBuiltState(res, null /*no state*/);
+ }
+ return false; // when a project's nature is added/removed don't process children
+ }
+ }
+ }
+ return true;
+ }
+ return true;
+ }
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyModelManager.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyModelManager.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyModelManager.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -75,6 +75,7 @@
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.ISourceFolder;
import org.rubypeople.rdt.core.ISourceFolderRoot;
+import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.LoadpathContainerInitializer;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
@@ -115,6 +116,7 @@
public static final String DELTA_LISTENER_PERF = RubyCore.PLUGIN_ID + "/perf/rubydeltalistener"; //$NON-NLS-1$
public static final String RECONCILE_PERF = RubyCore.PLUGIN_ID + "/perf/reconcile"; //$NON-NLS-1$
+ private final static String INDEXED_SECONDARY_TYPES = "#@*_indexing secondary cache_*@#"; //$NON-NLS-1$
/**
* Name of the extension point for contributing classpath variable initializers
@@ -746,6 +748,7 @@
public Map resolvedPathToRawEntries; // reverse map from resolved
// path to raw entries
public IPath outputLocation;
+ public Hashtable secondaryTypes;
public IEclipsePreferences preferences;
public Hashtable options;
@@ -943,7 +946,7 @@
| IResourceChangeEvent.PRE_DELETE
| IResourceChangeEvent.PRE_CLOSE);
-// startIndexing();
+ startIndexing();
// process deltas since last activated in indexer thread so that indexes are up-to-date.
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658
@@ -980,6 +983,14 @@
}
}
+ /**
+ * Initiate the background indexing process.
+ * This should be deferred after the plugin activation.
+ */
+ private void startIndexing() {
+ getIndexManager().reset();
+ }
+
public void loadVariablesAndContainers() throws CoreException {
// backward compatibility, consider persistent property
QualifiedName qName = new QualifiedName(RubyCore.PLUGIN_ID, "variables"); //$NON-NLS-1$
@@ -2783,4 +2794,120 @@
return indexManager;
}
+ /**
+ * Remove from secondary types cache all types belonging to a given file.
+ * Clean secondary types cache built while indexing if requested.
+ *
+ * Project's secondary types cache is found using file location.
+ *
+ * @param file File to remove
+ */
+ public void secondaryTypesRemoving(IFile file, boolean cleanIndexCache) {
+ if (VERBOSE) {
+ StringBuffer buffer = new StringBuffer("JavaModelManager.removeFromSecondaryTypesCache("); //$NON-NLS-1$
+ buffer.append(file.getName());
+ buffer.append(')');
+ Util.verbose(buffer.toString());
+ }
+ if (file != null) {
+ PerProjectInfo projectInfo = getPerProjectInfo(file.getProject(), false);
+ if (projectInfo != null && projectInfo.secondaryTypes != null) {
+ if (VERBOSE) {
+ Util.verbose("-> remove file from cache of project: "+file.getProject().getName()); //$NON-NLS-1$
+ }
+
+ // Clean current cache
+ secondaryTypesRemoving(projectInfo.secondaryTypes, file);
+
+ // Clean indexing cache if necessary
+ if (!cleanIndexCache) return;
+ HashMap indexingCache = (HashMap) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
+ if (indexingCache != null) {
+ Set keys = indexingCache.keySet();
+ int filesSize = keys.size(), filesCount = 0;
+ IFile[] removed = null;
+ Iterator cachedFiles = keys.iterator();
+ while (cachedFiles.hasNext()) {
+ IFile cachedFile = (IFile) cachedFiles.next();
+ if (file.equals(cachedFile)) {
+ if (removed == null) removed = new IFile[filesSize];
+ filesSize--;
+ removed[filesCount++] = cachedFile;
+ }
+ }
+ if (removed != null) {
+ for (int i=0; i<filesCount; i++) {
+ indexingCache.remove(removed[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Remove from a given cache map all secondary types belonging to a given file.
+ * Note that there can have several secondary types per file...
+ */
+ private void secondaryTypesRemoving(Hashtable secondaryTypesMap, IFile file) {
+ if (VERBOSE) {
+ StringBuffer buffer = new StringBuffer("RubyModelManager.removeSecondaryTypesFromMap("); //$NON-NLS-1$
+ Iterator keys = secondaryTypesMap.keySet().iterator();
+ while (keys.hasNext()) {
+ String qualifiedName = (String) keys.next();
+ buffer.append(qualifiedName+':'+secondaryTypesMap.get(qualifiedName));
+ }
+ buffer.append(',');
+ buffer.append(file.getFullPath());
+ buffer.append(')');
+ Util.verbose(buffer.toString());
+ }
+ Set packageKeys = secondaryTypesMap.keySet();
+ int packagesSize = packageKeys.size(), removedPackagesCount = 0;
+ String[] removedPackages = null;
+ Iterator packages = packageKeys.iterator();
+ while (packages.hasNext()) {
+ String packName = (String) packages.next();
+ if (packName != INDEXED_SECONDARY_TYPES) { // skip indexing cache entry if present (!= is intentional)
+ HashMap types = (HashMap) secondaryTypesMap.get(packName);
+ Set nameKeys = types.keySet();
+ int namesSize = nameKeys.size(), removedNamesCount = 0;
+ String[] removedNames = null;
+ Iterator names = nameKeys.iterator();
+ while (names.hasNext()) {
+ String typeName = (String) names.next();
+ IType type = (IType) types.get(typeName);
+ if (file.equals(type.getResource())) {
+ if (removedNames == null) removedNames = new String[namesSize];
+ namesSize--;
+ removedNames[removedNamesCount++] = typeName;
+ }
+ }
+ if (removedNames != null) {
+ for (int i=0; i<removedNamesCount; i++) {
+ types.remove(removedNames[i]);
+ }
+ }
+ if (types.size() == 0) {
+ if (removedPackages == null) removedPackages = new String[packagesSize];
+ packagesSize--;
+ removedPackages[removedPackagesCount++] = packName;
+ }
+ }
+ }
+ if (removedPackages != null) {
+ for (int i=0; i<removedPackagesCount; i++) {
+ secondaryTypesMap.remove(removedPackages[i]);
+ }
+ }
+ if (VERBOSE) {
+ Util.verbose(" - new secondary types map:"); //$NON-NLS-1$
+ Iterator keys = secondaryTypesMap.keySet().iterator();
+ while (keys.hasNext()) {
+ String qualifiedName = (String) keys.next();
+ Util.verbose(" + "+qualifiedName+':'+secondaryTypesMap.get(qualifiedName) ); //$NON-NLS-1$
+ }
+ }
+ }
+
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolderRoot.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolderRoot.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolderRoot.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -244,7 +244,7 @@
return super.exists() && validateOnLoadpath().isOK();
}
- public ISourceFolder getSourceFolder(String[] names) {
+ public SourceFolder getSourceFolder(String[] names) {
return new SourceFolder(this, names);
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -1,7 +1,10 @@
package org.rubypeople.rdt.internal.core.search;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -9,11 +12,13 @@
import org.eclipse.core.runtime.SubProgressMonitor;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyScript;
+import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.WorkingCopyOwner;
import org.rubypeople.rdt.core.search.IRubySearchConstants;
import org.rubypeople.rdt.core.search.IRubySearchScope;
import org.rubypeople.rdt.core.search.SearchDocument;
+import org.rubypeople.rdt.core.search.SearchMatch;
import org.rubypeople.rdt.core.search.SearchParticipant;
import org.rubypeople.rdt.core.search.SearchPattern;
import org.rubypeople.rdt.core.search.SearchRequestor;
@@ -28,7 +33,7 @@
public class BasicSearchEngine {
- public static final boolean VERBOSE = false;
+ public static final boolean VERBOSE = true;
/*
* A list of working copies that take precedence over their original
@@ -233,4 +238,30 @@
public static IRubySearchScope createWorkspaceScope() {
return RubyModelManager.getRubyModelManager().getWorkspaceScope();
}
+
+ public static Collection<? extends IType> findType(String typeName) {
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.TYPE, typeName, IRubySearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH);
+ SearchParticipant[] participants = new SearchParticipant[] {getDefaultSearchParticipant()};
+ IRubySearchScope scope = createWorkspaceScope();
+ TypeRequestor requestor = new TypeRequestor();
+ try {
+ new BasicSearchEngine().search(pattern, participants, scope, requestor, null);
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return requestor.getTypes();
+ }
+
+ private static class TypeRequestor extends SearchRequestor {
+ private List<IType> types = new ArrayList<IType>();
+ @Override
+ public void acceptSearchMatch(SearchMatch match) throws CoreException {
+ Object element = match.getElement();
+ types.add((IType) element);
+ }
+ public List<IType> getTypes() {
+ return types;
+ }
+ }
}
Added: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/CollectingSearchRequestor.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/CollectingSearchRequestor.java (rev 0)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/CollectingSearchRequestor.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.rubypeople.rdt.core.search.SearchMatch;
+import org.rubypeople.rdt.core.search.SearchRequestor;
+
+/**
+ * Collects the results returned by a <code>SearchEngine</code>.
+ */
+public class CollectingSearchRequestor extends SearchRequestor {
+ private ArrayList<SearchMatch> fFound;
+
+ public CollectingSearchRequestor() {
+ fFound = new ArrayList<SearchMatch>();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jdt.core.search.SearchRequestor#acceptSearchMatch(org.eclipse.jdt.core.search.SearchMatch)
+ */
+ public void acceptSearchMatch(SearchMatch match) throws CoreException {
+ fFound.add(match);
+ }
+
+ /**
+ * @return a List of {@link SearchMatch}es (not sorted)
+ */
+ public List<SearchMatch> getResults() {
+ return fFound;
+ }
+}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/IndexManager.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/IndexManager.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/IndexManager.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -4,6 +4,7 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.zip.CRC32;
import org.eclipse.core.resources.IFile;
@@ -13,8 +14,10 @@
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
+import org.rubypeople.rdt.core.ILoadpathEntry;
import org.rubypeople.rdt.core.IRubyProject;
import org.rubypeople.rdt.core.RubyCore;
+import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.search.IRubySearchScope;
import org.rubypeople.rdt.core.search.SearchDocument;
import org.rubypeople.rdt.core.search.SearchParticipant;
@@ -22,6 +25,7 @@
import org.rubypeople.rdt.internal.compiler.util.SimpleLookupTable;
import org.rubypeople.rdt.internal.compiler.util.SimpleSet;
import org.rubypeople.rdt.internal.core.RubyModel;
+import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.core.RubyProject;
import org.rubypeople.rdt.internal.core.SourceParser;
import org.rubypeople.rdt.internal.core.index.DiskIndex;
@@ -408,7 +412,7 @@
if (RubyCore.getPlugin() == null) return;
SearchParticipant participant = BasicSearchEngine.getDefaultSearchParticipant();
SearchDocument document = participant.getDocument(resource.getFullPath().toString());
-// ((InternalSearchDocument) document).parser = parser; FIXME Uncomment and fix this when we have participants
+ ((InternalSearchDocument) document).parser = parser;
IPath indexLocation = computeIndexLocation(containerPath);
scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
}
@@ -499,4 +503,54 @@
public void indexLibrary(IPath projectPath, IProject project) {
// XXX Actually implement this?!
}
+ /**
+ * Trigger addition of the entire content of a project
+ * Note: the actual operation is performed in background
+ */
+ public void indexAll(IProject project) {
+ if (RubyCore.getPlugin() == null) return;
+
+ // Also request indexing of binaries on the classpath
+ // determine the new children
+ try {
+ RubyModel model = RubyModelManager.getRubyModelManager().getRubyModel();
+ RubyProject javaProject = (RubyProject) model.getRubyProject(project);
+ // only consider immediate libraries - each project will do the same
+ // NOTE: force to resolve CP variables before calling indexer - 19303, so that initializers
+ // will be run in the current thread.
+ ILoadpathEntry[] entries = javaProject.getResolvedLoadpath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+ for (int i = 0; i < entries.length; i++) {
+ ILoadpathEntry entry= entries[i];
+ if (entry.getEntryKind() == ILoadpathEntry.CPE_LIBRARY)
+ this.indexLibrary(entry.getPath(), project);
+ }
+ } catch(RubyModelException e){ // cannot retrieve classpath info
+ }
+
+ // check if the same request is not already in the queue
+ IndexRequest request = new IndexAllProject(project, this);
+ if (!isJobWaiting(request))
+ this.request(request);
+ }
+
+ /**
+ * Removes all indexes whose paths start with (or are equal to) the given path.
+ */
+ public synchronized void removeIndexFamily(IPath path) {
+ // only finds cached index files... shutdown removes all non-cached index files
+ ArrayList toRemove = null;
+ Object[] containerPaths = this.indexLocations.keyTable;
+ for (int i = 0, length = containerPaths.length; i < length; i++) {
+ IPath containerPath = (IPath) containerPaths[i];
+ if (containerPath == null) continue;
+ if (path.isPrefixOf(containerPath)) {
+ if (toRemove == null)
+ toRemove = new ArrayList();
+ toRemove.add(containerPath);
+ }
+ }
+ if (toRemove != null)
+ for (int i = 0, length = toRemove.size(); i < length; i++)
+ this.removeIndex((IPath) toRemove.get(i));
+ }
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexer.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexer.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexer.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -4,15 +4,18 @@
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
-import org.jruby.ast.Node;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.search.SearchDocument;
import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.core.SourceParser;
-import org.rubypeople.rdt.internal.core.parser.RubyParser;
+import org.rubypeople.rdt.internal.core.search.matching.ConstructorPattern;
+import org.rubypeople.rdt.internal.core.search.matching.FieldPattern;
+import org.rubypeople.rdt.internal.core.search.matching.MethodPattern;
+import org.rubypeople.rdt.internal.core.search.matching.TypeDeclarationPattern;
import org.rubypeople.rdt.internal.core.search.processing.JobManager;
+import org.rubypeople.rdt.internal.core.util.CharOperation;
-public class SourceIndexer {
+public class SourceIndexer implements IIndexConstants {
private SearchDocument document;
@@ -32,21 +35,20 @@
} else {
parser.requestor = requestor;
}
-
+
// Launch the parser
char[] source = null;
char[] name = null;
try {
source = document.getCharContents();
name = documentPath.toCharArray();
- } catch(Exception e){
+ } catch (Exception e) {
// ignore
}
- if (source == null || name == null) return; // could not retrieve document info (e.g. resource was discarded)
+ if (source == null || name == null)
+ return; // could not retrieve document info (e.g. resource was
+ // discarded)
try {
- RubyParser p = new RubyParser();
- Node ast = p.parse(new String(source));
- parser.acceptNode(ast);
parser.parse(source, name);
} catch (Exception e) {
if (JobManager.VERBOSE) {
@@ -55,4 +57,60 @@
}
}
+ public void addClassDeclaration(int modifiers, char[] packageName, char[] name, char[][] enclosingTypeNames, char[] superclass, char[][] superinterfaces, boolean secondary) {
+ char[] indexKey = TypeDeclarationPattern.createIndexKey(modifiers, name, packageName, enclosingTypeNames, secondary);
+ addIndexEntry(TYPE_DECL, indexKey);
+
+ if (superclass != null) {
+ addTypeReference(superclass);
+ }
+ // FIXME Add back in references to super type when we have SuperTypePattern!
+// addIndexEntry(SUPER_REF, SuperTypeReferencePattern.createIndexKey(modifiers, packageName, name, enclosingTypeNames, typeParameterSignatures, CLASS_SUFFIX, superclass, CLASS_SUFFIX));
+// if (superinterfaces != null) {
+// for (int i = 0, max = superinterfaces.length; i < max; i++) {
+// char[] superinterface = superinterfaces[i];
+// addTypeReference(superinterface);
+// addIndexEntry(SUPER_REF, SuperTypeReferencePattern.createIndexKey(modifiers, packageName, name, enclosingTypeNames, typeParameterSignatures, CLASS_SUFFIX, superinterface, MODULE_SUFFIX));
+// }
+// }
+ }
+
+ public void addFieldDeclaration(char[] typeName, char[] fieldName) {
+ addIndexEntry(FIELD_DECL, FieldPattern.createIndexKey(fieldName));
+ addTypeReference(typeName);
+ }
+ public void addFieldReference(char[] fieldName) {
+ addNameReference(fieldName);
+ }
+
+ public void addMethodDeclaration(char[] methodName, int arity) {
+ addIndexEntry(METHOD_DECL, MethodPattern.createIndexKey(methodName, arity));
+ }
+
+ public void addMethodReference(char[] methodName, int argCount) {
+ addIndexEntry(METHOD_REF, MethodPattern.createIndexKey(methodName, argCount));
+ }
+
+ public void addNameReference(char[] name) {
+ addIndexEntry(REF, name);
+ }
+
+ public void addTypeReference(char[] typeName) {
+ addNameReference(CharOperation.lastSegment(typeName, "::"));
+ }
+
+ protected void addIndexEntry(char[] category, char[] key) {
+ this.document.addIndexEntry(category, key);
+ }
+
+ public void addConstructorDeclaration(char[] typeName, int argCount) {
+ addIndexEntry(CONSTRUCTOR_DECL, ConstructorPattern.createIndexKey(CharOperation.lastSegment(typeName, "::"), argCount));
+ }
+
+ public void addConstructorReference(char[] typeName, int argCount) {
+ char[] simpleTypeName = CharOperation.lastSegment(typeName, "::");
+ addTypeReference(simpleTypeName);
+ addIndexEntry(CONSTRUCTOR_REF, ConstructorPattern.createIndexKey(simpleTypeName, argCount));
+ }
+
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexerRequestor.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexerRequestor.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/indexing/SourceIndexerRequestor.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -1,5 +1,6 @@
package org.rubypeople.rdt.internal.core.search.indexing;
+import org.rubypeople.rdt.core.Flags;
import org.rubypeople.rdt.core.compiler.CategorizedProblem;
import org.rubypeople.rdt.internal.compiler.ISourceElementRequestor;
@@ -12,8 +13,7 @@
}
public void acceptConstructorReference(String name, int argCount, int offset) {
- // TODO Auto-generated method stub
-
+ indexer.addConstructorReference(name.toCharArray(), argCount);
}
public void acceptFieldReference(String name, int offset) {
@@ -27,8 +27,7 @@
}
public void acceptMethodReference(String name, int argCount, int offset) {
- // TODO Auto-generated method stub
-
+ indexer.addMethodReference(name.toCharArray(), argCount);
}
public void acceptMixin(String string) {
@@ -42,8 +41,7 @@
}
public void acceptTypeReference(String name, int startOffset, int endOffset) {
- // TODO Auto-generated method stub
-
+ indexer.addTypeReference(name.toCharArray());
}
public void acceptUnknownReference(String name, int startOffset,
@@ -53,18 +51,15 @@
}
public void enterConstructor(MethodInfo constructor) {
- // TODO Auto-generated method stub
-
+ indexer.addConstructorDeclaration(constructor.name.toCharArray(), constructor.parameterNames.length);
}
public void enterField(FieldInfo field) {
- // TODO Auto-generated method stub
-
+ indexer.addFieldDeclaration(null, field.name.toCharArray());
}
public void enterMethod(MethodInfo method) {
- // TODO Auto-generated method stub
-
+ indexer.addMethodDeclaration(method.name.toCharArray(), method.parameterNames.length);
}
public void enterScript() {
@@ -72,9 +67,14 @@
}
- public void enterType(TypeInfo type) {
- // TODO Auto-generated method stub
-
+ public void enterType(TypeInfo type) {
+ String[] modules = type.modules;
+ char[][] mod = new char[modules.length][];
+ for (int i = 0; i < modules.length; i++) {
+ mod[i] = modules[i].toCharArray();
+ }
+ char[] packName = new char[0];
+ indexer.addClassDeclaration(type.isModule ? Flags.AccModule : 0, type.name.toCharArray(), packName, null, type.superclass.toCharArray(), mod, type.secondary);
}
public void exitConstructor(int endOffset) {
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldLocator.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -1,11 +1,74 @@
package org.rubypeople.rdt.internal.core.search.matching;
-import org.rubypeople.rdt.core.search.SearchPattern;
+import org.eclipse.core.runtime.CoreException;
+import org.rubypeople.rdt.core.IField;
+import org.rubypeople.rdt.core.IMember;
+import org.rubypeople.rdt.core.IParent;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.ISourceRange;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.core.RubyScript;
public class FieldLocator extends PatternLocator {
- public FieldLocator(SearchPattern pattern) {
+ private FieldPattern pattern;
+
+ public FieldLocator(FieldPattern pattern) {
super(pattern);
+ this.pattern = pattern;
}
+
+ @Override
+ public void reportMatches(RubyScript script, MatchLocator locator) {
+ reportMatches((IParent) script, locator);
+ }
+ private void reportMatches(IParent parent, MatchLocator locator) {
+ try {
+ IRubyElement[] children = parent.getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IRubyElement child = children[i];
+ if (child.isType(IRubyElement.FIELD) ||
+ child.isType(IRubyElement.GLOBAL) ||
+ child.isType(IRubyElement.CONSTANT) ||
+ child.isType(IRubyElement.CLASS_VAR) ||
+ child.isType(IRubyElement.INSTANCE_VAR)) {
+ int accuracy = getAccuracy((IField) child);
+ if (accuracy != IMPOSSIBLE_MATCH) {
+ IMember member = (IMember) child;
+ ISourceRange range = member.getSourceRange();
+ try {
+ locator.report(locator.newDeclarationMatch(child, accuracy, range.getOffset(), range.getLength()));
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ if (child instanceof IParent) {
+ IParent parentTwo = (IParent) child;
+ reportMatches(parentTwo, locator);
+ }
+ }
+ } catch (RubyModelException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private int getAccuracy(IField field) {
+ if (this.pattern.findReferences)
+ // must be a write only access with an initializer
+ if (this.pattern.writeAccess)
+ if (matchesName(this.pattern.name, field.getElementName().toCharArray()))
+ return ACCURATE_MATCH;
+
+ if (this.pattern.findDeclarations) {
+ if (matchesName(this.pattern.name, field.getElementName().toCharArray()))
+ return ACCURATE_MATCH;
+
+ }
+ return IMPOSSIBLE_MATCH;
+ }
+
}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldPattern.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldPattern.java 2007-04-13 16:00:49 UTC (rev 2310)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/FieldPattern.java 2007-04-13 18:50:01 UTC (rev 2311)
@@ -1,35 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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 ...
[truncated message content] |