SSR: find expression statement with type (IDEA-171214)

This commit is contained in:
Bas Leijdekkers
2017-04-28 21:03:59 +02:00
parent 0bbdfddeec
commit a2d73df8b4
3 changed files with 68 additions and 41 deletions
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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() {