From 968779ed5bb108fe28051e5bc8e1a9bc36f843c4 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Fri, 16 May 2014 19:09:09 +0400 Subject: [PATCH] IDEA-123484: override/implement actions are aware of traits --- .../groovy/annotator/GroovyAnnotator.java | 21 +- .../groovy/lang/psi/util/GrTraitUtil.java | 41 ++++ .../GroovyImplementMethodsHandler.java | 14 +- .../GroovyOverrideImplementExploreUtil.java | 191 ++++++++++++++++++ .../GroovyOverrideImplementUtil.java | 70 +++++++ .../GroovyOverrideMethodsHandler.java | 16 +- .../GroovyOverrideImplementTest.groovy | 1 + 7 files changed, 324 insertions(+), 30 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementExploreUtil.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 6f144b8052c0..ac23324e6dce 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -52,7 +52,6 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; import gnu.trove.THashSet; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; @@ -104,6 +103,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrRefer import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -592,18 +592,13 @@ public class GroovyAnnotator extends GroovyElementVisitor { public void visitOpenBlock(GrOpenBlock block) { if (block.getParent() instanceof GrMethod) { final GrMethod method = (GrMethod)block.getParent(); - if (method.getModifierList().hasExplicitModifier(PsiModifier.ABSTRACT) || isInterface(method.getContainingClass())) { + if (method.getModifierList().hasExplicitModifier(PsiModifier.ABSTRACT) || GrTraitUtil.isInterface(method.getContainingClass())) { final Annotation annotation = myHolder.createErrorAnnotation(block, GroovyBundle.message("abstract.methods.must.not.have.body")); registerMakeAbstractMethodNotAbstractFix(annotation, method, true); } } } - @Contract("null -> false") - private static boolean isInterface(@Nullable PsiClass aClass) { - return aClass != null && aClass.isInterface() && !PsiImplUtil.isTrait(aClass); - } - @Override public void visitMethod(GrMethod method) { checkMethodWithTypeParamsShouldHaveReturnType(myHolder, method); @@ -634,7 +629,7 @@ public class GroovyAnnotator extends GroovyElementVisitor { } } - if (method.getBlock() == null && !isAbstractOrNative(method)) { + if (method.getBlock() == null && !method.hasModifierProperty(PsiModifier.NATIVE) && !GrTraitUtil.isMethodAbstract(method)) { final Annotation annotation = myHolder.createErrorAnnotation(nameIdentifier, GroovyBundle.message("not.abstract.method.should.have.body")); //annotation.registerFix(new AddMethodBodyFix(method)); //todo make intentions work @@ -644,14 +639,6 @@ public class GroovyAnnotator extends GroovyElementVisitor { checkOverridingMethod(myHolder, method); } - private static boolean isAbstractOrNative(@NotNull GrMethod method) { - if (method.hasModifierProperty(PsiModifier.NATIVE)) return true; - if (method.getModifierList().hasExplicitModifier(PsiModifier.ABSTRACT)) return true; - - PsiClass aClass = method.getContainingClass(); - return isInterface(aClass); - } - private static void checkGetterOfImmutable(AnnotationHolder holder, GrMethod method) { if (!GroovyPropertyUtils.isSimplePropertyGetter(method)) return; @@ -1650,7 +1637,7 @@ public class GroovyAnnotator extends GroovyElementVisitor { if (typeDefinition.isAnnotationType()) { myHolder.createErrorAnnotation(implementsClause, GroovyBundle.message("annotation.types.may.not.have.implements.clause")); } - else if (isInterface(typeDefinition)) { + else if (GrTraitUtil.isInterface(typeDefinition)) { myHolder.createErrorAnnotation(implementsClause, GroovyBundle.message("no.implements.clause.allowed.for.interface")) .registerFix(new ChangeExtendsImplementsQuickFix(typeDefinition)); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java new file mode 100644 index 000000000000..fb6aedb18e3a --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 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. + */ +package org.jetbrains.plugins.groovy.lang.psi.util; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; + +import static com.intellij.psi.PsiModifier.ABSTRACT; + +/** + * Created by Max Medvedev on 16/05/14 + */ +public class GrTraitUtil { + @Contract("null -> false") + public static boolean isInterface(@Nullable PsiClass aClass) { + return aClass != null && aClass.isInterface() && !PsiImplUtil.isTrait(aClass); + } + + public static boolean isMethodAbstract(PsiMethod method) { + if (method.getModifierList().hasExplicitModifier(ABSTRACT)) return true; + + PsiClass aClass = method.getContainingClass(); + return isInterface(aClass); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyImplementMethodsHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyImplementMethodsHandler.java index ee0265baad7d..84327458742f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyImplementMethodsHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyImplementMethodsHandler.java @@ -25,6 +25,7 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; /** * User: Dmitry.Krasilschikov @@ -40,14 +41,15 @@ public class GroovyImplementMethodsHandler implements LanguageCodeInsightActionH public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return; PsiClass aClass = OverrideImplementUtil.getContextClass(project, editor, file, true); - if (aClass == null) return; + if (aClass instanceof GrTypeDefinition) { + GrTypeDefinition typeDefinition = (GrTypeDefinition)aClass; + if (GroovyOverrideImplementExploreUtil.getMethodSignaturesToImplement(typeDefinition).isEmpty()) { + HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found"); + return; + } - if (OverrideImplementUtil.getMethodSignaturesToImplement(aClass).isEmpty()) { - HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found"); - return; + GroovyOverrideImplementUtil.chooseAndImplementMethods(project, editor, typeDefinition); } - - OverrideImplementUtil.chooseAndImplementMethods(project, editor, aClass); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementExploreUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementExploreUtil.java new file mode 100644 index 000000000000..7a70ed38bb6a --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementExploreUtil.java @@ -0,0 +1,191 @@ +/* + * Copyright 2000-2014 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. + */ +package org.jetbrains.plugins.groovy.overrideImplement; + +import com.intellij.codeInsight.generation.OverrideImplementExploreUtil; +import com.intellij.psi.*; +import com.intellij.psi.infos.CandidateInfo; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrTraitMethod; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +/** + * Created by Max Medvedev on 16/05/14 + */ +public class GroovyOverrideImplementExploreUtil { + + @NotNull + public static Collection getMethodSignaturesToOverride(@NotNull GrTypeDefinition aClass) { + if (aClass.isAnnotationType()) return Collections.emptySet(); + return getMapToOverrideImplement(aClass, false, true).keySet(); + } + + @NotNull + public static Collection getMethodSignaturesToImplement(@NotNull GrTypeDefinition aClass) { + return getMapToOverrideImplement(aClass, true, true).keySet(); + } + + @NotNull + public static Collection getMethodsToOverrideImplement(GrTypeDefinition aClass, boolean toImplement) { + return getMapToOverrideImplement(aClass, toImplement, true).values(); + } + + @NotNull + public static Map getMapToOverrideImplement(GrTypeDefinition aClass, boolean toImplement, boolean skipImplemented) { + Map abstracts = ContainerUtil.newLinkedHashMap(); + Map finals = ContainerUtil.newLinkedHashMap(); + Map concretes = ContainerUtil.newLinkedHashMap(); + + PsiUtilCore.ensureValid(aClass); + Collection allMethodSignatures = aClass.getVisibleSignatures(); + PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper(); + for (HierarchicalMethodSignature signature : allMethodSignatures) { + PsiMethod method = signature.getMethod(); + if (method instanceof GrTraitMethod) { + for (HierarchicalMethodSignature superSignature : signature.getSuperSignatures()) { + processMethod(aClass, skipImplemented, abstracts, finals, concretes, resolveHelper, superSignature, superSignature.getMethod()); + } + } + else { + processMethod(aClass, skipImplemented, abstracts, finals, concretes, resolveHelper, signature, method); + } + } + + final Map result = new TreeMap(new OverrideImplementExploreUtil.MethodSignatureComparator()); + if (toImplement || aClass.isInterface()) { + collectMethodsToImplement(aClass, abstracts, finals, concretes, result); + } + else { + for (Map.Entry entry : concretes.entrySet()) { + MethodSignature signature = entry.getKey(); + PsiMethod concrete = entry.getValue(); + if (finals.get(signature) == null) { + PsiMethod abstractOne = abstracts.get(signature); + if (abstractOne == null || !abstractOne.getContainingClass().isInheritor(concrete.getContainingClass(), true) || + CommonClassNames.JAVA_LANG_OBJECT.equals(concrete.getContainingClass().getQualifiedName())) { + PsiSubstitutor subst = OverrideImplementExploreUtil.correctSubstitutor(concrete, signature.getSubstitutor()); + CandidateInfo info = new CandidateInfo(concrete, subst); + result.put(signature, info); + } + } + } + } + + return result; + } + + private static void processMethod(GrTypeDefinition aClass, + boolean skipImplemented, + Map abstracts, + Map finals, + Map concretes, + PsiResolveHelper resolveHelper, HierarchicalMethodSignature signature, PsiMethod method) { + PsiUtilCore.ensureValid(method); + + if (method.hasModifierProperty(PsiModifier.STATIC) || !resolveHelper.isAccessible(method, aClass, aClass)) return; + PsiClass hisClass = method.getContainingClass(); + if (hisClass == null) return; + // filter non-immediate super constructors + if (method.isConstructor() && (!aClass.isInheritor(hisClass, false) || aClass instanceof PsiAnonymousClass || aClass.isEnum())) { + return; + } + // filter already implemented + if (skipImplemented) { + PsiMethod implemented = MethodSignatureUtil.findMethodBySignature(aClass, signature, false); + if (implemented != null && !(implemented instanceof GrTraitMethod)) { + return; + } + } + + if (method.hasModifierProperty(PsiModifier.FINAL)) { + finals.put(signature, method); + return; + } + + Map map = method.hasModifierProperty(PsiModifier.ABSTRACT) ? abstracts : concretes; + fillMap(signature, method, map); + if (isDefaultMethod(method)) { + fillMap(signature, method, concretes); + } + } + + private static void fillMap(HierarchicalMethodSignature signature, PsiMethod method, Map map) { + final PsiMethod other = map.get(signature); + if (other == null || preferLeftForImplement(method, other)) { + map.put(signature, method); + } + } + + private static boolean preferLeftForImplement(PsiMethod left, PsiMethod right) { + if (PsiUtil.getAccessLevel(left.getModifierList()) > PsiUtil.getAccessLevel(right.getModifierList())) return true; + PsiClass lClass = left.getContainingClass(); + PsiClass rClass = right.getContainingClass(); + if (lClass != null && !lClass.isInterface()) return true; + if (rClass != null && !rClass.isInterface()) return false; + // implement annotated method + PsiAnnotation[] leftAnnotations = left.getModifierList().getAnnotations(); + PsiAnnotation[] rightAnnotations = right.getModifierList().getAnnotations(); + return leftAnnotations.length > rightAnnotations.length; + } + + private static boolean isDefaultMethod(PsiMethod method) { + return method instanceof GrMethod && !method.getModifierList().hasExplicitModifier(PsiModifier.ABSTRACT) && + PsiImplUtil.isTrait(method.getContainingClass()); + } + + public static void collectMethodsToImplement(PsiClass aClass, + Map abstracts, + Map finals, + Map concretes, + Map result) { + for (Map.Entry entry : abstracts.entrySet()) { + MethodSignature signature = entry.getKey(); + PsiMethod abstractOne = entry.getValue(); + PsiMethod concrete = concretes.get(signature); + if (concrete == null + || PsiUtil.getAccessLevel(concrete.getModifierList()) < PsiUtil.getAccessLevel(abstractOne.getModifierList()) + || !abstractOne.getContainingClass().isInterface() && abstractOne.getContainingClass().isInheritor(concrete.getContainingClass(), true) + || isDefaultMethod(abstractOne)) { + if (finals.get(signature) == null) { + PsiSubstitutor subst = OverrideImplementExploreUtil.correctSubstitutor(abstractOne, signature.getSubstitutor()); + CandidateInfo info = new CandidateInfo(abstractOne, subst); + result.put(signature, info); + } + } + } + + for (final PsiMethod method : new GroovyMethodImplementor().getMethodsToImplement(aClass)) { + MethodSignature signature = MethodSignatureUtil.createMethodSignature(method.getName(), method.getParameterList(), + method.getTypeParameterList(), PsiSubstitutor.EMPTY, + method.isConstructor()); + CandidateInfo info = new CandidateInfo(method, PsiSubstitutor.EMPTY); + result.put(signature, info); + } + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java index ee1d32b37deb..5bb2923aab5d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java @@ -17,14 +17,24 @@ package org.jetbrains.plugins.groovy.overrideImplement; import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInsight.generation.OverrideImplementUtil; +import com.intellij.codeInsight.generation.PsiMethodMember; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.featureStatistics.ProductivityFeatureNames; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.JavaTemplateUtil; +import com.intellij.ide.util.MemberChooser; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,9 +48,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil; import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; import java.util.Properties; /** @@ -160,6 +175,61 @@ public class GroovyOverrideImplementUtil { } } + public static void chooseAndOverrideMethods(@NotNull Project project, + @NotNull Editor editor, + @NotNull GrTypeDefinition aClass){ + FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT); + chooseAndOverrideOrImplementMethods(project, editor, aClass, false); + } + + public static void chooseAndImplementMethods(@NotNull Project project, + @NotNull Editor editor, + @NotNull GrTypeDefinition aClass){ + FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT); + chooseAndOverrideOrImplementMethods(project, editor, aClass, true); + } + + public static void chooseAndOverrideOrImplementMethods(@NotNull Project project, + @NotNull final Editor editor, + @NotNull final GrTypeDefinition aClass, + boolean toImplement) { + LOG.assertTrue(aClass.isValid()); + ApplicationManager.getApplication().assertReadAccessAllowed(); + + Collection candidates = GroovyOverrideImplementExploreUtil.getMethodsToOverrideImplement(aClass, toImplement); + Collection secondary = toImplement || aClass.isInterface() ? ContainerUtil.newArrayList() + : GroovyOverrideImplementExploreUtil.getMethodsToOverrideImplement(aClass, true); + + if (toImplement) { + for (Iterator iterator = candidates.iterator(); iterator.hasNext(); ) { + CandidateInfo candidate = iterator.next(); + PsiElement element = candidate.getElement(); + if (element instanceof GrMethod) { + GrMethod method = (GrMethod)element; + if (PsiImplUtil.isTrait(method.getContainingClass()) && !GrTraitUtil.isMethodAbstract(method)) { + iterator.remove(); + secondary.add(candidate); + } + } + } + } + + final MemberChooser chooser = OverrideImplementUtil.showOverrideImplementChooser(editor, aClass, toImplement, candidates, secondary); + if (chooser == null) return; + + final List selectedElements = chooser.getSelectedElements(); + if (selectedElements == null || selectedElements.isEmpty()) return; + + LOG.assertTrue(aClass.isValid()); + new WriteCommandAction(project, aClass.getContainingFile()) { + @Override + protected void run(@NotNull Result result) throws Throwable { + OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(editor, aClass, selectedElements, chooser.isCopyJavadoc(), + chooser.isInsertOverrideAnnotation()); + } + }.execute(); + } + @NotNull private static String callSuper(PsiMethod superMethod, PsiMethod overriding) { @NonNls StringBuilder buffer = new StringBuilder(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideMethodsHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideMethodsHandler.java index 705c62fc1ef3..424178ee8f06 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideMethodsHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideMethodsHandler.java @@ -16,7 +16,6 @@ package org.jetbrains.plugins.groovy.overrideImplement; import com.intellij.codeInsight.CodeInsightUtilBase; -import com.intellij.codeInsight.generation.OverrideImplementExploreUtil; import com.intellij.codeInsight.generation.OverrideImplementUtil; import com.intellij.codeInsight.hint.HintManager; import com.intellij.lang.LanguageCodeInsightActionHandler; @@ -26,6 +25,7 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; /** * User: Dmitry.Krasilschikov @@ -41,14 +41,16 @@ public class GroovyOverrideMethodsHandler implements LanguageCodeInsightActionHa public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return; PsiClass aClass = OverrideImplementUtil.getContextClass(project, editor, file, true); - if (aClass == null) return; + if (aClass instanceof GrTypeDefinition) { + GrTypeDefinition typeDefinition = (GrTypeDefinition)aClass; - if (OverrideImplementExploreUtil.getMethodSignaturesToOverride(aClass).isEmpty()) { - HintManager.getInstance().showErrorHint(editor, "No methods to override have been found"); - return; + if (GroovyOverrideImplementExploreUtil.getMethodSignaturesToOverride(typeDefinition).isEmpty()) { + HintManager.getInstance().showErrorHint(editor, "No methods to override have been found"); + return; + } + + GroovyOverrideImplementUtil.chooseAndOverrideMethods(project, editor, typeDefinition); } - - OverrideImplementUtil.chooseAndOverrideMethods(project, editor, aClass); } @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy index f31a6e36098c..8a9907be53e0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy @@ -14,6 +14,7 @@ * limitations under the License. */ package org.jetbrains.plugins.groovy.lang.overriding + import com.intellij.codeInsight.generation.OverrideImplementUtil import com.intellij.openapi.command.WriteCommandAction import com.intellij.psi.JavaPsiFacade