mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-167980 Add quick fix to merge two annotations which are not marked as repeatable
GitOrigin-RevId: 6cc5742354b484ea996ec6a0d2bfa29f3013a08a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
73ed3aa311
commit
2ba9a65828
@@ -511,4 +511,6 @@ public abstract class QuickFixFactory {
|
||||
public abstract IntentionAction createAddMissingEnumBranchesFix(@NotNull PsiSwitchBlock switchBlock, @NotNull Set<String> missingCases);
|
||||
|
||||
public abstract IntentionAction createAddSwitchDefaultFix(@NotNull PsiSwitchBlock switchBlock, @Nullable String message);
|
||||
|
||||
public abstract IntentionAction createCollapseAnnotationsFix(PsiAnnotation annotation);
|
||||
}
|
||||
+4
-1
@@ -204,7 +204,10 @@ public class AnnotationsHighlightUtil {
|
||||
if (metaAnno == null) {
|
||||
String explanation = JavaErrorMessages.message("annotation.non.repeatable", annotationType.getQualifiedName());
|
||||
String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation);
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
|
||||
HighlightInfo info =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
|
||||
QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createCollapseAnnotationsFix(annotationToCheck));
|
||||
return info;
|
||||
}
|
||||
|
||||
String explanation = doCheckRepeatableAnnotation(metaAnno);
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
// 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.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressWarnings("foo")
|
||||
public class CollapseAnnotationsFix extends LocalQuickFixAndIntentionActionOnPsiElement {
|
||||
private CollapseAnnotationsFix(PsiAnnotation annotation) {
|
||||
super(annotation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Collapse repeating annotations";
|
||||
}
|
||||
|
||||
int[] x;
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable Editor editor,
|
||||
@NotNull PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
if (!(startElement instanceof PsiAnnotation)) return;
|
||||
PsiAnnotation annotation = (PsiAnnotation)startElement;
|
||||
PsiNameValuePair attribute = ArrayUtil.getFirstElement(annotation.getParameterList().getAttributes());
|
||||
if (attribute == null) return;
|
||||
PsiAnnotationMemberValue origValue = attribute.getValue();
|
||||
if (origValue == null) return;
|
||||
List<PsiAnnotation> annotations = findCollapsibleAnnotations(annotation, attribute);
|
||||
List<PsiAnnotationMemberValue> values = new ArrayList<>();
|
||||
CommentTracker ct = new CommentTracker();
|
||||
for (PsiAnnotation anno : annotations) {
|
||||
PsiAnnotationMemberValue value = anno.getParameterList().getAttributes()[0].getValue();
|
||||
if (value instanceof PsiArrayInitializerMemberValue) {
|
||||
PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers();
|
||||
for (PsiAnnotationMemberValue initializer : initializers) {
|
||||
values.add(ct.markUnchanged(initializer));
|
||||
}
|
||||
}
|
||||
else if (value != null) {
|
||||
values.add(ct.markUnchanged(value));
|
||||
}
|
||||
if (anno != annotation) {
|
||||
ct.delete(anno);
|
||||
}
|
||||
}
|
||||
String newValue = StreamEx.of(values).map(PsiElement::getText).joining(", ", "{", "}");
|
||||
PsiAnnotation dummy = JavaPsiFacade.getElementFactory(project).createAnnotationFromText("@x(" + newValue + ")", origValue);
|
||||
ct.replaceAndRestoreComments(origValue, Objects.requireNonNull(dummy.getParameterList().getAttributes()[0].getValue()));
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
private static List<PsiAnnotation> findCollapsibleAnnotations(PsiAnnotation annotation, PsiNameValuePair attribute) {
|
||||
PsiAnnotationOwner owner = annotation.getOwner();
|
||||
String name = annotation.getQualifiedName();
|
||||
if (owner == null || name == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PsiAnnotation> annotations = new ArrayList<>();
|
||||
for (PsiAnnotation other : owner.getAnnotations()) {
|
||||
if (name.equals(other.getQualifiedName())) {
|
||||
PsiNameValuePair[] otherAttributes = other.getParameterList().getAttributes();
|
||||
if (otherAttributes.length == 1) {
|
||||
PsiNameValuePair otherAttribute = otherAttributes[0];
|
||||
if (otherAttribute.getAttributeName().equals(attribute.getAttributeName())) {
|
||||
annotations.add(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CollapseAnnotationsFix from(PsiAnnotation annotation) {
|
||||
PsiAnnotationOwner owner = annotation.getOwner();
|
||||
String name = annotation.getQualifiedName();
|
||||
PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
|
||||
if (owner == null || name == null || attributes.length != 1) return null;
|
||||
PsiNameValuePair attribute = attributes[0];
|
||||
if (attribute.getValue() == null) return null;
|
||||
PsiMethod annoMethod = findAttributeMethod(attribute);
|
||||
if (annoMethod == null || !(annoMethod.getReturnType() instanceof PsiArrayType)) return null;
|
||||
List<PsiAnnotation> annotations = findCollapsibleAnnotations(annotation, attribute);
|
||||
if (annotations.size() < 2) return null;
|
||||
return new CollapseAnnotationsFix(annotation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod findAttributeMethod(PsiNameValuePair attribute) {
|
||||
PsiReference ref = attribute.getReference();
|
||||
if (ref == null) return null;
|
||||
PsiElement target = ref.resolve();
|
||||
if (PsiUtil.isAnnotationMethod(target)) {
|
||||
return (PsiAnnotationMethod)target;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -931,5 +931,10 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
@Override
|
||||
public IntentionAction createAddSwitchDefaultFix(@NotNull PsiSwitchBlock switchBlock, String message) {
|
||||
return new CreateDefaultBranchFix(switchBlock, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntentionAction createCollapseAnnotationsFix(PsiAnnotation annotation) {
|
||||
return CollapseAnnotationsFix.from(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@SuppressWarnings({"foo", "bar", "baz"})
|
||||
class X{}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@XYZ(data = {1, 2, 3, 4})
|
||||
@XYZ(5)
|
||||
class X{}
|
||||
@interface XYZ {
|
||||
int value() default 0;
|
||||
|
||||
int[] data();
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@SuppressWarnings({"foo", "bar", "baz"})
|
||||
class X{}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@SuppressWarnings({"foo", "bar"})
|
||||
class X{}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@SuppressWarnings({"foo", "bar"})
|
||||
@<caret>SuppressWarnings("baz")
|
||||
class X{}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@X<caret>YZ(data = 1)
|
||||
@XYZ(data = {2, 3})
|
||||
@XYZ(data = {4})
|
||||
@XYZ(5)
|
||||
class X{}
|
||||
@interface XYZ {
|
||||
int value() default 0;
|
||||
|
||||
int[] data();
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@<caret>SuppressWarnings("foo")
|
||||
@SuppressWarnings("bar")
|
||||
@SuppressWarnings("baz")
|
||||
class X{}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Collapse repeating annotations" "true"
|
||||
|
||||
@<caret>SuppressWarnings("foo")
|
||||
@SuppressWarnings("bar")
|
||||
class X{}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// 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.java.codeInsight.intention;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightIntentionActionTestCase;
|
||||
|
||||
public class CollapseAnnotationsFixTest extends LightIntentionActionTestCase {
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/collapseAnnotationsFix";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user