From 7582e25009b19dcc804b49c9ab628ba715113275 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 25 Apr 2016 17:45:22 +0200 Subject: [PATCH] SSR: find diamond types with pattern with explicit types --- .../impl/matcher/JavaMatchingVisitor.java | 82 +++++++++++++------ .../StructuralSearchTest.java | 12 +++ 2 files changed, 67 insertions(+), 27 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 477987466086..52d539d16e4f 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 @@ -719,6 +719,52 @@ public class JavaMatchingVisitor extends JavaElementVisitor { } } } + private static PsiTypeElement[] getTypeParameters(PsiJavaCodeReferenceElement referenceElement, boolean replaceDiamondWithExplicitTypes) { + final PsiReferenceParameterList referenceElementParameterList = referenceElement.getParameterList(); + if (referenceElementParameterList == null) { + return null; + } + final PsiTypeElement[] typeParameterElements = referenceElementParameterList.getTypeParameterElements(); + if (typeParameterElements.length != 1 || !replaceDiamondWithExplicitTypes) { + return typeParameterElements; + } + final PsiType type = typeParameterElements[0].getType(); + if (!(type instanceof PsiDiamondType)) { + return typeParameterElements; + } + final PsiDiamondType diamondType = (PsiDiamondType)type; + final PsiDiamondType.DiamondInferenceResult inferenceResult = diamondType.resolveInferredTypes(); + final StringBuilder text = new StringBuilder(referenceElement.getQualifiedName()); + text.append('<'); + boolean comma = false; + for (PsiType inferredType : inferenceResult.getInferredTypes()) { + if (comma) { + text.append(','); + } + else { + comma = true; + } + text.append(inferredType.getCanonicalText()); + } + text.append('>'); + final PsiJavaCodeReferenceElement newReferenceElement = + JavaPsiFacade.getElementFactory(referenceElement.getProject()).createReferenceFromText(text.toString(), referenceElement); + final PsiReferenceParameterList newParameterList = newReferenceElement.getParameterList(); + return newParameterList == null ? null : newParameterList.getTypeParameterElements(); + } + + private static boolean hasDiamondTypeParameter(PsiElement element) { + if (!(element instanceof PsiJavaCodeReferenceElement)) { + return false; + } + final PsiJavaCodeReferenceElement javaCodeReferenceElement = (PsiJavaCodeReferenceElement)element; + final PsiReferenceParameterList parameterList = javaCodeReferenceElement.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiTypeElement[] elements = parameterList.getTypeParameterElements(); + return elements.length == 1 && elements[0].getType() instanceof PsiDiamondType; + } private boolean matchType(final PsiElement patternType, final PsiElement matchedType) { PsiElement patternElement = getInnermostComponent(patternType); @@ -726,10 +772,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor { PsiElement[] typeParameters = null; if (matchedElement instanceof PsiJavaCodeReferenceElement) { - final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)matchedElement).getParameterList(); - if (parameterList != null) { - typeParameters = parameterList.getTypeParameterElements(); - } + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)matchedElement; + typeParameters = getTypeParameters(referenceElement, !hasDiamondTypeParameter(patternElement)); } else if (matchedElement instanceof PsiTypeParameter) { matchedElement = ((PsiTypeParameter)matchedElement).getNameIdentifier(); @@ -821,13 +865,11 @@ public class JavaMatchingVisitor extends JavaElementVisitor { else { final PsiElement element2 = ((PsiJavaReference)matchedElement).resolve(); - if (element2 instanceof PsiClass) { - final String name = ((PsiClass)element2).getQualifiedName(); - return caseSensitive ? text.equals(name) : text.equalsIgnoreCase(name); - } - else { - return MatchUtils.compareWithNoDifferenceToPackage(text, text2, !caseSensitive); + if (!(element2 instanceof PsiClass)) { + return false; } + final String name = ((PsiClass)element2).getQualifiedName(); + return caseSensitive ? text.equals(name) : text.equalsIgnoreCase(name); } } @@ -837,27 +879,13 @@ public class JavaMatchingVisitor extends JavaElementVisitor { if (element instanceof PsiClass) { result = ((PsiClass)element).getQualifiedName(); if (result == null) result = element.getText(); + } else if (element instanceof PsiJavaCodeReferenceElement) { + result = ((PsiJavaCodeReferenceElement)element).getCanonicalText(); } else { result = element.getText(); } - final int whitespace = lastIndexOfWhitespace(result); - if (whitespace >= 0) { - // strips off any annotations - result = result.substring(whitespace + 1); - } final int index = result.indexOf('<'); - if (index == -1) { - return result; - } - return result.substring(0, index); - } - - @Contract(pure = true) - private static int lastIndexOfWhitespace(@NotNull CharSequence s) { - for (int i = s.length() - 1; i >= 0; i--) { - if (Character.isWhitespace(s.charAt(i))) return i; - } - return -1; + return index == -1 ? result : result.substring(0, index); } private boolean checkMatchWithingHierarchy(PsiElement el2, SubstitutionHandler handler, PsiElement context) { diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index cb08a9e98583..c7f68b7a5eec 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -3467,4 +3467,16 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("find parameterized method calls 3", 3, findMatchesCount(source, "'_a.<'_b>'_c('_d*)")); assertEquals("find parameterized method calls 4", 4, findMatchesCount(source, "'_a.<'_b+>'_c('_d*)")); } + + public void testFindDiamondTypes() { + String source = "class A {}" + + "class B {{" + + " A a1 = new A<>();" + + " A a2 = new A();" + + " A a3 = new A<>();" + + " A a4 = new A<>();" + + "}}"; + assertEquals("find diamond new expressions", 3, findMatchesCount(source, "new A<>()")); + assertEquals("find parameterized new expressions", 2, findMatchesCount(source, "new A()")); + } }