diff --git a/build.gradle b/build.gradle index 5c3559d..9e47b87 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ dependencies { // See https://www.jetbrains.com/intellij-repository/snapshots // See https://www.jetbrains.com/intellij-repository/releases intellij { - version = '2021.2' + version = '2021.3' plugins = ['java', 'coverage'] pluginName = 'Save Actions' // Do not touch the plugin.xml file diff --git a/src/main/java/com/dubreuia/processors/java/InspectionRunnable.java b/src/main/java/com/dubreuia/processors/java/InspectionRunnable.java index cbe6aa1..9a473a7 100644 --- a/src/main/java/com/dubreuia/processors/java/InspectionRunnable.java +++ b/src/main/java/com/dubreuia/processors/java/InspectionRunnable.java @@ -38,74 +38,72 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; + +import java.io.Serializable; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; /** * Implements a runnable for inspections commands. */ -class InspectionRunnable implements Runnable { +class InspectionRunnable implements Runnable, Serializable { private static final Logger LOGGER = Logger.getInstance(SaveActionsService.class); + private static final long serialVersionUID = -9189508316598162392L; private final Project project; private final Set psiFiles; - private final LocalInspectionTool inspectionTool; + private final InspectionToolWrapper toolWrapper; InspectionRunnable(Project project, Set psiFiles, LocalInspectionTool inspectionTool) { - this.project = project; this.psiFiles = psiFiles; - this.inspectionTool = inspectionTool; + toolWrapper = new LocalInspectionToolWrapper(inspectionTool); + LOGGER.info(String.format("Running inspection for %s", inspectionTool.getShortName())); } @Override public void run() { - InspectionManager inspectionManager = InspectionManager.getInstance(project); GlobalInspectionContext context = inspectionManager.createNewGlobalContext(); - InspectionToolWrapper toolWrapper = new LocalInspectionToolWrapper(inspectionTool); - for (PsiFile psiFile : psiFiles) { - List problemDescriptors = - getProblemDescriptors(context, toolWrapper, psiFile); - for (ProblemDescriptor problemDescriptor : problemDescriptors) { - QuickFix[] fixes = problemDescriptor.getFixes(); - if (fixes != null) { - writeQuickFixes(problemDescriptor, fixes); - } - } - } + psiFiles.forEach(pf -> getProblemDescriptors(context, pf).forEach(this::writeQuickFixes)); } private List getProblemDescriptors( - GlobalInspectionContext context, - InspectionToolWrapper toolWrapper, - PsiFile psiFile) { - - List problemDescriptors; + GlobalInspectionContext context, + PsiFile psiFile) { try { - problemDescriptors = - InspectionEngine.runInspectionOnFile(psiFile, toolWrapper, context); + return InspectionEngine.runInspectionOnFile(psiFile, toolWrapper, context); } catch (IndexNotReadyException exception) { - LOGGER.info("Cannot inspect files: index not ready (" + exception.getMessage() + ")"); + LOGGER.error(String.format("Cannot inspect file %s: index not ready (%s)", + psiFile.getName(), + exception.getMessage())); return Collections.emptyList(); } - return problemDescriptors; } - @SuppressWarnings({"squid:S1905", "squid:S3740"}) - private void writeQuickFixes(ProblemDescriptor problemDescriptor, QuickFix[] fixes) { + @SuppressWarnings({"unchecked", "squid:S1905", "squid:S3740"}) + private void writeQuickFixes(ProblemDescriptor problemDescriptor) { + QuickFix[] fixes = problemDescriptor.getFixes(); + if (fixes == null) { + return; + } + + Set> quickFixes = Arrays.stream(fixes) + .filter(Objects::nonNull) + .map(qf -> (QuickFix) qf) + .collect(Collectors.toSet()); - for (QuickFix fix : fixes) { - if (fix != null) { - @SuppressWarnings("unchecked") QuickFix typedFix = - (QuickFix) fix; - try { - typedFix.applyFix(project, problemDescriptor); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } + for (QuickFix typedFix : quickFixes) { + try { + LOGGER.info(String.format("Applying fix \"%s\"", typedFix.getName())); + typedFix.applyFix(project, problemDescriptor); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); } } } diff --git a/src/main/java/com/dubreuia/processors/java/inspection/CustomSerializableHasSerialVersionUidFieldInspection.java b/src/main/java/com/dubreuia/processors/java/inspection/CustomSerializableHasSerialVersionUidFieldInspection.java new file mode 100644 index 0000000..15e9edb --- /dev/null +++ b/src/main/java/com/dubreuia/processors/java/inspection/CustomSerializableHasSerialVersionUidFieldInspection.java @@ -0,0 +1,36 @@ +package com.dubreuia.processors.java.inspection; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.SerializableHasSerialVersionUidFieldInspection; +import com.intellij.codeInspection.USerializableInspectionBase; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UClass; + +/** + * Wrapper for the SerializableHasSerialVersionUidFieldInspection class. + *

+ * We have to set isOnTheFly to true. Otherwise, the inspection will not be applied. + * + * @since IDEA 2021.3 + */ +public class CustomSerializableHasSerialVersionUidFieldInspection extends USerializableInspectionBase { + + + public CustomSerializableHasSerialVersionUidFieldInspection() { + super(new Class[]{UClass.class}); + } + + @Override + public @NonNls @NotNull String getID() { + return "serial"; + } + + @Override + public ProblemDescriptor @Nullable [] checkClass(@NotNull UClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { + SerializableHasSerialVersionUidFieldInspection inspection = new SerializableHasSerialVersionUidFieldInspection(); + return inspection.checkClass(aClass, manager, true); + } +} diff --git a/src/main/java/com/dubreuia/processors/java/inspection/SerializableHasSerialVersionUIDFieldInspectionWrapper.java b/src/main/java/com/dubreuia/processors/java/inspection/SerializableHasSerialVersionUIDFieldInspectionWrapper.java index a8d28ee..185eba9 100644 --- a/src/main/java/com/dubreuia/processors/java/inspection/SerializableHasSerialVersionUIDFieldInspectionWrapper.java +++ b/src/main/java/com/dubreuia/processors/java/inspection/SerializableHasSerialVersionUIDFieldInspectionWrapper.java @@ -55,22 +55,37 @@ public static LocalInspectionTool get() { } private enum SerializableClass { - CLASS_NAME_INTELLIJ_2021_3("com.intellij.codeInspection.SerializableHasSerialVersionUidFieldInspection"), - CLASS_NAME_INTELLIJ_2018_3("com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspection"), - CLASS_NAME_INTELLIJ_2016("com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspectionBase"); + CLASS_NAME_INTELLIJ_2021_3("com.intellij.codeInspection.SerializableHasSerialVersionUidFieldInspection", + "com.dubreuia.processors.java.inspection.CustomSerializableHasSerialVersionUidFieldInspection"), + CLASS_NAME_INTELLIJ_2018_3("com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspection", + "com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspection"), + CLASS_NAME_INTELLIJ_2016("com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspectionBase", + "com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspectionBase"); + /** + * Field className: Inspection class provided by IDE + */ private final String className; - SerializableClass(String className) { + /** + * Field targetClass: Inspection class to run. Needed to apply wrapper class for Idea 2021.3 and up. + * + * @see CustomSerializableHasSerialVersionUidFieldInspection + */ + private final String targetClass; + + SerializableClass(String className, String targetClass) { this.className = className; + this.targetClass = targetClass; } public LocalInspectionTool getInspectionInstance() { try { - Class inspectionClass = - Class.forName(className).asSubclass(LocalInspectionTool.class); - LOGGER.info("Found serial version uid class " + inspectionClass.getName()); - return inspectionClass.cast(inspectionClass.getDeclaredConstructor().newInstance()); + Class.forName(className).asSubclass(LocalInspectionTool.class); + Class targetInspectionClass = + Class.forName(targetClass).asSubclass(LocalInspectionTool.class); + LOGGER.info(String.format("Found serial version uid class %s", targetInspectionClass.getName())); + return targetInspectionClass.cast(targetInspectionClass.getDeclaredConstructor().newInstance()); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { return null; }