diff --git a/java/java-impl/src/com/intellij/codeInspection/deprecation/DeprecatedDefenderSyntaxInspection.java b/java/java-impl/src/com/intellij/codeInspection/deprecation/DeprecatedDefenderSyntaxInspection.java new file mode 100644 index 000000000000..1a9024d14e9f --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/deprecation/DeprecatedDefenderSyntaxInspection.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2012 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.deprecation; + +import com.intellij.codeInspection.*; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.PsiModifierListImpl; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +// todo[r.sh] drop this after transition period finished +public class DeprecatedDefenderSyntaxInspection extends BaseJavaLocalInspectionTool { + private final LocalQuickFix myQuickFix = new MyQuickFix(); + + @Nullable + @Override + public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) { + final PsiJavaToken marker = PsiModifierListImpl.findExtensionMethodMarker(method); + return marker == null ? null : new ProblemDescriptor[]{ + manager.createProblemDescriptor(marker, getDisplayName(), myQuickFix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly) + }; + } + + private static class MyQuickFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return InspectionsBundle.message("deprecated.defender.syntax.fix"); + } + + @NotNull + @Override + public String getFamilyName() { + return ""; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement marker = descriptor.getPsiElement(); + if (marker != null && PsiUtil.isJavaToken(marker, JavaTokenType.DEFAULT_KEYWORD)) { + final PsiElement parent = marker.getParent(); + if (parent instanceof PsiMethod) { + marker.delete(); + final PsiMethod method = (PsiMethod)parent; + if (!method.hasModifierProperty(PsiModifier.DEFAULT)) { + PsiUtil.setModifierProperty(method, PsiModifier.DEFAULT, true); + } + } + } + } + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java index c1edcb49481a..4f05d58165dc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java @@ -180,7 +180,7 @@ public class PsiModifierListImpl extends JavaStubPsiElement } @Nullable - private static PsiJavaToken findExtensionMethodMarker(@Nullable PsiMethod method) { + public static PsiJavaToken findExtensionMethodMarker(@Nullable PsiMethod method) { // todo[r.sh] drop this after transition period finished if (method == null) return null; final PsiCodeBlock body = method.getBody(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethodSyntax.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethodSyntax.java new file mode 100644 index 000000000000..63411f68c522 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethodSyntax.java @@ -0,0 +1,8 @@ +interface I { + void m1() default { } + + default void m2() default { } + + @SuppressWarnings("extensionSyntax") + void m3() default { } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index b5b235211baf..41ef5fe88de1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -17,11 +17,11 @@ package com.intellij.codeInsight.daemon; import com.intellij.ExtensionPoints; import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.compiler.JavacQuirksInspection; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.defUse.DefUseInspection; +import com.intellij.codeInspection.deprecation.DeprecatedDefenderSyntaxInspection; import com.intellij.codeInspection.redundantCast.RedundantCastInspection; import com.intellij.codeInspection.reference.EntryPoint; import com.intellij.codeInspection.reference.RefElement; @@ -45,13 +45,13 @@ import java.util.List; public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/advHighlighting7"; - private void doTest(boolean checkWarnings, boolean checkInfos, InspectionProfileEntry... tools) throws Exception { - for (InspectionProfileEntry tool : tools) { enableInspectionTool(tool); } + private void doTest(boolean checkWarnings, boolean checkInfos, Class... classes) { + enableInspectionTools(classes); doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, checkInfos); } - private void doTest(boolean checkWarnings, boolean checkWeakWarnings, boolean checkInfos, InspectionProfileEntry... tools) throws Exception { - for (InspectionProfileEntry tool : tools) { enableInspectionTool(tool); } + private void doTest(boolean checkWarnings, boolean checkWeakWarnings, boolean checkInfos, Class... classes) { + enableInspectionTools(classes); doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, checkWeakWarnings, checkInfos); } @@ -93,16 +93,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testDiamondNeg12() throws Exception { doTest(false, false); } public void testDiamondNeg13() throws Exception { doTest(false, false); } public void testDiamondNeg14() throws Exception { doTest(false, false); } - public void testDiamondMisc() throws Exception { - final LanguageLevel oldLevel = getLanguageLevel(); - try { - setLanguageLevel(LanguageLevel.JDK_1_7); - doTest(false, false); - } - finally { - setLanguageLevel(oldLevel); - } - } + public void testDiamondMisc() throws Exception { setLanguageLevel(LanguageLevel.JDK_1_7); doTest(false, false); } public void testHighlightInaccessibleFromClassModifierList() throws Exception { doTest(false, false); } public void testInnerInTypeArguments() throws Exception { doTest(false, false); } @@ -138,28 +129,25 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { } } - public void testJavacQuirks() throws Exception { - setLanguageLevel(LanguageLevel.JDK_1_6); - doTest(true, false); - } - + public void testJavacQuirks() throws Exception { setLanguageLevel(LanguageLevel.JDK_1_6); doTest(true, false); } public void testNumericLiterals() throws Exception { doTest(false, false); } public void testMultiCatch() throws Exception { doTest(false, false); } public void testTryWithResources() throws Exception { doTest(false, false); } - public void testTryWithResourcesWarn() throws Exception { doTest(true, false, new DefUseInspection()); } + public void testTryWithResourcesWarn() throws Exception { doTest(true, false, DefUseInspection.class); } public void testSafeVarargsApplicability() throws Exception { doTest(true, false); } public void testUncheckedGenericsArrayCreation() throws Exception { doTest(true, false); } public void testGenericsArrayCreation() throws Exception { doTest(false, false); } public void testPreciseRethrow() throws Exception { doTest(false, false); } public void testImprovedCatchAnalysis() throws Exception { doTest(true, false); } public void testPolymorphicTypeCast() throws Exception { doTest(true, false); } - public void testErasureClashConfusion() throws Exception { doTest(true, false, new UnusedDeclarationInspection()); } - public void testUnused() throws Exception { doTest(true, false, new UnusedDeclarationInspection()); } + public void testErasureClashConfusion() throws Exception { doTest(true, false, UnusedDeclarationInspection.class); } + public void testUnused() throws Exception { doTest(true, false, UnusedDeclarationInspection.class); } public void testSuperBound() throws Exception { doTest(false, false); } public void testExtendsBound() throws Exception { doTest(false, false); } public void testIDEA84533() throws Exception { doTest(false, false); } public void testClassLiteral() throws Exception { doTest(false, false); } public void testExtensionMethods() throws Exception { doTest(false, false); } + public void testExtensionMethodSyntax() throws Exception { doTest(true, false, DeprecatedDefenderSyntaxInspection.class); } public void testMethodReferences() throws Exception { doTest(false, true, false); } public void testUsedMethodsByMethodReferences() throws Exception { doTest(true, true, false); } public void testLambdaExpressions() throws Exception { doTest(false, true, false); } diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 6e88899071d3..9d98b3381774 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -652,4 +652,7 @@ inspection.javadoc.problem.pointing.to.itself=Javadoc pointing to itself inspection.redirect.template=Injected element has problem: {0} (in {3}). nothing.found=Nothing found -special.annotations.list.annotation.pattern=Add Annotations Pattern \ No newline at end of file +special.annotations.list.annotation.pattern=Add Annotations Pattern + +deprecated.defender.syntax.description=Deprecated extension method syntax +deprecated.defender.syntax.fix=Convert extension method syntax diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 805522d0eeed..db4fec954357 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -22,9 +22,7 @@ import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInspection.GlobalInspectionTool; -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.*; import com.intellij.ide.highlighter.ProjectFileType; import com.intellij.ide.startup.StartupManagerEx; @@ -44,6 +42,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.editor.impl.EditorFactoryImpl; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl; import com.intellij.openapi.fileTypes.FileType; @@ -437,6 +436,35 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da } } + // todo: use Class once on Java 7 + protected void enableInspectionTools(@NotNull Class... classes) { + final InspectionProfileEntry[] tools = new InspectionProfileEntry[classes.length]; + + final List eps = ContainerUtil.newArrayList(); + ContainerUtil.addAll(eps, Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)); + ContainerUtil.addAll(eps, Extensions.getExtensions(InspectionEP.GLOBAL_INSPECTION)); + ContainerUtil.addAll(eps, (InspectionEP[])Extensions.getExtensions("com.intellij.specialTool")); + + next: + for (int i = 0; i < classes.length; i++) { + for (InspectionEP ep : eps) { + if (classes[i].getName().equals(ep.implementationClass)) { + tools[i] = ep.instantiateTool(); + continue next; + } + } + throw new IllegalArgumentException("Unable to find extension point for " + classes[i].getName()); + } + + enableInspectionTools(tools); + } + + protected void enableInspectionTools(@NotNull InspectionProfileEntry... tools) { + for (InspectionProfileEntry tool : tools) { + enableInspectionTool(tool); + } + } + protected void enableInspectionTool(@NotNull InspectionProfileEntry tool) { if (tool instanceof InspectionTool) { enableInspectionTool(myAvailableInspectionTools, (InspectionTool)tool); diff --git a/resources-en/src/inspectionDescriptions/DeprecatedDefenderSyntax.html b/resources-en/src/inspectionDescriptions/DeprecatedDefenderSyntax.html new file mode 100644 index 000000000000..b82bf836209c --- /dev/null +++ b/resources-en/src/inspectionDescriptions/DeprecatedDefenderSyntax.html @@ -0,0 +1,6 @@ + + +Detects deprecated extension method syntax:
void m() default { }
+Allows to convert it to the correct form:
default void m() { }
+ + \ No newline at end of file diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index bff5f454b5b9..7712b3e7767d 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -456,6 +456,9 @@ +