good code is red (in presence of raw overriding)
authorAlexey Kudravtsev <cdr@intellij.com>
Mon, 15 Feb 2010 09:57:57 +0000 (15 12:57 +0300)
committerAlexey Kudravtsev <cdr@intellij.com>
Mon, 15 Feb 2010 10:54:03 +0000 (15 13:54 +0300)
java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java
java/openapi/src/com/intellij/codeInsight/ClassUtil.java
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java

index 4775d87..8229bc9 100644 (file)
@@ -980,7 +980,7 @@ public class GenericsHighlightUtil {
         holder.add(highlightInfo);
         return;
       }
-      highlightInfo = HighlightClassUtil.checkClassWithAbstractMethods(enumConstant.getContainingClass(), enumConstant.getNameIdentifier());
+      highlightInfo = HighlightClassUtil.checkClassWithAbstractMethods(enumConstant.getContainingClass(), enumConstant.getNameIdentifier().getTextRange());
       if (highlightInfo != null) {
         holder.add(highlightInfo);
         return;
index 2e9dd27..1cbbbf8 100644 (file)
@@ -31,13 +31,13 @@ import com.intellij.codeInsight.daemon.impl.quickfix.*;
 import com.intellij.codeInsight.intention.IntentionAction;
 import com.intellij.codeInsight.intention.QuickFixFactory;
 import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileTypes.StdFileTypes;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModuleUtil;
 import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.fileTypes.StdFileTypes;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.source.jsp.jspJava.JspClass;
 import com.intellij.psi.search.GlobalSearchScope;
@@ -72,30 +72,43 @@ public class HighlightClassUtil {
              && parent.getParent() instanceof PsiNewExpression
              && !PsiUtilBase.hasErrorElementChild(parent.getParent())) {
       PsiAnonymousClass aClass = (PsiAnonymousClass)parent;
-      highlightInfo = checkClassWithAbstractMethods(aClass, ref);
+      highlightInfo = checkClassWithAbstractMethods(aClass, ref.getTextRange());
     }
     return highlightInfo;
   }
 
-  public static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, PsiElement highlightElement) {
-    Collection<HierarchicalMethodSignature> allMethods = aClass.getVisibleSignatures();
-    PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass, allMethods);
+  static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, TextRange textRange) {
+    PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass);
 
-    if (abstractMethod != null && abstractMethod.getContainingClass() != null) {
-      String baseClassName = HighlightUtil.formatClass(aClass, false);
-      String methodName = HighlightUtil.formatMethod(abstractMethod);
-      String message = JavaErrorMessages.message("class.must.be.abstract",
-                                                 baseClassName,
-                                                 methodName,
-                                                 HighlightUtil.formatClass(abstractMethod.getContainingClass(), false));
+    if (abstractMethod == null || abstractMethod.getContainingClass() == null) {
+      return null;
+    }
+    String baseClassName = HighlightUtil.formatClass(aClass, false);
+    String methodName = HighlightUtil.formatMethod(abstractMethod);
+    String message = JavaErrorMessages.message("class.must.be.abstract",
+                                               baseClassName,
+                                               methodName,
+                                               HighlightUtil.formatClass(abstractMethod.getContainingClass(), false));
 
-      HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, highlightElement, message);
-      if (ClassUtil.getAnyMethodToImplement(aClass, allMethods) != null) {
-        QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
-      }
-      return highlightInfo;
+    HighlightInfo errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, textRange, message);
+    if (ClassUtil.getAnyMethodToImplement(aClass) != null) {
+      QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
     }
-    return null;
+    if (!(aClass instanceof PsiAnonymousClass)
+        && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, aClass.getModifierList()) == null) {
+      IntentionAction fix = QUICK_FIX_FACTORY.createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false);
+      QuickFixAction.registerQuickFixAction(errorResult, fix);
+    }
+    return errorResult;
+  }
+
+  static HighlightInfo checkClassMustBeAbstract(final PsiClass aClass, final TextRange textRange) {
+    if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass.getRBrace() == null
+        || aClass.isEnum() && hasEnumConstants(aClass)
+      ) {
+      return null;
+    }
+    return checkClassWithAbstractMethods(aClass, textRange);
   }
 
 
@@ -105,7 +118,7 @@ public class HighlightClassUtil {
       String baseClassName = aClass.getName();
       String message = JavaErrorMessages.message("abstract.cannot.be.instantiated", baseClassName);
       errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, highlighElement, message);
-      if (!aClass.isInterface() && ClassUtil.getAnyAbstractMethod(aClass, aClass.getVisibleSignatures()) == null) {
+      if (!aClass.isInterface() && ClassUtil.getAnyAbstractMethod(aClass) == null) {
         // suggest to make not abstract only if possible
         IntentionAction fix = QUICK_FIX_FACTORY.createModifierListFix(aClass, PsiModifier.ABSTRACT, false, false);
         QuickFixAction.registerQuickFixAction(errorResult, fix);
@@ -114,36 +127,6 @@ public class HighlightClassUtil {
     return errorResult;
   }
 
-
-  static HighlightInfo checkClassMustBeAbstract(PsiClass aClass) {
-    if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass.getRBrace() == null ||
-        aClass.isEnum() && hasEnumConstants(aClass)
-    ) {
-      return null;
-    }
-    HighlightInfo errorResult = null;
-    Collection<HierarchicalMethodSignature> allMethods = aClass.getVisibleSignatures();
-    PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass, allMethods);
-    if (abstractMethod != null) {
-      String message = JavaErrorMessages.message("class.must.be.abstract",
-                                                 HighlightUtil.formatClass(aClass, false),
-                                                 HighlightUtil.formatMethod(abstractMethod),
-                                                 HighlightUtil.formatClass(abstractMethod.getContainingClass()));
-
-      TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
-      errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, textRange, message);
-      if (ClassUtil.getAnyMethodToImplement(aClass, allMethods) != null) {
-        QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
-      }
-      if (!(aClass instanceof PsiAnonymousClass)
-          && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, aClass.getModifierList()) == null) {
-        IntentionAction fix = QUICK_FIX_FACTORY.createModifierListFix(aClass, PsiModifier.ABSTRACT, true, false);
-        QuickFixAction.registerQuickFixAction(errorResult, fix);
-      }
-    }
-    return errorResult;
-  }
-
   private static boolean hasEnumConstants(PsiClass aClass) {
     PsiField[] fields = aClass.getFields();
     for (PsiField field : fields) {
index 393f3f2..2f50f7a 100644 (file)
@@ -328,7 +328,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
 
   @Override public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) {
     super.visitEnumConstantInitializer(enumConstantInitializer);
-    if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(enumConstantInitializer));
+    if (!myHolder.hasErrorResults()) {
+      TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(enumConstantInitializer);
+      myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(enumConstantInitializer, textRange));
+    }
   }
 
   @Override public void visitExpression(PsiExpression expression) {
@@ -599,7 +602,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
     else if (parent instanceof PsiClass) {
       PsiClass aClass = (PsiClass)parent;
       if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkDuplicateNestedClass(aClass));
-      if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(aClass));
+      if (!myHolder.hasErrorResults()) {
+        TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
+        myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(aClass, textRange));
+      }
       if (!myHolder.hasErrorResults()) {
         myHolder.add(HighlightClassUtil.checkClassDoesNotCallSuperConstructorOrHandleExceptions(aClass, myRefCountHolder, myResolveHelper));
       }
index ac7768f..797385f 100644 (file)
@@ -149,7 +149,7 @@ public class PsiSuperMethodImplUtil {
       if (superClass == null) continue;
       if (!visited.add(superClass)) continue; // cyclic inheritance
       final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor();
-      PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor);
+      PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext);
 
       final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0;
       Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper);
@@ -263,7 +263,10 @@ public class PsiSuperMethodImplUtil {
 
   private static PsiSubstitutor obtainFinalSubstitutor(PsiClass superClass,
                                                        PsiSubstitutor superSubstitutor,
-                                                       PsiSubstitutor derivedSubstitutor) {
+                                                       PsiSubstitutor derivedSubstitutor, boolean inRawContext) {
+    if (inRawContext) {
+      superSubstitutor = JavaPsiFacadeEx.getElementFactory(superClass.getProject()).createRawSubstitutor(derivedSubstitutor, superSubstitutor.getSubstitutionMap().keySet().toArray(PsiTypeParameter.EMPTY_ARRAY));
+    }
     Map<PsiTypeParameter, PsiType> map = null;
     for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) {
       PsiType type = superSubstitutor.substitute(typeParameter);
dissimilarity index 76%
index c06d03d..e7b0fbf 100644 (file)
-/*
- * Copyright 2000-2009 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.
- */
-
-/**
- * @author Alexey
- */
-package com.intellij.codeInsight;
-
-import com.intellij.psi.*;
-import gnu.trove.THashSet;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-public class ClassUtil {
-  public static PsiMethod getAnyAbstractMethod(PsiClass aClass, Collection<HierarchicalMethodSignature> allMethodsCollection) {
-    PsiMethod methodToImplement = getAnyMethodToImplement(aClass, allMethodsCollection);
-    if (methodToImplement != null) {
-      return methodToImplement;
-    }
-    PsiMethod[] methods = aClass.getMethods();
-    for (PsiMethod method : methods) {
-      if (method.hasModifierProperty(PsiModifier.ABSTRACT)) return method;
-    }
-
-    return abstractPackageLocalMethod(aClass, allMethodsCollection);
-/*
-    // the only remaining possiblity for class to have abstract method here is
-    //  from package local abstract method defined in inherited class from other package
-    PsiManager manager = aClass.getManager();
-    for (List<MethodSignatureBackedByPsiMethod> sameSignatureMethods : allMethodsCollection.values()) {
-      // look for abstract package locals
-      for (int i = sameSignatureMethods.size() - 1; i >= 0; i--) {
-        MethodSignatureBackedByPsiMethod methodSignature1 = sameSignatureMethods.get(i);
-        PsiMethod method1 = methodSignature1.getMethod();
-        PsiClass class1 = method1.getContainingClass();
-        if (class1 == null) {
-          sameSignatureMethods.remove(i);
-          continue;
-        }
-        if (!method1.hasModifierProperty(PsiModifier.ABSTRACT)
-            || !method1.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)
-            || manager.arePackagesTheSame(class1, aClass)) {
-          continue;
-        }
-        // check if abstract package local method gets overriden by not abstract
-        // i.e. there is direct subclass in the same package which overrides this method
-        for (int j = sameSignatureMethods.size() - 1; j >= 0; j--) {
-          MethodSignatureBackedByPsiMethod methodSignature2 = sameSignatureMethods.get(j);
-          PsiMethod method2 = methodSignature2.getMethod();
-          PsiClass class2 = method2.getContainingClass();
-          if (i == j || class2 == null) continue;
-          if (class2.isInheritor(class1, true)
-              // NB! overriding method may be abstract
-//              && !method2.hasModifierProperty(PsiModifier.ABSTRACT)
-&& manager.arePackagesTheSame(class1, class2)) {
-            sameSignatureMethods.remove(i);
-            break;
-          }
-        }
-      }
-      for (int i = sameSignatureMethods.size() - 1; i >= 0; i--) {
-        MethodSignatureBackedByPsiMethod methodSignature = sameSignatureMethods.get(i);
-        PsiMethod method = methodSignature.getMethod();
-        PsiClass class1 = method.getContainingClass();
-        if (class1 == null
-            || !method.hasModifierProperty(PsiModifier.ABSTRACT)
-            || !method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)
-            || manager.arePackagesTheSame(class1, aClass)) {
-          continue;
-        }
-        return method;
-      }
-    }
-    return null;
-*/
-  }
-
-  private static PsiMethod abstractPackageLocalMethod(PsiClass aClass, Collection<HierarchicalMethodSignature> allMethodsCollection) {
-    Set<PsiMethod> allMethods = new THashSet<PsiMethod>(Arrays.asList(aClass.getAllMethods()));
-    Set<PsiMethod> suspects = new THashSet<PsiMethod>();
-    // check all methods collection first for sibling overrides
-    for (HierarchicalMethodSignature signature : allMethodsCollection) {
-      removeSupers(signature, allMethods, suspects);
-      PsiMethod method = signature.getMethod();
-      if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
-        suspects.add(method);
-      }
-      allMethods.remove(method);
-    }
-    while (!allMethods.isEmpty()) {
-      PsiMethod method = allMethods.iterator().next();
-      removeSupers(method.getHierarchicalMethodSignature(), allMethods, suspects);
-      if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
-        suspects.add(method);
-      }
-      allMethods.remove(method);
-    }
-    return suspects.isEmpty() ? null : suspects.iterator().next();
-  }
-
-  private static void removeSupers(@NotNull HierarchicalMethodSignature hierarchicalMethodSignature, Set<PsiMethod> allMethods, Set<PsiMethod> suspects) {
-    for (HierarchicalMethodSignature superS : hierarchicalMethodSignature.getSuperSignatures()) {
-      PsiMethod superMethod = superS.getMethod();
-      allMethods.remove(superMethod);
-      suspects.remove(superMethod);
-      assert superS != hierarchicalMethodSignature;
-      removeSupers(superS, allMethods, suspects);
-    }
-  }
-
-  public static PsiMethod getAnyMethodToImplement(PsiClass aClass, Collection<HierarchicalMethodSignature> allMethodsCollection) {
-    for (HierarchicalMethodSignature signatureHierarchical : allMethodsCollection) {
-      final PsiMethod method = signatureHierarchical.getMethod();
-      PsiClass containingClass = method.getContainingClass();
-      if (containingClass == null) {
-        continue;
-      }
-      if (!aClass.equals(containingClass) &&
-          method.hasModifierProperty(PsiModifier.ABSTRACT)
-          && !method.hasModifierProperty(PsiModifier.STATIC)
-          && !method.hasModifierProperty(PsiModifier.PRIVATE)) {
-        return method;
-      }
-      else {
-        final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper();
-        final List<HierarchicalMethodSignature> superSignatures = signatureHierarchical.getSuperSignatures();
-        for (HierarchicalMethodSignature superSignatureHierarchical : superSignatures) {
-          final PsiMethod superMethod = superSignatureHierarchical.getMethod();
-          if (superMethod.hasModifierProperty(PsiModifier.ABSTRACT) && !resolveHelper.isAccessible(superMethod, method, null)) return superMethod;
-        }
-      }
-    }
-
-    return null;
-  }
-
-}
\ No newline at end of file
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * @author Alexey
+ */
+package com.intellij.codeInsight;
+
+import com.intellij.psi.*;
+import gnu.trove.THashSet;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Set;
+
+public class ClassUtil {
+  public static PsiMethod getAnyAbstractMethod(@NotNull PsiClass aClass) {
+    PsiMethod methodToImplement = getAnyMethodToImplement(aClass);
+    if (methodToImplement != null) {
+      return methodToImplement;
+    }
+    PsiMethod[] methods = aClass.getMethods();
+    for (PsiMethod method : methods) {
+      if (method.hasModifierProperty(PsiModifier.ABSTRACT)) return method;
+    }
+
+    return null;
+  }
+
+  public static PsiMethod getAnyMethodToImplement(PsiClass aClass) {
+    Set<PsiMethod> alreadyImplemented = new THashSet<PsiMethod>();
+    for (HierarchicalMethodSignature signatureHierarchical : aClass.getVisibleSignatures()) {
+      for (PsiMethod superS : signatureHierarchical.getMethod().findSuperMethods()) {
+        add(superS, alreadyImplemented);
+      }
+    }
+    PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper();
+    for (HierarchicalMethodSignature signatureHierarchical : aClass.getVisibleSignatures()) {
+      PsiMethod method = signatureHierarchical.getMethod();
+      PsiClass containingClass = method.getContainingClass();
+      if (containingClass == null) {
+        continue;
+      }
+      if (!aClass.equals(containingClass)
+          && method.hasModifierProperty(PsiModifier.ABSTRACT)
+          && !method.hasModifierProperty(PsiModifier.STATIC)
+          && !method.hasModifierProperty(PsiModifier.PRIVATE)
+          && !alreadyImplemented.contains(method)) {
+        return method;
+      }
+      final List<HierarchicalMethodSignature> superSignatures = signatureHierarchical.getSuperSignatures();
+      for (HierarchicalMethodSignature superSignatureHierarchical : superSignatures) {
+        final PsiMethod superMethod = superSignatureHierarchical.getMethod();
+        if (superMethod.hasModifierProperty(PsiModifier.ABSTRACT) && !resolveHelper.isAccessible(superMethod, method, null)) {
+          return superMethod;
+        }
+      }
+    }
+
+    return checkPackageLocalInSuperClass(aClass);
+  }
+
+  private static PsiMethod checkPackageLocalInSuperClass(PsiClass aClass) {
+    // super class can have package local sbstract methods not accessible for overriding
+    PsiClass superClass = aClass.getSuperClass();
+    if (superClass == null) return null;
+    if ("java.lang.Object".equals(aClass.getQualifiedName())) return null;
+    if (JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, superClass)) return null;
+
+    for (HierarchicalMethodSignature methodSignature : superClass.getVisibleSignatures()) {
+      PsiMethod method = methodSignature.getMethod();
+      if (method.hasModifierProperty(PsiModifier.ABSTRACT) && method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) return method;
+    }
+    return null;
+  }
+
+  private static boolean add(PsiMethod method, Set<PsiMethod> alreadyImplemented) {
+    boolean already = alreadyImplemented.add(method);
+
+    for (PsiMethod superSig : method.findSuperMethods()) {
+      already &= add(superSig, alreadyImplemented);
+    }
+    return already;
+  }
+}
\ No newline at end of file
index 35707bf..f04ee3a 100644 (file)
@@ -26,8 +26,8 @@ import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
-import com.intellij.psi.infos.CandidateInfo;
 import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.ClassUtil;
 import com.intellij.psi.util.PsiTreeUtil;
 import gnu.trove.TObjectHashingStrategy;
 import org.jetbrains.annotations.NotNull;
@@ -76,10 +76,12 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
 import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
-import org.jetbrains.plugins.groovy.overrideImplement.GroovyOverrideImplementUtil;
 import org.jetbrains.plugins.groovy.overrideImplement.quickFix.ImplementMethodsQuickFix;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 
 /**
  * @author ven
@@ -645,12 +647,11 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
     if (typeDefinition.isEnum() || typeDefinition.isAnnotationType()) return;
     if (typeDefinition instanceof GrTypeParameter) return;
 
-    Collection<CandidateInfo> collection = GroovyOverrideImplementUtil.getMethodsToImplement(typeDefinition);
-    if (collection.isEmpty()) return;
+    PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(typeDefinition);
 
-    final PsiElement element = collection.iterator().next().getElement();
-    assert element instanceof PsiNamedElement;
-    String notImplementedMethodName = ((PsiNamedElement)element).getName();
+    if (abstractMethod == null) return;
+
+    String notImplementedMethodName = abstractMethod.getName();
 
     final int startOffset = typeDefinition.getTextOffset();
     int endOffset = typeDefinition.getNameIdentifierGroovy().getTextRange().getEndOffset();