mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SSR: fix generics matching & replacing (IDEA-190128)
This commit is contained in:
+14
-4
@@ -58,14 +58,24 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
|
||||
@Override
|
||||
public String getText(PsiElement match, int start, int end) {
|
||||
if (match instanceof PsiIdentifier) {
|
||||
PsiElement parent = match.getParent();
|
||||
final PsiElement parent = match.getParent();
|
||||
if (parent instanceof PsiJavaCodeReferenceElement && !(parent instanceof PsiExpression)) {
|
||||
match = parent; // care about generic
|
||||
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parent;
|
||||
final String text = referenceElement.getText();
|
||||
if (end != -1) {
|
||||
return text.substring(start, end);
|
||||
}
|
||||
final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
|
||||
if (parameterList != null) {
|
||||
// get text without type parameters
|
||||
return text.substring(start, parameterList.getStartOffsetInParent());
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
final String matchText = match.getText();
|
||||
if (start==0 && end==-1) return matchText;
|
||||
return matchText.substring(start,end == -1? matchText.length():end);
|
||||
if (start == 0 && end == -1) return matchText;
|
||||
return matchText.substring(start, (end == -1) ? matchText.length() : end);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+30
-9
@@ -670,19 +670,22 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
|
||||
return (referenceElement != null) ? referenceElement : getInnermostComponentTypeElement(typeElement);
|
||||
}
|
||||
|
||||
private static PsiTypeElement[] getTypeParameters(PsiJavaCodeReferenceElement referenceElement, boolean replaceDiamondWithExplicitTypes) {
|
||||
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) {
|
||||
if (typeParameterElements.length != 1 || replaceDiamondWithExplicitTypes == Boolean.FALSE) {
|
||||
return typeParameterElements;
|
||||
}
|
||||
final PsiType type = typeParameterElements[0].getType();
|
||||
if (!(type instanceof PsiDiamondType)) {
|
||||
return typeParameterElements;
|
||||
}
|
||||
if (replaceDiamondWithExplicitTypes == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiDiamondType diamondType = (PsiDiamondType)type;
|
||||
final PsiDiamondType.DiamondInferenceResult inferenceResult = diamondType.resolveInferredTypes();
|
||||
final StringBuilder text = new StringBuilder(referenceElement.getQualifiedName());
|
||||
@@ -704,17 +707,28 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
|
||||
return newParameterList == null ? null : newParameterList.getTypeParameterElements();
|
||||
}
|
||||
|
||||
private static boolean hasDiamondTypeParameter(PsiElement element) {
|
||||
private Boolean shouldReplaceDiamondWithExplicitTypes(PsiElement element) {
|
||||
if (!(element instanceof PsiJavaCodeReferenceElement)) {
|
||||
return false;
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
final PsiJavaCodeReferenceElement javaCodeReferenceElement = (PsiJavaCodeReferenceElement)element;
|
||||
final PsiReferenceParameterList parameterList = javaCodeReferenceElement.getParameterList();
|
||||
if (parameterList == null) {
|
||||
return false;
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
final PsiTypeElement[] elements = parameterList.getTypeParameterElements();
|
||||
return elements.length == 1 && elements[0].getType() instanceof PsiDiamondType;
|
||||
if (elements.length != 1) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
final PsiTypeElement typeElement = elements[0];
|
||||
final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(typeElement);
|
||||
if (handler instanceof SubstitutionHandler) {
|
||||
final SubstitutionHandler substitutionHandler = (SubstitutionHandler)handler;
|
||||
if (substitutionHandler.getMinOccurs() > 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return Boolean.valueOf(!(typeElement.getType() instanceof PsiDiamondType));
|
||||
}
|
||||
|
||||
private boolean matchType(final PsiElement patternType, final PsiElement matchedType) {
|
||||
@@ -726,7 +740,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
|
||||
PsiElement[] typeParameters = null;
|
||||
if (matchedElement instanceof PsiJavaCodeReferenceElement) {
|
||||
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)matchedElement;
|
||||
typeParameters = getTypeParameters(referenceElement, !hasDiamondTypeParameter(patternElement));
|
||||
typeParameters = getTypeParameters(referenceElement, shouldReplaceDiamondWithExplicitTypes(patternElement));
|
||||
}
|
||||
else if (matchedElement instanceof PsiTypeParameter) {
|
||||
matchedElement = ((PsiTypeParameter)matchedElement).getNameIdentifier();
|
||||
@@ -743,13 +757,20 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
|
||||
if (patternElement instanceof PsiJavaCodeReferenceElement) {
|
||||
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)patternElement;
|
||||
final PsiReferenceParameterList list = referenceElement.getParameterList();
|
||||
boolean typeParametersMatched = false;
|
||||
if (list != null) {
|
||||
final PsiTypeElement[] elements = list.getTypeParameterElements();
|
||||
if (elements.length > 0 && (typeParameters == null || !myMatchingVisitor.matchSequentially(elements, typeParameters))) {
|
||||
return false;
|
||||
if (elements.length > 0) {
|
||||
typeParametersMatched = true;
|
||||
if (!myMatchingVisitor.matchSequentially(elements, (typeParameters == null) ? PsiElement.EMPTY_ARRAY : typeParameters)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
patternElement = referenceElement.getReferenceNameElement();
|
||||
if (typeParametersMatched && matchedElement instanceof PsiJavaCodeReferenceElement) {
|
||||
matchedElement = ((PsiJavaCodeReferenceElement)matchedElement).getReferenceNameElement();
|
||||
}
|
||||
}
|
||||
|
||||
final int matchedArrayDimensions = getArrayDimensions(matchedType);
|
||||
|
||||
+39
@@ -2460,4 +2460,43 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
" }" +
|
||||
"}", Replacer.testReplace(in, what, by, options, getProject(), true));
|
||||
}
|
||||
|
||||
public void testReplaceGenerics() {
|
||||
options.setToShortenFQN(false);
|
||||
String in = "import java.util.ArrayList;" +
|
||||
"import java.util.List;" +
|
||||
"class X {" +
|
||||
" List<String> list = new java.util.LinkedList<String>();" +
|
||||
" List<Integer> list2 = new java.util.ArrayList<Integer>();" +
|
||||
" List<Double> list3 = new ArrayList<>();" +
|
||||
"}";
|
||||
|
||||
assertEquals("should properly replace with diamond",
|
||||
"import java.util.ArrayList;" +
|
||||
"import java.util.List;" +
|
||||
"class X {" +
|
||||
" List<String> list = new java.util.LinkedList<>();" +
|
||||
" List<Integer> list2 = new ArrayList<>();" +
|
||||
" List<Double> list3 = new ArrayList<>();" +
|
||||
"}",
|
||||
Replacer.testReplace(in, "new '_X<'_p+>()", "new $X$<>()", options, getProject(), true));
|
||||
assertEquals("should keep generics when matching without",
|
||||
"import java.util.ArrayList;" +
|
||||
"import java.util.List;" +
|
||||
"class X {" +
|
||||
" List<String> list = new /*1*/java.util.LinkedList<String>();" +
|
||||
" List<Integer> list2 = new /*1*/ArrayList<Integer>();" +
|
||||
" List<Double> list3 = new /*1*/ArrayList<>();" +
|
||||
"}",
|
||||
Replacer.testReplace(in, "new '_X()", "new /*1*/$X$()", options, getProject(), true));
|
||||
assertEquals("should not duplicate generic parameters",
|
||||
"import java.util.ArrayList;" +
|
||||
"import java.util.List;" +
|
||||
"class X {" +
|
||||
" List<String> list = new java.util.LinkedList</*0*/String>();" +
|
||||
" List<Integer> list2 = new ArrayList</*0*/Integer>();" +
|
||||
" List<Double> list3 = new ArrayList<>();" +
|
||||
"}",
|
||||
Replacer.testReplace(in, "new '_X<'_p+>()", "new $X$</*0*/$p$>()", options, getProject(), true));
|
||||
}
|
||||
}
|
||||
+1
@@ -2682,6 +2682,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
|
||||
"}}";
|
||||
assertEquals("find diamond new expressions", 3, findMatchesCount(source, "new A<>()"));
|
||||
assertEquals("find parameterized new expressions", 2, findMatchesCount(source, "new A<Integer, String>()"));
|
||||
assertEquals("find non-diamond", 1, findMatchesCount(source, "new A<'_p{1,100}>()"));
|
||||
}
|
||||
|
||||
public void testFindSuperCall() {
|
||||
|
||||
Reference in New Issue
Block a user