[java-inspections] ConvertRecordToClassFix: ModCommand; fix and test preview

GitOrigin-RevId: d6f5fb8b21e233edd636f5ee315e5e7b167f9b91
This commit is contained in:
Tagir Valeev
2023-06-16 09:48:04 +00:00
committed by intellij-monorepo-bot
parent c9c9d58c9f
commit f447c73105
29 changed files with 45 additions and 51 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2020 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.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature;
@@ -21,20 +21,18 @@ public class RecordCanBeClassInspection extends AbstractBaseJavaLocalInspectionT
if (InspectionProjectProfileManager.isInformationLevel(getShortName(), aClass)) {
PsiElement brace = aClass.getLBrace();
if (brace != null) {
holder.registerProblem(aClass, TextRange.create(0, brace.getStartOffsetInParent() + brace.getTextLength()),
JavaBundle.message("inspection.message.record.can.be.converted.to.class"),
new ConvertRecordToClassFix(aClass));
holder.problem(aClass, JavaBundle.message("inspection.message.record.can.be.converted.to.class"))
.range(TextRange.create(0, brace.getStartOffsetInParent() + brace.getTextLength()))
.fix(new ConvertRecordToClassFix(aClass)).register();
}
else {
holder.registerProblem(aClass, JavaBundle.message("inspection.message.record.can.be.converted.to.class"),
new ConvertRecordToClassFix(aClass));
holder.problem(aClass, JavaBundle.message("inspection.message.record.can.be.converted.to.class")).fix(new ConvertRecordToClassFix(aClass)).register();
}
}
else {
PsiIdentifier identifier = aClass.getNameIdentifier();
if (identifier != null) {
holder.registerProblem(identifier, JavaBundle.message("inspection.message.record.can.be.converted.to.class"),
new ConvertRecordToClassFix(aClass));
holder.problem(identifier, JavaBundle.message("inspection.message.record.can.be.converted.to.class")).fix(new ConvertRecordToClassFix(aClass)).register();
}
}
}
@@ -8,7 +8,6 @@ import com.intellij.codeInsight.daemon.impl.quickfix.InsertMissingTokenFix;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper;
import com.intellij.codeInspection.ConvertRecordToClassFix;
import com.intellij.core.JavaPsiBundle;
import com.intellij.psi.*;
@@ -45,8 +44,7 @@ public class JavaErrorQuickFixProvider implements ErrorQuickFixProvider {
case PsiKeyword.RECORD -> {
HighlightUtil.registerIncreaseLanguageLevelFixes(errorElement, HighlightingFeature.RECORDS, registrar);
if (ConvertRecordToClassFix.tryMakeRecord(errorElement) != null) {
IntentionAction action = PriorityIntentionActionWrapper.lowPriority(new ConvertRecordToClassFix(errorElement));
registrar.add(action);
registrar.add(new ConvertRecordToClassFix(errorElement).asIntention());
}
}
case PsiKeyword.SEALED -> HighlightUtil.registerIncreaseLanguageLevelFixes(errorElement, HighlightingFeature.SEALED_CLASSES, registrar);
@@ -1,18 +1,17 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection;
import com.intellij.codeInsight.AnnotationTargetUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.codeInsight.intention.PriorityAction;
import com.intellij.codeInsight.intention.impl.ConvertCompactConstructorToCanonicalAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.java.JavaBundle;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.java.parser.DeclarationParser;
import com.intellij.lang.java.parser.JavaParser;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
@@ -42,7 +41,7 @@ import java.util.Objects;
import static com.intellij.psi.CommonClassNames.SERIAL_VERSION_UID_FIELD_NAME;
public class ConvertRecordToClassFix extends LocalQuickFixAndIntentionActionOnPsiElement {
public class ConvertRecordToClassFix extends PsiUpdateModCommandAction<PsiElement> {
private final LanguageLevel myLanguageLevel;
public ConvertRecordToClassFix(@NotNull PsiElement candidate) {
@@ -51,13 +50,14 @@ public class ConvertRecordToClassFix extends LocalQuickFixAndIntentionActionOnPs
}
@Override
public @IntentionFamilyName @NotNull String getFamilyName() {
return JavaBundle.message("intention.family.name.convert.record.to.class");
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiElement element) {
return Presentation.of(getFamilyName())
.withPriority(PriorityAction.Priority.LOW);
}
@Override
public @IntentionName @NotNull String getText() {
return getFamilyName();
public @IntentionFamilyName @NotNull String getFamilyName() {
return JavaBundle.message("intention.family.name.convert.record.to.class");
}
@Nullable
@@ -75,11 +75,7 @@ public class ConvertRecordToClassFix extends LocalQuickFixAndIntentionActionOnPs
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
protected void invoke(@NotNull ActionContext context, @NotNull PsiElement startElement, @NotNull EditorUpdater updater) {
PsiClass recordClass;
if (startElement instanceof PsiErrorElement) {
recordClass = tryMakeRecord(startElement);
@@ -92,6 +88,8 @@ public class ConvertRecordToClassFix extends LocalQuickFixAndIntentionActionOnPs
JavaDummyElement dummyElement = new JavaDummyElement(
recordClassText, builder -> JavaParser.INSTANCE.getDeclarationParser().parse(builder, DeclarationParser.Context.CLASS),
LanguageLevel.JDK_16);
Project project = context.project();
PsiFile file = startElement.getContainingFile();
DummyHolder holder = DummyHolderFactory.createHolder(file.getManager(), dummyElement, recordClass);
PsiClass converted = (PsiClass)Objects.requireNonNull(SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()));
postProcessAnnotations(recordClass, converted);
@@ -294,7 +292,7 @@ public class ConvertRecordToClassFix extends LocalQuickFixAndIntentionActionOnPs
private void insertMethods(StringBuilder result, PsiClass psiClass, PsiRecordComponent @NotNull [] components) {
boolean hasEquals = false, hasHashCode = false, hasToString = false;
for (PsiMethod method : psiClass.getMethods()) {
if (!method.isPhysical() && JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null) {
if (method instanceof SyntheticElement && JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null) {
result.append(method.getText()).append("\n");
}
hasEquals |= MethodUtils.isEquals(method);
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
import java.lang.annotation.*;
import java.util.Objects;
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
import java.lang.annotation.*;
import java.util.Objects;
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class Range implements Cloneable {
private final int x;
private final int y;
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
package com.example;
interface Runnable {}
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class Range {
private final int x;
private final int y;
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class Range {
static final Range ZERO = new Range(0);
private final int x;
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class R<T> {
private final T t;
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class Rec {
private final int x;
private final int y;
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
class X {
private static final class R {
private R() {
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class R {
R() {
}
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
import java.util.Objects;
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE_USE})
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
<caret>record Range(int x, int y) implements Cloneable {
Range(int x, int y) {
if (x > y) {
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
package com.example;
interface Runnable {}
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
record <caret>Range(int x, int y) {
/**
* Checks invariant
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
record <caret>Range(int x, int y) {
static final Range ZERO = new Range(0);
@@ -1,2 +1,2 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final record <caret>R<T>(T t) {}
@@ -1,2 +1,2 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
record <caret>Rec(int x, int y
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
class X {
private record <caret>R() {}
}
@@ -1,2 +1,2 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
record R() {<caret>}
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
/**
* Cool record.
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
final class Point {
private final double x;
private final double y;
@@ -1,6 +1,6 @@
import java.util.Objects;
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
public final class Point {
private final int x;
private final int y;
@@ -1,4 +1,4 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
record Point(double x, double y) {
void foo() {}
}<caret>
@@ -1,2 +1,2 @@
// "Convert record to class" "true"
// "Convert record to class" "true-preview"
public record Point(int x, int y) {}<caret>