mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 09:12:22 +07:00
[java] Ignore static and final methods in OverrideOnlyInspection
#IDEA-367314 Fixed GitOrigin-RevId: 418750107648323fe36a75c492d05a9e499268b2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6c7da7b25a
commit
69ddce69ae
@@ -1,15 +1,14 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil
|
||||
import com.intellij.codeInspection.apiUsage.ApiUsageProcessor
|
||||
import com.intellij.codeInspection.apiUsage.ApiUsageUastVisitor
|
||||
import com.intellij.lang.jvm.JvmModifier
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.PsiModifierListOwner
|
||||
import com.intellij.psi.util.MethodSignatureUtil
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
@@ -28,7 +27,6 @@ private inline val ANNOTATION_NAME get() = ApiStatus.OverrideOnly::class.java.ca
|
||||
*/
|
||||
@VisibleForTesting
|
||||
class OverrideOnlyInspection : LocalInspectionTool() {
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor =
|
||||
if (AnnotatedApiUsageUtil.canAnnotationBeUsedInFile(ANNOTATION_NAME, holder.file)) {
|
||||
ApiUsageUastVisitor.createPsiElementVisitor(OverrideOnlyProcessor(holder))
|
||||
@@ -38,19 +36,21 @@ class OverrideOnlyInspection : LocalInspectionTool() {
|
||||
}
|
||||
|
||||
private class OverrideOnlyProcessor(private val problemsHolder: ProblemsHolder) : ApiUsageProcessor {
|
||||
|
||||
private fun isLibraryElement(element: PsiElement): Boolean {
|
||||
val containingVirtualFile = PsiUtilCore.getVirtualFile(element)
|
||||
return containingVirtualFile != null && ProjectFileIndex.getInstance(element.project).isInLibraryClasses(containingVirtualFile)
|
||||
private fun PsiMethod.isOverridable(): Boolean {
|
||||
return !hasModifier(JvmModifier.PRIVATE) && !hasModifier(JvmModifier.FINAL) && !hasModifier(JvmModifier.STATIC)
|
||||
}
|
||||
|
||||
private fun isOverrideOnlyMethod(method: PsiMethod) =
|
||||
method.hasAnnotation(ANNOTATION_NAME) ||
|
||||
!method.hasModifierProperty(PsiModifier.STATIC) && method.containingClass?.hasAnnotation(ANNOTATION_NAME) == true
|
||||
private fun isLibraryElement(method: PsiMethod): Boolean {
|
||||
val containingVirtualFile = PsiUtilCore.getVirtualFile(method)
|
||||
return containingVirtualFile != null && ProjectFileIndex.getInstance(method.project).isInLibraryClasses(containingVirtualFile)
|
||||
}
|
||||
|
||||
private fun isOverrideOnlyMethod(method: PsiMethod): Boolean {
|
||||
return method.hasAnnotation(ANNOTATION_NAME) || method.containingClass?.hasAnnotation(ANNOTATION_NAME) == true
|
||||
}
|
||||
|
||||
private fun isInsideOverridenOnlyMethod(sourceNode: UElement, target: PsiMethod): Boolean = sourceNode.getContainingUMethod()?.let {
|
||||
val psiMethod = it.javaPsi as? PsiMethod ?: return false
|
||||
MethodSignatureUtil.areSignaturesEqual(psiMethod, target)
|
||||
MethodSignatureUtil.areSignaturesEqual(it.javaPsi, target)
|
||||
} ?: false
|
||||
|
||||
private fun isSuperCall(qualifier: UExpression?) = qualifier is USuperExpression
|
||||
@@ -67,7 +67,7 @@ class OverrideOnlyInspection : LocalInspectionTool() {
|
||||
}
|
||||
|
||||
override fun processReference(sourceNode: UElement, target: PsiModifierListOwner, qualifier: UExpression?) {
|
||||
if (target is PsiMethod && isOverrideOnlyMethod(target) && isLibraryElement(target)
|
||||
if (target is PsiMethod && target.isOverridable() && isLibraryElement(target) && isOverrideOnlyMethod(target)
|
||||
&& !isSuperOrDelegateCall(sourceNode, target, qualifier)) {
|
||||
val elementToHighlight = sourceNode.sourcePsi ?: return
|
||||
val methodName = HighlightMessageUtil.getSymbolName(target) ?: return
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -8,6 +8,7 @@ import library.KotlinInterface;
|
||||
|
||||
import library.JavaClassOverrideOnly;
|
||||
import library.JavaInterfaceOverrideOnly;
|
||||
import library.JavaMembersOverrideOnly;
|
||||
import library.KotlinClassOverrideOnly;
|
||||
import library.KotlinInterfaceOverrideOnly;
|
||||
|
||||
@@ -20,6 +21,7 @@ class Invoker {
|
||||
|
||||
JavaClassOverrideOnly javaClassOverrideOnly,
|
||||
JavaInterfaceOverrideOnly javaInterfaceOverrideOnly,
|
||||
JavaMembersOverrideOnly javeMembersOverrideOnly,
|
||||
KotlinClassOverrideOnly kotlinClassOverrideOnly,
|
||||
KotlinInterfaceOverrideOnly kotlinInterfaceOverrideOnly
|
||||
) {
|
||||
@@ -29,13 +31,17 @@ class Invoker {
|
||||
kotlinInterface.<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>();
|
||||
|
||||
javaClassOverrideOnly.<warning descr="Method 'overrideOnlyMethod()' can only be overridden">overrideOnlyMethod</warning>();
|
||||
javaClassOverrideOnly.finalMethod(); // no warning because it's a final method
|
||||
javaInterfaceOverrideOnly.<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>();
|
||||
javeMembersOverrideOnly.<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>();
|
||||
javeMembersOverrideOnly.finalMethod(); // no warning because it's a final method
|
||||
kotlinClassOverrideOnly.<warning descr="Method 'overrideOnlyMethod()' can only be overridden">overrideOnlyMethod</warning>();
|
||||
kotlinInterfaceOverrideOnly.<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>();
|
||||
|
||||
//No warning
|
||||
JavaClassOverrideOnly.staticMethod();
|
||||
JavaInterfaceOverrideOnly.staticMethod();
|
||||
JavaMembersOverrideOnly.staticMethod();
|
||||
KotlinClassOverrideOnly.staticMethod();
|
||||
KotlinInterfaceOverrideOnly.staticMethod();
|
||||
}
|
||||
@@ -47,15 +53,19 @@ class Invoker {
|
||||
Consumer<KotlinInterface> d = KotlinInterface::<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>;
|
||||
|
||||
Consumer<JavaClassOverrideOnly> a1 = JavaClassOverrideOnly::<warning descr="Method 'overrideOnlyMethod()' can only be overridden">overrideOnlyMethod</warning>;
|
||||
Consumer<JavaClassOverrideOnly> a2 = JavaClassOverrideOnly::finalMethod; // no warning because it's a final method
|
||||
Consumer<JavaInterfaceOverrideOnly> b1 = JavaInterfaceOverrideOnly::<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>;
|
||||
Consumer<KotlinClassOverrideOnly> c1 = KotlinClassOverrideOnly::<warning descr="Method 'overrideOnlyMethod()' can only be overridden">overrideOnlyMethod</warning>;
|
||||
Consumer<KotlinInterfaceOverrideOnly> d1 = KotlinInterfaceOverrideOnly::<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>;
|
||||
Consumer<JavaMembersOverrideOnly> c1 = JavaMembersOverrideOnly::<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>;
|
||||
Consumer<JavaMembersOverrideOnly> c2 = JavaMembersOverrideOnly::finalMethod; // no warning because it's a final method
|
||||
Consumer<KotlinClassOverrideOnly> d1 = KotlinClassOverrideOnly::<warning descr="Method 'overrideOnlyMethod()' can only be overridden">overrideOnlyMethod</warning>;
|
||||
Consumer<KotlinInterfaceOverrideOnly> e1 = KotlinInterfaceOverrideOnly::<warning descr="Method 'implementOnlyMethod()' can only be overridden">implementOnlyMethod</warning>;
|
||||
|
||||
//No warning
|
||||
Runnable a2 = JavaClassOverrideOnly::staticMethod;
|
||||
Runnable a3 = JavaClassOverrideOnly::staticMethod;
|
||||
Runnable b2 = JavaInterfaceOverrideOnly::staticMethod;
|
||||
Runnable c2 = KotlinClassOverrideOnly::staticMethod;
|
||||
Runnable d2 = KotlinInterfaceOverrideOnly::staticMethod;
|
||||
Runnable c3 = JavaMembersOverrideOnly::staticMethod;
|
||||
Runnable d2 = KotlinClassOverrideOnly::staticMethod;
|
||||
Runnable e2 = KotlinInterfaceOverrideOnly::staticMethod;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,7 @@ public abstract class JavaClassOverrideOnly {
|
||||
|
||||
public abstract void overrideOnlyMethod();
|
||||
|
||||
public static void staticMethod() {}
|
||||
public static void staticMethod() { }
|
||||
|
||||
public final void finalMethod() { }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package library;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.OverrideOnly;
|
||||
|
||||
public abstract class JavaMembersOverrideOnly {
|
||||
@OverrideOnly
|
||||
public abstract void implementOnlyMethod();
|
||||
|
||||
@OverrideOnly
|
||||
public static void staticMethod() { }
|
||||
|
||||
@OverrideOnly
|
||||
public final void finalMethod() { }
|
||||
}
|
||||
Reference in New Issue
Block a user