SSR: find diamond types with pattern with explicit types

This commit is contained in:
Bas Leijdekkers
2016-04-25 18:48:31 +02:00
parent 48a292b315
commit 7582e25009
2 changed files with 67 additions and 27 deletions
@@ -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) {
@@ -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<X, Y> {}" +
"class B {{" +
" A<Integer, String> a1 = new A<>();" +
" A<Integer, String> a2 = new A<Integer, String>();" +
" A<Double, Boolean> a3 = new A<>();" +
" A<Double, Boolean> a4 = new A<>();" +
"}}";
assertEquals("find diamond new expressions", 3, findMatchesCount(source, "new A<>()"));
assertEquals("find parameterized new expressions", 2, findMatchesCount(source, "new A<Integer, String>()"));
}
}