[java-intentions] More ModCommands (IDEA-322693)

GitOrigin-RevId: ac544ca3f30695ccf6f8c389444d6ab6bb182ade
This commit is contained in:
Tagir Valeev
2023-06-30 15:40:36 +02:00
committed by intellij-monorepo-bot
parent 555d12b0d2
commit 5ad96f7b38
15 changed files with 229 additions and 418 deletions

View File

@@ -119,7 +119,7 @@ final class ModuleHighlightUtil {
.descriptionAndTooltip(message);
rootModuleInfos.stream().map(f -> PsiManager.getInstance(project).findFile(f)).filter(f -> f != file).findFirst().ifPresent(
duplicate -> {
IntentionAction action = new GoToSymbolFix(duplicate, JavaErrorBundle
var action = new GoToSymbolFix(duplicate, JavaErrorBundle
.message("module.open.duplicate.text"));
info.registerFix(action, null, null, null, null);
}

View File

@@ -5,7 +5,6 @@ import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
@@ -97,7 +96,6 @@ public class ExtendsListFix extends LocalQuickFixAndIntentionActionOnPsiElement
@NotNull PsiElement endElement) {
final PsiClass myClass = (PsiClass)startElement;
invokeImpl(myClass);
UndoUtil.markPsiFileForUndo(file);
}
protected void invokeImpl(PsiClass myClass) {

View File

@@ -1,62 +1,36 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.modcommand.ModCommand;
import com.intellij.modcommand.ModNavigate;
import com.intellij.modcommand.PsiBasedModCommandAction;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class GoToSymbolFix implements IntentionAction {
private final SmartPsiElementPointer<NavigatablePsiElement> myPointer;
public class GoToSymbolFix extends PsiBasedModCommandAction<NavigatablePsiElement> {
private final @IntentionName String myMessage;
public GoToSymbolFix(@NotNull NavigatablePsiElement symbol, @NotNull @Nls String message) {
myPointer = SmartPointerManager.getInstance(symbol.getProject()).createSmartPsiElementPointer(symbol);
super(symbol);
myMessage = message;
}
@NotNull
@Override
public String getText() {
public String getFamilyName() {
return myMessage;
}
@NotNull
@Override
public String getFamilyName() {
return getText();
protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull NavigatablePsiElement element) {
return new ModNavigate(element.getContainingFile().getVirtualFile(), 0, 0, 0);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return myPointer.getElement() != null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
NavigatablePsiElement e = myPointer.getElement();
if (e != null && e.isValid()) {
e.navigate(true);
}
}
@Override
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
NavigatablePsiElement element = myPointer.getElement();
if (element == null) return IntentionPreviewInfo.EMPTY;
protected @NotNull IntentionPreviewInfo generatePreview(ActionContext context, NavigatablePsiElement element) {
return IntentionPreviewInfo.navigate(element);
}
@Override
public boolean startInWriteAction() {
return false;
}
}

View File

@@ -1,74 +1,51 @@
// 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.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.intention.FileModifier;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.codeInsight.intention.PriorityAction;
import com.intellij.codeInspection.PsiUpdateModCommandAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.CommentTracker;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
public final class MoveParenthesisFix implements IntentionAction, HighPriorityAction {
private final PsiCallExpression myCall;
public final class MoveParenthesisFix extends PsiUpdateModCommandAction<PsiCallExpression> {
private final int myPos;
private final int myShiftSize;
public MoveParenthesisFix(PsiCallExpression call, int pos, int shiftSize) {
myCall = call;
super(call);
myPos = pos;
myShiftSize = shiftSize;
}
@Override
public @IntentionName @NotNull String getText() {
public @NotNull @IntentionFamilyName String getFamilyName() {
return QuickFixBundle.message("intention.move.parenthesis.name");
}
@Override
public @NotNull @IntentionFamilyName String getFamilyName() {
return getText();
protected @NotNull Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiCallExpression element) {
return Presentation.of(getFamilyName()).withPriority(PriorityAction.Priority.HIGH);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return !project.isDisposed() && myCall.isValid() && BaseIntentionAction.canModify(myCall);
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PsiCallExpression copy = copyWithShift(myCall, myPos, myShiftSize);
protected void invoke(@NotNull ActionContext context, @NotNull PsiCallExpression call, @NotNull ModPsiUpdater updater) {
PsiCallExpression copy = copyWithShift(call, myPos, myShiftSize);
if (copy != null) {
new CommentTracker().replaceAndRestoreComments(myCall, copy);
new CommentTracker().replaceAndRestoreComments(call, copy);
}
}
@Override
public boolean startInWriteAction() {
return true;
}
@Override
public @NotNull FileModifier getFileModifierForPreview(@NotNull PsiFile target) {
return new MoveParenthesisFix(PsiTreeUtil.findSameElementInCopy(myCall, target), myPos, myShiftSize);
}
private static PsiCallExpression copyWithShift(PsiCallExpression parentCall, int pos, int shift) {
PsiCallExpression parentCopy = (PsiCallExpression)parentCall.copy();

View File

@@ -100,7 +100,7 @@ public abstract class DeprecationInspectionBase extends LocalInspectionTool {
if (deprecatedElement instanceof PsiMethod method && methodCall != null) {
PsiMethod replacement = findReplacementInJavaDoc(method, methodCall);
if (replacement != null) {
return new ReplaceMethodCallFix((PsiMethodCallExpression)elementToHighlight.getParent().getParent(), replacement);
return new ReplaceMethodCallFix((PsiMethodCallExpression)elementToHighlight.getParent().getParent(), replacement).asQuickFix();
}
}
if (deprecatedElement instanceof PsiField field) {
@@ -108,7 +108,7 @@ public abstract class DeprecationInspectionBase extends LocalInspectionTool {
if (referenceExpression != null) {
PsiMember replacement = findReplacementInJavaDoc(field, referenceExpression);
if (replacement != null) {
return new ReplaceFieldReferenceFix(referenceExpression, replacement);
return new ReplaceFieldReferenceFix(referenceExpression, replacement).asQuickFix();
}
}
}

View File

@@ -1,23 +1,10 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 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.deprecation
import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview
import com.intellij.codeInspection.LocalQuickFixOnPsiElement
import com.intellij.openapi.project.Project
import com.intellij.codeInspection.PsiUpdateModCommandAction
import com.intellij.modcommand.ModCommandAction
import com.intellij.modcommand.ModCommandAction.Presentation
import com.intellij.modcommand.ModPsiUpdater
import com.intellij.psi.*
import com.intellij.psi.codeStyle.JavaCodeStyleManager
import com.intellij.psi.util.PsiFormatUtil
@@ -40,15 +27,15 @@ private fun generateQualifierText(expr: PsiReferenceExpression,
}
}
internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMethod: PsiMethod) : LocalQuickFixOnPsiElement(expr) {
@SafeFieldForPreview
internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMethod: PsiMethod) :
PsiUpdateModCommandAction<PsiMethodCallExpression>(expr) {
private val myReplacementMethodPointer =
SmartPointerManager.getInstance(replacementMethod.project).createSmartPsiElementPointer(replacementMethod)
private val myReplacementText =
PsiFormatUtil.formatMethod(replacementMethod, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_CONTAINING_CLASS or PsiFormatUtilBase.SHOW_NAME, 0)
override fun getText(): String {
return InspectionGadgetsBundle.message("replace.method.call.fix.text", myReplacementText)
override fun getPresentation(context: ModCommandAction.ActionContext, element: PsiMethodCallExpression): Presentation {
return Presentation.of(InspectionGadgetsBundle.message("replace.method.call.fix.text", myReplacementText))
}
@Nls
@@ -56,12 +43,12 @@ internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMe
return InspectionGadgetsBundle.message("replace.method.call.fix.family.name")
}
override fun invoke(project: Project, file: PsiFile, startElement: PsiElement, endElement: PsiElement) {
val expr = (startElement as? PsiMethodCallExpression) ?: return
override fun invoke(context: ModCommandAction.ActionContext, expr: PsiMethodCallExpression, updater: ModPsiUpdater) {
val replacementMethod = myReplacementMethodPointer.element ?: return
val qualifierText = generateQualifierText(expr.methodExpression, replacementMethod)
val project = context.project
val elementFactory = JavaPsiFacade.getElementFactory(project)
val newMethodCall = elementFactory.createExpressionFromText(qualifierText + replacementMethod.name + expr.argumentList.text, expr)
val replaced = expr.replace(newMethodCall) as PsiMethodCallExpression
@@ -69,8 +56,8 @@ internal class ReplaceMethodCallFix(expr: PsiMethodCallExpression, replacementMe
}
}
internal class ReplaceFieldReferenceFix(expr: PsiReferenceExpression, replacementMember: PsiMember) : LocalQuickFixOnPsiElement(expr) {
@SafeFieldForPreview
internal class ReplaceFieldReferenceFix(expr: PsiReferenceExpression, replacementMember: PsiMember) :
PsiUpdateModCommandAction<PsiReferenceExpression>(expr) {
private val myReplacementMemberPointer =
SmartPointerManager.getInstance(replacementMember.project).createSmartPsiElementPointer(replacementMember)
private val myReplacementText =
@@ -87,16 +74,16 @@ internal class ReplaceFieldReferenceFix(expr: PsiReferenceExpression, replacemen
return InspectionGadgetsBundle.message("replace.field.reference.fix.family.name")
}
override fun getText(): String {
return InspectionGadgetsBundle.message("replace.field.reference.fix.text", myReplacementText)
override fun getPresentation(context: ModCommandAction.ActionContext, element: PsiReferenceExpression): Presentation {
return Presentation.of(InspectionGadgetsBundle.message("replace.field.reference.fix.text", myReplacementText))
}
override fun invoke(project: Project, file: PsiFile, startElement: PsiElement, endElement: PsiElement) {
val expr = (startElement as? PsiReferenceExpression) ?: return
override fun invoke(context: ModCommandAction.ActionContext, expr: PsiReferenceExpression, updater: ModPsiUpdater) {
val replacementMember = myReplacementMemberPointer.element ?: return
val qualifierText = generateQualifierText(expr, replacementMember)
val project = context.project
val replaced = expr.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(
qualifierText + replacementMember.name + (if (replacementMember is PsiMethod) "()" else ""), expr))
JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced)

View File

@@ -187,7 +187,7 @@ move.class.to.package.family=Move Class to Package
move.class.to.package.text=Move to package ''{0}''
# change if (!a == b) ... => if (!(a == b)) ...
negation.broader.scope.family=Negation Broader Scope
negation.broader.scope.family=Negation broader scope
negation.broader.scope.text=Change to ''!({0})''
optimize.imports.fix=Optimize imports

View File

@@ -2,56 +2,51 @@
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.FileModifier;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.codeInspection.PsiUpdateModCommandAction;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* if (!a == b) ... => if (!(a == b)) ...
*/
public class NegationBroadScopeFix implements IntentionAction {
private final PsiPrefixExpression myPrefixExpression;
public class NegationBroadScopeFix extends PsiUpdateModCommandAction<PsiPrefixExpression> {
public NegationBroadScopeFix(@NotNull PsiPrefixExpression prefixExpression) {
myPrefixExpression = prefixExpression;
super(prefixExpression);
}
@Override
public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) {
return new NegationBroadScopeFix(PsiTreeUtil.findSameElementInCopy(myPrefixExpression, target));
}
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiPrefixExpression expression) {
PsiExpression operand = expression.getOperand();
if (operand == null) return null;
@Override
@NotNull
public String getText() {
PsiExpression operand = myPrefixExpression.getOperand();
String text = operand == null ? "" : operand.getText() + " ";
PsiElement parent = myPrefixExpression.getParent();
PsiElement parent = expression.getParent();
String text = operand.getText() + " ";
String rop;
if (parent instanceof PsiInstanceOfExpression) {
if (parent instanceof PsiInstanceOfExpression instanceOf) {
if (instanceOf.getOperand() != expression) return null;
text += PsiKeyword.INSTANCEOF + " ";
final PsiTypeElement typeElement = ((PsiInstanceOfExpression)parent).getCheckType();
final PsiTypeElement typeElement = instanceOf.getCheckType();
rop = typeElement == null ? "" : typeElement.getText();
}
else if (parent instanceof PsiBinaryExpression) {
text += ((PsiBinaryExpression)parent).getOperationSign().getText() + " ";
final PsiExpression rOperand = ((PsiBinaryExpression)parent).getROperand();
else if (parent instanceof PsiBinaryExpression binaryExpression) {
if (binaryExpression.getLOperand() != expression) return null;
if (!TypeConversionUtil.isBooleanType(binaryExpression.getType())) return null;
text += binaryExpression.getOperationSign().getText() + " ";
final PsiExpression rOperand = binaryExpression.getROperand();
rop = rOperand == null ? "" : rOperand.getText();
}
else {
rop = "<expr>";
return null;
}
text += rop;
return QuickFixBundle.message("negation.broader.scope.text", text);
return Presentation.of(QuickFixBundle.message("negation.broader.scope.text", text));
}
@Override
@@ -61,40 +56,15 @@ public class NegationBroadScopeFix implements IntentionAction {
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!myPrefixExpression.isValid() || myPrefixExpression.getOperand() == null) return false;
PsiElement parent = myPrefixExpression.getParent();
if (parent instanceof PsiInstanceOfExpression && ((PsiInstanceOfExpression)parent).getOperand() == myPrefixExpression) {
return true;
}
return parent instanceof PsiBinaryExpression binaryExpression &&
binaryExpression.getLOperand() == myPrefixExpression &&
TypeConversionUtil.isBooleanType(binaryExpression.getType());
}
@NotNull
@Override
public PsiElement getElementToMakeWritable(@NotNull PsiFile file) {
return myPrefixExpression.getContainingFile();
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!isAvailable(project, editor, file)) return;
PsiExpression operand = myPrefixExpression.getOperand();
protected void invoke(@NotNull ActionContext context, @NotNull PsiPrefixExpression myPrefixExpression, @NotNull ModPsiUpdater updater) {
PsiExpression operand = Objects.requireNonNull(myPrefixExpression.getOperand());
PsiElement unnegated = myPrefixExpression.replace(operand);
PsiElement parent = unnegated.getParent();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(file.getProject());
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project());
PsiPrefixExpression negated = (PsiPrefixExpression)factory.createExpressionFromText("!(xxx)", parent);
PsiParenthesizedExpression parentheses = (PsiParenthesizedExpression)negated.getOperand();
parentheses.getExpression().replace(parent.copy());
PsiParenthesizedExpression parentheses = (PsiParenthesizedExpression)Objects.requireNonNull(negated.getOperand());
Objects.requireNonNull(parentheses.getExpression()).replace(parent.copy());
parent.replace(negated);
}
@Override
public boolean startInWriteAction() {
return true;
}
}

View File

@@ -1,19 +1,17 @@
// 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.codeInsight.intention.impl;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils;
import com.intellij.codeInspection.PsiUpdateModCommandAction;
import com.intellij.java.JavaBundle;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.DummyHolder;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.util.LambdaRefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
@@ -25,7 +23,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Set;
public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
public class InlineStreamMapAction extends PsiUpdateModCommandAction<PsiIdentifier> {
private static final Logger LOG = Logger.getInstance(InlineStreamMapAction.class.getName());
public static final class Holder {
private static final Set<String> MAP_METHODS =
@@ -35,21 +33,23 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
.of("flatMap", "flatMapToInt", "flatMapToLong", "flatMapToDouble", "forEach", "forEachOrdered", "anyMatch", "noneMatch", "allMatch")
.append(MAP_METHODS).toSet();
}
public InlineStreamMapAction() {
super(PsiIdentifier.class);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull final PsiElement element) {
if (!(element instanceof PsiIdentifier)) return false;
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiIdentifier element) {
final PsiElement parent = element.getParent();
if (!(parent instanceof PsiReferenceExpression)) return false;
if (!(parent instanceof PsiReferenceExpression)) return null;
final PsiElement gParent = parent.getParent();
if (!(gParent instanceof PsiMethodCallExpression curCall)) return false;
if (!isMapCall(curCall)) return false;
if (!(gParent instanceof PsiMethodCallExpression curCall)) return null;
if (!isMapCall(curCall)) return null;
PsiMethodCallExpression nextCall = getNextExpressionToMerge(curCall);
if(nextCall == null) return false;
if(nextCall == null) return null;
String key = curCall.getArgumentList().isEmpty() || nextCall.getArgumentList().isEmpty() ?
"intention.inline.map.merge.text" : "intention.inline.map.inline.text";
setText(JavaBundle.message(key, element.getText(), nextCall.getMethodExpression().getReferenceName()));
return true;
return Presentation.of(JavaBundle.message(key, element.getText(), nextCall.getMethodExpression().getReferenceName()));
}
private static boolean isMapCall(@NotNull PsiMethodCallExpression methodCallExpression) {
@@ -165,7 +165,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
protected void invoke(@NotNull ActionContext context, @NotNull PsiIdentifier element, @NotNull ModPsiUpdater updater) {
PsiMethodCallExpression mapCall = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
if(mapCall == null) return;
@@ -190,7 +190,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
CommentTracker ct = new CommentTracker();
if (!lambda.isPhysical() && !IntentionPreviewUtils.isPreviewElement(lambda)) {
if (lambda.getContainingFile() instanceof DummyHolder) {
lambda = (PsiLambdaExpression)nextCall.getArgumentList().add(lambda);
}
PsiElement body = lambda.getBody();
@@ -201,7 +201,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
LOG.assertTrue(nextParameters.length == 1);
PsiParameter[] prevParameters = previousLambda.getParameterList().getParameters();
LOG.assertTrue(prevParameters.length == 1);
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project());
for(PsiReferenceExpression ref : VariableAccessUtils.getVariableReferences(nextParameters[0], body)) {
PsiExpression replacement = ct.markUnchanged(previousBody);
if (ref.getParent() instanceof PsiExpression &&
@@ -221,7 +221,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
} else {
ct.replaceAndRestoreComments(nextQualifier, prevQualifier);
}
CodeStyleManager.getInstance(project).reformat(lambda);
CodeStyleManager.getInstance(context.project()).reformat(lambda);
}
@Nullable

View File

@@ -295,7 +295,7 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
@NotNull
@Override
public IntentionAction createNegationBroadScopeFix(@NotNull PsiPrefixExpression expr) {
return new NegationBroadScopeFix(expr);
return new NegationBroadScopeFix(expr).asIntention();
}
@NotNull

View File

@@ -1,6 +1,6 @@
// "Change to '!(1 == 1)'" "true-preview"
public class Foo {
void task() {
if (<caret>!(1 == 1)) {}
if (!<caret>(1 == 1)) {}
}
}

View File

@@ -1,45 +1,31 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.inheritance;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
import com.intellij.codeInspection.ModCommands;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.modcommand.ModCommand;
import com.intellij.modcommand.ModCommandAction;
import com.intellij.modcommand.ModCommandQuickFix;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Query;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.ClassUtils;
import org.jetbrains.annotations.NotNull;
class StaticInheritanceFix extends InspectionGadgetsFix {
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
class StaticInheritanceFix extends ModCommandQuickFix {
private final boolean myReplaceInWholeProject;
StaticInheritanceFix(boolean replaceInWholeProject) {
@@ -61,17 +47,8 @@ class StaticInheritanceFix extends InspectionGadgetsFix {
}
@Override
public boolean startInWriteAction() {
return false;
}
@Override
public void doFix(final @NotNull Project project, @NotNull ProblemDescriptor descriptor) {
doFix(project, descriptor, false);
}
private void doFix(final Project project, ProblemDescriptor descriptor, boolean inPreview) {
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)descriptor.getPsiElement();
public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)descriptor.getStartElement();
final PsiClass iface = (PsiClass)referenceElement.resolve();
assert iface != null;
final PsiField[] allFields = iface.getAllFields();
@@ -80,83 +57,58 @@ class StaticInheritanceFix extends InspectionGadgetsFix {
assert implementingClass != null;
final PsiFile file = implementingClass.getContainingFile();
if (inPreview) {
processUsages(allFields, implementingClass, project, true, iface, file);
} else {
ProgressManager.getInstance().run(new Task.Modal(project,
JavaAnalysisBundle.message("static.inheritrance.fix.replace.progress", iface.getName()), false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
processUsages(allFields, implementingClass, project, false, iface, file);
}
});
}
return ModCommands.psiUpdate(ModCommandAction.ActionContext.from(descriptor), updater ->
processUsages(allFields, implementingClass, project, iface, file, updater));
}
private void processUsages(PsiField[] allFields,
PsiClass implementingClass,
Project project,
boolean inPreview,
PsiClass iface,
PsiFile file) {
private void processUsages(@NotNull PsiField @NotNull [] allFields,
PsiClass implementingClass,
Project project,
PsiClass iface,
PsiFile file,
@NotNull ModPsiUpdater updater) {
Map<PsiReferenceExpression, PsiClass> replacements = findReplacements(allFields, implementingClass, updater);
PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory().createType(iface);
IntentionAction fix = QuickFixFactory.getInstance().createExtendsListFix(updater.getWritable(implementingClass), classType, false);
fix.invoke(project, null, file);
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
replacements.forEach((referenceExpression, containingClass) -> {
final PsiReferenceExpression qualified = (PsiReferenceExpression)
elementFactory.createExpressionFromText("xxx." + referenceExpression.getText(), referenceExpression);
final PsiReferenceExpression newReference = (PsiReferenceExpression)referenceExpression.replace(qualified);
final PsiReferenceExpression qualifier = (PsiReferenceExpression)newReference.getQualifierExpression();
assert qualifier != null : DebugUtil.psiToString(newReference, true);
qualifier.bindToElement(containingClass);
});
}
@NotNull
private Map<PsiReferenceExpression, PsiClass> findReplacements(@NotNull PsiField @NotNull [] allFields,
@NotNull PsiClass implementingClass,
@NotNull ModPsiUpdater updater) {
Map<PsiReferenceExpression, PsiClass> replacements = new LinkedHashMap<>();
for (final PsiField field : allFields) {
SearchScope scope = ReadAction.compute(() -> implementingClass.getUseScope());
if (inPreview) {
scope = scope.intersectWith(new LocalSearchScope(file));
}
SearchScope scope = implementingClass.getUseScope();
final Query<PsiReference> search = ReferencesSearch.search(field, scope, false);
for (PsiReference reference : search) {
if (!(reference instanceof PsiReferenceExpression referenceExpression)) {
continue;
}
if (!myReplaceInWholeProject) {
boolean isInheritor =
ReadAction.compute(() -> {
boolean isInheritor1 = false;
PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class);
while (aClass != null) {
isInheritor1 = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true);
if (isInheritor1) break;
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
}
return isInheritor1;
});
boolean isInheritor = false;
PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class);
while (aClass != null) {
isInheritor = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true);
if (isInheritor) break;
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
}
if (!isInheritor) continue;
}
final Runnable runnable = () -> {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
final PsiReferenceExpression qualified = (PsiReferenceExpression)
elementFactory.createExpressionFromText("xxx." + referenceExpression.getText(), referenceExpression);
final PsiReferenceExpression newReference = (PsiReferenceExpression)referenceExpression.replace(qualified);
final PsiReferenceExpression qualifier = (PsiReferenceExpression)newReference.getQualifierExpression();
assert qualifier != null : DebugUtil.psiToString(newReference, true);
final PsiClass containingClass = field.getContainingClass();
qualifier.bindToElement(containingClass);
};
if (inPreview) {
runnable.run();
} else {
WriteCommandAction.runWriteCommandAction(project, null, null, runnable,
ReadAction.compute(() -> referenceExpression.getContainingFile()));
}
final PsiClass containingClass = Objects.requireNonNull(field.getContainingClass());
replacements.put(updater.getWritable(referenceExpression), containingClass);
}
}
final Runnable runnable = () -> {
PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory().createType(iface);
IntentionAction fix = QuickFixFactory.getInstance().createExtendsListFix(implementingClass, classType, false);
fix.invoke(project, null, file);
};
if (inPreview) {
runnable.run();
} else {
WriteCommandAction.runWriteCommandAction(project, null, null, runnable, file);
}
}
@Override
public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) {
doFix(project, previewDescriptor, true);
return IntentionPreviewInfo.DIFF;
return replacements;
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.siyeh.ig.inheritance;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiJavaCodeReferenceElement;
@@ -22,7 +23,6 @@ import com.intellij.psi.PsiReferenceList;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
@@ -38,8 +38,8 @@ public class StaticInheritanceInspection extends BaseInspection {
}
@Override
protected InspectionGadgetsFix @NotNull [] buildFixes(Object... infos) {
return new InspectionGadgetsFix[]{new StaticInheritanceFix(false), new StaticInheritanceFix(true)};
protected LocalQuickFix @NotNull [] buildFixes(Object... infos) {
return new LocalQuickFix[]{new StaticInheritanceFix(false), new StaticInheritanceFix(true)};
}

View File

@@ -1,19 +1,18 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ipp.datetime;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.codeInsight.intention.PriorityAction;
import com.intellij.codeInspection.ModCommands;
import com.intellij.modcommand.ModCommand;
import com.intellij.modcommand.PsiBasedModCommandAction;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.TypeUtils;
import com.siyeh.ipp.base.Intention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
@@ -25,7 +24,11 @@ import static com.siyeh.ig.callMatcher.CallMatcher.*;
/**
* @author Bas Leijdekkers
*/
public class ShowDateTimeExampleOutputIntention extends Intention implements HighPriorityAction {
public class ShowDateTimeExampleOutputIntention extends PsiBasedModCommandAction<PsiExpression> {
public ShowDateTimeExampleOutputIntention() {
super(PsiExpression.class);
}
private static final CallMatcher DATE_TIME_FORMATTER_METHODS = anyOf(
staticCall("java.time.format.DateTimeFormatter", "ofPattern"),
@@ -33,107 +36,87 @@ public class ShowDateTimeExampleOutputIntention extends Intention implements Hig
);
private static final CallMatcher SIMPLE_DATE_FORMAT_METHODS =
instanceCall("java.text.SimpleDateFormat", "applyPattern", "applyLocalizedPattern").parameterTypes(CommonClassNames.JAVA_LANG_STRING);
Boolean dateTimeFormatter = null;
@Override
public @NotNull String getFamilyName() {
return IntentionPowerPackBundle.message("show.example.date.time.output.intention.family.name");
}
enum Formatter {
NONE, DATE_TIME_FORMATTER, SIMPLE_DATE_FORMAT
}
private static @NotNull Formatter getFormatter(@NotNull PsiExpression expression) {
if (!(expression.getParent() instanceof PsiExpressionList parent)) return Formatter.NONE;
final PsiType type = expression.getType();
if (!TypeUtils.isJavaLangString(type)) return Formatter.NONE;
final PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiMethodCallExpression call) {
if (SIMPLE_DATE_FORMAT_METHODS.test(call)) {
return Formatter.SIMPLE_DATE_FORMAT;
}
if (DATE_TIME_FORMATTER_METHODS.test(call)) {
return Formatter.DATE_TIME_FORMATTER;
}
return Formatter.NONE;
}
if (grandParent instanceof PsiNewExpression newExpression) {
final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
if (classReference == null || !"SimpleDateFormat".equals(classReference.getReferenceName())) {
return Formatter.NONE;
}
final PsiElement target = classReference.resolve();
if (!(target instanceof PsiClass aClass)) {
return Formatter.NONE;
}
if (!InheritanceUtil.isInheritor(aClass, "java.text.SimpleDateFormat")) {
return Formatter.NONE;
}
return Formatter.SIMPLE_DATE_FORMAT;
}
return Formatter.NONE;
}
@Override
public @NotNull String getText() {
return getFamilyName();
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiExpression expression) {
while (expression.getParent() instanceof PsiExpression parent) {
expression = parent;
}
Formatter formatter = getFormatter(expression);
if (formatter == Formatter.NONE) return null;
final Object value = ExpressionUtils.computeConstantExpression(expression);
return value instanceof String ? Presentation.of(getFamilyName()).withPriority(PriorityAction.Priority.HIGH) : null;
}
@Override
public boolean startInWriteAction() {
return false;
}
@Override
protected @NotNull PsiElementPredicate getElementPredicate() {
return new PsiElementPredicate() {
@Override
public boolean satisfiedBy(PsiElement element) {
if (!(element instanceof PsiExpression expression)) {
return false;
protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull PsiExpression expression) {
while (expression.getParent() instanceof PsiExpression parent) {
expression = parent;
}
Formatter formatter = getFormatter(expression);
final Object value = ExpressionUtils.computeConstantExpression(expression);
if (!(value instanceof String)) return ModCommands.nop();
return switch (formatter) {
case NONE -> ModCommands.nop();
case DATE_TIME_FORMATTER -> {
try {
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern((String)value);
//noinspection HardCodedStringLiteral
yield ModCommands.info(LocalDateTime.now().format(fmt));
}
final PsiType type = expression.getType();
if (!TypeUtils.isJavaLangString(type)) {
return false;
catch (IllegalArgumentException e) {
yield ModCommands.error(IntentionPowerPackBundle.message("invalid.pattern.hint.text"));
}
PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression).getParent();
if (parent == null) return false;
final PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiMethodCallExpression) {
if (SIMPLE_DATE_FORMAT_METHODS.test((PsiMethodCallExpression)grandParent)) {
dateTimeFormatter = false;
}
else if (DATE_TIME_FORMATTER_METHODS.test((PsiMethodCallExpression)grandParent)) {
dateTimeFormatter = true;
}
else {
return false;
}
}
case SIMPLE_DATE_FORMAT -> {
try {
final SimpleDateFormat format = new SimpleDateFormat((String)value);
yield ModCommands.info(format.format(new Date()));
}
else if (grandParent instanceof PsiNewExpression newExpression) {
final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
if (classReference == null || !"SimpleDateFormat".equals(classReference.getReferenceName())) {
return false;
}
final PsiElement target = classReference.resolve();
if (!(target instanceof PsiClass aClass)) {
return false;
}
if (!InheritanceUtil.isInheritor(aClass, "java.text.SimpleDateFormat")) {
return false;
}
dateTimeFormatter = false;
return true;
catch (IllegalArgumentException e) {
yield ModCommands.error(IntentionPowerPackBundle.message("invalid.pattern.hint.text"));
}
else {
return false;
}
final Object value = ExpressionUtils.computeConstantExpression(expression);
return value instanceof String;
}
};
}
@Override
protected void processIntention(Editor editor, @NotNull PsiElement element) {
if (!(element instanceof PsiExpression expression) || dateTimeFormatter == null) {
return;
}
final Object value = ExpressionUtils.computeConstantExpression(expression);
if (!(value instanceof String)) {
return;
}
String example;
if (dateTimeFormatter) {
try {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern((String)value);
//noinspection HardCodedStringLiteral
example = LocalDateTime.now().format(formatter);
}
catch (IllegalArgumentException e) {
example = IntentionPowerPackBundle.message("invalid.pattern.hint.text");
}
}
else {
try {
final SimpleDateFormat format = new SimpleDateFormat((String)value);
example = format.format(new Date());
}
catch (IllegalArgumentException e) {
example = IntentionPowerPackBundle.message("invalid.pattern.hint.text");
}
}
HintManager.getInstance().showInformationHint(editor, example);
}
@Override
protected void processIntention(@NotNull PsiElement element) {
assert false;
}
}

View File

@@ -1,20 +1,18 @@
// Copyright 2000-2021 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.uiDesigner.binding;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.daemon.impl.quickfix.DeleteElementFix;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.ui.UIBundle;
import com.intellij.uiDesigner.UIDesignerBundle;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
public class FormClassAnnotator implements Annotator {
@@ -30,7 +28,7 @@ public class FormClassAnnotator implements Annotator {
}
else if (psiElement instanceof PsiClass aClass) {
final List<PsiFile> formsBoundToClass = FormClassIndex.findFormsBoundToClass(aClass.getProject(), aClass);
if (formsBoundToClass.size() > 0) {
if (!formsBoundToClass.isEmpty()) {
holder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(aClass.getNameIdentifier()).gutterIconRenderer(new BoundIconRenderer(aClass)).create();
}
}
@@ -54,37 +52,9 @@ public class FormClassAnnotator implements Annotator {
if (field.hasInitializer()) {
final String message = UIDesignerBundle.message("field.is.overwritten.by.generated.code", field.getName());
holder.newAnnotation(HighlightSeverity.WARNING, message).range(field.getInitializer())
.withFix(new IntentionAction() {
@Override
@NotNull
public String getText() {
return message;
}
@Override
@NotNull
public String getFamilyName() {
return UIBundle.message("remove.field.initializer.quick.fix");
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return field.getInitializer() != null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
final PsiExpression initializer = field.getInitializer();
LOG.assertTrue(initializer != null);
initializer.delete();
}
@Override
public boolean startInWriteAction() {
return true;
}
}).create();
PsiExpression initializer = Objects.requireNonNull(field.getInitializer());
holder.newAnnotation(HighlightSeverity.WARNING, message).range(initializer)
.withFix(new DeleteElementFix(initializer, UIBundle.message("remove.field.initializer.quick.fix"))).create();
}
}
}