|
From: <caw...@us...> - 2007-04-13 14:12:20
|
Revision: 2307
http://svn.sourceforge.net/rubyeclipse/?rev=2307&view=rev
Author: cawilliams
Date: 2007-04-13 07:12:19 -0700 (Fri, 13 Apr 2007)
Log Message:
-----------
Modified Paths:
--------------
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/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/SourceFolder.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/RubySearchScope.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/RubySearchPattern.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/util/CharOperation.java
Added Paths:
-----------
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/OrPattern.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
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 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -8,4 +8,28 @@
* the workspace before starting the search.
*/
int WAIT_UNTIL_READY_TO_SEARCH = IJob.WaitUntilReady;
+
+ /**
+ * The search result is a declaration.
+ * Can be used in conjunction with any of the nature of searched elements
+ * so as to better narrow down the search.
+ */
+ int DECLARATIONS= 0;
+
+ /**
+ * The search result is a reference.
+ * Can be used in conjunction with any of the nature of searched elements
+ * so as to better narrow down the search.
+ * References can contain implementers since they are more generic kind
+ * of matches.
+ */
+ int REFERENCES= 2;
+
+ /**
+ * The search result is a declaration, a reference, or an implementer
+ * of an interface.
+ * Can be used in conjunction with any of the nature of searched elements
+ * so as to better narrow down the search.
+ */
+ int ALL_OCCURRENCES= 3;
}
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 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -1,6 +1,9 @@
package org.rubypeople.rdt.core.search;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.internal.core.search.indexing.IIndexConstants;
import org.rubypeople.rdt.internal.core.search.matching.InternalSearchPattern;
+import org.rubypeople.rdt.internal.core.search.matching.QualifiedTypeDeclarationPattern;
import org.rubypeople.rdt.internal.core.util.CharOperation;
public abstract class SearchPattern extends InternalSearchPattern {
@@ -238,4 +241,113 @@
return true; // called from findIndexMatches(), override as necessary if index key is encoded
}
+ public static SearchPattern createPattern(int elementType, String stringPattern, int limitTo, int matchRule) {
+ switch (elementType) {
+ case IRubyElement.TYPE:
+ return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.TYPE_SUFFIX);
+ case IRubyElement.METHOD:
+ return createMethodOrConstructorPattern(stringPattern, limitTo, matchRule, false/*not a constructor*/);
+ default:
+ break;
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the given name matches the given pattern.
+ * <p>
+ * This method should be re-implemented in subclasses that need to define how
+ * a name matches a pattern.
+ * </p>
+ *
+ * @param pattern the given pattern, or <code>null</code> to represent "*"
+ * @param name the given name
+ * @return whether the given name matches the given pattern
+ */
+ public boolean matchesName(char[] pattern, char[] name) {
+ if (pattern == null) return true; // null is as if it was "*"
+ if (name != null) {
+ boolean isCaseSensitive = (this.matchRule & R_CASE_SENSITIVE) != 0;
+ boolean isCamelCase = (this.matchRule & R_CAMELCASE_MATCH) != 0;
+ int matchMode = this.matchRule & MODE_MASK;
+ boolean sameLength = pattern.length == name.length;
+ boolean canBePrefix = name.length >= pattern.length;
+ boolean matchFirstChar = !isCaseSensitive || pattern.length == 0 || (name.length > 0 && pattern[0] == name[0]);
+ if (isCamelCase && matchFirstChar && CharOperation.camelCaseMatch(pattern, name)) {
+ return true;
+ }
+ switch (matchMode) {
+ case R_EXACT_MATCH :
+ case R_FULL_MATCH :
+ if (!isCamelCase) {
+ if (sameLength && matchFirstChar) {
+ return CharOperation.equals(pattern, name, isCaseSensitive);
+ }
+ break;
+ }
+ // fall through next case to match as prefix if camel case failed
+ case R_PREFIX_MATCH :
+ if (canBePrefix && matchFirstChar) {
+ return CharOperation.prefixEquals(pattern, name, isCaseSensitive);
+ }
+ break;
+
+ case R_PATTERN_MATCH :
+ if (!isCaseSensitive)
+ pattern = CharOperation.toLowerCase(pattern);
+ return CharOperation.match(pattern, name, isCaseSensitive);
+
+ case R_REGEXP_MATCH :
+ // TODO (frederic) implement regular expression match
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Type pattern are formed by [qualification '.']type [typeArguments].
+ * e.g. java.lang.Object
+ * Runnable
+ * List<String>
+ *
+ * @since 3.1
+ * Type arguments can be specified to search references to parameterized types.
+ * and look as follow: '<' { [ '?' {'extends'|'super'} ] type ( ',' [ '?' {'extends'|'super'} ] type )* | '?' } '>'
+ * Please note that:
+ * - '*' is not valid inside type arguments definition <>
+ * - '?' is treated as a wildcard when it is inside <> (ie. it must be put on first position of the type argument)
+ */
+ private static SearchPattern createTypePattern(String patternString, int limitTo, int matchRule, char indexSuffix) {
+ char[] typeChars = patternString.toCharArray();
+ char[] typePart = patternString.toCharArray();
+ char[] qualificationChars;
+ // get qualification name
+ int lastDotPosition = CharOperation.lastIndexOf('.', typePart);
+ if (lastDotPosition >= 0) {
+ qualificationChars = CharOperation.subarray(typePart, 0, lastDotPosition);
+ if (qualificationChars.length == 1 && qualificationChars[0] == '*')
+ qualificationChars = null;
+ typeChars = CharOperation.subarray(typePart, lastDotPosition+1, typePart.length);
+ } else {
+ typeChars = typePart;
+ }
+ if (typeChars.length == 1 && typeChars[0] == '*') {
+ typeChars = null;
+ }
+ switch (limitTo) {
+ case IRubySearchConstants.DECLARATIONS : // cannot search for explicit member types
+ return new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, indexSuffix, matchRule);
+ case IRubySearchConstants.REFERENCES :
+ return new TypeReferencePattern(qualificationChars, typeChars, matchRule);
+// case IRubySearchConstants.IMPLEMENTORS :
+// return new SuperTypeReferencePattern(qualificationChars, typeChars, SuperTypeReferencePattern.ONLY_SUPER_INTERFACES, indexSuffix, matchRule);
+ case IRubySearchConstants.ALL_OCCURRENCES :
+ return new OrPattern(
+ new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, indexSuffix, matchRule),// cannot search for explicit member types
+ new TypeReferencePattern(qualificationChars, typeChars, matchRule));
+ }
+ return null;
+ }
+
}
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 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -41,12 +41,15 @@
import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyCore;
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.SearchParticipant;
+import org.rubypeople.rdt.core.search.SearchPattern;
import org.rubypeople.rdt.internal.core.RubyElement;
import org.rubypeople.rdt.internal.core.RubyScript;
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.indexing.IndexManager;
import org.rubypeople.rdt.internal.core.util.ASTUtil;
import org.rubypeople.rdt.internal.ti.DefaultTypeInferrer;
import org.rubypeople.rdt.internal.ti.ITypeGuess;
@@ -146,6 +149,11 @@
}
private void suggestTypeNames() {
+ BasicSearchEngine engine = new BasicSearchEngine();
+ 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) {
if (!fContext.prefixStartsWith(name))
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolder.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolder.java 2007-04-13 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SourceFolder.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -23,7 +23,7 @@
public class SourceFolder extends Openable implements ISourceFolder {
- String[] names;
+ public String[] names;
public SourceFolder(SourceFolderRoot parent, String[] names) {
super(parent);
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 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/BasicSearchEngine.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -1,11 +1,13 @@
package org.rubypeople.rdt.internal.core.search;
import java.util.HashMap;
+import java.util.HashSet;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
+import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.WorkingCopyOwner;
@@ -17,6 +19,7 @@
import org.rubypeople.rdt.core.search.SearchRequestor;
import org.rubypeople.rdt.internal.core.DefaultWorkingCopyOwner;
import org.rubypeople.rdt.internal.core.RubyModelManager;
+import org.rubypeople.rdt.internal.core.RubyProject;
import org.rubypeople.rdt.internal.core.RubyScript;
import org.rubypeople.rdt.internal.core.search.indexing.IndexManager;
import org.rubypeople.rdt.internal.core.search.matching.MatchLocator;
@@ -41,7 +44,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).
*
* @see SearchEngine#search(SearchPattern, SearchParticipant[], IRubySearchScope, SearchRequestor, IProgressMonitor)
@@ -55,6 +58,47 @@
}
/**
+ * @see SearchEngine#createRubySearchScope(IRubyElement[]) for detailed comment.
+ */
+ public static IRubySearchScope createRubySearchScope(IRubyElement[] elements) {
+ return createRubySearchScope(elements, true);
+ }
+
+ /**
+ * @see SearchEngine#createRubySearchScope(IRubyElement[], boolean) for detailed comment.
+ */
+ public static IRubySearchScope createRubySearchScope(IRubyElement[] elements, boolean includeReferencedProjects) {
+ int includeMask = IRubySearchScope.SOURCES | IRubySearchScope.APPLICATION_LIBRARIES | IRubySearchScope.SYSTEM_LIBRARIES;
+ if (includeReferencedProjects) {
+ includeMask |= IRubySearchScope.REFERENCED_PROJECTS;
+ }
+ return createRubySearchScope(elements, includeMask);
+ }
+
+ /**
+ * @see SearchEngine#createRubySearchScope(IRubyElement[], int) for detailed comment.
+ */
+ public static IRubySearchScope createRubySearchScope(IRubyElement[] elements, int includeMask) {
+ RubySearchScope scope = new RubySearchScope();
+ HashSet visitedProjects = new HashSet(2);
+ for (int i = 0, length = elements.length; i < length; i++) {
+ IRubyElement element = elements[i];
+ if (element != null) {
+ try {
+ if (element instanceof RubyProject) {
+ scope.add((RubyProject)element, includeMask, visitedProjects);
+ } else {
+ scope.add(element);
+ }
+ } catch (RubyModelException e) {
+ // ignore
+ }
+ }
+ }
+ return scope;
+ }
+
+ /**
* Searches for matches to a given query. Search queries can be created using helper
* 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).
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/RubySearchScope.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/RubySearchScope.java 2007-04-13 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/RubySearchScope.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -5,20 +5,28 @@
import java.util.Map;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
import org.rubypeople.rdt.core.ILoadpathContainer;
import org.rubypeople.rdt.core.ILoadpathEntry;
+import org.rubypeople.rdt.core.IMember;
+import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyModel;
+import org.rubypeople.rdt.core.ISourceFolderRoot;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.search.IRubySearchScope;
import org.rubypeople.rdt.internal.core.LoadpathEntry;
import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.core.RubyProject;
+import org.rubypeople.rdt.internal.core.SourceFolder;
import org.rubypeople.rdt.internal.core.util.Util;
public class RubySearchScope implements IRubySearchScope {
+ private ArrayList elements;
+
/* The paths of the resources in this search scope
(or the classpath entries' paths if the resources are projects)
*/
@@ -306,5 +314,132 @@
public IPath[] enclosingProjectsAndJars() {
return this.enclosingProjectsAndJars;
}
+
+ /**
+ * Add ruby project all fragment roots to current ruby search scope.
+ * @see #add(RubyProject, IPath, int, HashSet, ILoadpathEntry)
+ */
+ public void add(RubyProject project, int includeMask, HashSet visitedProject) throws RubyModelException {
+ add(project, null, includeMask, visitedProject, null);
+ }
+
+ /**
+ * Add an element to the ruby search scope.
+ * @param element The element we want to add to current ruby search scope
+ * @throws RubyModelException May happen if some Ruby Model info are not available
+ */
+ public void add(IRubyElement element) throws RubyModelException {
+ IPath containerPath = null;
+ String containerPathToString = null;
+ int includeMask = SOURCES | APPLICATION_LIBRARIES | SYSTEM_LIBRARIES;
+ switch (element.getElementType()) {
+ case IRubyElement.RUBY_MODEL:
+ // a workspace sope should be used
+ break;
+ case IRubyElement.RUBY_PROJECT:
+ add((RubyProject)element, null, includeMask, new HashSet(2), null);
+ break;
+ case IRubyElement.SOURCE_FOLDER_ROOT:
+ ISourceFolderRoot root = (ISourceFolderRoot)element;
+ IPath rootPath = root.getPath();
+ containerPath = root.getParent().getPath();
+ containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+ IResource rootResource = root.getResource();
+ if (rootResource != null && rootResource.isAccessible()) {
+ String relativePath = Util.relativePath(rootResource.getFullPath(), containerPath.segmentCount());
+ add(relativePath, containerPathToString, false/*not a package*/);
+ } else {
+ add("", containerPathToString, false/*not a package*/); //$NON-NLS-1$
+ }
+ break;
+ case IRubyElement.SOURCE_FOLDER:
+ root = (ISourceFolderRoot)element.getParent();
+ if (root.isArchive()) {
+ String relativePath = Util.concatWith(((SourceFolder) element).names, '/');
+ containerPath = root.getPath();
+ containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+ add(relativePath, containerPathToString, true/*package*/);
+ } else {
+ IResource resource = element.getResource();
+ if (resource != null) {
+ if (resource.isAccessible()) {
+ containerPath = root.getParent().getPath();
+ } else {
+ // for working copies, get resource container full path
+ containerPath = resource.getParent().getFullPath();
+ }
+ containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+ String relativePath = Util.relativePath(resource.getFullPath(), containerPath.segmentCount());
+ add(relativePath, containerPathToString, true/*package*/);
+ }
+ }
+ break;
+ default:
+ // remember sub-cu (or sub-class file) ruby elements
+ if (element instanceof IMember) {
+ if (this.elements == null) {
+ this.elements = new ArrayList();
+ }
+ this.elements.add(element);
+ }
+ root = (ISourceFolderRoot) element.getAncestor(IRubyElement.SOURCE_FOLDER_ROOT);
+ String relativePath;
+
+ containerPath = root.getParent().getPath();
+ relativePath = Util.relativePath(getPath(element, false/*full path*/), 1/*remove project segmet*/);
+
+ containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+ add(relativePath, containerPathToString, false/*not a package*/);
+ }
+
+ if (containerPath != null)
+ addEnclosingProjectOrJar(containerPath);
+ }
+ /**
+ * Adds the given path to this search scope. Remember if subfolders need to be included
+ * and associated access restriction as well.
+ */
+ private void add(String relativePath, String containerPath, boolean isPackage) {
+ // normalize containerPath and relativePath
+ containerPath = normalize(containerPath);
+ relativePath = normalize(relativePath);
+ int length = this.containerPaths.length,
+ index = (containerPath.hashCode()& 0x7FFFFFFF) % length;
+ String currentRelativePath, currentContainerPath;
+ while ((currentRelativePath = this.relativePaths[index]) != null && (currentContainerPath = this.containerPaths[index]) != null) {
+ if (currentRelativePath.equals(relativePath) && currentContainerPath.equals(containerPath))
+ return;
+ if (++index == length) {
+ index = 0;
+ }
+ }
+ this.relativePaths[index] = relativePath;
+ this.containerPaths[index] = containerPath;
+ this.isPkgPath[index] = isPackage;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++this.pathsCount > this.threshold)
+ rehash();
+ }
+
+ private IPath getPath(IRubyElement element, boolean relativeToRoot) {
+ switch (element.getElementType()) {
+ case IRubyElement.RUBY_MODEL:
+ return Path.EMPTY;
+ case IRubyElement.RUBY_PROJECT:
+ return element.getPath();
+ case IRubyElement.SOURCE_FOLDER_ROOT:
+ if (relativeToRoot)
+ return Path.EMPTY;
+ return element.getPath();
+ case IRubyElement.SOURCE_FOLDER:
+ String relativePath = Util.concatWith(((SourceFolder) element).names, '/');
+ return getPath(element.getParent(), relativeToRoot).append(new Path(relativePath));
+ case IRubyElement.SCRIPT:
+ return getPath(element.getParent(), relativeToRoot).append(new Path(element.getElementName()));
+ default:
+ return getPath(element.getParent(), relativeToRoot);
+ }
+ }
}
Modified: 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/MatchLocator.java 2007-04-13 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -424,12 +424,11 @@
this.patternLocator.clear();
}
- protected void locateMatches(RubyProject javaProject, PossibleMatch[] possibleMatches, int start, int length) throws CoreException {
+ protected void locateMatches(RubyProject rubyProject, PossibleMatch[] possibleMatches, int start, int length) throws CoreException {
for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
PossibleMatch possibleMatch = possibleMatches[i];
RubyScript script = (RubyScript) possibleMatch.openable;
- SearchMatch[] matches = this.patternLocator.reportMatches(script);
- for (int j = 0; j < matches.length; j++) report(matches[j]);
+ this.patternLocator.reportMatches(script, this);
possibleMatch.cleanUp();
}
}
Added: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/OrPattern.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/OrPattern.java (rev 0)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/OrPattern.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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.matching;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.rubypeople.rdt.core.search.IRubySearchScope;
+import org.rubypeople.rdt.core.search.SearchParticipant;
+import org.rubypeople.rdt.core.search.SearchPattern;
+import org.rubypeople.rdt.internal.core.index.Index;
+import org.rubypeople.rdt.internal.core.search.IndexQueryRequestor;
+import org.rubypeople.rdt.internal.core.search.indexing.IIndexConstants;
+
+public class OrPattern extends SearchPattern implements IIndexConstants {
+
+ protected SearchPattern[] patterns;
+
+ /*
+ * Whether this pattern is erasure match.
+ */
+// boolean isErasureMatch;
+
+ /**
+ * One of {@link #R_ERASURE_MATCH}, {@link #R_EQUIVALENT_MATCH}, {@link #R_FULL_MATCH}.
+ */
+ int matchCompatibility;
+
+ public OrPattern(SearchPattern leftPattern, SearchPattern rightPattern) {
+ super(Math.max(leftPattern.getMatchRule(), rightPattern.getMatchRule()));
+ ((InternalSearchPattern)this).kind = OR_PATTERN;
+ ((InternalSearchPattern)this).mustResolve = ((InternalSearchPattern) leftPattern).mustResolve || ((InternalSearchPattern) rightPattern).mustResolve;
+
+ SearchPattern[] leftPatterns = leftPattern instanceof OrPattern ? ((OrPattern) leftPattern).patterns : null;
+ SearchPattern[] rightPatterns = rightPattern instanceof OrPattern ? ((OrPattern) rightPattern).patterns : null;
+ int leftSize = leftPatterns == null ? 1 : leftPatterns.length;
+ int rightSize = rightPatterns == null ? 1 : rightPatterns.length;
+ this.patterns = new SearchPattern[leftSize + rightSize];
+
+ if (leftPatterns == null)
+ this.patterns[0] = leftPattern;
+ else
+ System.arraycopy(leftPatterns, 0, this.patterns, 0, leftSize);
+ if (rightPatterns == null)
+ this.patterns[leftSize] = rightPattern;
+ else
+ System.arraycopy(rightPatterns, 0, this.patterns, leftSize, rightSize);
+
+ // Store erasure match
+ matchCompatibility = 0;
+ for (int i = 0, length = this.patterns.length; i < length; i++) {
+ matchCompatibility |= ((RubySearchPattern) this.patterns[i]).matchCompatibility;
+ }
+ }
+ void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IRubySearchScope scope, IProgressMonitor progressMonitor) throws IOException {
+ // per construction, OR pattern can only be used with a PathCollector (which already gather results using a set)
+ try {
+ index.startQuery();
+ for (int i = 0, length = this.patterns.length; i < length; i++)
+ ((InternalSearchPattern)this.patterns[i]).findIndexMatches(index, requestor, participant, scope, progressMonitor);
+ } finally {
+ index.stopQuery();
+ }
+ }
+
+ public SearchPattern getBlankPattern() {
+ return null;
+ }
+
+ boolean isErasureMatch() {
+ return (this.matchCompatibility & R_ERASURE_MATCH) != 0;
+ }
+
+ boolean isPolymorphicSearch() {
+ for (int i = 0, length = this.patterns.length; i < length; i++)
+ if (((InternalSearchPattern) this.patterns[i]).isPolymorphicSearch()) return true;
+ return false;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(this.patterns[0].toString());
+ for (int i = 1, length = this.patterns.length; i < length; i++) {
+ buffer.append("\n| "); //$NON-NLS-1$
+ buffer.append(this.patterns[i].toString());
+ }
+ return buffer.toString();
+ }
+}
Added: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java (rev 0)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * 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.matching;
+
+import org.rubypeople.rdt.core.search.SearchPattern;
+import org.rubypeople.rdt.internal.core.search.indexing.IIndexConstants;
+import org.rubypeople.rdt.internal.core.util.CharOperation;
+
+public class QualifiedTypeDeclarationPattern extends TypeDeclarationPattern implements IIndexConstants {
+
+public char[] qualification;
+public int packageIndex;
+
+public QualifiedTypeDeclarationPattern(char[] qualification, char[] simpleName, char typeSuffix, int matchRule) {
+ this(matchRule);
+
+ this.qualification = isCaseSensitive() ? qualification : CharOperation.toLowerCase(qualification);
+ this.simpleName = (isCaseSensitive() || isCamelCase()) ? simpleName : CharOperation.toLowerCase(simpleName);
+ this.typeSuffix = typeSuffix;
+
+ ((InternalSearchPattern)this).mustResolve = this.qualification != null || typeSuffix != TYPE_SUFFIX;
+}
+QualifiedTypeDeclarationPattern(int matchRule) {
+ super(matchRule);
+}
+public void decodeIndexKey(char[] key) {
+ int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+ this.simpleName = CharOperation.subarray(key, 0, slash);
+
+ int start = slash + 1;
+ slash = CharOperation.indexOf(SEPARATOR, key, start);
+ int secondSlash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
+ this.packageIndex = -1; // used to compute package vs. enclosingTypeNames in MultiTypeDeclarationPattern
+ if (start + 1 == secondSlash) {
+ this.qualification = CharOperation.NO_CHAR; // no package name or enclosingTypeNames
+ } else if (slash + 1 == secondSlash) {
+ this.qualification = CharOperation.subarray(key, start, slash); // only a package name
+ } else if (slash == start) {
+ this.qualification = CharOperation.subarray(key, slash + 1, secondSlash); // no package name
+ this.packageIndex = 0;
+ } else {
+ this.qualification = CharOperation.subarray(key, start, secondSlash);
+ this.packageIndex = slash - start;
+ this.qualification[this.packageIndex] = '.';
+ }
+
+ // Continue key read by the end to decode modifiers
+ int last = key.length-1;
+ this.secondary = key[last] == 'S';
+ if (this.secondary) {
+ last -= 2;
+ }
+ this.modifiers = key[last-1] + (key[last]<<16);
+ decodeModifiers();
+}
+public SearchPattern getBlankPattern() {
+ return new QualifiedTypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
+}
+public char[] getPackageName() {
+ if (this.packageIndex == -1)
+ return this.qualification;
+ return internedPackageNames.add(CharOperation.subarray(this.qualification, 0, this.packageIndex));
+}
+public char[][] getEnclosingTypeNames() {
+ if (this.packageIndex == -1)
+ return CharOperation.NO_CHAR_CHAR;
+ if (this.packageIndex == 0)
+ return CharOperation.splitOn('.', this.qualification);
+
+ char[] names = CharOperation.subarray(this.qualification, this.packageIndex + 1, this.qualification.length);
+ return CharOperation.splitOn('.', names);
+}
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+ QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
+ switch(this.typeSuffix) {
+ case CLASS_SUFFIX :
+ switch (pattern.typeSuffix) {
+ case CLASS_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ break;
+ default:
+ return false;
+ }
+ break;
+ case MODULE_SUFFIX :
+ switch (pattern.typeSuffix) {
+ case MODULE_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ break;
+ default:
+ return false;
+ }
+ break;
+ case CLASS_AND_MODULE_SUFFIX :
+ switch (pattern.typeSuffix) {
+ case CLASS_SUFFIX :
+ case MODULE_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+
+ return matchesName(this.simpleName, pattern.simpleName) && matchesName(this.qualification, pattern.qualification);
+}
+protected StringBuffer print(StringBuffer output) {
+ switch (this.typeSuffix){
+ case CLASS_SUFFIX :
+ output.append("ClassDeclarationPattern: qualification<"); //$NON-NLS-1$
+ break;
+ case CLASS_AND_MODULE_SUFFIX:
+ output.append("ClassAndInterfaceDeclarationPattern: qualification<"); //$NON-NLS-1$
+ break;
+ case MODULE_SUFFIX :
+ output.append("InterfaceDeclarationPattern: qualification<"); //$NON-NLS-1$
+ break;
+ default :
+ output.append("TypeDeclarationPattern: qualification<"); //$NON-NLS-1$
+ break;
+ }
+ if (this.qualification != null)
+ output.append(this.qualification);
+ else
+ output.append("*"); //$NON-NLS-1$
+ output.append(">, type<"); //$NON-NLS-1$
+ if (simpleName != null)
+ output.append(simpleName);
+ else
+ output.append("*"); //$NON-NLS-1$
+ output.append("> "); //$NON-NLS-1$
+ return super.print(output);
+}
+}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/RubySearchPattern.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/RubySearchPattern.java 2007-04-13 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/RubySearchPattern.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -58,6 +58,10 @@
return null;
}
+ int getMatchMode() {
+ return this.matchMode;
+ }
+
boolean isCamelCase() {
return this.isCamelCase;
}
@@ -65,4 +69,36 @@
boolean isCaseSensitive () {
return this.isCaseSensitive;
}
+
+ protected StringBuffer print(StringBuffer output) {
+ output.append(", "); //$NON-NLS-1$
+ if (this.isCamelCase) {
+ output.append("camel case + "); //$NON-NLS-1$
+ }
+ switch(getMatchMode()) {
+ case R_EXACT_MATCH :
+ output.append("exact match,"); //$NON-NLS-1$
+ break;
+ case R_PREFIX_MATCH :
+ output.append("prefix match,"); //$NON-NLS-1$
+ break;
+ case R_PATTERN_MATCH :
+ output.append("pattern match,"); //$NON-NLS-1$
+ break;
+ case R_REGEXP_MATCH :
+ output.append("regexp match, "); //$NON-NLS-1$
+ break;
+ }
+ if (isCaseSensitive())
+ output.append(" case sensitive"); //$NON-NLS-1$
+ else
+ output.append(" case insensitive"); //$NON-NLS-1$
+ if ((this.matchCompatibility & R_ERASURE_MATCH) != 0) {
+ output.append(", erasure only"); //$NON-NLS-1$
+ }
+ if ((this.matchCompatibility & R_EQUIVALENT_MATCH) != 0) {
+ output.append(", equivalent oronly"); //$NON-NLS-1$
+ }
+ return output;
+ }
}
Modified: 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/matching/TypeDeclarationPattern.java 2007-04-13 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/TypeDeclarationPattern.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -1,9 +1,358 @@
+/*******************************************************************************
+ * 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.matching;
-public class TypeDeclarationPattern extends RubySearchPattern {
+import java.io.IOException;
- TypeDeclarationPattern(int matchRule) {
- super(TYPE_DECL_PATTERN, matchRule);
+import org.rubypeople.rdt.core.search.SearchPattern;
+import org.rubypeople.rdt.internal.core.index.EntryResult;
+import org.rubypeople.rdt.internal.core.index.Index;
+import org.rubypeople.rdt.internal.core.search.indexing.IIndexConstants;
+import org.rubypeople.rdt.internal.core.util.CharOperation;
+
+public class TypeDeclarationPattern extends RubySearchPattern implements IIndexConstants {
+
+public char[] simpleName;
+public char[] pkg;
+public char[][] enclosingTypeNames;
+
+// set to CLASS_SUFFIX for only matching classes
+// set to INTERFACE_SUFFIX for only matching interfaces
+// set to ENUM_SUFFIX for only matching enums
+// set to ANNOTATION_TYPE_SUFFIX for only matching annotation types
+// set to TYPE_SUFFIX for matching both classes and interfaces
+public char typeSuffix;
+public int modifiers;
+public boolean secondary = false;
+
+protected static char[][] CATEGORIES = { TYPE_DECL };
+
+// want to save space by interning the package names for each match
+static PackageNameSet internedPackageNames = new PackageNameSet(1001);
+static class PackageNameSet {
+
+public char[][] names;
+public int elementSize; // number of elements in the table
+public int threshold;
+
+PackageNameSet(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.5f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.names = new char[extraRoom][];
+}
+
+char[] add(char[] name) {
+ int length = names.length;
+ int index = CharOperation.hashCode(name) % length;
+ char[] current;
+ while ((current = names[index]) != null) {
+ if (CharOperation.equals(current, name)) return current;
+ if (++index == length) index = 0;
}
+ names[index] = name;
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold) rehash();
+ return name;
}
+
+void rehash() {
+ PackageNameSet newSet = new PackageNameSet(elementSize * 2); // double the number of expected elements
+ char[] current;
+ for (int i = names.length; --i >= 0;)
+ if ((current = names[i]) != null)
+ newSet.add(current);
+
+ this.names = newSet.names;
+ this.elementSize = newSet.elementSize;
+ this.threshold = newSet.threshold;
+}
+}
+
+/*
+ * Create index key for type declaration pattern:
+ * key = typeName / packageName / enclosingTypeName / modifiers
+ * or for secondary types
+ * key = typeName / packageName / enclosingTypeName / modifiers / 'S'
+ */
+public static char[] createIndexKey(int modifiers, char[] typeName, char[] packageName, char[][] enclosingTypeNames, boolean secondary) { //, char typeSuffix) {
+ int typeNameLength = typeName == null ? 0 : typeName.length;
+ int packageLength = packageName == null ? 0 : packageName.length;
+ int enclosingNamesLength = 0;
+ if (enclosingTypeNames != null) {
+ for (int i = 0, length = enclosingTypeNames.length; i < length;) {
+ enclosingNamesLength += enclosingTypeNames[i].length;
+ if (++i < length)
+ enclosingNamesLength++; // for the '.' separator
+ }
+ }
+
+ int resultLength = typeNameLength + packageLength + enclosingNamesLength + 5;
+ if (secondary) resultLength += 2;
+ char[] result = new char[resultLength];
+ int pos = 0;
+ if (typeNameLength > 0) {
+ System.arraycopy(typeName, 0, result, pos, typeNameLength);
+ pos += typeNameLength;
+ }
+ result[pos++] = SEPARATOR;
+ if (packageLength > 0) {
+ System.arraycopy(packageName, 0, result, pos, packageLength);
+ pos += packageLength;
+ }
+ result[pos++] = SEPARATOR;
+ if (enclosingTypeNames != null && enclosingNamesLength > 0) {
+ for (int i = 0, length = enclosingTypeNames.length; i < length;) {
+ char[] enclosingName = enclosingTypeNames[i];
+ int itsLength = enclosingName.length;
+ System.arraycopy(enclosingName, 0, result, pos, itsLength);
+ pos += itsLength;
+ if (++i < length)
+ result[pos++] = '.';
+ }
+ }
+ result[pos++] = SEPARATOR;
+ result[pos++] = (char) modifiers;
+ result[pos] = (char) (modifiers>>16);
+ if (secondary) {
+ result[++pos] = SEPARATOR;
+ result[++pos] = 'S';
+ }
+ return result;
+}
+
+public TypeDeclarationPattern(
+ char[] pkg,
+ char[][] enclosingTypeNames,
+ char[] simpleName,
+ char typeSuffix,
+ int matchRule) {
+
+ this(matchRule);
+
+ this.pkg = isCaseSensitive() ? pkg : CharOperation.toLowerCase(pkg);
+ if (isCaseSensitive() || enclosingTypeNames == null) {
+ this.enclosingTypeNames = enclosingTypeNames;
+ } else {
+ int length = enclosingTypeNames.length;
+ this.enclosingTypeNames = new char[length][];
+ for (int i = 0; i < length; i++)
+ this.enclosingTypeNames[i] = CharOperation.toLowerCase(enclosingTypeNames[i]);
+ }
+ this.simpleName = (isCaseSensitive() || isCamelCase()) ? simpleName : CharOperation.toLowerCase(simpleName);
+ this.typeSuffix = typeSuffix;
+
+ ((InternalSearchPattern)this).mustResolve = (this.pkg != null && this.enclosingTypeNames != null) || typeSuffix != TYPE_SUFFIX;
+}
+TypeDeclarationPattern(int matchRule) {
+ super(TYPE_DECL_PATTERN, matchRule);
+}
+/*
+ * Type entries are encoded as:
+ * simpleTypeName / packageName / enclosingTypeName / modifiers
+ * e.g. Object/java.lang//0
+ * e.g. Cloneable/java.lang//512
+ * e.g. LazyValue/javax.swing/UIDefaults/0
+ * or for secondary types as:
+ * simpleTypeName / packageName / enclosingTypeName / modifiers / S
+ */
+public void decodeIndexKey(char[] key) {
+ int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+ this.simpleName = CharOperation.subarray(key, 0, slash);
+
+ int start = ++slash;
+ if (key[start] == SEPARATOR) {
+ this.pkg = CharOperation.NO_CHAR;
+ } else {
+ slash = CharOperation.indexOf(SEPARATOR, key, start);
+ this.pkg = internedPackageNames.add(CharOperation.subarray(key, start, slash));
+ }
+
+ // Continue key read by the end to decode modifiers
+ int last = key.length-1;
+ this.secondary = key[last] == 'S';
+ if (this.secondary) {
+ last -= 2;
+ }
+ this.modifiers = key[last-1] + (key[last]<<16);
+ decodeModifiers();
+
+ // Retrieve enclosing type names
+ start = slash + 1;
+ last -= 2; // position of ending slash
+ if (start == last) {
+ this.enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+ } else {
+ if (last == (start+1) && key[start] == ZERO_CHAR) {
+ this.enclosingTypeNames = ONE_ZERO_CHAR;
+ } else {
+ this.enclosingTypeNames = CharOperation.splitOn("::", key, start, last);
+ }
+ }
+}
+protected void decodeModifiers() {
+
+ // Extract suffix from modifiers instead of index key
+ switch (this.modifiers & (ClassFileConstants.AccModule)) {
+ case ClassFileConstants.AccModule:
+ this.typeSuffix = MODULE_SUFFIX;
+ break;
+ default:
+ this.typeSuffix = CLASS_SUFFIX;
+ break;
+ }
+}
+public SearchPattern getBlankPattern() {
+ return new TypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
+}
+public char[][] getIndexCategories() {
+ return CATEGORIES;
+}
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+ TypeDeclarationPattern pattern = (TypeDeclarationPattern) decodedPattern;
+ switch(this.typeSuffix) {
+ case CLASS_SUFFIX :
+ switch (pattern.typeSuffix) {
+ case CLASS_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ break;
+ default:
+ return false;
+ }
+ break;
+ case MODULE_SUFFIX :
+ switch (pattern.typeSuffix) {
+ case MODULE_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ break;
+ default:
+ return false;
+ }
+ break;
+ case CLASS_AND_MODULE_SUFFIX :
+ switch (pattern.typeSuffix) {
+ case CLASS_SUFFIX :
+ case MODULE_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+
+ if (!matchesName(this.simpleName, pattern.simpleName))
+ return false;
+
+ // check package - exact match only
+ if (this.pkg != null && !CharOperation.equals(this.pkg, pattern.pkg, isCaseSensitive()))
+ return false;
+
+ // check enclosingTypeNames - exact match only
+ if (this.enclosingTypeNames != null) {
+ if (this.enclosingTypeNames.length == 0)
+ return pattern.enclosingTypeNames.length == 0;
+ if (this.enclosingTypeNames.length == 1 && pattern.enclosingTypeNames.length == 1)
+ return CharOperation.equals(this.enclosingTypeNames[0], pattern.enclosingTypeNames[0], isCaseSensitive());
+ if (pattern.enclosingTypeNames == ONE_ZERO_CHAR)
+ return true; // is a local or anonymous type
+ return CharOperation.equals(this.enclosingTypeNames, pattern.enclosingTypeNames, isCaseSensitive());
+ }
+ return true;
+}
+EntryResult[] queryIn(Index index) throws IOException {
+ char[] key = this.simpleName; // can be null
+ int matchRule = getMatchRule();
+
+ switch(getMatchMode()) {
+ case R_PREFIX_MATCH :
+ // do a prefix query with the simpleName
+ break;
+ case R_EXACT_MATCH :
+ if (this.isCamelCase) break;
+ matchRule &= ~R_EXACT_MATCH;
+ if (this.simpleName != null) {
+ matchRule |= R_PREFIX_MATCH;
+ key = this.pkg == null
+ ? CharOperation.append(this.simpleName, SEPARATOR)
+ : CharOperation.concat(this.simpleName, SEPARATOR, this.pkg, SEPARATOR, CharOperation.NO_CHAR);
+ break; // do a prefix query with the simpleName and possibly the pkg
+ }
+ matchRule |= R_PATTERN_MATCH;
+ // fall thru to encode the key and do a pattern query
+ case R_PATTERN_MATCH :
+ if (this.pkg == null) {
+ if (this.simpleName == null) {
+ switch(this.typeSuffix) {
+ case CLASS_SUFFIX :
+ case MODULE_SUFFIX :
+ case CLASS_AND_MODULE_SUFFIX :
+ // null key already returns all types
+ // key = new char[] {ONE_STAR[0], SEPARATOR, ONE_STAR[0]};
+ break;
+ }
+ } else if (this.simpleName[this.simpleName.length - 1] != '*') {
+ key = CharOperation.concat(this.simpleName, ONE_STAR, SEPARATOR);
+ }
+ break; // do a pattern query with the current encoded key
+ }
+ // must decode to check enclosingTypeNames due to the encoding of local types
+ key = CharOperation.concat(
+ this.simpleName == null ? ONE_STAR : this.simpleName, SEPARATOR, this.pkg, SEPARATOR, ONE_STAR);
+ break;
+ case R_REGEXP_MATCH :
+ // TODO (frederic) implement regular expression match
+ break;
+ }
+
+ return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
+}
+protected StringBuffer print(StringBuffer output) {
+ switch (this.typeSuffix){
+ case CLASS_SUFFIX :
+ output.append("ClassDeclarationPattern: pkg<"); //$NON-NLS-1$
+ break;
+ case CLASS_AND_MODULE_SUFFIX:
+ output.append("ClassAndInterfaceDeclarationPattern: pkg<"); //$NON-NLS-1$
+ break;
+ case MODULE_SUFFIX :
+ output.append("InterfaceDeclarationPattern: pkg<"); //$NON-NLS-1$
+ break;
+ default :
+ output.append("TypeDeclarationPattern: pkg<"); //$NON-NLS-1$
+ break;
+ }
+ if (pkg != null)
+ output.append(pkg);
+ else
+ output.append("*"); //$NON-NLS-1$
+ output.append(">, enclosing<"); //$NON-NLS-1$
+ if (enclosingTypeNames != null) {
+ for (int i = 0; i < enclosingTypeNames.length; i++){
+ output.append(enclosingTypeNames[i]);
+ if (i < enclosingTypeNames.length - 1)
+ output.append('.');
+ }
+ } else {
+ output.append("*"); //$NON-NLS-1$
+ }
+ output.append(">, type<"); //$NON-NLS-1$
+ if (simpleName != null)
+ output.append(simpleName);
+ else
+ output.append("*"); //$NON-NLS-1$
+ output.append(">"); //$NON-NLS-1$
+ return super.print(output);
+}
+}
Modified: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/CharOperation.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/CharOperation.java 2007-04-13 13:04:55 UTC (rev 2306)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/CharOperation.java 2007-04-13 14:12:19 UTC (rev 2307)
@@ -1275,4 +1275,198 @@
System.arraycopy(array, start, result, 0, end - start);
return result;
}
+
+/**
+ * Answers the concatenation of the three arrays inserting the sep1 character between the
+ * first two arrays and sep2 between the last two.
+ * It answers null if the three arrays are null.
+ * If the first array is null, then it answers the concatenation of second and third inserting
+ * the sep2 character between them.
+ * If the second array is null, then it answers the concatenation of first and third inserting
+ * the sep1 character between them.
+ * If the third array is null, then it answers the concatenation of first and second inserting
+ * the sep1 character between them.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * sep1 = '/'
+ * second = { 'a' }
+ * sep2 = ':'
+ * third = { 'b' }
+ * => result = { ' a' , ':', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = null
+ * sep2 = ':'
+ * third = { 'b' }
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { 'b' }
+ * sep2 = ':'
+ * third = null
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { 'b' }
+ * sep2 = ':'
+ * third = { 'c' }
+ * => result = { ' a' , '/', 'b' , ':', 'c' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first the first array to concatenate
+ * @param sep1 the character to insert
+ * @param second the second array to concatenate
+ * @param sep2 the character to insert
+ * @param third the second array to concatenate
+ * @return the concatenation of the three arrays inserting the sep1 character between the
+ * two arrays and sep2 between the last two.
+ */
+public static final char[] concat(
+ char[] first,
+ char sep1,
+ char[] second,
+ char sep2,
+ char[] third) {
+ if (first == null)
+ return concat(second, third, sep2);
+ if (second == null)
+ return concat(first, third, sep1);
+ if (third == null)
+ return concat(first, second, sep1);
+
+ int length1 = first.length;
+ int length2 = second.length;
+ int length3 = third.length;
+ char[] result = new char[length1 + length2 + length3 + 2];
+ System.arraycopy(first, 0, result, 0, length1);
+ result[length1] = sep1;
+ System.arraycopy(second, 0, result, length1 + 1, length2);
+ result[length1 + length2 + 1] = sep2;
+ System.arraycopy(third, 0, result, length1 + length2 + 2, length3);
+ return result;
}
+
+/**
+ * Answers a new array with appending the suffix character at the end of the array.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * array = { 'a', 'b' }
+ * suffix = 'c'
+ * => result = { 'a', 'b' , 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = null
+ * suffix = 'c'
+ * => result = { 'c' }
+ * </pre></li>
+ * </ol>
+ *
+ * @param array the array that is concanated with the suffix character
+ * @param suffix the suffix character
+ * @return the new array
+ */
+public static final char[] append(char[] array, char suffix) {
+ if (array == null)
+ return new char[] { suffix };
+ int length = array.length;
+ System.arraycopy(array, 0, array = new char[length + 1], 0, length);
+ array[length] = suffix;
+ return array;
+}
+
+/**
+ * If isCaseSensite is true, answers true if the two arrays are identical character
+ * by character, otherwise false.
+ * If it is false, answers true if the two arrays are identical character by
+ * character without checking the case, otherwise false.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = null
+ * isCaseSensitive = true
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { } }
+ * second = null
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { 'A' } }
+ * second = { { 'a' } }
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { 'A' } }
+ * second = { { 'a' } }
+ * isCaseSensitive = false
+ * result => true
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first the first array
+ * @param second the second array
+ * @param isCaseSensitive check whether or not the equality should be case sensitive
+ * @return true if the two arrays are identical character by character according to the value
+ * of isCaseSensitive, otherwise false
+ */
+public static final boolean equals(
+ char[][] first,
+ char[][] second,
+ boolean isCaseSensitive) {
+
+ if (isCaseSensitive) {
+ return equals(first, second);
+ }
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+
+ for (int i = first.length; --i >= 0;)
+ if (!equals(first[i], second[i], false))
+ return false;
+ return true;
+}
+
+public static char[][] splitOn(String divider, char[] key, int start, int last) {
+ String newKey = new String(key);
+ newKey = newKey.substring(start, last);
+ String[] result = newKey.split(divider);
+ char[][] resultEnd = new char[result.length][];
+ for (int i = 0; i < resultEnd.length; i++) {
+ resultEnd[i] = result[i].toCharArray();
+ }
+ return resultEnd;
+}
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|