SRR: improve java array declaration matching

This commit is contained in:
Bas Leijdekkers
2015-10-02 16:16:42 +02:00
parent eb4b2613f7
commit 247b885ce9
2 changed files with 82 additions and 69 deletions
@@ -21,7 +21,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.structuralsearch.MatchOptions;
@@ -444,7 +443,6 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
final MatchingHandler allRemainingClassContentElementHandler = unmatchedHandlerName != null ? pattern.getHandler(unmatchedHandlerName) : null;
MatchContext.MatchedElementsListener newListener = null;
assert javaPattern instanceof JavaCompiledPattern;
if (allRemainingClassContentElementHandler != null) {
myMatchingVisitor.getMatchContext().setMatchedElementsListener(
newListener = new MatchContext.MatchedElementsListener() {
@@ -686,29 +684,47 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
myMatchingVisitor.setResult(false);
}
private static int countCStyleArrayDeclarationDims(final PsiElement type2) {
if (type2 != null) {
final PsiElement parentElement = type2.getParent();
if (parentElement instanceof PsiVariable) {
final PsiIdentifier psiIdentifier = ((PsiVariable)parentElement).getNameIdentifier();
if (psiIdentifier == null) return 0;
int count = 0;
for (PsiElement sibling = psiIdentifier.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) {
if (sibling instanceof PsiJavaToken) {
final IElementType tokenType = ((PsiJavaToken)sibling).getTokenType();
if (tokenType == JavaTokenType.LBRACKET) ++count;
else if (tokenType != JavaTokenType.RBRACKET) break;
}
}
return count;
}
private static int getArrayDimensions(final PsiElement element) {
if (element == null) {
return 0;
}
final PsiElement parent = element.getParent();
if (parent instanceof PsiVariable) {
final PsiVariable variable = (PsiVariable)parent;
final PsiType type = variable.getType();
return type.getArrayDimensions();
}
else if (parent instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)parent;
final PsiType type = method.getReturnType();
return (type == null) ? 0 : type.getArrayDimensions();
}
else if (element instanceof PsiTypeElement) {
final PsiTypeElement typeElement = (PsiTypeElement)element;
final PsiType type = typeElement.getType();
return type.getArrayDimensions();
}
return 0;
}
private static PsiTypeElement getInnermostComponentTypeElement(PsiTypeElement typeElement) {
PsiElement child = typeElement.getFirstChild();
while (child instanceof PsiTypeElement) {
typeElement = (PsiTypeElement)child;
child = typeElement.getFirstChild();
}
return typeElement;
}
private static PsiElement getInnermostComponent(PsiElement element) {
if (!(element instanceof PsiTypeElement)) {
return element;
}
final PsiTypeElement typeElement = (PsiTypeElement)element;
final PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement();
return (referenceElement != null) ? referenceElement : getInnermostComponentTypeElement(typeElement);
}
private void copyResults(final MatchResultImpl ourResult) {
if (ourResult.hasSons()) {
for (MatchResult son : ourResult.getAllSons()) {
@@ -718,25 +734,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
}
private boolean matchType(final PsiElement patternType, final PsiElement matchedType) {
PsiElement patternElement = patternType;
PsiElement matchedElement = matchedType;
PsiType type1 = null;
PsiType type2 = null;
// check for generics
if (patternType instanceof PsiTypeElement &&
((PsiTypeElement)patternType).getInnermostComponentReferenceElement() != null
) {
patternElement = ((PsiTypeElement)patternType).getInnermostComponentReferenceElement();
type1 = ((PsiTypeElement)patternType).getType();
}
if (matchedType instanceof PsiTypeElement &&
((PsiTypeElement)matchedType).getInnermostComponentReferenceElement() != null
) {
matchedElement = ((PsiTypeElement)matchedType).getInnermostComponentReferenceElement();
type2 = ((PsiTypeElement)matchedType).getType();
}
PsiElement patternElement = getInnermostComponent(patternType);
PsiElement matchedElement = getInnermostComponent(matchedType);
PsiElement[] typeParameters = null;
if (matchedElement instanceof PsiJavaCodeReferenceElement) {
@@ -757,34 +756,20 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
matchedElement = ((PsiMethod)matchedType).getNameIdentifier();
}
PsiReferenceParameterList list = null;
if (patternElement instanceof PsiJavaCodeReferenceElement) {
list = ((PsiJavaCodeReferenceElement)patternElement).getParameterList();
patternElement = ((PsiJavaCodeReferenceElement)patternElement).getReferenceNameElement();
}
if (list != null && list.getTypeParameterElements().length > 0) {
boolean result = typeParameters != null && myMatchingVisitor.matchSequentially(list.getTypeParameterElements(), typeParameters);
if (!result) return false;
}
else {
if (matchedType instanceof PsiTypeElement) {
type2 = ((PsiTypeElement)matchedType).getType();
if (typeParameters == null || typeParameters.length == 0) {
final PsiJavaCodeReferenceElement innermostComponentReferenceElement =
((PsiTypeElement)matchedType).getInnermostComponentReferenceElement();
if (innermostComponentReferenceElement != null) matchedElement = innermostComponentReferenceElement;
}
else {
matchedElement = matchedType;
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)patternElement;
final PsiReferenceParameterList list = referenceElement.getParameterList();
if (list != null) {
final PsiTypeElement[] elements = list.getTypeParameterElements();
if (elements.length > 0 && (typeParameters == null || !myMatchingVisitor.matchSequentially(elements, typeParameters))) {
return false;
}
}
patternElement = referenceElement.getReferenceNameElement();
}
final int patternArrayDimensions = (type1 != null ? type1.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(patternType);
final int matchedArrayDimensions = (type2 != null ? type2.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(matchedType);
final int matchedArrayDimensions = getArrayDimensions(matchedType);
final int patternArrayDimensions = getArrayDimensions(patternType);
if (myMatchingVisitor.getMatchContext().getPattern().isTypedVar(patternElement)) {
final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(patternElement);
@@ -685,14 +685,42 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
1,
findMatchesCount(s11,s12_3)
);
}
public void testFindArrayDeclarations() {
String source = "class A {" +
" String ss[][];" +
" int f()[] {" +
" return null;" +
" }" +
"}";
String source = "class A { String ss[][]; }";
String target = "String[][] $s$;";
assertEquals(
"should find multi dimensional c-style array declarations",
1,
findMatchesCount(source, target)
);
assertEquals("should find multi-dimensional c-style array declarations", 1, findMatchesCount(source, target));
String target2 = "class '_A { int[] 'f(); }";
assertEquals("should find c-style method return type declarations", 1, findMatchesCount(source, target2));
String target3 = "class '_A { int 'f(); }";
assertEquals("should not find methods with array return types",0, findMatchesCount(source, target3));
String source2 = "class A {" +
" void y(int... i) {}" +
" void y(String... ss) {}" +
" void y(boolean b) {}" +
"}";
assertEquals("find ellipsis type 1", 1, findMatchesCount(source2, "String[] '_a"));
assertEquals("find ellipsis type 2", 1, findMatchesCount(source2, "int[] '_a"));
assertEquals("find ellipsis type 3", 1, findMatchesCount(source2, "class '_X { void '_m(int... '_a); }"));
assertEquals("find ellipsis type 4", 2, findMatchesCount(source2, "'_T[] '_a"));
String source3 = "class A {" +
" private int[] is;" +
"}";
assertEquals("find primitive array 1", 1, findMatchesCount(source3, "int[] '_a;"));
assertEquals("find primitive array 2", 1, findMatchesCount(source3, "'_T[] '_a;"));
assertEquals("find primitive array 3", 1, findMatchesCount(source3, "'_T:[regex( int )][] '_a;"));
assertEquals("find primitive array 4", 1, findMatchesCount(source3, "'_T:[regex( int\\[\\] )] '_a;"));
}
// @todo support back references (\1 in another reg exp or as fild member)