From c9d7ee00abb5faea36f52b9c528f44a8966a2b29 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 12 Jan 2012 15:03:29 +0100 Subject: [PATCH] IDEA-79688 (Inspection "Cloneable class without clone()" not provide clone method insertion) --- .../siyeh/InspectionGadgetsBundle.properties | 5 +- .../CloneableImplementsCloneInspection.java | 55 ++++++++++++++----- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index f3a289ae5045..5586e14f0484 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -251,6 +251,7 @@ clone.method.in.non.cloneable.interface.problem.descriptor=#ref() d cloneable.class.without.clone.display.name=Cloneable class without 'clone()' cloneable.class.without.clone.problem.descriptor=#ref does not define 'clone()' #loc cloneable.class.without.clone.ignore.option=Ignore classes cloneable due to inheritance +cloneable.class.without.clone.quickfix=Generate 'clone()' method class.without.tostring.display.name=Class without 'toString()' class.without.tostring.problem.descriptor=Class #ref should probably implement 'toString()', for debugging purposes #loc use.obsolete.collection.type.display.name=Use of obsolete collection type @@ -1098,7 +1099,7 @@ abstract.class.with.only.one.direct.inheritor.problem.descriptor=Abstract class #other abstract.method.overrides.abstract.method.remove.quickfix=Remove redundant abstract method declaration class.may.be.interface.convert.quickfix=Convert class to interface -class.without.constructor.create.quickfix=Create empty constructor +class.without.constructor.create.quickfix=Generate empty constructor class.without.no.arg.constructor.ignore.option=Ignore if class has default constructor extends.annotation.problem.descriptor=Class ''{0}'' explicitly extends annotation interface #ref #loc extends.concrete.collection.problem.descriptor=Class #ref explicitly extends ''{0}'' #loc @@ -1111,7 +1112,7 @@ non.protected.constructor.in.abstract.class.ignore.option=Ignore for non-public public.constructor.in.non.public.class.problem.descriptor=Constructor is declared #ref in non-public class ''{0}'' #loc static.inheritance.replace.quickfix=Replace inheritance with qualified references in {0} utility.class.with.public.constructor.make.quickfix=Make {0, choice, 1#constructor|2#constructors} private -utility.class.without.private.constructor.create.quickfix=Create empty private constructor +utility.class.without.private.constructor.create.quickfix=Generate empty private constructor utility.class.without.private.constructor.make.quickfix=Make constructor private annotation.naming.convention.problem.descriptor.short=Annotation name #ref is too short #loc annotation.naming.convention.problem.descriptor.long=Annotation name #ref is too long #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java index 562ee2d13296..31552bb0a1de 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,15 @@ */ package com.siyeh.ig.cloneable; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiTypeParameter; +import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.CloneUtils; import org.jetbrains.annotations.NotNull; @@ -43,22 +45,49 @@ public class CloneableImplementsCloneInspection extends BaseInspection { @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "cloneable.class.without.clone.display.name"); + return InspectionGadgetsBundle.message("cloneable.class.without.clone.display.name"); } @Override @NotNull public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "cloneable.class.without.clone.problem.descriptor"); + return InspectionGadgetsBundle.message("cloneable.class.without.clone.problem.descriptor"); } @Override public JComponent createOptionsPanel() { return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( - "cloneable.class.without.clone.ignore.option"), - this, "m_ignoreCloneableDueToInheritance"); + "cloneable.class.without.clone.ignore.option"), this, "m_ignoreCloneableDueToInheritance"); + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new CreateCloneMethodFix(); + } + + private static class CreateCloneMethodFix extends InspectionGadgetsFix { + @NotNull + @Override + public String getName() { + return InspectionGadgetsBundle.message("cloneable.class.without.clone.quickfix"); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiClass)) { + return; + } + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + final StringBuilder cloneMethod = new StringBuilder("public "); + cloneMethod.append(element.getText()); + cloneMethod.append(" clone() throws java.lang.CloneNotSupportedException {\nreturn ("); + cloneMethod.append(element.getText()); + cloneMethod.append(") super.clone();\n}"); + final PsiMethod method = factory.createMethodFromText(cloneMethod.toString(), element); + parent.add(method); + } } @Override @@ -66,14 +95,12 @@ public class CloneableImplementsCloneInspection extends BaseInspection { return new CloneableImplementsCloneVisitor(); } - private class CloneableImplementsCloneVisitor - extends BaseInspectionVisitor { + private class CloneableImplementsCloneVisitor extends BaseInspectionVisitor { @Override public void visitClass(@NotNull PsiClass aClass) { // no call to super, so it doesn't drill down - if (aClass.isInterface() || aClass.isAnnotationType() - || aClass.isEnum()) { + if (aClass.isInterface() || aClass.isAnnotationType() || aClass.isEnum()) { return; } if (aClass instanceof PsiTypeParameter) {