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 3f25fac119fd..f82516006af1 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 @@ -237,11 +237,11 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { - final PsiArrayInitializerExpression expr2 = (PsiArrayInitializerExpression)myMatchingVisitor.getElement(); - + final PsiArrayInitializerExpression other = getExpression(PsiArrayInitializerExpression.class); + if (other == null) return; myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially( new ArrayBackedNodeIterator(expression.getInitializers()), - new ArrayBackedNodeIterator(expr2.getInitializers()) + new ArrayBackedNodeIterator(other.getInitializers()) )); } @@ -351,14 +351,13 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitLambdaExpression(PsiLambdaExpression expression) { - final PsiElement other = myMatchingVisitor.getElement(); - if (!myMatchingVisitor.setResult(other instanceof PsiLambdaExpression)) return; - final PsiLambdaExpression expression2 = (PsiLambdaExpression)other; + final PsiLambdaExpression other = getExpression(PsiLambdaExpression.class); + if (other == null) return; final PsiParameterList parameterList1 = expression.getParameterList(); if (!myMatchingVisitor.setResult( - parameterList1.isEmpty() || myMatchingVisitor.matchSons(parameterList1, expression2.getParameterList()))) return; + parameterList1.isEmpty() || myMatchingVisitor.matchSons(parameterList1, other.getParameterList()))) return; final PsiElement body1 = getElementToMatch(expression.getBody()); - myMatchingVisitor.setResult(body1 == null || myMatchingVisitor.matchSequentially(body1, getElementToMatch(expression2.getBody()))); + myMatchingVisitor.setResult(body1 == null || myMatchingVisitor.matchSequentially(body1, getElementToMatch(other.getBody()))); } private static PsiElement getElementToMatch(PsiElement element) { @@ -514,17 +513,16 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitArrayAccessExpression(final PsiArrayAccessExpression slice) { - final PsiElement other = myMatchingVisitor.getElement(); - if (myMatchingVisitor.setResult(other instanceof PsiArrayAccessExpression)) { - final PsiArrayAccessExpression slice2 = (PsiArrayAccessExpression)other; - myMatchingVisitor.setResult(myMatchingVisitor.match(slice.getArrayExpression(), slice2.getArrayExpression()) && - myMatchingVisitor.match(slice.getIndexExpression(), slice2.getIndexExpression())); + final PsiArrayAccessExpression other = getExpression(PsiArrayAccessExpression.class); + if (other != null) { + myMatchingVisitor.setResult(myMatchingVisitor.match(slice.getArrayExpression(), other.getArrayExpression()) && + myMatchingVisitor.match(slice.getIndexExpression(), other.getIndexExpression())); } } @Override public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { - if (!myMatchingVisitor.setResult(myMatchingVisitor.getElement() instanceof PsiMethodReferenceExpression)) return; + if (getExpression(PsiMethodReferenceExpression.class) == null) return; super.visitMethodReferenceExpression(expression); } @@ -539,10 +537,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { special = true; } - final PsiElement element = myMatchingVisitor.getElement(); - PsiElement other = element instanceof PsiExpression && context.getOptions().isLooseMatching() ? - PsiUtil.skipParenthesizedExprDown((PsiExpression)element) : - element; + final PsiElement other = myMatchingVisitor.getElement(); final PsiExpression qualifier = reference.getQualifierExpression(); if (_handler instanceof SubstitutionHandler && (qualifier == null || special)) { final SubstitutionHandler handler = (SubstitutionHandler)_handler; @@ -550,7 +545,12 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(checkMatchWithinHierarchy(other, handler, reference)); } else { - myMatchingVisitor.setResult(handler.handle(other, context)); + final PsiElement deparenthesized = other instanceof PsiExpression && context.getOptions().isLooseMatching() ? + PsiUtil.skipParenthesizedExprDown((PsiExpression)other) : other; + myMatchingVisitor.setResult(handler.validate(deparenthesized, 0, -1, context)); + if (myMatchingVisitor.getResult()) { + handler.addResult(other, 0, -1, context); + } } return; } @@ -877,16 +877,16 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitConditionalExpression(final PsiConditionalExpression cond) { - final PsiConditionalExpression cond2 = (PsiConditionalExpression)myMatchingVisitor.getElement(); - + final PsiConditionalExpression cond2 = getExpression(PsiConditionalExpression.class); + if (cond2 == null) return; myMatchingVisitor.setResult(myMatchingVisitor.match(cond.getCondition(), cond2.getCondition()) && myMatchingVisitor.matchSons(cond, cond2)); } @Override public void visitPolyadicExpression(PsiPolyadicExpression expression) { - final PsiPolyadicExpression expr2 = (PsiPolyadicExpression)myMatchingVisitor.getElement(); - + final PsiPolyadicExpression expr2 = getExpression(PsiPolyadicExpression.class); + if (expr2 == null) return; if (myMatchingVisitor.setResult(expression.getOperationTokenType().equals(expr2.getOperationTokenType()))) { final PsiExpression[] operands1 = expression.getOperands(); final PsiExpression[] operands2 = expr2.getOperands(); @@ -988,9 +988,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitMethodCallExpression(final PsiMethodCallExpression mcall) { - final PsiElement element = myMatchingVisitor.getElement(); - if (!myMatchingVisitor.setResult(element instanceof PsiMethodCallExpression)) return; - final PsiMethodCallExpression mcall2 = (PsiMethodCallExpression)element; + final PsiMethodCallExpression mcall2 = getExpression(PsiMethodCallExpression.class); + if (mcall2 == null) return; final PsiReferenceExpression mcallRef1 = mcall.getMethodExpression(); final PsiReferenceExpression mcallRef2 = mcall2.getMethodExpression(); @@ -1078,8 +1077,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitLiteralExpression(final PsiLiteralExpression const1) { - final PsiLiteralExpression const2 = (PsiLiteralExpression)myMatchingVisitor.getElement(); - + final PsiLiteralExpression const2 = getExpression(PsiLiteralExpression.class); + if (const2 == null) return; final MatchingHandler handler = (MatchingHandler)const1.getUserData(CompiledPattern.HANDLER_KEY); if (handler instanceof SubstitutionHandler) { final PsiType type1 = const1.getType(); @@ -1119,13 +1118,11 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitAssignmentExpression(final PsiAssignmentExpression assign) { - final PsiElement other = myMatchingVisitor.getElement(); - if (myMatchingVisitor.setResult(other instanceof PsiAssignmentExpression)) { - final PsiAssignmentExpression assign2 = (PsiAssignmentExpression)other; - - myMatchingVisitor.setResult(assign.getOperationTokenType().equals(assign2.getOperationTokenType()) && - myMatchingVisitor.match(assign.getLExpression(), assign2.getLExpression()) && - myMatchingVisitor.match(assign.getRExpression(), assign2.getRExpression())); + final PsiAssignmentExpression other = getExpression(PsiAssignmentExpression.class); + if (other != null) { + myMatchingVisitor.setResult(assign.getOperationTokenType().equals(other.getOperationTokenType()) && + myMatchingVisitor.match(assign.getLExpression(), other.getLExpression()) && + myMatchingVisitor.match(assign.getRExpression(), other.getRExpression())); } } @@ -1210,18 +1207,18 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitPostfixExpression(final PsiPostfixExpression postfix) { - final PsiPostfixExpression postfix2 = (PsiPostfixExpression)myMatchingVisitor.getElement(); - - myMatchingVisitor.setResult(postfix.getOperationTokenType().equals(postfix2.getOperationTokenType()) - && myMatchingVisitor.match(postfix.getOperand(), postfix2.getOperand())); + final PsiPostfixExpression postfix2 = getExpression(PsiPostfixExpression.class); + if (postfix2 == null) return; + myMatchingVisitor.setResult(postfix.getOperationTokenType().equals(postfix2.getOperationTokenType()) && + myMatchingVisitor.match(postfix.getOperand(), postfix2.getOperand())); } @Override public void visitPrefixExpression(final PsiPrefixExpression prefix) { - final PsiPrefixExpression prefix2 = (PsiPrefixExpression)myMatchingVisitor.getElement(); - - myMatchingVisitor.setResult(prefix.getOperationTokenType().equals(prefix2.getOperationTokenType()) - && myMatchingVisitor.match(prefix.getOperand(), prefix2.getOperand())); + final PsiPrefixExpression prefix2 = getExpression(PsiPrefixExpression.class); + if (prefix2 == null) return; + myMatchingVisitor.setResult(prefix.getOperationTokenType().equals(prefix2.getOperationTokenType()) && + myMatchingVisitor.match(prefix.getOperand(), prefix2.getOperand())); } @Override @@ -1248,12 +1245,12 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitSuperExpression(final PsiSuperExpression super1) { - myMatchingVisitor.setResult(myMatchingVisitor.getElement() instanceof PsiSuperExpression); + getExpression(PsiSuperExpression.class); } @Override public void visitThisExpression(final PsiThisExpression this1) { - myMatchingVisitor.setResult(myMatchingVisitor.getElement() instanceof PsiThisExpression); + getExpression(PsiThisExpression.class); } @Override @@ -1355,16 +1352,15 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitInstanceOfExpression(final PsiInstanceOfExpression instanceOf) { - final PsiElement other = myMatchingVisitor.getElement(); - if (!myMatchingVisitor.setResult(other instanceof PsiInstanceOfExpression)) return; - final PsiInstanceOfExpression instanceOf2 = (PsiInstanceOfExpression)other; - if (!myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getOperand(), instanceOf2.getOperand()))) return; - myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getCheckType(), instanceOf2.getCheckType())); + final PsiInstanceOfExpression other = getExpression(PsiInstanceOfExpression.class); + if (other == null) return; + if (!myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getOperand(), other.getOperand()))) return; + myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getCheckType(), other.getCheckType())); } @Override public void visitNewExpression(final PsiNewExpression new1) { - final PsiElement other = myMatchingVisitor.getElement(); + final PsiExpression other = getExpression(); final PsiJavaCodeReferenceElement classReference = new1.getClassReference(); if (other instanceof PsiArrayInitializerExpression && other.getParent() instanceof PsiVariable && @@ -1378,7 +1374,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(false); return; } - final PsiType otherType = ((PsiArrayInitializerExpression)other).getType(); + final PsiType otherType = other.getType(); if (handler instanceof SubstitutionHandler && otherType != null) { final PsiElementFactory factory = JavaPsiFacade.getElementFactory(other.getProject()); final PsiTypeElement otherTypeElement = factory.createTypeElement(otherType.getDeepComponentType()); @@ -1450,20 +1446,18 @@ public class JavaMatchingVisitor extends JavaElementVisitor { @Override public void visitTypeCastExpression(final PsiTypeCastExpression cast) { - final PsiElement other = myMatchingVisitor.getElement(); - if (myMatchingVisitor.setResult(other instanceof PsiTypeCastExpression)) { - final PsiTypeCastExpression cast2 = (PsiTypeCastExpression)other; - myMatchingVisitor.setResult(myMatchingVisitor.match(cast.getCastType(), cast2.getCastType()) && - myMatchingVisitor.match(cast.getOperand(), cast2.getOperand())); + final PsiTypeCastExpression other = getExpression(PsiTypeCastExpression.class); + if (other != null) { + myMatchingVisitor.setResult(myMatchingVisitor.match(cast.getCastType(), other.getCastType()) && + myMatchingVisitor.match(cast.getOperand(), other.getOperand())); } } @Override public void visitClassObjectAccessExpression(final PsiClassObjectAccessExpression expr) { - final PsiElement other = myMatchingVisitor.getElement(); - if (myMatchingVisitor.setResult(other instanceof PsiClassObjectAccessExpression)) { - final PsiClassObjectAccessExpression expr2 = (PsiClassObjectAccessExpression)other; - myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getOperand(), expr2.getOperand())); + final PsiClassObjectAccessExpression other = getExpression(PsiClassObjectAccessExpression.class); + if (other != null) { + myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getOperand(), other.getOperand())); } } @@ -1591,4 +1585,15 @@ public class JavaMatchingVisitor extends JavaElementVisitor { saveOrDropResult(methodNameNode, isTypedVar, method2.getNameIdentifier()); } } + + @SuppressWarnings("unchecked") + private T getExpression(Class aClass) { + final PsiExpression other = getExpression(); + return myMatchingVisitor.setResult(aClass.isInstance(other)) ? (T)other : null; + } + + private PsiExpression getExpression() { + final PsiElement other = myMatchingVisitor.getElement(); + return (other instanceof PsiExpression) ? PsiUtil.skipParenthesizedExprDown((PsiExpression)other) : null; + } } 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 b8e3c962569c..fdd7ef75bb04 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.impl.matcher.compiler; import com.intellij.dupLocator.iterators.NodeIterator; @@ -12,6 +12,7 @@ import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.structuralsearch.MalformedPatternException; import com.intellij.structuralsearch.StructuralSearchUtil; import com.intellij.structuralsearch.impl.matcher.CompiledPattern; @@ -194,6 +195,17 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } } + @Override + public void visitExpression(PsiExpression expression) { + super.visitExpression(expression); + if (!(expression.getParent() instanceof PsiExpressionStatement) && !(expression instanceof PsiParenthesizedExpression)) { + final MatchingHandler handler = myCompilingVisitor.getContext().getPattern().getHandler(expression); + if (handler.getFilter() == null) { + handler.setFilter(e -> DefaultFilter.accepts((e instanceof PsiExpression) ? PsiUtil.skipParenthesizedExprDown((PsiExpression)e) : e, expression)); + } + } + } + @Override public void visitLiteralExpression(PsiLiteralExpression expression) { String text = expression.getText(); diff --git a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directIntArray/after/Test.java b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directIntArray/after/Test.java index fba1ac7d3d16..8dbba12048fe 100644 --- a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directIntArray/after/Test.java +++ b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directIntArray/after/Test.java @@ -9,7 +9,7 @@ class Test { System.out.println(a.incrementAndGet(0)); a.getAndDecrement(0); if (a.decrementAndGet(0) == 0) { - a.getAndAdd(0, (2)); + a.getAndAdd(0, ((2))); a.set(0, a.get(0) * 2); if (a.get(0) == 0) { System.out.println(a.get(0) + 7); diff --git a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/reverseIntArray/after/Test.java b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/reverseIntArray/after/Test.java index 0b5bb1455e2a..401714230d3c 100644 --- a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/reverseIntArray/after/Test.java +++ b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/reverseIntArray/after/Test.java @@ -9,7 +9,7 @@ class Test { System.out.println(++a[0]); a[0]--; if (--a[0] == 0) { - a[0] += 2; + a[0] += ((2)); a[0] = a[0] * 2; if (a[0] == 0) { System.out.println(a[0] + 7); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java index 1f0c18f53a9f..1402b8e09cbc 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch; import com.intellij.openapi.fileTypes.StdFileTypes; @@ -2276,4 +2276,33 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "}", replacer.testReplace(in, what, by, options, true)); } + + public void testReplaceParentheses() { + String in = "public class MyFile {\n" + + " void test(String a, Object b) {\n" + + " if(a.length() == 0) {\n" + + " System.out.println(\"empty\");\n" + + " }\n" + + " if(((String) b).length() == 0) {\n" + + " System.out.println(\"empty\");\n" + + " }\n" + + " }\n" + + "}"; + + String what = "'_expr:[exprtype( String )].length() == 0"; + String by = "$expr$.isEmpty()"; + assertEquals("parentheses should remain", + + "public class MyFile {\n" + + " void test(String a, Object b) {\n" + + " if(a.isEmpty()) {\n" + + " System.out.println(\"empty\");\n" + + " }\n" + + " if(((String) b).isEmpty()) {\n" + + " System.out.println(\"empty\");\n" + + " }\n" + + " }\n" + + "}", + replacer.testReplace(in, what, by, options, true)); + } } \ No newline at end of file diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index b7ed351bce79..7cfd561fb7ec 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -2215,6 +2215,12 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String pattern2 = "System.out.println('_v);" + "System.out.println('_v);"; assertEquals(1, findMatchesCount(source, pattern2)); + + String source2 = "class B {{" + + " System.out.println((3 * 8) + 2 + (((2))));" + + "}}"; + String pattern3 = "3 * 8 + 2 + 2"; + assertEquals(1, findMatchesCount(source2, pattern3)); } public void testFindSelfAssignment() {