diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java index a200ebd04f89..b1c858b0d9bb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/UnusedSymbolUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -26,6 +26,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.impl.source.PsiClassImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchHelper; @@ -135,14 +136,15 @@ public class UnusedSymbolUtil { } else { //class maybe used in some weird way, e.g. from XML, therefore the only constructor is used too - if (containingClass != null && method.isConstructor() + boolean isConstructor = method.isConstructor(); + if (containingClass != null && isConstructor && containingClass.getConstructors().length == 1 && isClassUsed(project, containingFile, containingClass, progress, helper)) { return true; } if (isImplicitUsage(project, method, progress)) return true; - if (method.findSuperMethods().length != 0) { + if (!isConstructor && FindSuperElementsHelper.findSuperElements(method).length != 0) { return true; } if (!weAreSureThereAreNoUsages(project, containingFile, method, progress, helper)) { @@ -193,7 +195,7 @@ public class UnusedSymbolUtil { @NotNull PsiFile containingFile, @NotNull PsiMember member, @NotNull ProgressIndicator progress, - final PsiFile ignoreFile, + @Nullable PsiFile ignoreFile, @NotNull Processor usageInfoProcessor) { String name = member.getName(); if (name == null) { @@ -247,10 +249,8 @@ public class UnusedSymbolUtil { } else if (member instanceof PsiMethod) { PsiMethod method = (PsiMethod)member; - JavaMethodFindUsagesOptions o = new JavaMethodFindUsagesOptions(project); - //o.isIncludeOverloadUsages = true; - options = o; - options.isSearchForTextOccurrences = method.isConstructor();; + options = new JavaMethodFindUsagesOptions(project); + options.isSearchForTextOccurrences = method.isConstructor(); } else if (member instanceof PsiVariable) { options = new JavaVariableFindUsagesOptions(project); @@ -271,7 +271,7 @@ public class UnusedSymbolUtil { @NotNull ProgressIndicator progress, @NotNull GlobalUsageHelper helper) { final PsiClass containingClass = member.getContainingClass(); - if (containingClass == null || !(containingClass instanceof PsiClassImpl)) return true; + if (!(containingClass instanceof PsiClassImpl)) return true; final PsiMethod valuesMethod = ((PsiClassImpl)containingClass).getValuesMethod(); return valuesMethod == null || isMethodReferenced(project, containingFile, valuesMethod, progress, helper); } diff --git a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java new file mode 100644 index 000000000000..f52bffd65b4c --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java @@ -0,0 +1,125 @@ +/* + * Copyright 2000-2015 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 com.intellij.psi.impl; + +import com.intellij.psi.*; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Processor; +import com.intellij.util.containers.FactoryMap; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class FindSuperElementsHelper { + @NotNull + public static PsiElement[] findSuperElements(@NotNull PsiElement element) { + if (element instanceof PsiClass) { + PsiClass aClass = (PsiClass) element; + List allSupers = new ArrayList(Arrays.asList(aClass.getSupers())); + for (Iterator iterator = allSupers.iterator(); iterator.hasNext();) { + PsiClass superClass = iterator.next(); + if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) iterator.remove(); + } + return allSupers.toArray(new PsiClass[allSupers.size()]); + } + if (element instanceof PsiMethod) { + PsiMethod method = (PsiMethod) element; + if (method.isConstructor()) { + PsiMethod constructorInSuper = PsiSuperMethodUtil.findConstructorInSuper(method); + if (constructorInSuper != null) { + return new PsiMethod[]{constructorInSuper}; + } + } + else { + PsiMethod[] superMethods = method.findSuperMethods(false); + if (superMethods.length == 0) { + PsiMethod superMethod = getSiblingInheritedViaSubClass(method); + if (superMethod != null) { + superMethods = new PsiMethod[]{superMethod}; + } + } + return superMethods; + } + } + return PsiElement.EMPTY_ARRAY; + } + + public static PsiMethod getSiblingInheritedViaSubClass(@NotNull PsiMethod method) { + return getSiblingInheritedViaSubClass(method, createSubClassCache()); + } + + public static PsiMethod getSiblingInheritedViaSubClass(@NotNull final PsiMethod method, + @NotNull Map subClassCache) { + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return null; + if (method.hasModifierProperty(PsiModifier.STATIC)) return null; + final PsiClass containingClass = method.getContainingClass(); + boolean hasSubClass = containingClass != null && !containingClass.isInterface() && subClassCache.get(containingClass) != null; + if (!hasSubClass) { + return null; + } + final Collection checkedInterfaces = new THashSet(); + final PsiMethod[] result = new PsiMethod[1]; + ClassInheritorsSearch.search(containingClass, true).forEach(new Processor() { + @Override + public boolean process(PsiClass inheritor) { + for (PsiClassType interfaceType : inheritor.getImplementsListTypes()) { + PsiClassType.ClassResolveResult resolved = interfaceType.resolveGenerics(); + PsiClass anInterface = resolved.getElement(); + if (anInterface == null || !checkedInterfaces.add(anInterface)) continue; + for (PsiMethod superMethod : anInterface.findMethodsByName(method.getName(), true)) { + PsiClass superInterface = superMethod.getContainingClass(); + if (superInterface == null) { + continue; + } + + // calculate substitutor of containingClass --> inheritor + PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY); + // calculate substitutor of inheritor --> superInterface + substitutor = TypeConversionUtil.getSuperClassSubstitutor(superInterface, inheritor, substitutor); + + final MethodSignature superSignature = superMethod.getSignature(substitutor); + final MethodSignature derivedSignature = method.getSignature(PsiSubstitutor.EMPTY); + boolean isOverridden = MethodSignatureUtil.isSubsignature(superSignature, derivedSignature); + + if (isOverridden) { + result[0] = superMethod; + return false; + } + } + } + return true; + } + }); + return result[0]; + } + + @NotNull + public static Map createSubClassCache() { + return new FactoryMap() { + @Nullable + @Override + protected PsiClass create(PsiClass aClass) { + return ClassInheritorsSearch.search(aClass, false).findFirst(); + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java index 4c705206a0a1..a0a7a0352ba5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -31,8 +31,8 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.search.searches.AllOverridingMethodsSearch; -import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; @@ -48,12 +48,12 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; public class JavaLineMarkerProvider implements LineMarkerProvider { - - protected final DaemonCodeAnalyzerSettings myDaemonSettings; - protected final EditorColorsManager myColorsManager; + private final DaemonCodeAnalyzerSettings myDaemonSettings; + private final EditorColorsManager myColorsManager; public JavaLineMarkerProvider(DaemonCodeAnalyzerSettings daemonSettings, EditorColorsManager colorsManager) { myDaemonSettings = daemonSettings; @@ -72,19 +72,14 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { method.hasModifierProperty(PsiModifier.ABSTRACT) == superSignature.getMethod().hasModifierProperty(PsiModifier.ABSTRACT); final Icon icon = overrides ? AllIcons.Gutter.OverridingMethod : AllIcons.Gutter.ImplementingMethod; - final MarkerType type = MarkerType.OVERRIDING_METHOD; - ArrowUpLineMarkerInfo info = new ArrowUpLineMarkerInfo(element, icon, type); - return NavigateAction.setNavigateAction(info, "Go to super method", "GotoSuperMethod"); + return createSuperMethodLineMarkerInfo(element, icon, Pass.UPDATE_ALL); } } final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(element); final PsiElement firstChild = element.getFirstChild(); if (interfaceMethod != null && firstChild != null) { - final Icon icon = AllIcons.Gutter.ImplementingMethod; - final MarkerType type = MarkerType.OVERRIDING_METHOD; - ArrowUpLineMarkerInfo info = new ArrowUpLineMarkerInfo(firstChild, icon, type); - return NavigateAction.setNavigateAction(info, "Go to super method", "GotoSuperMethod"); + return createSuperMethodLineMarkerInfo(firstChild, AllIcons.Gutter.ImplementingMethod, Pass.UPDATE_ALL); } if (myDaemonSettings.SHOW_METHOD_SEPARATORS && firstChild == null) { @@ -128,6 +123,12 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { return null; } + @NotNull + private static LineMarkerInfo createSuperMethodLineMarkerInfo(@NotNull PsiElement name, @NotNull Icon icon, int passId) { + ArrowUpLineMarkerInfo info = new ArrowUpLineMarkerInfo(name, icon, MarkerType.OVERRIDING_METHOD, passId); + return NavigateAction.setNavigateAction(info, "Go to super method", IdeActions.ACTION_GOTO_SUPER); + } + private static int getCategory(@NotNull PsiElement element, @NotNull CharSequence documentChars) { if (element instanceof PsiField || element instanceof PsiTypeParameter) return 1; if (element instanceof PsiClass || element instanceof PsiClassInitializer) return 2; @@ -147,37 +148,92 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { @Override public void collectSlowLineMarkers(@NotNull final List elements, @NotNull final Collection result) { ApplicationManager.getApplication().assertReadAccessAllowed(); + Map subClassCache = FindSuperElementsHelper.createSubClassCache(); - Set methods = new HashSet(); + Collection methods = new THashSet(); //noinspection ForLoopReplaceableByForEach for (int i = 0; i < elements.size(); i++) { PsiElement element = elements.get(i); ProgressManager.checkCanceled(); - if (element instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)element; + if (!(element instanceof PsiIdentifier)) continue; + PsiElement parent = element.getParent(); + if (parent instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)parent; if (PsiUtil.canBeOverriden(method)) { methods.add(method); } } - else if (element instanceof PsiClass && !(element instanceof PsiTypeParameter)) { - collectInheritingClasses((PsiClass)element, result); + else if (parent instanceof PsiClass && !(parent instanceof PsiTypeParameter)) { + collectInheritingClasses((PsiClass)parent, result, subClassCache); } } if (!methods.isEmpty()) { - collectOverridingAccessors(methods, result); + collectOverridingMethods(methods, result); + collectSiblingInheritedMethods(methods, result, subClassCache); } } - public static void collectInheritingClasses(PsiClass aClass, Collection result) { + private static void collectSiblingInheritedMethods(@NotNull final Collection methods, + @NotNull Collection result, + @NotNull Map subClassCache) { + for (PsiMethod method : methods) { + ProgressManager.checkCanceled(); + PsiClass aClass = method.getContainingClass(); + if (aClass == null || aClass.hasModifierProperty(PsiModifier.FINAL) || aClass.isInterface()) continue; + + System.err.println("collectSiblingInheritedMethods for "+method+" in "+aClass.getQualifiedName()); + + boolean canHaveSiblingSuper = !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.STATIC) && method.hasModifierProperty(PsiModifier.PUBLIC)&& !method.hasModifierProperty(PsiModifier.FINAL)&& !method.hasModifierProperty(PsiModifier.NATIVE); + System.err.println("canHaveSiblingSuper = " + canHaveSiblingSuper); + if (!canHaveSiblingSuper) continue; + + PsiMethod siblingInheritedViaSubClass = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache); + System.err.println("siblingInheritedViaSubClass = " + siblingInheritedViaSubClass); + if (siblingInheritedViaSubClass == null) { + continue; + } + PsiElement range = getMethodRange(method); + LineMarkerInfo info = createSuperMethodLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, Pass.UPDATE_OVERRIDEN_MARKERS); + result.add(info); + PsiClass sClass = siblingInheritedViaSubClass.getContainingClass(); + String sName = sClass == null ? null : sClass.getQualifiedName(); + System.err.println("Added sibling "+siblingInheritedViaSubClass+" in "+sName+" to results: "+result); + } + } + + @NotNull + private static PsiElement getMethodRange(@NotNull PsiMethod method) { + PsiElement range; + if (method.isPhysical()) { + range = method.getNameIdentifier(); + } + else { + final PsiElement navigationElement = method.getNavigationElement(); + range = navigationElement instanceof PsiNameIdentifierOwner + ? ((PsiNameIdentifierOwner)navigationElement).getNameIdentifier() + : navigationElement; + } + if (range == null) { + range = method; + } + return range; + } + + public static void collectInheritingClasses(@NotNull PsiClass aClass, + @NotNull Collection result, + @NotNull Map subClassCache) { if (aClass.hasModifierProperty(PsiModifier.FINAL)) { return; } if (CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) return; // It's useless to have overridden markers for object. - if (ClassInheritorsSearch.search(aClass, false).findFirst() != null || FunctionalExpressionSearch.search(aClass).findFirst() != null) { + PsiClass subClass = subClassCache.get(aClass); + if (subClass != null || FunctionalExpressionSearch.search(aClass).findFirst() != null) { final Icon icon = aClass.isInterface() ? AllIcons.Gutter.ImplementedMethod : AllIcons.Gutter.OverridenMethod; PsiElement range = aClass.getNameIdentifier(); - if (range == null) range = aClass; + if (range == null) { + range = aClass; + } MarkerType type = MarkerType.SUBCLASSED_CLASS; LineMarkerInfo info = new LineMarkerInfo(range, range.getTextRange(), icon, Pass.UPDATE_OVERRIDEN_MARKERS, type.getTooltip(), @@ -188,7 +244,7 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { } } - private static void collectOverridingAccessors(final Set methods, Collection result) { + private static void collectOverridingMethods(@NotNull final Collection methods, @NotNull Collection result) { final Set overridden = new HashSet(); Set classes = new THashSet(); for (PsiMethod method : methods) { @@ -229,22 +285,9 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { ProgressManager.checkCanceled(); boolean overrides = !method.hasModifierProperty(PsiModifier.ABSTRACT); - final Icon icon = overrides ? AllIcons.Gutter.OverridenMethod : AllIcons.Gutter.ImplementedMethod; - PsiElement range; - if (method.isPhysical()) { - range = method.getNameIdentifier(); - } - else { - final PsiElement navigationElement = method.getNavigationElement(); - if (navigationElement instanceof PsiNameIdentifierOwner) { - range = ((PsiNameIdentifierOwner)navigationElement).getNameIdentifier(); - } - else { - range = navigationElement; - } - } - if (range == null) range = method; + PsiElement range = getMethodRange(method); final MarkerType type = MarkerType.OVERRIDDEN_METHOD; + final Icon icon = overrides ? AllIcons.Gutter.OverridenMethod : AllIcons.Gutter.ImplementedMethod; LineMarkerInfo info = new LineMarkerInfo(range, range.getTextRange(), icon, Pass.UPDATE_OVERRIDEN_MARKERS, type.getTooltip(), type.getNavigationHandler(), @@ -255,8 +298,8 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { } private static class ArrowUpLineMarkerInfo extends MergeableLineMarkerInfo { - private ArrowUpLineMarkerInfo(@NotNull PsiElement element, Icon icon, @NotNull MarkerType markerType) { - super(element, element.getTextRange(), icon, Pass.UPDATE_ALL, markerType.getTooltip(), + private ArrowUpLineMarkerInfo(@NotNull PsiElement element, @NotNull Icon icon, @NotNull MarkerType markerType, int passId) { + super(element, element.getTextRange(), icon, passId, markerType.getTooltip(), markerType.getNavigationHandler(), GutterIconRenderer.Alignment.LEFT); } @@ -274,6 +317,7 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { return myIcon; } + @NotNull @Override public Function getCommonTooltip(@NotNull List infos) { return new Function() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java index 89785c572d84..d956ddcc054d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -34,6 +34,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; +import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.SearchScope; @@ -45,6 +46,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.CommonProcessors; import com.intellij.util.Function; import com.intellij.util.NullableFunction; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -105,9 +107,9 @@ public class MarkerType { }); @Nullable - public static String calculateOverridingMethodTooltip(PsiMethod method, boolean acceptSelf) { + private static String calculateOverridingMethodTooltip(@NotNull PsiMethod method, boolean acceptSelf) { PsiMethod[] superMethods = composeSuperMethods(method, acceptSelf); - if (superMethods == null) return null; + if (superMethods.length == 0) return null; PsiMethod superMethod = superMethods[0]; boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); @@ -121,10 +123,11 @@ public class MarkerType { else{ key = sameSignature ? "method.overrides" : "method.overrides.in"; } - return composeText(superMethods, "", DaemonBundle.message(key), "GotoSuperMethod"); + return composeText(superMethods, "", DaemonBundle.message(key), IdeActions.ACTION_GOTO_SUPER); } - private static String composeText(PsiElement[] methods, String start, String pattern, String actionId) { + @NotNull + private static String composeText(@NotNull PsiElement[] methods, @NotNull String start, @NotNull String pattern, @NotNull String actionId) { Shortcut[] shortcuts = ActionManager.getInstance().getAction(actionId).getShortcutSet().getShortcuts(); Shortcut shortcut = ArrayUtil.getFirstElement(shortcuts); String postfix = "
Click"; @@ -133,9 +136,9 @@ public class MarkerType { return GutterIconTooltipHelper.composeText(Arrays.asList(methods), start, pattern, postfix); } - public static void navigateToOverridingMethod(MouseEvent e, PsiMethod method, boolean acceptSelf) { + private static void navigateToOverridingMethod(MouseEvent e, @NotNull PsiMethod method, boolean acceptSelf) { PsiMethod[] superMethods = composeSuperMethods(method, acceptSelf); - if (superMethods == null) return; + if (superMethods.length == 0) return; boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(superMethods); PsiElementListNavigator.openTargets(e, superMethods, DaemonBundle.message("navigation.title.super.method", method.getName()), @@ -143,17 +146,23 @@ public class MarkerType { new MethodCellRenderer(showMethodNames)); } - @Nullable - private static PsiMethod[] composeSuperMethods(PsiMethod method, boolean acceptSelf) { - PsiMethod[] superMethods = method.findSuperMethods(false); + @NotNull + private static PsiMethod[] composeSuperMethods(@NotNull PsiMethod method, boolean acceptSelf) { + PsiElement[] superElements = FindSuperElementsHelper.findSuperElements(method); + + PsiMethod[] superMethods = ContainerUtil.map(superElements, new Function() { + @Override + public PsiMethod fun(PsiElement element) { + return (PsiMethod)element; + } + }, PsiMethod.EMPTY_ARRAY); if (acceptSelf) { superMethods = ArrayUtil.prepend(method, superMethods); } - if (superMethods.length == 0) return null; return superMethods; } - private static PsiElement getParentMethod(PsiElement element) { + private static PsiElement getParentMethod(@NotNull PsiElement element) { final PsiElement parent = element.getParent(); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(parent); return interfaceMethod != null ? interfaceMethod : parent; @@ -179,7 +188,7 @@ public class MarkerType { } }); - public static String getOverriddenMethodTooltip(final PsiMethod method) { + private static String getOverriddenMethodTooltip(@NotNull PsiMethod method) { PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(5); OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter(processor)); @@ -206,7 +215,7 @@ public class MarkerType { return composeText(overridings, start, pattern, IdeActions.ACTION_GOTO_IMPLEMENTATION); } - public static void navigateToOverriddenMethod(MouseEvent e, final PsiMethod method) { + private static void navigateToOverriddenMethod(MouseEvent e, @NotNull final PsiMethod method) { if (DumbService.isDumb(method.getProject())) { DumbService.getInstance(method.getProject()).showDumbModeNotification( "Navigation to overriding classes is not possible during index update"); @@ -267,7 +276,7 @@ public class MarkerType { } }); - public static String getSubclassedClassTooltip(PsiClass aClass) { + private static String getSubclassedClassTooltip(@NotNull PsiClass aClass) { PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(5, new THashSet()); ClassInheritorsSearch.search(aClass, true).forEach(new PsiElementProcessorAdapter(processor)); @@ -298,7 +307,7 @@ public class MarkerType { return composeText(subclasses, start, pattern, IdeActions.ACTION_GOTO_IMPLEMENTATION); } - public static void navigateToSubclassedClass(MouseEvent e, final PsiClass aClass) { + private static void navigateToSubclassedClass(MouseEvent e, @NotNull final PsiClass aClass) { if (DumbService.isDumb(aClass.getProject())) { DumbService.getInstance(aClass.getProject()).showDumbModeNotification("Navigation to overriding methods is not possible during index update"); return; @@ -331,7 +340,7 @@ public class MarkerType { private final PsiClass myClass; private final PsiClassOrFunctionalExpressionListCellRenderer myRenderer; - public SubclassUpdater(PsiClass aClass, PsiClassOrFunctionalExpressionListCellRenderer renderer) { + private SubclassUpdater(@NotNull PsiClass aClass, @NotNull PsiClassOrFunctionalExpressionListCellRenderer renderer) { super(aClass.getProject(), SEARCHING_FOR_OVERRIDDEN_METHODS); myClass = aClass; myRenderer = renderer; @@ -374,14 +383,13 @@ public class MarkerType { } }); } - } private static class OverridingMethodsUpdater extends ListBackgroundUpdaterTask { private final PsiMethod myMethod; private final PsiElementListCellRenderer myRenderer; - public OverridingMethodsUpdater(PsiMethod method, PsiElementListCellRenderer renderer) { + private OverridingMethodsUpdater(@NotNull PsiMethod method, @NotNull PsiElementListCellRenderer renderer) { super(method.getProject(), SEARCHING_FOR_OVERRIDING_METHODS); myMethod = method; myRenderer = renderer; diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/actions/ShowSiblingsAction.java b/java/java-impl/src/com/intellij/codeInsight/hint/actions/ShowSiblingsAction.java index 41aea6e9c181..11a101da3edd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/actions/ShowSiblingsAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/actions/ShowSiblingsAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -29,15 +29,11 @@ import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.presentation.java.SymbolPresentationUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Consumer; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; public class ShowSiblingsAction extends ShowImplementationsAction { - public ShowSiblingsAction() { - super(); - } - @Override - public void performForContext(DataContext dataContext, final boolean invokedByShortcut) { + public void performForContext(@NotNull DataContext dataContext, final boolean invokedByShortcut) { final Project project = CommonDataKeys.PROJECT.getData(dataContext); final PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext); @@ -61,7 +57,7 @@ public class ShowSiblingsAction extends ShowImplementationsAction { } final NavigatablePsiElement[] superElements = (NavigatablePsiElement[])findSuperElements(element); - if (superElements == null || superElements.length == 0) return; + if (superElements.length == 0) return; final boolean isMethod = superElements[0] instanceof PsiMethod; final JBPopup popup = PsiElementListNavigator.navigateOrCreatePopup(superElements, "Choose super " + (isMethod ? "method" : "class or interface"), "Super " + (isMethod ? "methods" : "classes/interfaces"), @@ -81,11 +77,11 @@ public class ShowSiblingsAction extends ShowImplementationsAction { } private void showSiblings(boolean invokedByShortcut, - Project project, + @NotNull Project project, Editor editor, PsiFile file, boolean invokedFromEditor, - PsiElement element) { + @NotNull PsiElement element) { final PsiElement[] impls = getSelfAndImplementations(editor, element, createImplementationsSearcher(), false); final String text = SymbolPresentationUtil.getSymbolPresentableText(element); showImplementations(impls, project, text, editor, file, element, invokedFromEditor, invokedByShortcut); @@ -96,11 +92,11 @@ public class ShowSiblingsAction extends ShowImplementationsAction { return false; } - @Nullable + @NotNull private static PsiElement[] findSuperElements(final PsiElement element) { PsiNameIdentifierOwner parent = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiClass.class); if (parent == null) { - return null; + return PsiElement.EMPTY_ARRAY; } return FindSuperElementsHelper.findSuperElements(parent); diff --git a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java index 95668b59fa69..1663d31da4a8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -32,7 +32,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class JavaGotoSuperHandler implements CodeInsightActionHandler { @Override @@ -41,7 +40,7 @@ public class JavaGotoSuperHandler implements CodeInsightActionHandler { int offset = editor.getCaretModel().getOffset(); PsiElement[] superElements = findSuperElements(file, offset); - if (superElements == null || superElements.length == 0) return; + if (superElements.length == 0) return; if (superElements.length == 1) { PsiElement superElement = superElements[0].getNavigationElement(); final PsiFile containingFile = superElement.getContainingFile(); @@ -50,24 +49,25 @@ public class JavaGotoSuperHandler implements CodeInsightActionHandler { if (virtualFile == null) return; OpenFileDescriptor descriptor = new OpenFileDescriptor(project, virtualFile, superElement.getTextOffset()); FileEditorManager.getInstance(project).openTextEditor(descriptor, true); - } else { - if (superElements[0] instanceof PsiMethod) { - boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature((PsiMethod[])superElements); - PsiElementListNavigator.openTargets(editor, (PsiMethod[])superElements, - CodeInsightBundle.message("goto.super.method.chooser.title"), - CodeInsightBundle.message("goto.super.method.findUsages.title", ((PsiMethod)superElements[0]).getName()), - new MethodCellRenderer(showMethodNames)); - } - else { - NavigationUtil.getPsiElementPopup(superElements, CodeInsightBundle.message("goto.super.class.chooser.title")).showInBestPositionFor(editor); - } + } + else if (superElements[0] instanceof PsiMethod) { + boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature((PsiMethod[])superElements); + PsiElementListNavigator.openTargets(editor, (PsiMethod[])superElements, + CodeInsightBundle.message("goto.super.method.chooser.title"), + CodeInsightBundle + .message("goto.super.method.findUsages.title", ((PsiMethod)superElements[0]).getName()), + new MethodCellRenderer(showMethodNames)); + } + else { + NavigationUtil.getPsiElementPopup(superElements, CodeInsightBundle.message("goto.super.class.chooser.title")) + .showInBestPositionFor(editor); } } - @Nullable - private PsiElement[] findSuperElements(PsiFile file, int offset) { + @NotNull + private PsiElement[] findSuperElements(@NotNull PsiFile file, int offset) { PsiElement element = getElement(file, offset); - if (element == null) return null; + if (element == null) return PsiElement.EMPTY_ARRAY; final PsiElement psiElement = PsiTreeUtil.getParentOfType(element, PsiFunctionalExpression.class, PsiMember.class); if (psiElement instanceof PsiFunctionalExpression) { @@ -79,13 +79,13 @@ public class JavaGotoSuperHandler implements CodeInsightActionHandler { final PsiNameIdentifierOwner parent = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class); if (parent == null) { - return null; + return PsiElement.EMPTY_ARRAY; } return FindSuperElementsHelper.findSuperElements(parent); } - protected PsiElement getElement(PsiFile file, int offset) { + protected PsiElement getElement(@NotNull PsiFile file, int offset) { return file.findElementAt(offset); } diff --git a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java index 5e3a2d10c36d..a1a22653a60e 100644 --- a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java +++ b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -26,6 +26,7 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; +import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.presentation.java.SymbolPresentationUtil; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; @@ -34,6 +35,7 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -41,20 +43,24 @@ public class SuperMethodWarningUtil { private SuperMethodWarningUtil() {} @NotNull - public static PsiMethod[] checkSuperMethods(final PsiMethod method, String actionString) { - return checkSuperMethods(method, actionString, null); + public static PsiMethod[] checkSuperMethods(@NotNull PsiMethod method, @NotNull String actionString) { + return checkSuperMethods(method, actionString, Collections.emptyList()); } @NotNull - public static PsiMethod[] checkSuperMethods(final PsiMethod method, String actionString, Collection ignore) { + public static PsiMethod[] checkSuperMethods(@NotNull PsiMethod method, @NotNull String actionString, @NotNull Collection ignore) { PsiClass aClass = method.getContainingClass(); if (aClass == null) return new PsiMethod[]{method}; final Collection superMethods = DeepestSuperMethodsSearch.search(method).findAll(); - if (ignore != null) { - superMethods.removeAll(ignore); - } + superMethods.removeAll(ignore); + if (superMethods.isEmpty()) { + PsiMethod siblingSuperMethod = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method); + if (siblingSuperMethod != null) { + superMethods.add(siblingSuperMethod); + } + } if (superMethods.isEmpty()) return new PsiMethod[]{method}; @@ -85,7 +91,7 @@ public class SuperMethodWarningUtil { } - public static PsiMethod checkSuperMethod(final PsiMethod method, String actionString) { + public static PsiMethod checkSuperMethod(@NotNull PsiMethod method, @NotNull String actionString) { PsiClass aClass = method.getContainingClass(); if (aClass == null) return method; @@ -110,10 +116,10 @@ public class SuperMethodWarningUtil { return null; } - public static void checkSuperMethod(final PsiMethod method, - final String actionString, - final PsiElementProcessor processor, - final Editor editor) { + public static void checkSuperMethod(@NotNull PsiMethod method, + @NotNull String actionString, + @NotNull final PsiElementProcessor processor, + @NotNull Editor editor) { PsiClass aClass = method.getContainingClass(); if (aClass == null) { processor.execute(method); @@ -137,7 +143,7 @@ public class SuperMethodWarningUtil { return; } - final PsiMethod[] methods = new PsiMethod[]{superMethod, method}; + final PsiMethod[] methods = {superMethod, method}; final String renameBase = actionString + " base method"; final String renameCurrent = actionString + " only current method"; final JBList list = new JBList(renameBase, renameCurrent); @@ -148,6 +154,7 @@ public class SuperMethodWarningUtil { .setResizable(false) .setRequestFocus(true) .setItemChoosenCallback(new Runnable() { + @Override public void run() { final Object value = list.getSelectedValue(); if (value instanceof String) { diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java index a614854ba728..797a22e8d68a 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -61,7 +61,7 @@ public class JavaAllOverridingMethodsSearcher implements QueryExecutor allSupers = new ArrayList(Arrays.asList(aClass.getSupers())); - for (Iterator iterator = allSupers.iterator(); iterator.hasNext();) { - PsiClass superClass = iterator.next(); - if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) iterator.remove(); - } - return allSupers.toArray(new PsiClass[allSupers.size()]); - } else if (element instanceof PsiMethod) { - PsiMethod method = (PsiMethod) element; - if (method.isConstructor()) { - PsiMethod constructorInSuper = PsiSuperMethodUtil.findConstructorInSuper(method); - if (constructorInSuper != null) { - return new PsiMethod[]{constructorInSuper}; - } - } else { - return method.findSuperMethods(false); - } - } - return null; - } - -} diff --git a/java/java-tests/testData/codeInsight/gotosuper/SiblingInheritance.after.java b/java/java-tests/testData/codeInsight/gotosuper/SiblingInheritance.after.java new file mode 100644 index 000000000000..8c4289162396 --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotosuper/SiblingInheritance.after.java @@ -0,0 +1,11 @@ +package z; + +interface I { + void run(); +} +abstract class A { + public void run() {} +} + +class Foo extends A implements I { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/gotosuper/SiblingInheritance.java b/java/java-tests/testData/codeInsight/gotosuper/SiblingInheritance.java new file mode 100644 index 000000000000..d8d3e2970a93 --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotosuper/SiblingInheritance.java @@ -0,0 +1,11 @@ +package z; + +interface I { + void run(); +} +abstract class A { + public void run() {} +} + +class Foo extends A implements I { +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/navigation/JavaGotoSuperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java similarity index 51% rename from java/java-tests/testSrc/com/intellij/codeInsight/navigation/JavaGotoSuperTest.java rename to java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java index e666583564b0..1a04900bc371 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/navigation/JavaGotoSuperTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.codeInsight.navigation; +package com.intellij.codeInsight.daemon.impl; import com.intellij.JavaTestUtil; import com.intellij.codeInsight.CodeInsightActionHandler; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.LineMarkerInfo; -import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; +import com.intellij.ide.DataManager; import com.intellij.lang.CodeInsightActions; import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Document; import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -38,7 +39,7 @@ public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase { return JavaTestUtil.getJavaTestDataPath(); } - protected String getBasePath() { + private static String getBasePath() { return "/codeInsight/gotosuper/"; } @@ -46,6 +47,13 @@ public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase { doTest(); } + private void doTest() { + configureByFile(getBasePath() + getTestName(false) + ".java"); + final CodeInsightActionHandler handler = CodeInsightActions.GOTO_SUPER.forLanguage(JavaLanguage.INSTANCE); + handler.invoke(getProject(), getEditor(), getFile()); + checkResultByFile(getBasePath() + getTestName(false) + ".after.java"); + } + public void testLambdaMarker() throws Exception { configureByFile(getBasePath() + getTestName(false) + ".java"); int offset = myEditor.getCaretModel().getOffset(); @@ -67,10 +75,52 @@ public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase { fail("Gutter expected"); } - private void doTest() throws Throwable { - configureByFile(getBasePath() + getTestName(false) + ".java"); - final CodeInsightActionHandler handler = CodeInsightActions.GOTO_SUPER.forLanguage(JavaLanguage.INSTANCE); - handler.invoke(getProject(), getEditor(), getFile()); - checkResultByFile(getBasePath() + getTestName(false) + ".after.java"); + public void testSiblingInheritance() throws Throwable { + doTest(); } + + public void testSiblingInheritanceLineMarkers() throws Throwable { + configureByFile(getBasePath() + "SiblingInheritance.java"); + PsiJavaFile file = (PsiJavaFile)getFile(); + PsiClass i = JavaPsiFacade.getInstance(getProject()).findClass("z.I", GlobalSearchScope.fileScope(file)); + PsiClass a = JavaPsiFacade.getInstance(getProject()).findClass("z.A", GlobalSearchScope.fileScope(file)); + PsiMethod iRun = i.getMethods()[0]; + assertEquals("run", iRun.getName()); + PsiMethod aRun = a.getMethods()[0]; + assertEquals("run", aRun.getName()); + doHighlighting(); + Document document = getEditor().getDocument(); + List markers = DaemonCodeAnalyzerImpl.getLineMarkers(document, getProject()); + assertTrue(markers.size() >= 2); + LineMarkerInfo iMarker = findMarkerWithElement(markers, iRun.getNameIdentifier()); + assertSame(MarkerType.OVERRIDDEN_METHOD.getNavigationHandler(), iMarker.getNavigationHandler()); + + LineMarkerInfo aMarker = findMarkerWithElement(markers, aRun.getNameIdentifier()); + assertSame(MarkerType.OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler()); + } + + private static LineMarkerInfo findMarkerWithElement(List markers, PsiElement psiMethod) { + LineMarkerInfo marker = ContainerUtil.find(markers, info -> { + return info.getElement().equals(psiMethod); + }); + assertNotNull(markers.toString(), marker); + return marker; + } + + public void testSiblingInheritanceGoDown() throws Throwable { + configureByFile(getBasePath() + "SiblingInheritance.after.java"); + AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_GOTO_IMPLEMENTATION); + AnActionEvent event = new AnActionEvent( + null, + DataManager.getInstance().getDataContextFromFocus().getResultSync(), + "", + action.getTemplatePresentation(), + ActionManager.getInstance(), + 0); + action.update(event); + assertTrue(event.getPresentation().isEnabledAndVisible()); + action.actionPerformed(event); + checkResultByFile(getBasePath() + "SiblingInheritance.java"); + } + } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspectionBase.java index ca8ec8f0ea0d..d5c2cacee541 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspectionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -17,6 +17,8 @@ package com.siyeh.ig.abstraction; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.*; +import com.intellij.psi.impl.FindSuperElementsHelper; +import com.intellij.util.ArrayUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -28,10 +30,10 @@ import com.siyeh.ig.ui.ExternalizableStringSet; import org.jetbrains.annotations.NotNull; public class PublicMethodNotExposedInInterfaceInspectionBase extends BaseInspection { - @SuppressWarnings({"PublicField"}) + @SuppressWarnings("PublicField") public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet(); - @SuppressWarnings({"PublicField"}) + @SuppressWarnings("PublicField") public boolean onlyWarnIfContainingClassImplementsAnInterface = false; @Override @@ -115,7 +117,11 @@ public class PublicMethodNotExposedInInterfaceInspectionBase extends BaseInspect } private boolean exposedInInterface(PsiMethod method) { - final PsiMethod[] superMethods = method.findSuperMethods(); + PsiMethod[] superMethods = method.findSuperMethods(); + PsiMethod siblingInherited = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method); + if (siblingInherited != null && !ArrayUtil.contains(siblingInherited, superMethods)) { + superMethods = ArrayUtil.append(superMethods, siblingInherited); + } for (final PsiMethod superMethod : superMethods) { final PsiClass superClass = superMethod.getContainingClass(); if (superClass == null) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java index 375807f13b3e..74ac21ee25cc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java @@ -18,6 +18,7 @@ package com.siyeh.ig.classlayout; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; +import com.intellij.psi.impl.FindSuperElementsHelper; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -67,6 +68,10 @@ public class NoopMethodInAbstractClassInspection extends BaseInspection { if (!MethodUtils.isEmpty(method)) { return; } + if (FindSuperElementsHelper.getSiblingInheritedViaSubClass(method) != null) { + // it may be an explicit intention to have non-abstract method here in order to sibling-inherit the method in subclass + return; + } registerMethodError(method); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyLineMarkerProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyLineMarkerProvider.java index 17045deb6ff7..7bfc95d97102 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyLineMarkerProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyLineMarkerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -33,6 +33,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.impl.FindSuperElementsHelper; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.search.searches.AllOverridingMethodsSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; @@ -60,18 +61,15 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import javax.swing.*; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author ilyas * Same logic as for Java LMP */ public class GroovyLineMarkerProvider implements LineMarkerProvider { - protected final DaemonCodeAnalyzerSettings myDaemonSettings; - protected final EditorColorsManager myColorsManager; + private final DaemonCodeAnalyzerSettings myDaemonSettings; + private final EditorColorsManager myColorsManager; public GroovyLineMarkerProvider(DaemonCodeAnalyzerSettings daemonSettings, EditorColorsManager colorsManager) { myDaemonSettings = daemonSettings; @@ -152,7 +150,7 @@ public class GroovyLineMarkerProvider implements LineMarkerProvider { return null; } - private static boolean hasSuperMethods(GrMethod method) { + private static boolean hasSuperMethods(@NotNull GrMethod method) { final GrReflectedMethod[] reflectedMethods = method.getReflectedMethods(); if (reflectedMethods.length > 0) { for (GrReflectedMethod reflectedMethod : reflectedMethods) { @@ -166,7 +164,7 @@ public class GroovyLineMarkerProvider implements LineMarkerProvider { } } - private static int getGroovyCategory(PsiElement element, CharSequence documentChars) { + private static int getGroovyCategory(@NotNull PsiElement element, @NotNull CharSequence documentChars) { if (element instanceof GrVariableDeclarationImpl) { GrVariable[] variables = ((GrVariableDeclarationImpl)element).getVariables(); if (variables.length == 1 && variables[0] instanceof GrField && variables[0].getInitializerGroovy() instanceof GrClosableBlock) { @@ -193,6 +191,7 @@ public class GroovyLineMarkerProvider implements LineMarkerProvider { @Override public void collectSlowLineMarkers(@NotNull final List elements, @NotNull final Collection result) { Set methods = new HashSet(); + Map subClassCache = FindSuperElementsHelper.createSubClassCache(); for (PsiElement element : elements) { ProgressManager.checkCanceled(); if (element instanceof GrField) { @@ -208,13 +207,13 @@ public class GroovyLineMarkerProvider implements LineMarkerProvider { } } else if (element instanceof PsiClass && !(element instanceof PsiTypeParameter)) { - JavaLineMarkerProvider.collectInheritingClasses((PsiClass)element, result); + JavaLineMarkerProvider.collectInheritingClasses((PsiClass)element, result, subClassCache); } } collectOverridingMethods(methods, result); } - private static void collectOverridingMethods(final Set methods, Collection result) { + private static void collectOverridingMethods(@NotNull final Set methods, @NotNull Collection result) { final Set overridden = new HashSet(); Set classes = new THashSet(); @@ -264,7 +263,7 @@ public class GroovyLineMarkerProvider implements LineMarkerProvider { } } - private static boolean isCorrectTarget(PsiMethod method) { + private static boolean isCorrectTarget(@NotNull PsiMethod method) { if (method instanceof GrTraitMethod) return false; final PsiElement navigationElement = method.getNavigationElement();