|
From: <caw...@us...> - 2007-03-13 19:16:11
|
Revision: 2158
http://svn.sourceforge.net/rubyeclipse/?rev=2158&view=rev
Author: cawilliams
Date: 2007-03-13 12:15:56 -0700 (Tue, 13 Mar 2007)
Log Message:
-----------
Modified Paths:
--------------
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/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/util/CharOperation.java
Added Paths:
-----------
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/ConstructorPattern.java
branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/RubySearchPattern.java
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-03-13 18:55:31 UTC (rev 2157)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java 2007-03-13 19:15:56 UTC (rev 2158)
@@ -240,4 +240,55 @@
return this.matchRule;
}
+ /**
+ * 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;
+ }
}
Added: branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/ConstructorPattern.java
===================================================================
--- branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/ConstructorPattern.java (rev 0)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/ConstructorPattern.java 2007-03-13 19:15:56 UTC (rev 2158)
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * 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 java.io.IOException;
+
+import org.rubypeople.rdt.core.Flags;
+import org.rubypeople.rdt.core.IMethod;
+import org.rubypeople.rdt.core.RubyModelException;
+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;
+import org.rubypeople.rdt.internal.core.util.Util;
+
+public class ConstructorPattern extends RubySearchPattern implements IIndexConstants {
+
+protected boolean findDeclarations;
+protected boolean findReferences;
+
+public char[] declaringQualification;
+public char[] declaringSimpleName;
+
+public char[][] parameterQualifications;
+public char[][] parameterSimpleNames;
+public int parameterCount;
+public boolean varargs = false;
+
+// Signatures and arguments for generic search
+char[][][] parametersTypeSignatures;
+char[][][][] parametersTypeArguments;
+boolean constructorParameters = false;
+char[][] constructorArguments;
+
+protected static char[][] REF_CATEGORIES = { CONSTRUCTOR_REF };
+protected static char[][] REF_AND_DECL_CATEGORIES = { CONSTRUCTOR_REF, CONSTRUCTOR_DECL };
+protected static char[][] DECL_CATEGORIES = { CONSTRUCTOR_DECL };
+
+/**
+ * Constructor entries are encoded as TypeName '/' Arity:
+ * e.g. 'X/0'
+ */
+public static char[] createIndexKey(char[] typeName, int argCount) {
+ char[] countChars = argCount < 10
+ ? COUNTS[argCount]
+ : ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
+ return CharOperation.concat(typeName, countChars);
+}
+
+ConstructorPattern(int matchRule) {
+ super(CONSTRUCTOR_PATTERN, matchRule);
+}
+public ConstructorPattern(
+ boolean findDeclarations,
+ boolean findReferences,
+ char[] declaringSimpleName,
+ char[] declaringQualification,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames,
+ int matchRule) {
+
+ this(matchRule);
+
+ this.findDeclarations = findDeclarations;
+ this.findReferences = findReferences;
+
+ this.declaringQualification = isCaseSensitive() ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
+ this.declaringSimpleName = (isCaseSensitive() || isCamelCase()) ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
+ if (parameterSimpleNames != null) {
+ this.parameterCount = parameterSimpleNames.length;
+ boolean synthetic = this.parameterCount>0 && declaringQualification != null && CharOperation.equals(CharOperation.concat(parameterQualifications[0], parameterSimpleNames[0], '.'), declaringQualification);
+ int offset = 0;
+ if (synthetic) {
+ // skip first synthetic parameter
+ this.parameterCount--;
+ offset++;
+ }
+ this.parameterQualifications = new char[this.parameterCount][];
+ this.parameterSimpleNames = new char[this.parameterCount][];
+ for (int i = 0; i < this.parameterCount; i++) {
+ this.parameterQualifications[i] = isCaseSensitive() ? parameterQualifications[i+offset] : CharOperation.toLowerCase(parameterQualifications[i+offset]);
+ this.parameterSimpleNames[i] = isCaseSensitive() ? parameterSimpleNames[i+offset] : CharOperation.toLowerCase(parameterSimpleNames[i+offset]);
+ }
+ } else {
+ this.parameterCount = -1;
+ }
+ ((InternalSearchPattern)this).mustResolve = mustResolve();
+}
+/*
+ * Instanciate a method pattern with signatures for generics search
+ */
+public ConstructorPattern(
+ boolean findDeclarations,
+ boolean findReferences,
+ char[] declaringSimpleName,
+ char[] declaringQualification,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames,
+ String[] parameterSignatures,
+ IMethod method,
+// boolean varargs,
+ int matchRule) {
+
+ this(findDeclarations,
+ findReferences,
+ declaringSimpleName,
+ declaringQualification,
+ parameterQualifications,
+ parameterSimpleNames,
+ matchRule);
+
+ // Set flags
+ try {
+ this.varargs = (method.getFlags() & Flags.AccVarargs) != 0;
+ } catch (RubyModelException e) {
+ // do nothing
+ }
+
+ // Get unique key for parameterized constructors
+ String genericDeclaringTypeSignature = null;
+ String key;
+ if (method.isResolved() && new BindingKey(key = method.getKey()).isParameterizedType()) {
+ genericDeclaringTypeSignature = Util.getDeclaringTypeSignature(key);
+ } else {
+ constructorParameters = true;
+ }
+
+ // Store type signature and arguments for declaring type
+ if (genericDeclaringTypeSignature != null) {
+ this.typeSignatures = Util.splitTypeLevelsSignature(genericDeclaringTypeSignature);
+ setTypeArguments(Util.getAllTypeArguments(this.typeSignatures));
+ } else {
+ storeTypeSignaturesAndArguments(method.getDeclaringType());
+ }
+
+ // store type signatures and arguments for method parameters type
+ if (parameterSignatures != null) {
+ int length = parameterSignatures.length;
+ if (length > 0) {
+ parametersTypeSignatures = new char[length][][];
+ parametersTypeArguments = new char[length][][][];
+ for (int i=0; i<length; i++) {
+ parametersTypeSignatures[i] = Util.splitTypeLevelsSignature(parameterSignatures[i]);
+ parametersTypeArguments[i] = Util.getAllTypeArguments(parametersTypeSignatures[i]);
+ }
+ }
+ }
+
+ // Store type signatures and arguments for method
+ constructorArguments = extractMethodArguments(method);
+ if (hasConstructorArguments()) ((InternalSearchPattern)this).mustResolve = true;
+}
+/*
+ * Instanciate a method pattern with signatures for generics search
+ */
+public ConstructorPattern(
+ boolean findDeclarations,
+ boolean findReferences,
+ char[] declaringSimpleName,
+ char[] declaringQualification,
+ String declaringSignature,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames,
+ String[] parameterSignatures,
+ char[][] arguments,
+ int matchRule) {
+
+ this(findDeclarations,
+ findReferences,
+ declaringSimpleName,
+ declaringQualification,
+ parameterQualifications,
+ parameterSimpleNames,
+ matchRule);
+
+ // Store type signature and arguments for declaring type
+ if (declaringSignature != null) {
+ typeSignatures = Util.splitTypeLevelsSignature(declaringSignature);
+ setTypeArguments(Util.getAllTypeArguments(typeSignatures));
+ }
+
+ // Store type signatures and arguments for method parameters type
+ if (parameterSignatures != null) {
+ int length = parameterSignatures.length;
+ if (length > 0) {
+ parametersTypeSignatures = new char[length][][];
+ parametersTypeArguments = new char[length][][][];
+ for (int i=0; i<length; i++) {
+ parametersTypeSignatures[i] = Util.splitTypeLevelsSignature(parameterSignatures[i]);
+ parametersTypeArguments[i] = Util.getAllTypeArguments(parametersTypeSignatures[i]);
+ }
+ }
+ }
+
+ // Store type signatures and arguments for method
+ constructorArguments = arguments;
+ if (arguments == null || arguments.length == 0) {
+ if (getTypeArguments() != null && getTypeArguments().length > 0) {
+ constructorArguments = getTypeArguments()[0];
+ }
+ }
+ if (hasConstructorArguments()) ((InternalSearchPattern)this).mustResolve = true;
+}
+public void decodeIndexKey(char[] key) {
+ int last = key.length - 1;
+ this.parameterCount = 0;
+ this.declaringSimpleName = null;
+ int power = 1;
+ for (int i=last; i>=0; i--) {
+ if (key[i] == SEPARATOR) {
+ System.arraycopy(key, 0, this.declaringSimpleName = new char[i], 0, i);
+ break;
+ }
+ if (i == last) {
+ this.parameterCount = key[i] - '0';
+ } else {
+ power *= 10;
+ this.parameterCount += power * (key[i] - '0');
+ }
+ }
+}
+public SearchPattern getBlankPattern() {
+ return new ConstructorPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
+}
+public char[][] getIndexCategories() {
+ if (this.findReferences)
+ return this.findDeclarations ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+ if (this.findDeclarations)
+ return DECL_CATEGORIES;
+ return CharOperation.NO_CHAR_CHAR;
+}
+boolean hasConstructorArguments() {
+ return constructorArguments != null && constructorArguments.length > 0;
+}
+boolean hasConstructorParameters() {
+ return constructorParameters;
+}
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+ ConstructorPattern pattern = (ConstructorPattern) decodedPattern;
+
+ return (this.parameterCount == pattern.parameterCount || this.parameterCount == -1 || this.varargs)
+ && matchesName(this.declaringSimpleName, pattern.declaringSimpleName);
+}
+protected boolean mustResolve() {
+ if (this.declaringQualification != null) return true;
+
+ // parameter types
+ if (this.parameterSimpleNames != null)
+ for (int i = 0, max = this.parameterSimpleNames.length; i < max; i++)
+ if (this.parameterQualifications[i] != null) return true;
+ return this.findReferences; // need to check resolved default constructors and explicit constructor calls
+}
+EntryResult[] queryIn(Index index) throws IOException {
+ char[] key = this.declaringSimpleName; // can be null
+ int matchRule = getMatchRule();
+
+ switch(getMatchMode()) {
+ case R_EXACT_MATCH :
+ if (this.isCamelCase) break;
+ if (this.declaringSimpleName != null && this.parameterCount >= 0 && !this.varargs)
+ key = createIndexKey(this.declaringSimpleName, this.parameterCount);
+ else { // do a prefix query with the declaringSimpleName
+ matchRule &= ~R_EXACT_MATCH;
+ matchRule |= R_PREFIX_MATCH;
+ }
+ break;
+ case R_PREFIX_MATCH :
+ // do a prefix query with the declaringSimpleName
+ break;
+ case R_PATTERN_MATCH :
+ if (this.parameterCount >= 0 && !this.varargs)
+ key = createIndexKey(this.declaringSimpleName == null ? ONE_STAR : this.declaringSimpleName, this.parameterCount);
+ else if (this.declaringSimpleName != null && this.declaringSimpleName[this.declaringSimpleName.length - 1] != '*')
+ key = CharOperation.concat(this.declaringSimpleName, ONE_STAR, SEPARATOR);
+ // else do a pattern query with just the declaringSimpleName
+ 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) {
+ if (this.findDeclarations) {
+ output.append(this.findReferences
+ ? "ConstructorCombinedPattern: " //$NON-NLS-1$
+ : "ConstructorDeclarationPattern: "); //$NON-NLS-1$
+ } else {
+ output.append("ConstructorReferencePattern: "); //$NON-NLS-1$
+ }
+ if (declaringQualification != null)
+ output.append(declaringQualification).append('.');
+ if (declaringSimpleName != null)
+ output.append(declaringSimpleName);
+ else if (declaringQualification != null)
+ output.append("*"); //$NON-NLS-1$
+
+ output.append('(');
+ if (parameterSimpleNames == null) {
+ output.append("..."); //$NON-NLS-1$
+ } else {
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ if (i > 0) output.append(", "); //$NON-NLS-1$
+ if (parameterQualifications[i] != null) output.append(parameterQualifications[i]).append('.');
+ if (parameterSimpleNames[i] == null) output.append('*'); else output.append(parameterSimpleNames[i]);
+ }
+ }
+ output.append(')');
+ return super.print(output);
+}
+}
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-03-13 18:55:31 UTC (rev 2157)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java 2007-03-13 19:15:56 UTC (rev 2158)
@@ -8,6 +8,7 @@
import org.eclipse.core.runtime.OperationCanceledException;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyProject;
+import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.search.IRubySearchScope;
import org.rubypeople.rdt.core.search.SearchDocument;
@@ -15,6 +16,7 @@
import org.rubypeople.rdt.core.search.SearchPattern;
import org.rubypeople.rdt.core.search.SearchRequestor;
import org.rubypeople.rdt.internal.compiler.env.INameEnvironment;
+import org.rubypeople.rdt.internal.compiler.impl.ITypeRequestor;
import org.rubypeople.rdt.internal.compiler.lookup.LookupEnvironment;
import org.rubypeople.rdt.internal.compiler.util.SimpleLookupTable;
import org.rubypeople.rdt.internal.core.ExternalSourceFolderRoot;
@@ -25,10 +27,32 @@
import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
import org.rubypeople.rdt.internal.core.search.RubySearchDocument;
import org.rubypeople.rdt.internal.core.util.HandleFactory;
+import org.rubypeople.rdt.internal.core.util.Messages;
import org.rubypeople.rdt.internal.core.util.Util;
-public class MatchLocator {
+public class MatchLocator implements ITypeRequestor {
+ public static final int MAX_AT_ONCE;
+ static {
+ long maxMemory = Runtime.getRuntime().maxMemory();
+ int ratio = (int) Math.round(((double) maxMemory) / (64 * 0x100000));
+ switch (ratio) {
+ case 0:
+ case 1:
+ MAX_AT_ONCE = 100;
+ break;
+ case 2:
+ MAX_AT_ONCE = 200;
+ break;
+ case 3:
+ MAX_AT_ONCE = 300;
+ break;
+ default:
+ MAX_AT_ONCE = 400;
+ break;
+ }
+ }
+
// permanent state
public SearchPattern pattern;
public PatternLocator patternLocator;
@@ -222,5 +246,123 @@
this.bindings = null;
}
}
+
+ /**
+ * Locate the matches amongst the possible matches.
+ */
+ protected void locateMatches(RubyProject javaProject, PossibleMatchSet matchSet, int expected) throws CoreException {
+ PossibleMatch[] possibleMatches = matchSet.getPossibleMatches(javaProject.getSourceFolderRoots());
+ int length = possibleMatches.length;
+ // increase progress from duplicate matches not stored in matchSet while adding...
+ if (this.progressMonitor != null && expected>length) {
+ this.progressWorked += expected-length;
+ this.progressMonitor.worked( expected-length);
+ }
+ // locate matches (processed matches are limited to avoid problem while using VM default memory heap size)
+ for (int index = 0; index < length;) {
+ int max = Math.min(MAX_AT_ONCE, length - index);
+ locateMatches(javaProject, possibleMatches, index, max);
+ index += max;
+ }
+ this.patternLocator.clear();
+ }
+
+ protected void locateMatches(RubyProject javaProject, PossibleMatch[] possibleMatches, int start, int length) throws CoreException {
+ initialize(javaProject, length);
+ // create and resolve binding (equivalent to beginCompilation() in Compiler)
+ boolean mustResolvePattern = ((InternalSearchPattern)this.pattern).mustResolve;
+ boolean mustResolve = mustResolvePattern;
+ this.patternLocator.mayBeGeneric = this.options.sourceLevel >= ClassFileConstants.JDK1_5;
+ boolean bindingsWereCreated = mustResolve;
+ try {
+ for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
+ PossibleMatch possibleMatch = possibleMatches[i];
+ try {
+ if (!parseAndBuildBindings(possibleMatch, mustResolvePattern)) continue;
+ // Currently we only need to resolve over pattern flag if there's potential parameterized types
+ if (this.patternLocator.mayBeGeneric) {
+ // If pattern does not resolve then rely on possible match node set resolution
+ // which may have been modified while locator was adding possible matches to it
+ if (!mustResolvePattern && !mustResolve) {
+ mustResolve = possibleMatch.nodeSet.mustResolve;
+ bindingsWereCreated = mustResolve;
+ }
+ } else {
+ // Reset matching node resolution with pattern one if there's no potential parameterized type
+ // to minimize side effect on previous search behavior
+ possibleMatch.nodeSet.mustResolve = mustResolvePattern;
+ }
+ // possible match node resolution has been merged with pattern one, so rely on it to know
+ // whether we need to process compilation unit now or later
+ if (!possibleMatch.nodeSet.mustResolve) {
+ if (this.progressMonitor != null) {
+ this.progressWorked++;
+ if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
+ }
+ process(possibleMatch, bindingsWereCreated);
+ if (this.numberOfMatches>0 && this.matchesToProcess[this.numberOfMatches-1] == possibleMatch) {
+ // forget last possible match as it was processed
+ this.numberOfMatches--;
+ }
+ }
+ } finally {
+ if (!possibleMatch.nodeSet.mustResolve)
+ possibleMatch.cleanUp();
+ }
+ }
+ if (mustResolve)
+ this.lookupEnvironment.completeTypeBindings();
+
+ // create hierarchy resolver if needed
+ IType focusType = getFocusType();
+ if (focusType == null) {
+ this.hierarchyResolver = null;
+ } else if (!createHierarchyResolver(focusType, possibleMatches)) {
+ // focus type is not visible, use the super type names instead of the bindings
+ if (computeSuperTypeNames(focusType) == null) return;
+ }
+ } catch (AbortCompilation e) {
+ bindingsWereCreated = false;
+ }
+
+ if (!mustResolve) {
+ return;
+ }
+
+ // possible match resolution
+ for (int i = 0; i < this.numberOfMatches; i++) {
+ if (this.progressMonitor != null && this.progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+ PossibleMatch possibleMatch = this.matchesToProcess[i];
+ this.matchesToProcess[i] = null; // release reference to processed possible match
+ try {
+ process(possibleMatch, bindingsWereCreated);
+ } catch (AbortCompilation e) {
+ // problem with class path: it could not find base classes
+ // continue and try next matching openable reporting innacurate matches (since bindings will be null)
+ bindingsWereCreated = false;
+ } catch (RubyModelException e) {
+ // problem with class path: it could not find base classes
+ // continue and try next matching openable reporting innacurate matches (since bindings will be null)
+ bindingsWereCreated = false;
+ } finally {
+ if (this.progressMonitor != null) {
+ this.progressWorked++;
+ if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
+ }
+ if (this.options.verbose)
+ System.out.println(
+ Messages.bind(Messages.compilation_done,
+ new String[] {
+ String.valueOf(i + 1),
+ String.valueOf(this.numberOfMatches),
+ new String(possibleMatch.parsedUnit.getFileName())
+ }));
+ // cleanup compilation unit result
+ possibleMatch.cleanUp();
+ }
+ }
+ }
+
}
Modified: 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/PatternLocator.java 2007-03-13 18:55:31 UTC (rev 2157)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/PatternLocator.java 2007-03-13 19:15:56 UTC (rev 2158)
@@ -65,4 +65,11 @@
}
return null;
}
+
+ /*
+ * Clear caches
+ */
+ protected void clear() {
+ // nothing to clear by default
+ }
}
Added: 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 (rev 0)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/RubySearchPattern.java 2007-03-13 19:15:56 UTC (rev 2158)
@@ -0,0 +1,205 @@
+package org.rubypeople.rdt.internal.core.search.matching;
+
+import org.rubypeople.rdt.core.IMethod;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.core.search.SearchPattern;
+import org.rubypeople.rdt.internal.core.util.CharOperation;
+
+public class RubySearchPattern extends SearchPattern {
+
+
+ /*
+ * Whether this pattern is case sensitive.
+ */
+ boolean isCaseSensitive;
+
+ /*
+ * Whether this pattern is camel case.
+ */
+ boolean isCamelCase;
+
+ /**
+ * One of following pattern value:
+ * <ul>
+ * <li>{@link #R_EXACT_MATCH}</li>
+ * <li>{@link #R_PREFIX_MATCH}</li>
+ * <li>{@link #R_PATTERN_MATCH}</li>
+ * <li>{@link #R_REGEXP_MATCH}</li>
+ * <li>{@link #R_CAMELCASE_MATCH}</li>
+ * </ul>
+ */
+ int matchMode;
+
+ /**
+ * One of {@link #R_ERASURE_MATCH}, {@link #R_EQUIVALENT_MATCH}, {@link #R_FULL_MATCH}.
+ */
+ int matchCompatibility;
+
+ /**
+ * Mask used on match rule for match mode.
+ */
+ public static final int MATCH_MODE_MASK = R_EXACT_MATCH | R_PREFIX_MATCH | R_PATTERN_MATCH | R_REGEXP_MATCH;
+
+ /**
+ * Mask used on match rule for generic relevance.
+ */
+ public static final int MATCH_COMPATIBILITY_MASK = R_ERASURE_MATCH | R_EQUIVALENT_MATCH | R_FULL_MATCH;
+
+ // Signatures and arguments for parameterized types search
+ char[][] typeSignatures;
+ private char[][][] typeArguments;
+ private int flags = 0;
+ static final int HAS_TYPE_ARGUMENTS = 1;
+
+ protected RubySearchPattern(int patternKind, int matchRule) {
+ super(matchRule);
+ ((InternalSearchPattern)this).kind = patternKind;
+ // Use getMatchRule() instead of matchRule as super constructor may modify its value
+ // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=81377
+ int rule = getMatchRule();
+ this.isCaseSensitive = (rule & R_CASE_SENSITIVE) != 0;
+ this.isCamelCase = (rule & R_CAMELCASE_MATCH) != 0;
+ this.matchCompatibility = rule & MATCH_COMPATIBILITY_MASK;
+ this.matchMode = rule & MATCH_MODE_MASK;
+ }
+
+ public SearchPattern getBlankPattern() {
+ return null;
+ }
+
+ int getMatchMode() {
+ return this.matchMode;
+ }
+
+ boolean isCamelCase() {
+ return this.isCamelCase;
+ }
+
+ boolean isCaseSensitive () {
+ return this.isCaseSensitive;
+ }
+
+ boolean isErasureMatch() {
+ return (this.matchCompatibility & R_ERASURE_MATCH) != 0;
+ }
+
+ boolean isEquivalentMatch() {
+ return (this.matchCompatibility & R_EQUIVALENT_MATCH) != 0;
+ }
+
+ /**
+ * @return Returns the typeArguments.
+ */
+ final char[][][] getTypeArguments() {
+ return typeArguments;
+ }
+
+ /**
+ * Returns whether the pattern has signatures or not.
+ * If pattern {@link #typeArguments} field, this field shows that it was built
+ * on a generic source type.
+ * @return true if {@link #typeSignatures} field is not null and has a length greater than 0.
+ */
+ public final boolean hasSignatures() {
+ return this.typeSignatures != null && this.typeSignatures.length > 0;
+ }
+
+ /**
+ * Returns whether the pattern includes type arguments information or not.
+ * @return default is false
+ */
+ public final boolean hasTypeArguments() {
+ return (this.flags & HAS_TYPE_ARGUMENTS) != 0;
+ }
+
+ /**
+ * Returns whether the pattern includes type parameters information or not.
+ * @return true if {@link #typeArguments} contains type parameters instead
+ * type arguments signatures.
+ */
+ public final boolean hasTypeParameters() {
+ return !hasSignatures() && hasTypeArguments();
+ }
+
+ protected StringBuffer print(StringBuffer output) {
+ output.append(", "); //$NON-NLS-1$
+ if (hasTypeArguments() && hasSignatures()) {
+ output.append("signature:\""); //$NON-NLS-1$
+ output.append(this.typeSignatures[0]);
+ 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;
+ }
+
+ /*
+// * Extract method arguments using unique key for parameterized methods
+ * and type parameters for non-generic ones.
+ */
+ char[][] extractMethodArguments(IMethod method) {
+ String[] argumentsSignatures = null;
+ BindingKey key;
+ if (method.isResolved() && (key = new BindingKey(method.getKey())).isParameterizedType()) {
+ argumentsSignatures = key.getTypeArguments();
+ } else {
+ try {
+ ITypeParameter[] parameters = method.getTypeParameters();
+ if (parameters != null) {
+ int length = parameters.length;
+ if (length > 0) {
+ char[][] arguments = new char[length][];
+ for (int i=0; i<length; i++) {
+ arguments[i] = Signature.createTypeSignature(parameters[i].getElementName(), false).toCharArray();
+ }
+ return arguments;
+ }
+ }
+ }
+ catch (RubyModelException jme) {
+ // do nothing
+ }
+ return null;
+ }
+
+ // Parameterized method
+ if (argumentsSignatures != null) {
+ int length = argumentsSignatures.length;
+ if (length > 0) {
+ char[][] methodArguments = new char[length][];
+ for (int i=0; i<length; i++) {
+ methodArguments[i] = argumentsSignatures[i].toCharArray();
+ CharOperation.replace(methodArguments[i], new char[] { '$', '/' }, '.');
+ }
+ return methodArguments;
+ }
+ }
+ return null;
+ }
+
+}
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-03-13 18:55:31 UTC (rev 2157)
+++ branches/search_engine/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/CharOperation.java 2007-03-13 19:15:56 UTC (rev 2158)
@@ -1511,4 +1511,155 @@
char[] result = concatWith(array, '.');
return new String(result);
}
+
+ /**
+ * Answers the concatenation of the two arrays. It answers null if the two arrays are null.
+ * If the first array is null, then the second array is returned.
+ * If the second array is null, then the first array is returned.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = { 'a' }
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = null
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = { ' b' }
+ * => result = { ' a' , ' b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first the first array to concatenate
+ * @param second the second array to concatenate
+ * @return the concatenation of the two arrays, or null if the two arrays are null.
+ */
+ public static final char[] concat(char[] first, char[] second) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+
+ int length1 = first.length;
+ int length2 = second.length;
+ char[] result = new char[length1 + length2];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ return result;
+ }
+
+ /**
+ * Answers the result of a char[] conversion to lowercase. Answers null if the given chars array is null.
+ * <br>
+ * NOTE: If no conversion was necessary, then answers back the argument one.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * chars = { 'a' , 'b' }
+ * result => { 'a' , 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'A', 'b' }
+ * result => { 'a' , 'b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param chars the chars to convert
+ * @return the result of a char[] conversion to lowercase
+ */
+ final static public char[] toLowerCase(char[] chars) {
+ if (chars == null)
+ return null;
+ int length = chars.length;
+ char[] lowerChars = null;
+ for (int i = 0; i < length; i++) {
+ char c = chars[i];
+ char lc = ScannerHelper.toLowerCase(c);
+ if ((c != lc) || (lowerChars != null)) {
+ if (lowerChars == null) {
+ System.arraycopy(
+ chars,
+ 0,
+ lowerChars = new char[length],
+ 0,
+ i);
+ }
+ lowerChars[i] = lc;
+ }
+ }
+ return lowerChars == null ? chars : lowerChars;
+ }
+
+ /**
+ * Replace all occurrences of characters to be replaced with the remplacement character in the
+ * given array.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
+ * toBeReplaced = { 'b', 'c' }
+ * replacementChar = 'a'
+ * result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array the given array
+ * @param toBeReplaced characters to be replaced
+ * @param replacementChar the replacement character
+ * @throws NullPointerException if arrays are null.
+ * @since 3.1
+ */
+ public static final void replace(char[] array, char[] toBeReplaced, char replacementChar) {
+ replace(array, toBeReplaced, replacementChar, 0, array.length);
+ }
+
+ /**
+ * Replace all occurrences of characters to be replaced with the remplacement character in the
+ * given array from the start position (inclusive) to the end position (exclusive).
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
+ * toBeReplaced = { 'b', 'c' }
+ * replacementChar = 'a'
+ * start = 4
+ * end = 8
+ * result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'c', 'a', 'a', 'a', 'a' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array the given array
+ * @param toBeReplaced characters to be replaced
+ * @param replacementChar the replacement character
+ * @param start the given start position (inclusive)
+ * @param end the given end position (exclusive)
+ * @throws NullPointerException if arrays are null.
+ * @since 3.2
+ */
+ public static final void replace(char[] array, char[] toBeReplaced, char replacementChar, int start, int end) {
+ for (int i = end; --i >= start;)
+ for (int j = toBeReplaced.length; --j >= 0;)
+ if (array[i] == toBeReplaced[j])
+ array[i] = replacementChar;
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|