summaryrefslogtreecommitdiff
path: root/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/RegExpPredicate.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/RegExpPredicate.java')
-rw-r--r--platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/RegExpPredicate.java175
1 files changed, 175 insertions, 0 deletions
diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/RegExpPredicate.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/RegExpPredicate.java
new file mode 100644
index 000000000000..f7b8ecedcf3d
--- /dev/null
+++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/RegExpPredicate.java
@@ -0,0 +1,175 @@
+package com.intellij.structuralsearch.impl.matcher.predicates;
+
+import com.intellij.psi.*;
+import com.intellij.structuralsearch.MalformedPatternException;
+import com.intellij.structuralsearch.SSRBundle;
+import com.intellij.structuralsearch.StructuralSearchProfile;
+import com.intellij.structuralsearch.StructuralSearchUtil;
+import com.intellij.structuralsearch.impl.matcher.MatchContext;
+import com.intellij.structuralsearch.impl.matcher.MatchResultImpl;
+import com.intellij.structuralsearch.impl.matcher.MatchUtils;
+import com.intellij.structuralsearch.impl.matcher.handlers.MatchPredicate;
+import com.intellij.structuralsearch.plugin.util.SmartPsiPointer;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Root of handlers for pattern node matching. Handles simpliest type of the match.
+ */
+public final class RegExpPredicate extends MatchPredicate {
+ private Pattern pattern;
+ private final String baseHandlerName;
+ private boolean simpleString;
+ private final boolean couldBeOptimized;
+ private final String regexp;
+ private final boolean caseSensitive;
+ private boolean multiline;
+ private final boolean wholeWords;
+ private final boolean target;
+ private NodeTextGenerator myNodeTextGenerator;
+
+ public interface NodeTextGenerator {
+ String getText(PsiElement element);
+ }
+
+ public RegExpPredicate(final String regexp, final boolean caseSensitive, final String _baseHandlerName, boolean _wholeWords, boolean _target) {
+ couldBeOptimized = containsRegExp(regexp);
+ if (!_wholeWords) {
+ simpleString = couldBeOptimized;
+ }
+
+ this.regexp = regexp;
+ this.caseSensitive = caseSensitive;
+ this.wholeWords = _wholeWords;
+ baseHandlerName = _baseHandlerName;
+
+ if (!simpleString) {
+ compilePattern();
+ }
+ target = _target;
+ }
+
+ private static boolean containsRegExp(final String regexp) {
+ for(int i=0;i<regexp.length();++i) {
+ if(MatchUtils.SPECIAL_CHARS.indexOf(regexp.charAt(i))!=-1) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void compilePattern() {
+ try {
+ @NonNls String realRegexp = regexp;
+ if (wholeWords) {
+ realRegexp = ".*?\\b(?:" + realRegexp + ")\\b.*?";
+ }
+
+ pattern = Pattern.compile(
+ realRegexp,
+ (caseSensitive ? 0: Pattern.CASE_INSENSITIVE) | (multiline ? Pattern.DOTALL:0)
+ );
+ } catch(PatternSyntaxException ex) {
+ throw new MalformedPatternException(SSRBundle.message("error.incorrect.regexp.constraint", regexp, baseHandlerName));
+ }
+ }
+
+ public boolean couldBeOptimized() {
+ return couldBeOptimized;
+ }
+
+ public String getRegExp() {
+ return regexp;
+ }
+
+ /**
+ * Attempts to match given handler node against given node.
+ * @param matchedNode for matching
+ * @param context of the matching
+ * @return true if matching was successfull and false otherwise
+ */
+ public boolean match(PsiElement node,PsiElement matchedNode, int start, int end, MatchContext context) {
+ if (matchedNode==null) return false;
+ String text;
+
+ text = myNodeTextGenerator != null ? myNodeTextGenerator.getText(matchedNode) : getMeaningfulText(matchedNode);
+
+ boolean result = doMatch(text, start, end, context, matchedNode);
+
+ if (!result) {
+
+ if(StructuralSearchUtil.isIdentifier(matchedNode)) {
+ matchedNode = matchedNode.getParent();
+ }
+
+ String alternativeText = context.getPattern().getAlternativeTextToMatch(matchedNode, text);
+ if (alternativeText != null) {
+ result = doMatch(alternativeText, start, end, context, matchedNode);
+ }
+ }
+
+ return result;
+ }
+
+ public static String getMeaningfulText(PsiElement matchedNode) {
+ final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(matchedNode);
+ return profile != null ? profile.getMeaningfulText(matchedNode) : matchedNode.getText();
+ }
+
+ public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) {
+ return match(patternNode,matchedNode,0,-1,context);
+ }
+
+ boolean doMatch(String text, MatchContext context, PsiElement matchedElement) {
+ return doMatch(text,0,-1,context, matchedElement);
+ }
+
+ boolean doMatch(String text, int from, int end, MatchContext context,PsiElement matchedElement) {
+ if (from > 0 || end != -1) {
+ text = text.substring(from, end == -1 || end >= text.length() ? text.length():end);
+ }
+
+ if (simpleString) {
+ return (caseSensitive)?text.equals(regexp):text.equalsIgnoreCase(regexp);
+ }
+
+ if(!multiline && text.contains("\n")) setMultiline(true);
+ final Matcher matcher = pattern.matcher(text);
+
+ if (matcher.matches()) {
+ for (int i=1;i<=matcher.groupCount();++i) {
+ context.getResult().addSon(
+ new MatchResultImpl(
+ baseHandlerName + "_" + i,
+ matcher.group(i),
+ new SmartPsiPointer(matchedElement),
+ matcher.start(i),
+ matcher.end(i),
+ target
+ )
+ );
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ public void setNodeTextGenerator(final NodeTextGenerator nodeTextGenerator) {
+ myNodeTextGenerator = nodeTextGenerator;
+ }
+
+ public void setMultiline(boolean b) {
+ multiline = b;
+ compilePattern();
+ }
+
+ public boolean isWholeWords() {
+ return wholeWords;
+ }
+}