SSR: replace annotation parameters more reliably (IDEA-223146)

GitOrigin-RevId: a6342b4ef5920b380d850cc2ead087321848a559
This commit is contained in:
Bas Leijdekkers
2019-09-25 16:31:25 +02:00
committed by intellij-monorepo-bot
parent aa727f33b1
commit bfb8367066
3 changed files with 116 additions and 73 deletions

View File

@@ -61,53 +61,51 @@ public class AnnotationParamListElement extends CompositeElement {
@Override
public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) {
if (first.getElementType() == JavaElementType.NAME_VALUE_PAIR && last.getElementType() == JavaElementType.NAME_VALUE_PAIR) {
ASTNode lparenth = findChildByType(JavaTokenType.LPARENTH);
if (lparenth == null) {
CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this);
LeafElement created = Factory.createSingleLeafElement(JavaTokenType.LPARENTH, "(", 0, 1, treeCharTab, getManager());
super.addInternal(created, created, getFirstChildNode(), true);
}
ASTNode lparenth = findChildByType(JavaTokenType.LPARENTH);
if (lparenth == null) {
CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this);
LeafElement created = Factory.createSingleLeafElement(JavaTokenType.LPARENTH, "(", 0, 1, treeCharTab, getManager());
super.addInternal(created, created, getFirstChildNode(), true);
}
ASTNode rparenth = findChildByType(JavaTokenType.RPARENTH);
if (rparenth == null) {
CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this);
LeafElement created = Factory.createSingleLeafElement(JavaTokenType.RPARENTH, ")", 0, 1, treeCharTab, getManager());
super.addInternal(created, created, getLastChildNode(), false);
}
ASTNode rparenth = findChildByType(JavaTokenType.RPARENTH);
if (rparenth == null) {
CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this);
LeafElement created = Factory.createSingleLeafElement(JavaTokenType.RPARENTH, ")", 0, 1, treeCharTab, getManager());
super.addInternal(created, created, getLastChildNode(), false);
}
ASTNode[] nodes = getChildren(NAME_VALUE_PAIR_BIT_SET);
if (nodes.length == 1) {
ASTNode node = nodes[0];
if (node instanceof PsiNameValuePair) {
PsiNameValuePair pair = (PsiNameValuePair)node;
if (pair.getName() == null) {
PsiAnnotationMemberValue value = pair.getValue();
if (value != null) {
try {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(getPsi().getProject());
PsiAnnotation annotation = factory.createAnnotationFromText("@AAA(value = " + value.getText() + ")", null);
replaceChild(node, annotation.getParameterList().getAttributes()[0].getNode());
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
ASTNode[] nodes = getChildren(NAME_VALUE_PAIR_BIT_SET);
if (nodes.length == 1) {
ASTNode node = nodes[0];
if (node instanceof PsiNameValuePair) {
PsiNameValuePair pair = (PsiNameValuePair)node;
if (pair.getName() == null) {
PsiAnnotationMemberValue value = pair.getValue();
if (value != null) {
try {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(getPsi().getProject());
PsiAnnotation annotation = factory.createAnnotationFromText("@AAA(value = " + value.getText() + ")", null);
replaceChild(node, annotation.getParameterList().getAttributes()[0].getNode());
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
}
if (anchor == null) {
if (before == null) before = Boolean.TRUE;
anchor = findChildByType(before ? JavaTokenType.RPARENTH : JavaTokenType.LPARENTH);
}
TreeElement firstAdded = super.addInternal(first, last, anchor, before);
JavaSourceUtil.addSeparatingComma(this, first, NAME_VALUE_PAIR_BIT_SET);
return firstAdded;
}
return super.addInternal(first, last, anchor, before);
if (anchor == null) {
if (before == null) before = Boolean.TRUE;
anchor = findChildByType(before ? JavaTokenType.RPARENTH : JavaTokenType.LPARENTH);
}
TreeElement firstAdded = super.addInternal(first, last, anchor, before);
if (first == last && first.getElementType() == JavaElementType.NAME_VALUE_PAIR) {
JavaSourceUtil.addSeparatingComma(this, first, NAME_VALUE_PAIR_BIT_SET);
}
return firstAdded;
}
@Override

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -276,8 +275,9 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
if (originalMember == null) {
continue;
}
for (Iterator<? extends PsiElement> iterator = elements.iterator(); iterator.hasNext(); ) {
PsiElement element = iterator.next();
final Iterator<? extends PsiElement> iterator = elements.iterator();
while (iterator.hasNext()) {
final PsiElement element = iterator.next();
if (PsiElementOrderComparator.getInstance().compare(element, originalMember) < 0) {
addElementAndWhitespaceBeforeAnchor(replacementClass, element, anchor);
iterator.remove();
@@ -327,7 +327,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
}
}
private static void copyAnnotationParameters(PsiAnnotation original, PsiAnnotation query, PsiAnnotation replacement) {
private void copyAnnotationParameters(PsiAnnotation original, PsiAnnotation query, PsiAnnotation replacement) {
final PsiAnnotationParameterList originalParameters = original.getParameterList();
if (originalParameters.getTextLength() > 0) {
final PsiAnnotationParameterList replacementParameters = replacement.getParameterList();
@@ -338,15 +338,14 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
final List<? extends PsiElement> unmatchedAttributes = original.getUserData(GlobalMatchingVisitor.UNMATCHED_ELEMENTS_KEY);
if (unmatchedAttributes != null) {
for (PsiElement attribute : unmatchedAttributes) {
replacementParameters.add(whiteSpace(attribute.getPrevSibling(), " "));
replacementParameters.add(attribute);
}
}
}
}
private static void copyModifiersAndAnnotations(PsiModifierListOwner original,
PsiModifierListOwner query,
PsiModifierListOwner replacement) {
private void copyModifiersAndAnnotations(PsiModifierListOwner original, PsiModifierListOwner query, PsiModifierListOwner replacement) {
final PsiModifierList originalModifierList = original.getModifierList();
final PsiModifierList queryModifierList = query.getModifierList();
final PsiModifierList replacementModifierList = replacement.getModifierList();
@@ -354,39 +353,58 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
if (originalModifierList == null || queryModifierList == null || replacementModifierList == null) {
return;
}
if (originalModifierList.getTextLength() != 0) {
final PsiModifierList copy = (PsiModifierList)originalModifierList.copy();
for (String modifier : PsiModifier.MODIFIERS) {
if (replacementModifierList.hasExplicitModifier(modifier)) {
copy.setModifierProperty(modifier, true);
}
else if (queryModifierList.hasExplicitModifier(modifier) && !replacementModifierList.hasModifierProperty(modifier)) {
copy.setModifierProperty(modifier, false);
final List<? extends PsiElement> unmatchedAnnotations = originalModifierList.getUserData(GlobalMatchingVisitor.UNMATCHED_ELEMENTS_KEY);
final PsiElement anchor = replacementModifierList.getFirstChild();
boolean append = (anchor == null);
PsiElement child = originalModifierList.getFirstChild();
while (child != null) {
if (child instanceof PsiKeyword) {
append = true;
@PsiModifier.ModifierConstant final String modifierText = child.getText();
if (isCompatibleModifier(modifierText, replacementModifierList) && !queryModifierList.hasExplicitModifier(modifierText)) {
if (anchor != null) replacementModifierList.add(whiteSpace(child.getPrevSibling(), " "));
replacementModifierList.add(child);
}
}
final List<? extends PsiElement> unmatchedAnnotations = originalModifierList.getUserData(GlobalMatchingVisitor.UNMATCHED_ELEMENTS_KEY);
if (unmatchedAnnotations != null) {
outer:
for (PsiAnnotation copyAnnotation : copy.getAnnotations()) {
for (PsiElement unmatchedAnnotation : unmatchedAnnotations) {
if (AnnotationUtil.equal(copyAnnotation, (PsiAnnotation)unmatchedAnnotation)) {
continue outer;
}
else if (child instanceof PsiAnnotation && (unmatchedAnnotations == null || unmatchedAnnotations.contains(child))) {
if (append) {
if (anchor != null) replacementModifierList.add(whiteSpace(child.getPrevSibling(), " "));
replacementModifierList.add(child);
}
else {
final PsiElement next = replacementModifierList.addBefore(child, anchor).getNextSibling();
final PsiWhiteSpace whiteSpace = whiteSpace(child.getNextSibling(), " ");
if (!(next instanceof PsiWhiteSpace)) {
replacementModifierList.addBefore(whiteSpace, anchor);
}
else {
next.replace(whiteSpace);
}
copyAnnotation.delete();
}
}
for (PsiAnnotation annotation : replacementModifierList.getAnnotations()) {
copy.addBefore(annotation, copy.getFirstChild());
}
replacementModifierList.replace(copy);
child = child.getNextSibling();
}
}
private PsiWhiteSpace whiteSpace(PsiElement element, @SuppressWarnings("SameParameterValue") String defaultWs) {
return element instanceof PsiWhiteSpace
? (PsiWhiteSpace)element
: (PsiWhiteSpace)PsiParserFacade.SERVICE.getInstance(myProject).createWhiteSpaceFromText(defaultWs);
}
private static boolean isCompatibleModifier(String modifier, PsiModifierList modifierList) {
if (PsiModifier.PUBLIC.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) || PsiModifier.PRIVATE.equals(modifier)) {
return !modifierList.hasExplicitModifier(PsiModifier.PUBLIC)
&& !modifierList.hasExplicitModifier(PsiModifier.PROTECTED)
&& !modifierList.hasExplicitModifier(PsiModifier.PRIVATE);
}
return true;
}
private PsiElement handleSymbolReplacement(PsiElement replacement, final PsiElement el) {
PsiNamedElement nameElement = getSymbolReplacementTarget(el);
final PsiNamedElement nameElement = getSymbolReplacementTarget(el);
if (nameElement != null) {
PsiElement oldReplacement = replacement;
final PsiElement oldReplacement = replacement;
replacement = el.copy();
((PsiNamedElement)replacement).setName(oldReplacement.getText());
}

View File

@@ -2108,9 +2108,9 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
}
public void testReplaceAnnotation() {
String in1 = "@SuppressWarnings(\"ALL\")\n" +
"public class A {}";
String what = "@SuppressWarnings(\"ALL\")";
final String in1 = "@SuppressWarnings(\"ALL\")\n" +
"public class A {}";
final String what = "@SuppressWarnings(\"ALL\")";
final String expected1a = "public class A {}";
assertEquals(expected1a, replace(in1, what, ""));
@@ -2175,7 +2175,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
"}";
assertEquals(expected4, replace(in4, "@'_A('_p*=1)", "@$A$($p$=1, three=1)"));
final String expected4b = "class X { @Anno(one=2,two=1) String s;}";
final String expected4b = "class X { @Anno(one=2, two=1) String s;}";
assertEquals(expected4b, replace(in4, "@'_A('_p:one =1)", "@$A$($p$=2)"));
final String in5 = "@RunWith(SpringJUnit4ClassRunner.class)\n" +
@@ -2195,6 +2195,33 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
assertEquals(expected5, replace(in5, "@ContextConfiguration(classes = {'_X*})", "@ContextHierarchy(classes = {\n" +
" @ContextConfiguration(classes = {$X$, Object.class})\n" +
"})"));
final String in6 = "class X {\n" +
" @WastingTime @Override\n" +
" public @Constant @Sorrow String value() {\n" +
" return null;\n" +
" }\n" +
"}";
final String expected6 = "class X {\n" +
" @WastingTime @Override\n" +
" private @Constant @Sorrow String value() {\n" +
" return null;\n" +
" }\n" +
"}";
assertEquals(expected6, replace(in6, "'_ReturnType '_method('_ParameterType '_parameter*);",
"private $ReturnType$ $method$($ParameterType$ $parameter$);"));
final String in7 = "public class IssueLink {\n" +
" @XmlAttribute(name = \"default\", namespace = \"space\")\n" +
" @Deprecated\n" +
" public String typeInward;\n" +
"}";
final String expected7 = "public class IssueLink {\n" +
" @XmlAttribute(name=\"default\", namespace = \"space\")\n" +
" public String typeInward;\n" +
"}";
assertEquals(expected7, replace(in7, "@XmlAttribute(name=\"default\") @Deprecated '_Type '_field;",
"@XmlAttribute(name=\"default\") $Type$ $field$;"));
}
public void testReplacePolyadicExpression() {