From 3751017284fb7cb85e18211bed5ab5942e176d20 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 5 Jan 2015 10:52:27 +0100 Subject: [PATCH] IDEA-128435 (SSR searches case sensitively when not instructed to do so) --- .../impl/matcher/JavaMatchingVisitor.java | 38 +++++++++--------- .../compiler/JavaCompilingVisitor.java | 3 +- .../impl/matcher/GlobalMatchingVisitor.java | 13 +++++++ .../impl/matcher/MatchUtils.java | 10 ++++- .../StructuralSearchTest.java | 39 +++++++++++++++++++ 5 files changed, 80 insertions(+), 23 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index c409038c9cd2..b175aea4046e 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -87,7 +87,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(((MatchingHandler)userData).match(comment, comment2, myMatchingVisitor.getMatchContext())); } else { - myMatchingVisitor.setResult(comment.getText().equals(comment2.getText())); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(comment, comment2)); } } @@ -255,7 +255,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitElement(PsiElement el) { - myMatchingVisitor.setResult(el.textMatches(myMatchingVisitor.getElement())); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(el, myMatchingVisitor.getElement())); } @Override @@ -286,11 +286,11 @@ public class JavaMatchingVisitor extends JavaElementVisitor { boolean result; if (!(element instanceof PsiJavaToken)) { - result = token.textMatches(element); + result = myMatchingVisitor.matchText(token, element); } else { final PsiJavaToken anotherToken = (PsiJavaToken)element; - result = token.getTokenType() == anotherToken.getTokenType() && token.textMatches(anotherToken); + result = token.getTokenType() == anotherToken.getTokenType() && myMatchingVisitor.matchText(token, anotherToken); } myMatchingVisitor.setResult(result); @@ -645,7 +645,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { // just variable final PsiExpression reference2Qualifier = reference2.getQualifierExpression(); if (qualifier == null && reference2Qualifier == null) { - myMatchingVisitor.setResult(reference.getReferenceNameElement().textMatches(reference2.getReferenceNameElement())); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(reference.getReferenceNameElement(), reference2.getReferenceNameElement())); return; } @@ -658,9 +658,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(referenceElement, referenceElement2)); } else { - myMatchingVisitor.setResult( - (referenceElement2 != null && referenceElement != null && referenceElement.textMatches(referenceElement2)) || - referenceElement == referenceElement2); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(referenceElement, referenceElement2)); } if (!myMatchingVisitor.getResult()) { @@ -842,7 +840,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor { } final String text = getText(el); final String text2 = getText(el2); - final boolean equalsIgnorePackage = MatchUtils.compareWithNoDifferenceToPackage(text, text2); + final boolean caseSensitive = myMatchingVisitor.getMatchContext().getOptions().isCaseSensitiveMatch(); + final boolean equalsIgnorePackage = MatchUtils.compareWithNoDifferenceToPackage(text, text2, !caseSensitive); if (equalsIgnorePackage || !(el2 instanceof PsiJavaReference)) { return equalsIgnorePackage; } @@ -850,10 +849,11 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final PsiElement element2 = ((PsiJavaReference)el2).resolve(); if (element2 instanceof PsiClass) { - return text.equals(((PsiClass)element2).getQualifiedName()); + final String name = ((PsiClass)element2).getQualifiedName(); + return caseSensitive ? text.equals(name) : text.equalsIgnoreCase(name); } else { - return MatchUtils.compareWithNoDifferenceToPackage(text, text2); + return MatchUtils.compareWithNoDifferenceToPackage(text, text2, !caseSensitive); } } } @@ -975,7 +975,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final PsiVariable var2 = (PsiVariable)myMatchingVisitor.getElement(); try { - myMatchingVisitor.setResult((var.getName().equals(var2.getName()) || isTypedVar) && + myMatchingVisitor.setResult((myMatchingVisitor.matchText(var.getNameIdentifier(), var2.getNameIdentifier()) || isTypedVar) && ((var.getParent() instanceof PsiClass && ((PsiClass)var.getParent()).isInterface()) || myMatchingVisitor.match(var.getModifierList(), var2.getModifierList()))); if (myMatchingVisitor.getResult()) { @@ -1093,11 +1093,9 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final PsiReferenceExpression mcallRef1 = mcall.getMethodExpression(); final PsiReferenceExpression mcallRef2 = mcall2.getMethodExpression(); - final String mcallname1 = mcallRef1.getReferenceName(); - final String mcallname2 = mcallRef2.getReferenceName(); final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(mcallRef1.getReferenceNameElement()); - if (mcallname1 != null && !mcallname1.equals(mcallname2) && !isTypedVar) { + if (!myMatchingVisitor.matchText(mcallRef1.getReferenceNameElement(), mcallRef2.getReferenceNameElement()) && !isTypedVar) { myMatchingVisitor.setResult(false); return; } @@ -1177,7 +1175,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(handler.match(const1, const2, myMatchingVisitor.getMatchContext())); } else { - myMatchingVisitor.setResult(const1.textMatches(const2)); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(const1, const2)); } } @@ -1535,7 +1533,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitKeyword(PsiKeyword keyword) { - myMatchingVisitor.setResult(keyword.textMatches(myMatchingVisitor.getElement())); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(keyword, myMatchingVisitor.getElement())); } @Override @@ -1600,7 +1598,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(identifier2, myMatchingVisitor.getMatchContext())); } else { - myMatchingVisitor.setResult(identifier.textMatches(identifier2)); + myMatchingVisitor.setResult(myMatchingVisitor.matchText(identifier, identifier2)); } if (myMatchingVisitor.getResult()) { @@ -1641,7 +1639,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { } } - myMatchingVisitor.setResult((clazz.getName().equals(clazz2.getName()) || isTypedVar) && + myMatchingVisitor.setResult((myMatchingVisitor.matchText(clazz.getNameIdentifier(), clazz2.getNameIdentifier()) || isTypedVar) && compareClasses(clazz, clazz2)); if (myMatchingVisitor.getResult() && isTypedVar) { @@ -1680,7 +1678,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { return; } - myMatchingVisitor.setResult((method.getName().equals(method2.getName()) || isTypedVar) && + myMatchingVisitor.setResult((myMatchingVisitor.matchText(method.getNameIdentifier(), method2.getNameIdentifier()) || isTypedVar) && myMatchingVisitor.match(method.getModifierList(), method2.getModifierList()) && myMatchingVisitor.matchSons(method.getParameterList(), method2.getParameterList()) && myMatchingVisitor.match(method.getReturnTypeElement(), method2.getReturnTypeElement()) && diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java index d8c80db3425a..1733ead28937 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java @@ -383,7 +383,8 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { boolean classQualifier) { final SubstitutionHandler substitutionHandler = new SubstitutionHandler("__" + referenceText.replace('.', '_'), false, classQualifier ? 0 : 1, 1, false); - substitutionHandler.setPredicate(new RegExpPredicate(referenceText.replaceAll("\\.", "\\\\."), true, null, false, false)); + final boolean caseSensitive = myCompilingVisitor.getContext().getOptions().isCaseSensitiveMatch(); + substitutionHandler.setPredicate(new RegExpPredicate(referenceText.replaceAll("\\.", "\\\\."), caseSensitive, null, false, false)); myCompilingVisitor.getContext().getPattern().setHandler(expr, substitutionHandler); return substitutionHandler; } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java index 2af5f0fa47c5..f7451649974d 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java @@ -315,4 +315,17 @@ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { protected boolean isRightLooseMatching() { return false; } + + public boolean matchText(@Nullable PsiElement left, @Nullable PsiElement right) { + if (left == null) { + return right == null; + } + else if (right == null) { + return false; + } + final boolean caseSensitiveMatch = matchContext.getOptions().isCaseSensitiveMatch(); + final String leftText = left.getText(); + final String rightText = right.getText(); + return caseSensitiveMatch ? leftText.equals(rightText) : leftText.equalsIgnoreCase(rightText); + } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchUtils.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchUtils.java index 38c31d16524f..e4ea6100419c 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchUtils.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchUtils.java @@ -1,5 +1,6 @@ package com.intellij.structuralsearch.impl.matcher; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import org.jetbrains.annotations.NonNls; @@ -13,9 +14,14 @@ import org.jetbrains.annotations.NonNls; public class MatchUtils { public static final String SPECIAL_CHARS = "*(){}[]^$\\.-|"; - public static final boolean compareWithNoDifferenceToPackage(final String typeImage,@NonNls final String typeImage2) { + public static final boolean compareWithNoDifferenceToPackage(String typeImage, String typeImage2) { + return compareWithNoDifferenceToPackage(typeImage, typeImage2, false); + } + + public static final boolean compareWithNoDifferenceToPackage(final String typeImage,@NonNls final String typeImage2, boolean ignoreCase) { if (typeImage == null || typeImage2 == null) return typeImage == typeImage2; - return typeImage2.endsWith(typeImage) && ( + final boolean endsWith = ignoreCase ? StringUtil.endsWithIgnoreCase(typeImage2, typeImage) : typeImage2.endsWith(typeImage); + return endsWith && ( typeImage.length() == typeImage2.length() || typeImage2.charAt(typeImage2.length()-typeImage.length()-1)=='.' // package separator ); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 73d6780e2429..4503712bd3ac 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -3060,4 +3060,43 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String pattern = "/*$Text$*/"; assertEquals("should find comments in all the right places", 12, findMatchesCount(source, pattern)); } + + public void testCaseInsensitive() { + String source = "/* HELLO */\n" + + "class A {\n" + + " private char b = 'C';\n" + + " void m() {\n" + + " @X String s = \"\";\n" + + " s.equals(\"\");\n" + + " s = s;\n" + + " this.b = 'D';\n" + + " }\n" + + "}"; + String pattern1 = "a"; + assertEquals("should find symbol case insensitively", 1, findMatchesCount(source, pattern1)); + String pattern2 = "class a {}"; + assertEquals("should find class case insensitively", 1, findMatchesCount(source, pattern2)); + String pattern3 = "/* hello */"; + assertEquals("should find comment case insensitively", 1, findMatchesCount(source, pattern3)); + String pattern4 = "'c'"; + assertEquals("should find character literal case insensitively", 1, findMatchesCount(source, pattern4)); + String pattern5 = "char B = '_initializer;"; + assertEquals("should find variable case insensitively", 1, findMatchesCount(source, pattern5)); + String pattern6 = "class '_a {}"; + assertEquals("should find type parameter case insensitively", 1, findMatchesCount(source, pattern6)); + String pattern7 = "class '_A {" + + " void M();" + + "}"; + assertEquals("should find class with method case insensitively", 1, findMatchesCount(source, pattern7)); + String pattern8 = "'_a.EQUALS('_b)"; + assertEquals("should find method call case insensitively", 1, findMatchesCount(source, pattern8)); + String pattern9 = "S.'_call('_e)"; + assertEquals("should find qualifier case insensitively", 1, findMatchesCount(source, pattern9)); + String pattern10 = "S = S"; + assertEquals("should find reference case insensitively", 1, findMatchesCount(source, pattern10)); + String pattern11 = "this.B"; + assertEquals("should find qualified reference case insensitively", 1, findMatchesCount(source, pattern11)); + String pattern12 = "@x"; + assertEquals("should find annotation case insensitively", 1, findMatchesCount(source, pattern12)); + } }