diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 73eb0991a417..d49306eb8602 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -91,7 +91,7 @@ implementationClass="org.jetbrains.idea.devkit.inspections.ExtensionPointBeanClassInspection"/> - + diff --git a/plugins/devkit/src/inspections/DevKitEntryPoints.java b/plugins/devkit/src/inspections/DevKitEntryPoints.java deleted file mode 100644 index bb06e7171462..000000000000 --- a/plugins/devkit/src/inspections/DevKitEntryPoints.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2000-2013 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.codeInsight.daemon.ImplicitUsageProvider; -import com.intellij.psi.*; - -/** - * User: anna - */ -public class DevKitEntryPoints implements ImplicitUsageProvider { - - @Override - public boolean isImplicitUsage(PsiElement element) { - if (element instanceof PsiClass) { - final PsiClass psiClass = (PsiClass)element; - if (psiClass.isEnum() || - psiClass.isAnnotationType() || - psiClass.hasModifierProperty(PsiModifier.PRIVATE)) { - return false; - } - - final PsiClass domClass = - JavaPsiFacade.getInstance(element.getProject()).findClass("com.intellij.util.xml.DomElement", element.getResolveScope()); - if (domClass != null && psiClass.isInheritor(domClass, true)) { - return true; - } - } - return false; - } - - @Override - public boolean isImplicitRead(PsiElement element) { - return false; - } - - @Override - public boolean isImplicitWrite(PsiElement element) { - return false; - } -} diff --git a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java new file mode 100644 index 000000000000..fa87c70ad337 --- /dev/null +++ b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2013 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.codeInsight.daemon.ImplicitUsageProvider; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import org.jetbrains.annotations.Nullable; + +/** + * @author anna + */ +public class DevKitImplicitUsageProvider implements ImplicitUsageProvider { + + @Override + public boolean isImplicitUsage(PsiElement element) { + if (element instanceof PsiClass) { + final PsiClass psiClass = (PsiClass)element; + return isDomElementClass(psiClass); + } + + if (element instanceof PsiMethod) { + PsiMethod psiMethod = (PsiMethod)element; + return isDomElementMethod(psiMethod); + } + + return false; + } + + @Override + public boolean isImplicitRead(PsiElement element) { + return false; + } + + @Override + public boolean isImplicitWrite(PsiElement element) { + return false; + } + + private static boolean isDomElementClass(PsiClass psiClass) { + if (psiClass.isEnum() || + psiClass.isAnnotationType() || + psiClass.hasModifierProperty(PsiModifier.PRIVATE)) { + return false; + } + + return isDomElementInheritor(psiClass); + } + + private static boolean isDomElementMethod(PsiMethod psiMethod) { + if (!psiMethod.hasModifierProperty(PsiModifier.PUBLIC) || + psiMethod.hasModifierProperty(PsiModifier.STATIC) || + psiMethod.isConstructor() || + psiMethod.getParameterList().getParametersCount() > 1) { + return false; + } + + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass == null) { + return false; + } + + if (!isDomElementClass(containingClass)) { + return isDomElementVisitorMethod(psiMethod, containingClass); + } + + final PsiType returnType = psiMethod.getReturnType(); + if (!(returnType instanceof PsiClassType)) { + return false; + } + + PsiClassType returnClassType = (PsiClassType)returnType; + + // Dom getDom(), GenericAttributeValue getAttr(), ... + final PsiClass returnResolved = returnClassType.resolve(); + if (isDomElementInheritor(returnResolved)) { + return true; + } + + // List getDoms() + if (returnClassType.getParameterCount() == 1 && + InheritanceUtil.isInheritor(returnResolved, CommonClassNames.JAVA_UTIL_LIST)) { + final PsiType listType = returnClassType.getParameters()[0]; + return isDomElementInheritor(listType); + } + + return false; + } + + private static boolean isDomElementVisitorMethod(PsiMethod method, + PsiClass containingClass) { + if (method.getReturnType() != PsiType.VOID || + !method.getName().startsWith("visit") || + method.getParameterList().getParametersCount() != 1 || + !InheritanceUtil.isInheritor(containingClass, "com.intellij.util.xml.DomElementVisitor")) { + return false; + } + + final PsiType psiType = method.getParameterList().getParameters()[0].getType(); + return isDomElementInheritor(psiType); + } + + private static boolean isDomElementInheritor(@Nullable PsiType psiType) { + return InheritanceUtil.isInheritor(psiType, "com.intellij.util.xml.DomElement"); + } + + private static boolean isDomElementInheritor(@Nullable PsiClass psiClass) { + return InheritanceUtil.isInheritor(psiClass, "com.intellij.util.xml.DomElement"); + } +} \ No newline at end of file diff --git a/plugins/devkit/testData/codeInsight/ImplicitUsagesDomElement.java b/plugins/devkit/testData/codeInsight/ImplicitUsagesDomElement.java new file mode 100644 index 000000000000..2bbdc6b95671 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/ImplicitUsagesDomElement.java @@ -0,0 +1,32 @@ +import java.util.List; +import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.GenericAttributeValue; + +public abstract class ImplicitUsagesDomElement implements DomElement { + + public abstract GenericAttributeValue getStringAttribute(); + public abstract ImplicitUsagesDomElement getDomElement(); + + public abstract List getDoms(); + + public abstract ImplicitUsagesDomElement addDom(); + public abstract ImplicitUsagesDomElement addDomIndexed(int index); + + + // invalid =========== + + private GenericAttributeValue getStringAttributePrivate() { return null; }; + public static GenericAttributeValue getStringAttributeStatic() { return null; }; + + public String getNonDomString() { return null; }; + public int getNonDomPrimitiveType() { return 0; } + + private int normalPrivateMethod() { return 0; } + + public List getNonDomList() { return null; } + + + public abstract ImplicitUsagesDomElement addDomMoreThanOneParam(int i, int j); + public String addNonDom() { return null; } + +} \ No newline at end of file diff --git a/plugins/devkit/testData/codeInsight/ImplicitUsagesDomElementVisitor.java b/plugins/devkit/testData/codeInsight/ImplicitUsagesDomElementVisitor.java new file mode 100644 index 000000000000..938a9e8632d5 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/ImplicitUsagesDomElementVisitor.java @@ -0,0 +1,30 @@ +import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.DomElementVisitor; + +public class ImplicitUsagesDomElementVisitor implements DomElementVisitor { + + public static void main(String[] args) {} // suppress class unused + + interface MyDom extends DomElement {} + + public void visitMyDom(MyDom myDom) { myDom = null; } + public void visit(MyDom myDom) { myDom = null; } + + // invalid =========== + public String nonVoidReturnTypeMethod(MyDom myDom) { myDom = null; return null; } + public void doesNotStartWithVisit(MyDom myDom) { myDom = null; } + public void nonDomParameter(int i) { i = 0; } + private void visitMyDomMoreThanOneParam(MyDom myDom, int index) { myDom = null; index = 0; } + private void visitMyDomPrivate(MyDom myDom) { myDom = null; } + public static void visitMyDomStatic(MyDom myDom) { myDom = null; } + + + public static class NonDomElementVisitorClass { + + public static void main(String[] args) {} // suppress class unused + + public void visitMyDom(MyDom myDom) { myDom = null; } + + } + +} \ No newline at end of file diff --git a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.groovy b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.groovy index 25c19d643ee4..07df3077a4a7 100644 --- a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.groovy +++ b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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 org.jetbrains.idea.devkit.codeInsight import com.intellij.codeInsight.TargetElementUtilBase import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInspection.LocalInspectionTool +import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection +import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PluginPathManager import com.intellij.psi.ElementDescriptionUtil @@ -196,6 +198,24 @@ public class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase { myFixture.testHighlighting(true, true, true); } + public void testImplicitUsagesDomElement() { + myFixture.addClass("package com.intellij.util.xml; public interface DomElement {}") + myFixture.addClass("package com.intellij.util.xml; public interface GenericAttributeValue extends DomElement {}") + + myFixture.enableInspections(new UnusedSymbolLocalInspection(), new UnusedDeclarationInspection()) + myFixture.configureByFile("ImplicitUsagesDomElement.java") + myFixture.testHighlighting() + } + + public void testImplicitUsagesDomElementVisitor() { + myFixture.addClass("package com.intellij.util.xml; public interface DomElement {}") + myFixture.addClass("package com.intellij.util.xml; public interface DomElementVisitor {}") + + myFixture.enableInspections(new UnusedSymbolLocalInspection(), new UnusedDeclarationInspection()) + myFixture.configureByFile("ImplicitUsagesDomElementVisitor.java") + myFixture.testHighlighting() + } + static Collection> getInspectionClasses() { return Arrays.asList( //RegistrationProblemsInspection.class,