From 20b41d27934119dcf1863bd346d8e5b1d5d7b5fc Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 25 Aug 2014 12:18:06 +0400 Subject: [PATCH] allow plugins to suppress "interface never implemented" and "abstract class has no concrete subclass" inspections for classes which are implemented by proxies at runtime (e.g. for classes extending DomElement in DevKit) --- .../ImplementedAtRuntimeCondition.java | 29 ++++++++++++++++++ .../siyeh/ig/psiutils/InheritanceUtil.java | 6 ++++ plugins/devkit/resources/META-INF/plugin.xml | 1 + .../DevKitImplementedAtRuntimeCondition.java | 30 +++++++++++++++++++ .../DevKitImplicitUsageProvider.java | 2 +- .../DevKitImplicitUsageProviderTest.java | 3 +- resources/src/META-INF/IdeaPlugin.xml | 2 ++ 7 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java create mode 100644 plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java new file mode 100644 index 000000000000..55918450f481 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java @@ -0,0 +1,29 @@ +/* + * 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 com.intellij.codeInspection.inheritance; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public abstract class ImplementedAtRuntimeCondition { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.codeInsight.implementedAtRuntime"); + + public abstract boolean isImplementedAtRuntime(@NotNull PsiClass psiClass); +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java index 9661ba10e4c4..faea625f1db5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java @@ -15,6 +15,7 @@ */ package com.siyeh.ig.psiutils; +import com.intellij.codeInspection.inheritance.ImplementedAtRuntimeCondition; import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiClass; @@ -80,6 +81,11 @@ public class InheritanceUtil { public static boolean hasImplementation(@NotNull PsiClass aClass) { final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject()); if (aClass.isInterface() && FunctionalExpressionSearch.search(aClass, scope).findFirst() != null) return true; + for (ImplementedAtRuntimeCondition condition : ImplementedAtRuntimeCondition.EP_NAME.getExtensions()) { + if (condition.isImplementedAtRuntime(aClass)) { + return true; + } + } final Query search = ClassInheritorsSearch.search(aClass, scope, true, true); return !search.forEach(new Processor() { @Override diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 0a9501ebef94..ef3688448fda 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -152,6 +152,7 @@ implementationClass="org.jetbrains.idea.devkit.navigation.DescriptionTypeRelatedItemLineMarkerProvider"/> + diff --git a/plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java b/plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java new file mode 100644 index 000000000000..f6cbe5e97a74 --- /dev/null +++ b/plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java @@ -0,0 +1,30 @@ +/* + * 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.idea.devkit.inspections; + +import com.intellij.codeInspection.inheritance.ImplementedAtRuntimeCondition; +import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class DevKitImplementedAtRuntimeCondition extends ImplementedAtRuntimeCondition { + @Override + public boolean isImplementedAtRuntime(@NotNull PsiClass psiClass) { + return DevKitImplicitUsageProvider.isDomElementClass(psiClass); + } +} diff --git a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java index fa87c70ad337..7aeb7a047046 100644 --- a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java +++ b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java @@ -50,7 +50,7 @@ public class DevKitImplicitUsageProvider implements ImplicitUsageProvider { return false; } - private static boolean isDomElementClass(PsiClass psiClass) { + static boolean isDomElementClass(PsiClass psiClass) { if (psiClass.isEnum() || psiClass.isAnnotationType() || psiClass.hasModifierProperty(PsiModifier.PRIVATE)) { diff --git a/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java b/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java index bf33c2174159..cdfbd460643f 100644 --- a/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java +++ b/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; import com.intellij.openapi.application.PluginPathManager; import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.siyeh.ig.inheritance.AbstractClassNeverImplementedInspection; @TestDataPath("$CONTENT_ROOT/testData/inspections/implicitUsage") public class DevKitImplicitUsageProviderTest extends LightCodeInsightFixtureTestCase { @@ -37,7 +38,7 @@ public class DevKitImplicitUsageProviderTest extends LightCodeInsightFixtureTest myFixture.addClass("package com.intellij.util.xml; public interface DomElementVisitor {}"); myFixture.addClass("package com.intellij.util.xml; public interface GenericAttributeValue extends DomElement {}"); - myFixture.enableInspections(new UnusedSymbolLocalInspection(), new UnusedDeclarationInspection()); + myFixture.enableInspections(new UnusedSymbolLocalInspection(), new UnusedDeclarationInspection(), new AbstractClassNeverImplementedInspection()); } public void testImplicitUsagesDomElement() { diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index d96c213a18fd..ec30ca2614dc 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -46,6 +46,8 @@ +