From a2d73df8b4540684b37b15713af34debddf6d019 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 28 Apr 2017 21:02:29 +0200 Subject: [PATCH] SSR: find expression statement with type (IDEA-171214) --- .../matcher/handlers/StatementHandler.java | 41 +++++++----- .../matcher/predicates/ExprTypePredicate.java | 64 +++++++++++-------- .../StructuralSearchTest.java | 4 ++ 3 files changed, 68 insertions(+), 41 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/StatementHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/StatementHandler.java index c6361e2ad4e7..90c862068e7d 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/StatementHandler.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/StatementHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.structuralsearch.impl.matcher.handlers; import com.intellij.psi.*; @@ -8,25 +23,21 @@ import com.intellij.structuralsearch.impl.matcher.MatchContext; */ public class StatementHandler extends MatchingHandler { + @Override public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { - // filtering is done on SubstituionHandler level - if (patternNode==null) return false; - patternNode = ((PsiExpressionStatement)patternNode).getExpression(); + // filtering is done on SubstitutionHandler level + if (patternNode == null) return false; - /*if (matchedNode instanceof PsiExpressionStatement) { - //matchedNode = ((PsiExpressionStatement)matchedNode).getExpression(); - } else*/ if (( !(matchedNode instanceof PsiStatement) && - !(matchedNode instanceof PsiComment) // comments to be matched as statements - ) || - ( matchedNode instanceof PsiBlockStatement && - !(matchedNode.getParent() instanceof PsiBlockStatement) && - !(matchedNode.getParent().getParent() instanceof PsiSwitchStatement) - )) { - // typed statement does not match this things - // (BlockStatement could be nontop level in if, etc) + if ((!(matchedNode instanceof PsiStatement) && !(matchedNode instanceof PsiComment) /* comments are matched as statements */) || + (matchedNode instanceof PsiBlockStatement && + !(matchedNode.getParent() instanceof PsiBlockStatement) && + !(matchedNode.getParent().getParent() instanceof PsiSwitchStatement))) { + // typed statement does not match these things + // (BlockStatement could be non-top level in if, etc) return false; } - return context.getMatcher().match(patternNode,matchedNode); + patternNode = ((PsiExpressionStatement)patternNode).getExpression(); + return context.getMatcher().match(patternNode, matchedNode); } } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/predicates/ExprTypePredicate.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/predicates/ExprTypePredicate.java index d66db76c272d..d51365d60e01 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/predicates/ExprTypePredicate.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/predicates/ExprTypePredicate.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.structuralsearch.impl.matcher.predicates; import com.intellij.psi.*; @@ -7,52 +22,49 @@ import com.intellij.structuralsearch.impl.matcher.iterators.HierarchyNodeIterato import com.intellij.dupLocator.iterators.NodeIterator; /** - * Created by IntelliJ IDEA. - * User: Maxim.Mossienko + * @author Maxim.Mossienko * Date: Mar 23, 2004 * Time: 6:37:15 PM - * To change this template use File | Settings | File Templates. */ public class ExprTypePredicate extends MatchPredicate { private final RegExpPredicate delegate; private final boolean withinHierarchy; - public ExprTypePredicate(String type, String baseName, boolean _withinHierarchy, boolean caseSensitiveMatch,boolean target) { - delegate = new RegExpPredicate(type,caseSensitiveMatch,baseName,false,target); + public ExprTypePredicate(String type, String baseName, boolean _withinHierarchy, boolean caseSensitiveMatch, boolean target) { + delegate = new RegExpPredicate(type, caseSensitiveMatch, baseName, false, target); withinHierarchy = _withinHierarchy; } + @Override public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { return match(patternNode, matchedNode, 0, -1, context); } + @Override public boolean match(PsiElement node, PsiElement match, int start, int end, MatchContext context) { if (match instanceof PsiIdentifier) { // since we pickup tokens match = match.getParent(); } + else if (match instanceof PsiExpressionStatement) { + match = ((PsiExpressionStatement)match).getExpression(); + } - if (match instanceof PsiExpression) { - final PsiType type = evalType((PsiExpression)match,context); - if (type==null) return false; - - return doMatchWithTheType(type, context, match); - } else { + if (!(match instanceof PsiExpression)) { return false; } + final PsiType type = evalType((PsiExpression)match, context); + return type != null && doMatchWithTheType(type, context, match); } protected PsiType evalType(PsiExpression match, MatchContext context) { - PsiType type = null; - - if (match instanceof PsiReferenceExpression && - match.getParent() instanceof PsiMethodCallExpression) { - PsiMethod method = ((PsiMethodCallExpression)match.getParent()).resolveMethod(); - if (method!=null) type = method.getReturnType(); + if (match instanceof PsiReferenceExpression) { + final PsiElement parent = match.getParent(); + if (parent instanceof PsiMethodCallExpression) { + return ((PsiMethodCallExpression)parent).getType(); + } } - - if (type==null) type = match.getType(); - return type; + return match.getType(); } private boolean doMatchWithTheType(final PsiType type, MatchContext context, PsiElement matchedNode) { @@ -64,13 +76,13 @@ public class ExprTypePredicate extends MatchPredicate { if (type!=null) { final String presentableText = type.getPresentableText(); - boolean result = delegate.doMatch(presentableText,context, matchedNode); + boolean result = delegate.doMatch(presentableText, context, matchedNode); if (!result && type instanceof PsiArrayType && ((PsiArrayType)type).getComponentType() instanceof PsiClassType) { PsiClass clazz = ((PsiClassType)((PsiArrayType)type).getComponentType()).resolve(); if (clazz!=null) { // presentable text for array is not qualified! - result = delegate.doMatch(clazz.getQualifiedName()+"[]",context, matchedNode); + result = delegate.doMatch(clazz.getQualifiedName() + "[]", context, matchedNode); } } return result; @@ -79,17 +91,17 @@ public class ExprTypePredicate extends MatchPredicate { } } - public boolean checkClass(PsiClass clazz, MatchContext context) { + private boolean checkClass(PsiClass clazz, MatchContext context) { if (withinHierarchy) { - final NodeIterator parents = new HierarchyNodeIterator(clazz,true,true); + final NodeIterator parents = new HierarchyNodeIterator(clazz, true, true); - while(parents.hasNext() && !delegate.match(null,parents.current(),context)) { + while(parents.hasNext() && !delegate.match(null, parents.current(), context)) { parents.advance(); } return parents.hasNext(); } else { - return delegate.match(null,clazz,context); + return delegate.match(null, clazz, context); } } } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index e7e4c187323e..09eced4df611 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -600,6 +600,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " }" + "}"; assertEquals("Should find statements and comments in statement context only", 2, findMatchesCount(in2, "'_statement;")); + + String in3 = "new Object().hashCode();" + + "new Object().toString();"; + assertEquals("Find typed expression statements", 1, findMatchesCount(in3, "'_expr:[exprtype( int )];")); } public void testSearchClass() {