|
From: <caw...@us...> - 2007-05-15 17:34:22
|
Revision: 2478
http://svn.sourceforge.net/rubyeclipse/?rev=2478&view=rev
Author: cawilliams
Date: 2007-05-15 10:34:21 -0700 (Tue, 15 May 2007)
Log Message:
-----------
replace our existing symbol index stuff with a first cut at a fully fledged search engine
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/META-INF/MANIFEST.MF
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/AbstractRdtCompiler.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/CleanRdtCompiler.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/IncrementalRdtCompiler.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/RubyBuilder.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/RubyCodeAnalyzer.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/MatchLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/PatternLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/TypeReferencePattern.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/Messages.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/util/Util.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/core/TS_Core.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/TS_InternalCore.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/AbstractRdtTestCase.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TC_CleanRdtCompiler.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TC_IncrementalRdtCompiler.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TC_RubyCodeAnalyzer.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TS_InternalCoreBuilder.java
Added Paths:
-----------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/FieldReferenceMatch.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/TypeReferenceMatch.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/LocalVariableLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/LocalVariablePattern.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/OrLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/TypeReferenceLocator.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/matching/VariableLocator.java
Removed Paths:
-------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/SymbolIndexResourceChangeListener.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/IndexUpdater.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/MassIndexUpdater.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/builder/MassIndexUpdaterJob.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/ClassSymbol.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/ISymbolFinder.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/ISymbolTypes.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/Location.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/MethodSymbol.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/SearchResult.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/Symbol.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/SymbolIndex.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/symbols/SymbolSchedulingRule.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/ShamMassIndexUpdater.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/TC_SymbolIndexResourceEventListener.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/ShamIndexUpdater.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/ShamSymbolIndex.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TC_IndexUpdater.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TC_MassIndexUpdater.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/builder/TC_MassIndexUpdaterJob.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/symbols/TC_ClassSymbol.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/symbols/TC_Location.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/symbols/TC_SymbolIndex.java
trunk/org.rubypeople.rdt.core.tests/src/org/rubypeople/rdt/internal/core/symbols/TS_CoreSymbols.java
Modified: trunk/org.rubypeople.rdt.core/META-INF/MANIFEST.MF
===================================================================
--- trunk/org.rubypeople.rdt.core/META-INF/MANIFEST.MF 2007-05-15 16:35:35 UTC (rev 2477)
+++ trunk/org.rubypeople.rdt.core/META-INF/MANIFEST.MF 2007-05-15 17:34:21 UTC (rev 2478)
@@ -19,7 +19,6 @@
org.rubypeople.rdt.internal.core.parser,
org.rubypeople.rdt.internal.core.parser.warnings,
org.rubypeople.rdt.internal.core.search,
- org.rubypeople.rdt.internal.core.symbols,
org.rubypeople.rdt.internal.core.util,
org.rubypeople.rdt.internal.formatter,
org.rubypeople.rdt.internal.ti,
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java 2007-05-15 16:35:35 UTC (rev 2477)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java 2007-05-15 17:34:21 UTC (rev 2478)
@@ -12,7 +12,6 @@
import java.io.File;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
@@ -57,13 +56,8 @@
import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.core.RubyProject;
import org.rubypeople.rdt.internal.core.SetLoadpathOperation;
-import org.rubypeople.rdt.internal.core.SymbolIndexResourceChangeListener;
-import org.rubypeople.rdt.internal.core.builder.IndexUpdater;
-import org.rubypeople.rdt.internal.core.builder.MassIndexUpdaterJob;
import org.rubypeople.rdt.internal.core.builder.RubyBuilder;
import org.rubypeople.rdt.internal.core.parser.RubyParser;
-import org.rubypeople.rdt.internal.core.symbols.ISymbolFinder;
-import org.rubypeople.rdt.internal.core.symbols.SymbolIndex;
import org.rubypeople.rdt.internal.core.util.MementoTokenizer;
import org.rubypeople.rdt.internal.core.util.Util;
@@ -75,7 +69,6 @@
private static final String RUBY_PARSER_DEBUG_OPTION = RubyCore.PLUGIN_ID + "/rubyparser";//$NON-NLS-1$
private static final String MODEL_MANAGER_VERBOSE_OPTION = RubyCore.PLUGIN_ID + "/modelmanager";//$NON-NLS-1$
- private static final String SYMBOL_INDEX_VERBOSE_OPTION = RubyCore.PLUGIN_ID + "/symbolIndex";//$NON-NLS-1$
private static final String BUILDER_VERBOSE_OPTION = RubyCore.PLUGIN_ID + "/rubyBuilder";//$NON-NLS-1$
public final static String NATURE_ID = PLUGIN_ID + ".rubynature";//$NON-NLS-1$
@@ -288,17 +281,12 @@
* @since 1.0.0
*/
public static final String USER_LIBRARY_CONTAINER_ID= "org.rubypeople.rdt.USER_LIBRARY"; //$NON-NLS-1$
-
-
+
private static final boolean VERBOSE = false;
- private SymbolIndex symbolIndex;
- private ISymbolFinder symbolFinder;
-
public RubyCore() {
super();
RUBY_CORE_PLUGIN = this;
- symbolFinder = symbolIndex = new SymbolIndex();
}
/**
@@ -325,16 +313,9 @@
RubyParser.setDebugging(isDebugOptionTrue(RUBY_PARSER_DEBUG_OPTION));
RubyModelManager.setVerbose(isDebugOptionTrue(MODEL_MANAGER_VERBOSE_OPTION));
- SymbolIndex.setVerbose(isDebugOptionTrue(SYMBOL_INDEX_VERBOSE_OPTION));
RubyBuilder.setVerbose(isDebugOptionTrue(BUILDER_VERBOSE_OPTION));
ResourcesPlugin.getWorkspace().addResourceChangeListener(new RubyProjectListener(), IResourceChangeEvent.POST_CHANGE);
-
- SymbolIndexResourceChangeListener.register(symbolIndex);
- IndexUpdater indexUpdater = new IndexUpdater(symbolIndex);
- List rubyProjects = Arrays.asList(getRubyProjects());
- MassIndexUpdaterJob massUpdater = new MassIndexUpdaterJob(indexUpdater, rubyProjects);
- massUpdater.schedule();
}
/*
@@ -540,18 +521,6 @@
}
}
- public SymbolIndex getSymbolIndex() {
- return symbolIndex;
- }
-
- public ISymbolFinder getSymbolFinder() {
- return symbolFinder;
- }
-
- public void setSymbolFinder(ISymbolFinder symbolFinder) {
- this.symbolFinder = symbolFinder;
- }
-
/**
* Helper method for returning one option value only. Equivalent to
* <code>(String)JavaCore.getOptions().get(optionName)</code> Note that it
Added: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/FieldReferenceMatch.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/FieldReferenceMatch.java (rev 0)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/FieldReferenceMatch.java 2007-05-15 17:34:21 UTC (rev 2478)
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.rubypeople.rdt.core.IRubyElement;
+
+/**
+ * A Java search match that represents a field reference.
+ * The element is the inner-most enclosing member that references this field.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class FieldReferenceMatch extends SearchMatch {
+
+ private boolean isReadAccess;
+ private boolean isWriteAccess;
+
+ /**
+ * Creates a new field reference match.
+ *
+ * @param enclosingElement the inner-most enclosing member that references this field
+ * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+ * @param offset the offset the match starts at, or -1 if unknown
+ * @param length the length of the match, or -1 if unknown
+ * @param isReadAccess whether the match represents a read access
+ * @param isWriteAccess whethre the match represents a write access
+ * @param insideDocComment <code>true</code> if this search match is inside a doc
+ * comment, and <code>false</code> otherwise
+ * @param participant the search participant that created the match
+ * @param resource the resource of the element
+ */
+ public FieldReferenceMatch(IRubyElement enclosingElement, int accuracy, int offset, int length, boolean isReadAccess, boolean isWriteAccess, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+ super(enclosingElement, accuracy, offset, length, participant, resource);
+ this.isReadAccess = isReadAccess;
+ this.isWriteAccess = isWriteAccess;
+ setInsideDocComment(insideDocComment);
+ }
+
+ /**
+ * Returns whether the field reference is a read access to the field.
+ * Note that a field reference can be read and written at once in case of compound assignments (e.g. i += 0;)
+ *
+ * @return whether the field reference is a read access to the field.
+ */
+ public final boolean isReadAccess() {
+ return this.isReadAccess;
+ }
+
+ /**
+ * Returns whether the field reference is a write access to the field.
+ * Note that a field reference can be read and written at once in case of compound assignments (e.g. i += 0;)
+ *
+ * @return whether the field reference is a write access to the field.
+ */
+ public final boolean isWriteAccess() {
+ return this.isWriteAccess;
+ }
+
+}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java 2007-05-15 16:35:35 UTC (rev 2477)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/IRubySearchConstants.java 2007-05-15 17:34:21 UTC (rev 2478)
@@ -1,88 +1,95 @@
-package org.rubypeople.rdt.core.search;
-
-import org.rubypeople.rdt.internal.core.search.processing.IJob;
-
-public interface IRubySearchConstants {
- /**
- * The search operation waits for the underlying indexer to finish indexing
- * 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;
-
- /**
- * 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;
-
-/* Nature of searched element */
-
- /**
- * The searched element is a type, which may include classes and modules.
- */
- int TYPE= 0;
-
- /**
- * The searched element is a method.
- */
- int METHOD= 1;
-
- /**
- * The searched element is a constructor.
- */
- int CONSTRUCTOR= 3;
-
- /**
- * The searched element is a field.
- */
- int FIELD= 4;
-
- /**
- * The searched element is a class.
- * More selective than using {@link #TYPE}.
- */
- int CLASS= 5;
-
- /**
- * The searched element is a module.
- * More selective than using {@link #TYPE}.
- */
- int MODULE= 6;
-
-}
+package org.rubypeople.rdt.core.search;
+
+import org.rubypeople.rdt.internal.core.search.processing.IJob;
+
+public interface IRubySearchConstants {
+ /**
+ * The search operation waits for the underlying indexer to finish indexing
+ * 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= 1;
+
+ /**
+ * 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= 2;
+
+ /**
+ * 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 = 3;
+
+ /**
+ * 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 = 4;
+
+ /**
+ * Ignore declaring type while searching result.
+ * Can be used in conjunction with any of the nature of match.
+ * @since 1.0
+ */
+ int IGNORE_DECLARING_TYPE = 0x10;
+
+/* Nature of searched element */
+
+ /**
+ * The searched element is a type, which may include classes and modules.
+ */
+ int TYPE= 0;
+
+ /**
+ * The searched element is a method.
+ */
+ int METHOD= 1;
+
+ /**
+ * The searched element is a constructor.
+ */
+ int CONSTRUCTOR= 2;
+
+ /**
+ * The searched element is a field.
+ */
+ int FIELD= 3;
+
+ /**
+ * The searched element is a class.
+ * More selective than using {@link #TYPE}.
+ */
+ int CLASS= 4;
+
+ /**
+ * The searched element is a module.
+ * More selective than using {@link #TYPE}.
+ */
+ int MODULE= 5;
+
+}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java 2007-05-15 16:35:35 UTC (rev 2477)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchEngine.java 2007-05-15 17:34:21 UTC (rev 2478)
@@ -1,5 +1,6 @@
package org.rubypeople.rdt.core.search;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.RubyModelException;
@@ -100,4 +101,63 @@
return BasicSearchEngine.createRubySearchScope(elements);
}
+ /**
+ * Returns a Ruby search scope limited to the given Ruby elements.
+ * The Ruby elements resulting from a search with this scope will
+ * be children of the given elements.
+ *
+ * If an element is an IRubyProject, then it includes:
+ * - its source folders if IRubySearchScope.SOURCES is specified,
+ * - its application libraries (internal and external jars, class folders that are on the raw classpath,
+ * or the ones that are coming from a classpath path variable,
+ * or the ones that are coming from a classpath container with the K_APPLICATION kind)
+ * if IJavaSearchScope.APPLICATION_LIBRARIES is specified
+ * - its system libraries (internal and external jars, class folders that are coming from an
+ * IClasspathContainer with the K_SYSTEM kind)
+ * if IJavaSearchScope.APPLICATION_LIBRARIES is specified
+ * - its referenced projects (with their source folders and jars, recursively)
+ * if IJavaSearchScope.REFERENCED_PROJECTS is specified.
+ * If an element is an IPackageFragmentRoot, then only the package fragments of
+ * this package fragment root will be included.
+ * If an element is an IPackageFragment, then only the compilation unit and class
+ * files of this package fragment will be included. Subpackages will NOT be
+ * included.
+ *
+ * @param elements the Ruby elements the scope is limited to
+ * @param includeMask the bit-wise OR of all include types of interest
+ * @return a new Ruby search scope
+ * @see IRubySearchScope#SOURCES
+ * @see IRubySearchScope#APPLICATION_LIBRARIES
+ * @see IRubySearchScope#SYSTEM_LIBRARIES
+ * @see IRubySearchScope#REFERENCED_PROJECTS
+ * @since 1.0
+ */
+ public static IRubySearchScope createRubySearchScope(IRubyElement[] elements, int includeMask) {
+ return BasicSearchEngine.createRubySearchScope(elements, includeMask);
+ }
+
+ public static SearchParticipant getDefaultSearchParticipant() {
+ return BasicSearchEngine.getDefaultSearchParticipant();
+ }
+
+ /**
+ * 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
+ * being searched (for example, search method declarations in a case sensitive way).
+ *
+ * @param pattern the pattern to search
+ * @param participants the particpants in the search
+ * @param scope the search scope
+ * @param requestor the requestor to report the matches to
+ * @param monitor the progress monitor used to report progress
+ * @exception CoreException if the search failed. Reasons include:
+ * <ul>
+ * <li>the classpath is incorrectly set</li>
+ * </ul>
+ *@since 1.0
+ */
+ public void search(SearchPattern pattern, SearchParticipant[] participants, IRubySearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
+ this.basicEngine.search(pattern, participants, scope, requestor, monitor);
+ }
+
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java 2007-05-15 16:35:35 UTC (rev 2477)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/search/SearchPattern.java 2007-05-15 17:34:21 UTC (rev 2478)
@@ -1,791 +1,1207 @@
-package org.rubypeople.rdt.core.search;
-
-import org.rubypeople.rdt.core.IRubyElement;
-import org.rubypeople.rdt.internal.compiler.parser.ScannerHelper;
-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;
-import org.rubypeople.rdt.internal.core.search.matching.QualifiedTypeDeclarationPattern;
-import org.rubypeople.rdt.internal.core.search.matching.TypeReferencePattern;
-import org.rubypeople.rdt.internal.core.util.CharOperation;
-
-public abstract class SearchPattern extends InternalSearchPattern {
-// Rules for pattern matching: (exact, prefix, pattern) [ | case sensitive]
- /**
- * Match rule: The search pattern matches exactly the search result,
- * that is, the source of the search result equals the search pattern.
- */
- public static final int R_EXACT_MATCH = 0;
-
- /**
- * Match rule: The search pattern is a prefix of the search result.
- */
- public static final int R_PREFIX_MATCH = 0x0001;
-
- /**
- * Match rule: The search pattern contains one or more wild cards ('*' or '?').
- * A '*' wild-card can replace 0 or more characters in the search result.
- * A '?' wild-card replaces exactly 1 character in the search result.
- */
- public static final int R_PATTERN_MATCH = 0x0002;
-
- /**
- * Match rule: The search pattern contains a regular expression.
- */
- public static final int R_REGEXP_MATCH = 0x0004;
-
- /**
- * Match rule: The search pattern matches the search result only if cases are the same.
- * Can be combined to previous rules, e.g. {@link #R_EXACT_MATCH} | {@link #R_CASE_SENSITIVE}
- */
- public static final int R_CASE_SENSITIVE = 0x0008;
-
- /**
- * Match rule: The search pattern matches search results as raw/parameterized types/methods with same erasure.
- * This mode has no effect on other java elements search.<br>
- * Type search example:
- * <ul>
- * <li>pattern: <code>List<Exception></code></li>
- * <li>match: <code>List<Object></code></li>
- * </ul>
- * Method search example:
- * <ul>
- * <li>declaration: <code><T>foo(T t)</code></li>
- * <li>pattern: <code><Exception>foo(new Exception())</code></li>
- * <li>match: <code><Object>foo(new Object())</code></li>
- * </ul>
- * Can be combined to all other match rules, e.g. {@link #R_CASE_SENSITIVE} | {@link #R_ERASURE_MATCH}
- * This rule is not activated by default, so raw types or parameterized types with same erasure will not be found
- * for pattern List<String>,
- * Note that with this pattern, the match selection will be only on the erasure even for parameterized types.
- * @since 3.1
- */
- public static final int R_ERASURE_MATCH = 0x0010;
-
- /**
- * Match rule: The search pattern matches search results as raw/parameterized types/methods with equivalent type parameters.
- * This mode has no effect on other java elements search.<br>
- * Type search example:
- * <ul>
- * <li>pattern: <code>List<Exception></code></li>
- * <li>match:
- * <ul>
- * <li><code>List<? extends Throwable></code></li>
- * <li><code>List<? super RuntimeException></code></li>
- * <li><code>List<?></code></li>
- * </ul>
- * </li>
- * </ul>
- * Method search example:
- * <ul>
- * <li>declaration: <code><T>foo(T t)</code></li>
- * <li>pattern: <code><Exception>foo(new Exception())</code></li>
- * <li>match:
- * <ul>
- * <li><code><? extends Throwable>foo(new Exception())</code></li>
- * <li><code><? super RuntimeException>foo(new Exception())</code></li>
- * <li><code>foo(new Exception())</code></li>
- * </ul>
- * </ul>
- * Can be combined to all other match rules, e.g. {@link #R_CASE_SENSITIVE} | {@link #R_EQUIVALENT_MATCH}
- * This rule is not activated by default, so raw types or equivalent parameterized types will not be found
- * for pattern List<String>,
- * This mode is overridden by {@link #R_ERASURE_MATCH} as erasure matches obviously include equivalent ones.
- * That means that pattern with rule set to {@link #R_EQUIVALENT_MATCH} | {@link #R_ERASURE_MATCH}
- * will return same results than rule only set with {@link #R_ERASURE_MATCH}.
- * @since 3.1
- */
- public static final int R_EQUIVALENT_MATCH = 0x0020;
-
- /**
- * Match rule: The search pattern matches exactly the search result,
- * that is, the source of the search result equals the search pattern.
- * @since 3.1
- */
- public static final int R_FULL_MATCH = 0x0040;
-
- /**
- * Match rule: The search pattern contains a Camel Case expression.
- * <br>
- * Examples:
- * <ul>
- * <li><code>NPE</code> type string pattern will match
- * <code>NullPointerException</code> and <code>NpPermissionException</code> types,</li>
- * <li><code>NuPoEx</code> type string pattern will only match
- * <code>NullPointerException</code> type.</li>
- * </ul>
- * @see CharOperation#camelCaseMatch(char[], char[]) for a detailed explanation
- * of Camel Case matching.
- *<br>
- * Can be combined to {@link #R_PREFIX_MATCH} match rule. For example,
- * when prefix match rule is combined with Camel Case match rule,
- * <code>"nPE"</code> pattern will match <code>nPException</code>.
- *<br>
- * Match rule {@link #R_PATTERN_MATCH} may also be combined but both rules
- * will not be used simultaneously as they are mutually exclusive.
- * Used match rule depends on whether string pattern contains specific pattern
- * characters (e.g. '*' or '?') or not. If it does, then only Pattern match rule
- * will be used, otherwise only Camel Case match will be used.
- * For example, with <code>"NPE"</code> string pattern, search will only use
- * Camel Case match rule, but with <code>N*P*E*</code> string pattern, it will
- * use only Pattern match rule.
- *
- * @since 3.2
- */
- public static final int R_CAMELCASE_MATCH = 0x0080;
-
- private static final int MODE_MASK = R_EXACT_MATCH | R_PREFIX_MATCH | R_PATTERN_MATCH | R_REGEXP_MATCH;
-
- private int matchRule;
-
- /**
- * Creates a search pattern with the rule to apply for matching index keys.
- * It can be exact match, prefix match, pattern match or regexp match.
- * Rule can also be combined with a case sensitivity flag.
- *
- * @param matchRule one of {@link #R_EXACT_MATCH}, {@link #R_PREFIX_MATCH}, {@link #R_PATTERN_MATCH},
- * {@link #R_REGEXP_MATCH}, {@link #R_CAMELCASE_MATCH} combined with one of following values:
- * {@link #R_CASE_SENSITIVE}, {@link #R_ERASURE_MATCH} or {@link #R_EQUIVALENT_MATCH}.
- * e.g. {@link #R_EXACT_MATCH} | {@link #R_CASE_SENSITIVE} if an exact and case sensitive match is requested,
- * {@link #R_PREFIX_MATCH} if a prefix non case sensitive match is requested or {@link #R_EXACT_MATCH} | {@link #R_ERASURE_MATCH}
- * if a non case sensitive and erasure match is requested.<br>
- * Note that {@link #R_ERASURE_MATCH} or {@link #R_EQUIVALENT_MATCH} have no effect
- * on non-generic types/methods search.<br>
- * Note also that default behavior for generic types/methods search is to find exact matches.
- */
- public SearchPattern(int matchRule) {
- this.matchRule = matchRule;
- // Set full match implicit mode
- if ((matchRule & (R_EQUIVALENT_MATCH | R_ERASURE_MATCH )) == 0) {
- this.matchRule |= R_FULL_MATCH;
- }
- }
-
- /**
- * Returns a blank pattern that can be used as a record to decode an index key.
- * <p>
- * Implementors of this method should return a new search pattern that is going to be used
- * to decode index keys.
- * </p>
- *
- * @return a new blank pattern
- * @see #decodeIndexKey(char[])
- */
- public abstract SearchPattern getBlankPattern();
-
- /**
- * Decode the given index key in this pattern. The decoded index key is used by
- * {@link #matchesDecodedKey(SearchPattern)} to find out if the corresponding index entry
- * should be considered.
- * <p>
- * This method should be re-implemented in subclasses that need to decode an index key.
- * </p>
- *
- * @param key the given index key
- */
- public void decodeIndexKey(char[] key) {
- // called from findIndexMatches(), override as necessary
- }
-
- /**
- * Returns a key to find in relevant index categories, if null then all index entries are matched.
- * The key will be matched according to some match rule. These potential matches
- * will be further narrowed by the match locator, but precise match locating can be expensive,
- * and index query should be as accurate as possible so as to eliminate obvious false hits.
- * <p>
- * This method should be re-implemented in subclasses that need to narrow down the
- * index query.
- * </p>
- *
- * @return an index key from this pattern, or <code>null</code> if all index entries are matched.
- */
- public char[] getIndexKey() {
- return null; // called from queryIn(), override as necessary
- }
- /**
- * Returns an array of index categories to consider for this index query.
- * These potential matches will be further narrowed by the match locator, but precise
- * match locating can be expensive, and index query should be as accurate as possible
- * so as to eliminate obvious false hits.
- * <p>
- * This method should be re-implemented in subclasses that need to narrow down the
- * index query.
- * </p>
- *
- * @return an array of index categories
- */
- public char[][] getIndexCategories() {
- return CharOperation.NO_CHAR_CHAR; // called from queryIn(), override as necessary
- }
-
- /**
- * Returns the rule to apply for matching index keys. Can be exact match, prefix match, pattern match or regexp match.
- * Rule can also be combined with a case sensitivity flag.
- *
- * @return one of R_EXACT_MATCH, R_PREFIX_MATCH, R_PATTERN_MATCH, R_REGEXP_MATCH combined with R_CASE_SENSITIVE,
- * e.g. R_EXACT_MATCH | R_CASE_SENSITIVE if an exact and case sensitive match is requested,
- * or R_PREFIX_MATCH if a prefix non case sensitive match is requested.
- * [TODO (frederic) I hope R_ERASURE_MATCH doesn't need to be on this list. Because it would be a breaking API change.]
- */
- public final int getMatchRule() {
- return this.matchRule;
- }
- /**
- * Returns whether this pattern matches the given pattern (representing a decoded index key).
- * <p>
- * This method should be re-implemented in subclasses that need to narrow down the
- * index query.
- * </p>
- *
- * @param decodedPattern a pattern representing a decoded index key
- * @return whether this pattern matches the given pattern
- */
- public boolean matchesDecodedKey(SearchPattern decodedPattern) {
- 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*/);
- case IRubyElement.FIELD:
- case IRubyElement.CONSTANT:
- case IRubyElement.GLOBAL:
- case IRubyElement.CLASS_VAR:
- case IRubyElement.INSTANCE_VAR:
- return createFieldPattern(stringPattern, limitTo, matchRule);
- default:
- break;
- }
- return null;
- }
-
- /**
- * 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
- * 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[] typePart = patternString.toCharArray();
- char[] typeChars = null;
- char[] qualificationChars = null;
- // 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+2, 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;
- }
-
- /**
- * Method pattern are formed by:<br>
- * [declaringType '.'] selector ['(' parameterTypes ')']
- * <br>e.g.<ul>
- * <li>java.lang.Runnable.run() void</li>
- * <li>main(*)</li>
- * <li><String>toArray(String[])</li>
- * </ul>
- * Constructor pattern are formed by:<br>
- * [declaringQualification '.'] type ['(' parameterTypes ')']
- * <br>e.g.<ul>
- * <li>java.lang.Object()</li>
- * <li>Main(*)</li>
- * <li><Exception>Sample(Exception)</li>
- * </ul>
- * Type arguments have the same pattern that for type patterns
- * @see #createTypePattern(String,int,int,char)
- */
- private static SearchPattern createMethodOrConstructorPattern(String patternString, int limitTo, int matchRule, boolean isConstructor) {
- char[] selectorChars = patternString.toCharArray();
- // TODO Break up the patternString into declaring type, method name, etc
- char[][] parameterNames = new char[0][];
- char[] declaringTypeSimpleName = null;
- char[] declaringTypeQualification = null;
- // Create method/constructor pattern
- boolean findDeclarations = true;
- boolean findReferences = true;
- switch (limitTo) {
- case IRubySearchConstants.DECLARATIONS :
- findReferences = false;
- break;
- case IRubySearchConstants.REFERENCES :
- findDeclarations = false;
- break;
- case IRubySearchConstants.ALL_OCCURRENCES :
- break;
- }
- if (isConstructor) {
- return new ConstructorPattern(
- findDeclarations,
- findReferences,
- declaringTypeSimpleName,
- declaringTypeQualification,
- parameterNames,
- matchRule);
- } else {
- return new MethodPattern(
- findDeclarations,
- findReferences,
- selectorChars,
- declaringTypeQualification,
- declaringTypeSimpleName,
- parameterNames,
- matchRule);
- }
- }
-
- /**
- * Answers true if the pattern matches the given name using CamelCase rules, or false otherwise.
- * CamelCase matching does NOT accept explicit wild-cards '*' and '?' and is inherently case sensitive.
- * <br>
- * CamelCase denotes the convention of writing compound names without spaces, and capitalizing every term.
- * This function recognizes both upper and lower CamelCase, depending whether the leading character is capitalized
- * or not. The leading part of an upper CamelCase pattern is assumed to contain a sequence of capitals which are appearing
- * in the matching name; e.g. 'NPE' will match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
- * uses a lowercase first character. In Java, type names follow the upper CamelCase convention, whereas method or field
- * names follow the lower CamelCase convention.
- * <br>
- * The pattern may contain lowercase characters, which will be match in a case sensitive way. These characters must
- * appear in sequence in the name. For instance, 'NPExcep' will match 'NullPointerException', but not 'NullPointerExCEPTION'
- * or 'NuPoEx' will match 'NullPointerException', but not 'NoPointerException'.
- * <br><br>
- * Examples:
- * <ol>
- * <li><pre>
- * pattern = "NPE"
- * name = NullPointerException / NoPermissionException
- * result => true
- * </pre>
- * </li>
- * <li><pre>
- * pattern = "NuPoEx"
- * name = NullPointerException
- * result => true
- * </pre>
- * </li>
- * <li><pre>
- * pattern = "npe"
- * name = NullPointerException
- * result => false
- * </pre>
- * </li>
- * </ol>
- * @see CharOperation#camelCaseMatch(char[], char[])
- * Implementation has been entirely copied from this method except for array lengthes
- * which were obviously replaced with calls to {@link String#length()}.
- *
- * @param pattern the given pattern
- * @param name the given name
- * @return true if the pattern matches the given name, false otherwise
- * @since 3.2
- */
- public static final boolean camelCaseMatch(String pattern, String name) {
- if (pattern == null)
- return true; // null pattern is equivalent to '*'
- if (name == null)
- return false; // null name cannot match
-
- return camelCaseMatch(pattern, 0, pattern.length(), name, 0, name.length());
- }
-
- /**
- * Answers true if a sub-pattern matches the subpart of the given name using CamelCase rules, or false otherwise.
- * CamelCase matching does NOT accept explicit wild-cards '*' and '?' and is inherently case sensitive.
- * Can match only subset of name/pattern, considering end positions as non-inclusive.
- * The subpattern is defined by the patternStart and patternEnd positions.
- * <br>
- * CamelCase denotes the convention of writing compound names without spaces, and capitalizing every term.
- * This function recognizes both upper and lower CamelCase, depending whether the leading character is capitalized
- * or not. The leading part of an upper CamelCase pattern is assumed to contain a sequence of capitals which are appearing
- * in the matching name; e.g. 'NPE' will match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
- * uses a lowercase first character. In Java, type names follow the upper CamelCase convention, whereas method or field
- * names follow the lower CamelCase convention.
- * <br>
- * The pattern may contain lowercase characters, which will be match in a case sensitive way. These characters must
- * appear in sequence in the name. For instance, 'NPExcep' will match 'NullPointerException', but not 'NullPointerExCEPTION'
- * or 'NuPoEx' will match 'NullPointerException', but not 'NoPointerException'.
- * <br><br>
- * Examples:
- * <ol>
- * <li><pre>
- * pattern = "NPE"
- * patternStart = 0
- * patternEnd = 3
- * name = NullPointerException
- * nameStart = 0
- * nameEnd = 20
- * result => true
- * </pre>
- * </li>
- * <li><pre>
- * pattern = "NPE"
- * patternStart = 0
- * patternEnd = 3
- * name = NoPermissionException
- * nameStart = 0
- * nameEnd = 21
- * result => true
- * </pre>
- * </li>
- * <li><pre>
- * pattern = "NuPoEx"
- * patternStart = 0
- * patternEnd = 6
- * name = NullPointerException
- * nameStart = 0
- * nameEnd = 20
- * result => true
- * </pre>
- * </li>
- * <li><pre>
- * pattern = "NuPoEx"
- * patternStart = 0
- * patternEnd = 6
- * name = NoPermissionException
- * nameStart = 0
- * nameEnd = 21
- * result => false
- * </pre>
- * </li>
- * <li><pre>
- * pattern = "npe"
- * patternStart = 0
- * patternEnd = 3
- * name = NullPointerException
- * nameStart = 0
- * nameEnd = 20
- * result => false
- * </pre>
- * </li>
- * </ol>
- * @see CharOperation#camelCaseMatch(char[], int, int, char[], int, int)
- * Implementation has been entirely copied from this method except for array lengthes
- * which were obviously replaced with calls to {@link String#length()} and
- * for array direct access which were replaced with calls to {@link String#charAt(int)}.
- *
- * @param pattern the given pattern
- * @param patternStart the start index of the pattern, inclusive
- * @param patternEnd the end index of the pattern, exclusive
- * @param name the given name
- * @param nameStart the start index of the name, inclusive
- * @param nameEnd the end index of the name, exclusive
- * @return true if a sub-pattern matches the subpart of the given name, false otherwise
- * @since 3.2
- */
- public static final boolean camelCaseMatch(String pattern, int patternStart, int patternEnd, String name, int nameStart, int nameEnd) {
- if (name == null)
- return false; // null name cannot match
- if (pattern == null)
- return true; // null pattern is equivalent to '*'
- if (patternEnd < 0) patternEnd = pattern.length();
- if (nameEnd < 0) nameEnd = name.length();
-
- if (patternEnd <= patternStart) return nameEnd <= nameStart;
- if (nameEnd <= nameStart) return false;
- // check first pattern char
- if (name.charAt(nameStart) != pattern.charAt(patternStart)) {
- // first char must strictly match (upper/lower)
- return false;
- }
-
- char patternChar, nameChar;
- int iPattern = patternStart;
- int iName = nameStart;
-
- // Main loop is on pattern characters
- while (true) {
-
- iPattern++;
- iName++;
-
- if (iPattern == patternEnd) {
- // We have exhausted pattern, so it's a match
- return true;
- }
-
- if (iName == nameEnd){
- // We have exhausted name (and not pattern), so it's not a match
- return false;
- }
-
- // For as long as we're exactly matching, bring it on (even if it's a lower case character)
- if ((patternChar = pattern.charAt(iPattern)) == name.charAt(iName)) {
- continue;
- }
-
- // If characters are not equals, then it's not a match if patternChar is lowercase
- if (patternChar < ScannerHelper.MAX_OBVIOUS) {
- if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] & ScannerHelper.C_UPPER_LETTER) == 0) {
- return false;
- }
- }
- else if (Character.isJavaIdentifierPart(patternChar) && !Character.isUpperCase(patternChar)) {
- return false;
- }
-
- // patternChar is uppercase, so let's find the next uppercase in name
- while (true) {
- if (iName == nameEnd){
- // We have exhausted name (and not pattern), so it's not a match
- return false;
- }
-
- nameChar = name.charAt(iName);
-
- if (nameChar < ScannerHelper.MAX_OBVIOUS) {
- if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar] & (ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_SPECIAL | ScannerHelper.C_DIGIT)) != 0) {
- // nameChar is lowercase
- iName++;
- // nameChar is uppercase...
- } else if (patternChar != nameChar) {
- //.. and it does not match patternChar, so it's not a match
- return false;
- } else {
- //.. and it matched patternChar. Back to the big loop
- break;
- }
- }
- else if (Character.isJavaIdentifierPart(nameChar) && !Character.isUpperCase(nameChar)) {
- // nameChar is lowercase
- iName++;
- // nameChar is uppercase...
- } else if (patternChar != nameChar) {
- //.. and it does not match patternChar, so it's not a match
- return false;
- } else {
- //.. and it matched patternChar. Back to the big loop
- break;
- }
- }
- // At this point, either name has been exhausted, or it is at an uppercase letter.
- // Since pattern is also at an uppercase letter
- }
- }
-
- /**
- * Validate compatibility between given string pattern and match rule.
- *<br>
- * Optimized (ie. returned match rule is modified) combinations are:
- * <ul>
- * <li>{@link #R_PATTERN_MATCH} without any '*' or '?' in string pattern:
- * pattern match bit is unset,
- * </li>
- * <li>{@link #R_PATTERN_MATCH} and {@link #R_PREFIX_MATCH} bits simultaneously set:
- * prefix match bit is unset,
- * </li>
- * <li>{@link #R_PATTERN_MATCH} and {@link #R_CAMELCASE_MATCH} bits simultaneously set:
- * camel case match bit is unset,
- * </li>
- * <li>{@link #R_CAMELCASE_MATCH} with invalid combination of uppercase and lowercase characters:
- * camel case match bit is unset and replaced with prefix match pattern,
- * </li>
- * <li>{@link #R_CAMELCASE_MATCH} combined with {@link #R_PREFIX_MATCH} and {@link #R_CASE_SENSITIVE}
- * bits is reduced to only {@link #R_CAMELCASE_MATCH} as Camel Case search is already prefix and case sensitive,
- * </li>
- * </ul>
- *<br>
- * Rejected (ie. returned match rule -1) combinations are:
- * <ul>
- * <li>{@link #R_REGEXP_MATCH} with any other match mode bit set,
- * </li>
- * </ul>
- *
- * @param stringPattern The string pattern
- * @param matchRule The match rule
- * @return Optimized valid match rule or -1 if an incompatibility was detected.
- * @since 3.2
- */
- public static int validateMatchRule(String stringPattern, int matchRule) {
-
- // Verify Regexp match rule
- if ((matchRule & R_REGEXP_MATCH) != 0) {
- if ((matchRule & R_PATTERN_MATCH) != 0 || (matchRule & R_PREFIX_MATCH) != 0 || (matchRule & R_CAMELCASE_MATCH) != 0) {
- return -1;
- }
- }
-
- // Verify Pattern match rule
- int starIndex = stringPattern.indexOf('*');
- int questionIndex = stringPattern.indexOf('?');
- if (starIndex < 0 && questionIndex < 0) {
- // reset pattern match bit if any
- matchRule &= ~R_PATTERN_MATCH;
- } else {
- // force Pattern rule
- matchRule |= R_PATTERN_MATCH;
- }
- if ((matchRule & R_PATTERN_MATCH) != 0) {
- // remove Camel Case and Prefix match bits if any
- matchRule &= ~R_CAMELCASE_MATCH;
- matchRule &= ~R_PREFIX_MATCH;
- }
-
- // Verify Camel Case match rule
- if ((matchRule & R_CAMELCASE_MATCH) != 0) {
- // Verify sting pattern validity
- int length = stringPattern.length();
- boolean validCamelCase = true;
- boolean uppercase = false;
- for (int i=0; i<length && validCamelCase; i++) {
- char ch = stringPattern.charAt(i);
- validCamelCase = ScannerHelper.isJavaIdentifierStart(ch);
- // at least one uppercase character is need in CamelCase pattern
- // (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=136313)
- if (!uppercase) uppercase = ScannerHelper.isUpperCase(ch);
- }
- validCamelCase = validCamelCase && uppercase;
- // Verify bits compatibility
- if (validCamelCase) {
- if ((matchRule & R_PREFIX_MATCH) != 0) {
- if ((matchRule & R_CASE_SENSITIVE) != 0) {
- // This is equivalent to Camel Case match rule
- matchRule &= ~R_PREFIX_MATCH;
- matchRule &= ~R_CASE_SENSITIVE;
- }
- }
- } else {
- matchRule &= ~R_CAMELCASE_MATCH;
- if ((matchRule & R_PREFIX_MATCH) == 0) {
- matchRule |= R_PREFIX_MATCH;
- matchRule |= R_CASE_SENSITIVE;
- }
- }
- }
- return matchRule;
- }
-
-}
+package org.rubypeople.rdt.core.search;
+
+import org.rubypeople.rdt.core.IField;
+import org.rubypeople.rdt.core.IImportDeclaration;
+import org.rubypeople.rdt.core.IMember;
+import org.rubypeople.rdt.core.IMethod;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.compiler.parser.ScannerHelper;
+import org.rubypeople.rdt.internal.core.LocalVariable;
+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.LocalVariablePattern;
+import org.rubypeople.rdt.internal.core.search.matching.MatchLocator;
+import org.rubypeople.rdt.internal.core.search.matching.MethodPattern;
+import org.rubypeople.rdt.internal.core.search.matching.OrPattern;
+import org.rubypeople.rdt.internal.core.search.matching.QualifiedTypeDeclarationPattern;
+import org.rubypeople.rdt.internal.core.search.matching.TypeDeclarationPattern;
+import org.rubypeople.rdt.internal.core.search.matching.TypeReferencePattern;
+import org.rubypeople.rdt.internal.core.util.CharOperation;
+
+public abstract class SearchPattern extends InternalSearchPattern {
+// Rules for pattern matching: (exact, prefix, pattern) [ | case sensitive]
+ /**
+ * Match rule: The search pattern matches exactly the search result,
+ * that is, the source of the search result equals the search pattern.
+ */
+ public static final int R_EXACT_MATCH = 0;
+
+ /**
+ * Match rule: The search pattern is a prefix of the search result.
+ */
+ public static final int R_PREFIX_MATCH = 0x0001;
+
+ /**
+ * Match rule: The search pattern contains one or more wild cards ('*' or '?').
+ * A '*' wild-card can replace 0 or more characters in the search result.
+ * A '?' wild-card replaces exactly 1 character in the search result.
+ */
+ public static final int R_PATTERN_MATCH = 0x0002;
+
+ /**
+ * Match rule: The search pattern contains a regular expression.
+ */
+ public static final int R_REGEXP_MATCH = 0x0004;
+
+ /**
+ * Match rule: The search pattern matches the search result only if cases are the same.
+ * Can be combined to previous rules, e.g. {@link #R_EXACT_MATCH} | {@link #R_CASE_SENSITIVE}
+ */
+ public static final int R_CASE_SENSITIVE = 0x0008;
+
+ /**
+ * Match rule: The search pattern matches search results as raw/parameterized types/methods with same erasure.
+ * This mode has no effect on other java elements search.<br>
+ * Type search example:
+ * <ul>
+ * <li>pattern: <code>List<Exception></code></li>
+ * <li>match: <code>List<Object></code></li>
+ * </ul>
+ * Method search example:
+ * <ul>
+ * <li>declaration: <code><T>foo(T t)</code></li>
+ * <li>pattern: <code><Exception>foo(new Exception())</code></li>
+ * <li>match: <code><Object>foo(new Object())</code></li>
+ * </ul>
+ * Can be combined to all other match rules, e.g. {@link #R_CASE_SENSITIVE} | {@link #R_ERASURE_MATCH}
+ * This rule is not activated by default, so raw types or parameterized types with same erasure will not be found
+ * for pattern List<String>,
+ * Note that with this pattern, the match selection will be only on the erasure even for parameterized types.
+ * @since 3.1
+ */
+ public static final int R_ERASURE_MATCH = 0x0010;
+
+ /**
+ * Match rule: The search pattern matches search results as raw/parameterized types/methods with equivalent type parameters.
+ * This mode has no effect on other java elements search.<br>
+ * Type search example:
+ * <ul>
+ * <li>pattern: <code>List<Exception></code></li>
+ * <li>match:
+ * <ul>
+ * <li><code>List<? extends Throwable></code></li>
+ * <li><code>List<? super RuntimeException></code></li>
+ * <li><code>List<?></code></li>
+ * </ul>
+ * </li>
+ * </ul>
+ * Method search example:
+ * <ul>
+ * <li>declaration: <code><T>foo(T t)</code></li>
+ * <li>pattern: <code><Exception>foo(new Exception())</code></li>
+ * <li>match:
+ * <ul>
+ * <li><code><? extends Throwable>foo(new Exception())</code></li>
+ * <li><code><? super RuntimeException>foo(new Exception())</code></li>
+ * <li><code>foo(new Exception())</code></li>
+ * </ul>
+ * </ul>
+ * Can be combined to all other match rules, e.g. {@link #R_CASE_SENSITIVE} | {@link #R_EQUIVALENT_MATCH}
+ * This rule is not activated by default, so raw types or equivalent parameterized types will not be found
+ * for pattern List<String>,
+ * This mode is overridden by {@link #R_ERASURE_MATCH} as erasure matches obviously include equivalent ones.
+ * That means that pattern with rule set to {@link #R_EQUIVALENT_MATCH} | {@link #R_ERASURE_MATCH}
+ * will return same results than rule only set with {@link #R_ERASURE_MATCH}.
+ * @since 3.1
+ */
+ public static final int R_EQUIVALENT_MATCH = 0x0020;
+
+ /**
+ * Match rule: The search pattern matches exactly the search result,
+ * that is, the source of the search result equals the search pattern.
+ * @since 3.1
+ */
+ public static final int R_FULL_MATCH = 0x0040;
+
+ /**
+ * Match rule: The search pattern contains a Camel Case expression.
+ * <br>
+ * Examples:
+ * <ul>
+ * <li><code>NPE</code> type string pattern will match
+ * <code>NullPointerException</code> and <code>NpPermissionException</code> types,</li>
+ * <li><code>NuPoEx</code> type string pattern will only match
+ * <code>NullPointerException</code> type.</li>
+ * </ul>
+ * @see CharOperation#camelCaseMatch(char[], char[]) for a detailed explanation
+ * of Camel Case matching.
+ *<br>
+ * Can be combined to {@link #R_PREFIX_MATCH} match rule. For example,
+ * when prefix match rule is combined with Camel Case match rule,
+ * <code>"nPE"</code> pattern will match <code>nPException</code>.
+ *<br>
+ * Match rule {@link #R_PATTERN_MATCH} may also be combined but both rules
+ * will not be used simultaneously as they are mutually exclusive.
+ * Used match rule depends on whether string pattern contains specific pattern
+ * characters (e.g. '*' or '?') or not. If it does, then only Pattern match rule
+ * will be used, otherwise only Camel Case match will be used.
+ * For example, with <code>"NPE"</code> string pattern, search will only use
+ * Camel Case match rule, but with <code>N*P*E*</code> string pattern, it will
+ * use only Pattern match rule.
+ *
+ * @since 3.2
+ */
+ public static final int R_CAMELCASE_MATCH = 0x0080;
+
+ private static final int MODE_MASK = R_EXACT_MATCH | R_PREFIX_MATCH | R_PATTERN_MATCH | R_REGEXP_MATCH;
+
+ private int matchRule;
+
+ /**
+ * Creates a search pattern with the rule to apply for matching index keys.
+ * It can be exact match, prefix...
[truncated message content] |