Skip to content

Commit

Permalink
Merge branch 'InsertAnnotationMissingQuickFix-issue#577' of https://g…
Browse files Browse the repository at this point in the history
…ithub.com/anusreelakshmi934/liberty-tools-intellij into InsertAnnotationMissingQuickFix-issue#577
  • Loading branch information
anusreelakshmi934 committed Jan 24, 2024
2 parents 3c9e3cc + b4ecb6c commit c9527bb
Show file tree
Hide file tree
Showing 9 changed files with 522 additions and 165 deletions.
Original file line number Diff line number Diff line change
@@ -1,82 +1,148 @@
/*******************************************************************************
* Copyright (c) 2021, 2023 IBM Corporation and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
* Copyright (c) 2021, 2023 IBM Corporation and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.beanvalidation;

import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.JDTUtils;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.Messages;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.ModifyModifiersProposal;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.RemoveAnnotationsProposal;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.IJavaCodeActionParticipant;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.JavaCodeActionContext;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.JavaCodeActionResolveContext;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.lsp4mp.commons.CodeActionResolveData;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Quickfix for fixing {@link BeanValidationConstants#DIAGNOSTIC_CODE_STATIC} error by either action
* 1. Removing constraint annotation on static field or method
* 2. Removing static modifier from field or method
*
* @author Leslie Dawson (lamminade)
*
* @author Leslie Dawson (lamminade)
*/
public class BeanValidationQuickFix {
public class BeanValidationQuickFix implements IJavaCodeActionParticipant {

private static final Logger LOGGER = Logger.getLogger(BeanValidationQuickFix.class.getName());

private static final String ANNOTATION_NAME = "annotationName";

@Override
public String getParticipantId() {
return BeanValidationQuickFix.class.getName();
}

public List<? extends CodeAction> getCodeActions(JavaCodeActionContext context, Diagnostic diagnostic) {
List<CodeAction> codeActions = new ArrayList<>();
removeConstraintAnnotations(diagnostic, context.copy(), codeActions);
removeConstraintAnnotationsCodeActions(diagnostic, context, codeActions);

if (diagnostic.getCode().getLeft().equals(BeanValidationConstants.DIAGNOSTIC_CODE_STATIC)) {
removeStaticModifier(diagnostic, context.copy(), codeActions);
removeStaticModifierCodeActions(diagnostic, context, codeActions);
}
return codeActions;
}

private void removeConstraintAnnotations(Diagnostic diagnostic, JavaCodeActionContext context, List<CodeAction> codeActions) {
@Override
public CodeAction resolveCodeAction(JavaCodeActionResolveContext context) {

final CodeAction toResolve = context.getUnresolved();

String message = toResolve.getTitle();

if (message.equals(Messages.getMessage("RemoveStaticModifier"))) {
resolveStaticModifierCodeAction(context);
return toResolve;
}

resolveRemoveConstraintAnnotationsCodeAction(context);

return toResolve;
}

private void removeConstraintAnnotationsCodeActions(Diagnostic diagnostic, JavaCodeActionContext context, List<CodeAction> codeActions) {

final String annotationName = diagnostic.getData().toString().replace("\"", "");
final String name = Messages.getMessage("RemoveConstraintAnnotation", annotationName);
Map<String, Object> extendedData = new HashMap<>();
extendedData.put(ANNOTATION_NAME, annotationName);
codeActions.add(JDTUtils.createCodeAction(context, diagnostic, name, getParticipantId(), extendedData));
}

private void resolveRemoveConstraintAnnotationsCodeAction(JavaCodeActionResolveContext context) {

final CodeAction toResolve = context.getUnresolved();
final PsiElement node = context.getCoveredNode();
final PsiClass parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);
CodeActionResolveData data = (CodeActionResolveData) toResolve.getData();
String annotationName;
if (data.getExtendedDataEntry(ANNOTATION_NAME) instanceof String) {
annotationName = (String) data.getExtendedDataEntry(ANNOTATION_NAME);
} else {
annotationName = "";
}
final String name = toResolve.getTitle();
final PsiModifierListOwner modifierListOwner = PsiTreeUtil.getParentOfType(node, PsiModifierListOwner.class);

final String annotationName = diagnostic.getData().toString().replace("\"", "");
final PsiAnnotation[] annotations = modifierListOwner.getAnnotations();

if (annotations != null && annotations.length > 0) {
final Optional<PsiAnnotation> annotationToRemove =
Arrays.stream(annotations).filter(a -> annotationName.equals(a.getQualifiedName())).findFirst();
if (annotationToRemove.isPresent()) {
final String name = Messages.getMessage("RemoveConstraintAnnotation", annotationName);
boolean isFormatRequired = false;
final RemoveAnnotationsProposal proposal = new RemoveAnnotationsProposal(name, context.getSource().getCompilationUnit(),
context.getASTRoot(), parentType, 0, Collections.singletonList(annotationToRemove.get()));
final CodeAction codeAction = context.convertToCodeAction(proposal, diagnostic);
if (codeAction != null) {
codeActions.add(codeAction);
context.getASTRoot(), parentType, 0, Collections.singletonList(annotationToRemove.get()), isFormatRequired);

try {
WorkspaceEdit we = context.convertToWorkspaceEdit(proposal);
toResolve.setEdit(we);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Unable to create workspace edit for code action to remove constraint annotation", e);
}
}
}
}

private void removeStaticModifier(Diagnostic diagnostic, JavaCodeActionContext context, List<CodeAction> codeActions) {
private void resolveStaticModifierCodeAction(JavaCodeActionResolveContext context) {
final CodeAction toResolve = context.getUnresolved();
final PsiElement node = context.getCoveredNode();
final PsiClass parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);
final PsiModifierListOwner modifierListOwner = PsiTreeUtil.getParentOfType(node, PsiModifierListOwner.class);

final String name = Messages.getMessage("RemoveStaticModifier");
final ModifyModifiersProposal proposal = new ModifyModifiersProposal(name, context.getSource().getCompilationUnit(),
final ModifyModifiersProposal proposal = new ModifyModifiersProposal(toResolve.getTitle()
, context.getSource().getCompilationUnit(),
context.getASTRoot(), parentType, 0, modifierListOwner.getModifierList(), Collections.emptyList(),
Collections.singletonList("static"));
final CodeAction codeAction = context.convertToCodeAction(proposal, diagnostic);
if (codeAction != null) {
codeActions.add(codeAction);

try {
WorkspaceEdit we = context.convertToWorkspaceEdit(proposal);
toResolve.setEdit(we);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Unable to create workspace edit for code action to remove static modifier", e);
}
}
}

private void removeStaticModifierCodeActions(Diagnostic diagnostic, JavaCodeActionContext context,
List<CodeAction> codeActions) {

final String name = Messages.getMessage("RemoveStaticModifier");
codeActions.add(JDTUtils.createCodeAction(context, diagnostic, name, getParticipantId()));
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ public RemoveAnnotationsProposal(String label, PsiFile sourceCU, PsiFile invocat
List<PsiAnnotation> annotationsToRemove) {
super(label, sourceCU, invocationNode, binding, relevance, annotationsToRemove);
}

public RemoveAnnotationsProposal(String label, PsiFile sourceCU, PsiFile invocationNode,
PsiModifierListOwner binding, int relevance,
List<PsiAnnotation> annotationsToRemove, boolean isFormatRequired) {
super(label, sourceCU, invocationNode, binding, relevance, annotationsToRemove, isFormatRequired);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public abstract class RemoveElementsProposal extends ChangeCorrectionProposal {
private final PsiFile invocationNode;
private final PsiModifierListOwner binding;
private final List<? extends PsiElement> elementsToRemove;
private boolean isFormatRequired = true;

protected RemoveElementsProposal(String label, PsiFile sourceCU, PsiFile invocationNode,
PsiModifierListOwner binding, int relevance,
Expand All @@ -41,10 +42,23 @@ protected RemoveElementsProposal(String label, PsiFile sourceCU, PsiFile invocat
this.elementsToRemove = elementsToRemove;
}

protected RemoveElementsProposal(String label, PsiFile sourceCU, PsiFile invocationNode,
PsiModifierListOwner binding, int relevance,
List<? extends PsiElement> elementsToRemove, boolean isFormatRequired) {
super(label, CodeActionKind.QuickFix, relevance);
this.sourceCU = sourceCU;
this.invocationNode = invocationNode;
this.binding = binding;
this.elementsToRemove = elementsToRemove;
this.isFormatRequired = isFormatRequired;
}

@Override
public final Change getChange() {
elementsToRemove.forEach(PsiElement::delete);
PositionUtils.formatDocument(binding); // fix up whitespace
if(isFormatRequired) {
PositionUtils.formatDocument(binding); // fix up whitespace
}
final Document document = invocationNode.getViewProvider().getDocument();
return new Change(sourceCU.getViewProvider().getDocument(), document);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,66 +16,95 @@
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameterList;
import com.intellij.psi.util.PsiTreeUtil;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.JDTUtils;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.Messages;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.AddConstructorProposal;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.ModifyModifiersProposal;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.IJavaCodeActionParticipant;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.JavaCodeActionContext;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.JavaCodeActionResolveContext;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.corrections.proposal.ChangeCorrectionProposal;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.WorkspaceEdit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Quick fix for NoResourcePublicConstructorQuickFix that uses
* ModifyModifiersProposal.
*
* @author Shaunak Tulshibagwale
*
* @author Shaunak Tulshibagwale
*/
public class NoResourcePublicConstructorQuickFix {
public class NoResourcePublicConstructorQuickFix implements IJavaCodeActionParticipant {

private final static String TITLE_MESSAGE = Messages.getMessage("MakeConstructorPublic");
private static final Logger LOGGER = Logger.getLogger(NoResourcePublicConstructorQuickFix.class.getName());

@Override
public String getParticipantId() {
return NoResourcePublicConstructorQuickFix.class.getName();
}

public List<? extends CodeAction> getCodeActions(JavaCodeActionContext context, Diagnostic diagnostic) {

PsiElement node = context.getCoveredNode();
PsiMethod parentMethod = PsiTreeUtil.getParentOfType(node, PsiMethod.class);

if (parentMethod != null) {
List<CodeAction> codeActions = new ArrayList<>();

JavaCodeActionContext targetContext = context.copy();
node = targetContext.getCoveredNode();
PsiClass parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);
parentMethod = PsiTreeUtil.getParentOfType(node, PsiMethod.class);

ChangeCorrectionProposal proposal = new ModifyModifiersProposal(TITLE_MESSAGE, targetContext.getSource().getCompilationUnit(),
targetContext.getASTRoot(), parentType, 0, parentMethod.getModifierList(), Collections.singletonList("public"));

// Convert the proposal to LSP4J CodeAction
CodeAction codeAction = targetContext.convertToCodeAction(proposal, diagnostic);
codeAction.setTitle(TITLE_MESSAGE);
codeActions.add(codeAction);

final PsiParameterList list = parentMethod.getParameterList();
if (list != null && list.getParametersCount() > 0) {
targetContext = context.copy();
node = targetContext.getCoveredNode();
parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);

final String name = Messages.getMessage("NoargPublicConstructor");
proposal = new AddConstructorProposal(name,
targetContext.getSource().getCompilationUnit(), targetContext.getASTRoot(), parentType, 0, "public");
codeAction = targetContext.convertToCodeAction(proposal, diagnostic);
codeActions.add(codeAction);
}
codeActions.add(JDTUtils.createCodeAction(context, diagnostic, Messages.getMessage("MakeConstructorPublic"), getParticipantId()));
codeActions.add(JDTUtils.createCodeAction(context, diagnostic, Messages.getMessage("NoargPublicConstructor"), getParticipantId()));

return codeActions;
}
return Collections.emptyList();
}

@Override
public CodeAction resolveCodeAction(JavaCodeActionResolveContext context) {

final CodeAction toResolve = context.getUnresolved();
PsiElement node = context.getCoveredNode();
PsiMethod parentMethod = PsiTreeUtil.getParentOfType(node, PsiMethod.class);
PsiClass parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);

if (parentMethod != null) {

String message = toResolve.getTitle();

if (message.equals(Messages.getMessage("MakeConstructorPublic"))) {

ChangeCorrectionProposal proposal = new ModifyModifiersProposal(message, context.getSource().getCompilationUnit(),
context.getASTRoot(), parentType, 0, parentMethod.getModifierList(), Collections.singletonList("public"));

String warningMessage = "Unable to create workspace edit for code action to make constructor public";
convertWorkspaceEdit(proposal, warningMessage, context);

} else if (message.equals(Messages.getMessage("NoargPublicConstructor"))) {

ChangeCorrectionProposal proposal = new AddConstructorProposal(message,
context.getSource().getCompilationUnit(), context.getASTRoot(), parentType, 0, "public");

String warningMessage = "Unable to create workspace edit for code action to add no-arg public constructor to the class";
convertWorkspaceEdit(proposal, warningMessage, context);

}
}
return toResolve;
}

public void convertWorkspaceEdit(ChangeCorrectionProposal proposal, String warningMessage, JavaCodeActionResolveContext context) {
try {
WorkspaceEdit we = context.convertToWorkspaceEdit(proposal);
context.getUnresolved().setEdit(we);
} catch (Exception e) {
LOGGER.log(Level.WARNING, warningMessage, e);
}
}
}
12 changes: 12 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,18 @@
group="jakarta"
targetDiagnostic="jakarta-cdi#InvalidManagedBeanConstructor"
implementationClass="io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.cdi.ManagedBeanNoArgConstructorQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="jakarta"
targetDiagnostic="jakarta-jax_rs#NoPublicConstructors"
implementationClass="io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.jax_rs.NoResourcePublicConstructorQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="jakarta"
targetDiagnostic="jakarta-bean-validation#MakeNotStatic"
implementationClass="io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.beanvalidation.BeanValidationQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="jakarta"
targetDiagnostic="jakarta-bean-validation#FixTypeOfElement"
implementationClass="io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.beanvalidation.BeanValidationQuickFix"/>

<javaCodeActionParticipant kind="quickfix"
group="jakarta"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ MakeMethodPublic = Make method public

# NoResourcePublicConstructorQuickFix
MakeConstructorPublic = Make constructor public
NoargPublicConstructor = Add a no-arg public constructor to this class
NoargPublicConstructor = Add a default 'public' constructor to this class

# ResourceMethodDiagnosticsCollector
OnlyPublicMethods = Only public methods can be exposed as resource methods.
Expand Down
Loading

0 comments on commit c9527bb

Please sign in to comment.