IDEA-120161 ("Interface may be annotated @FunctionalInterface" inspection)

This commit is contained in:
Bas Leijdekkers
2014-02-01 19:04:03 +01:00
parent 20f6fd62ca
commit 27047db3d7
5 changed files with 147 additions and 0 deletions
@@ -503,6 +503,10 @@
key="method.return.always.constant.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.classlayout.MethodReturnAlwaysConstantInspection"/>
<localInspection language="JAVA" shortName="InterfaceMayBeAnnotatedFunctional" bundle="com.siyeh.InspectionGadgetsBundle"
key="interface.may.be.annotated.functional.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.classlayout.InterfaceMayBeAnnotatedFunctionalInspection"/>
<!--group.names.class.metrics-->
<localInspection language="JAVA" suppressId="OverlyComplexAnonymousInnerClass" shortName="AnonymousClassComplexity"
@@ -2063,3 +2063,5 @@ suppress.for.tests.scope.quickfix=Suppress for 'Tests' scope
implicit.default.charset.usage.display.name=Implicit usage of platform's default charset
implicit.default.charset.usage.problem.descriptor=Call to <code>#ref()</code> uses the platform's default charset
implicit.default.charset.usage.constructor.problem.descriptor=<code>new #ref()</code> call uses the platform's default charset
interface.may.be.annotated.functional.display.name=Interface may be annotated @FunctionalInterface
interface.may.be.annotated.functional.problem.descriptor=Interface <code>#ref</code> may be annotated with @FunctionalInterface
@@ -0,0 +1,80 @@
/*
* 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.siyeh.ig.classlayout;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.psi.LambdaHighlightingUtil;
import com.intellij.psi.LambdaUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.DelegatingFix;
import com.siyeh.ig.InspectionGadgetsFix;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers
*/
public class InterfaceMayBeAnnotatedFunctionalInspection extends BaseInspection {
@Nls
@NotNull
@Override
public String getDisplayName() {
return InspectionGadgetsBundle.message("interface.may.be.annotated.functional.display.name");
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message("interface.may.be.annotated.functional.problem.descriptor");
}
@Nullable
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
final PsiClass aClass = (PsiClass)infos[0];
return new DelegatingFix(new AddAnnotationPsiFix(LambdaUtil.JAVA_LANG_FUNCTIONAL_INTERFACE, aClass, PsiNameValuePair.EMPTY_ARRAY));
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new InterfaceMayBeAnnotatedFunctionalVisitor();
}
private static class InterfaceMayBeAnnotatedFunctionalVisitor extends BaseInspectionVisitor {
@Override
public void visitClass(PsiClass aClass) {
if (!PsiUtil.isLanguageLevel8OrHigher(aClass)) {
return;
}
super.visitClass(aClass);
if (!aClass.isInterface()) {
return;
}
if (LambdaHighlightingUtil.checkInterfaceFunctional(aClass) != null) {
return;
}
registerClassError(aClass, aClass);
}
}
}
@@ -0,0 +1,10 @@
<html>
<body>
Reports any <b>interface</b> that may be annotated as <b>@FunctionalInterface</b>, which is available in JDK 1.8.
Annotating an interface with <b>@FunctionalInterface</b> can be useful to indicate that the interface is supposed to be functional and
further <b>abstract</b> methods should not be added to it.
This inspection only reports if the project or module is configured to use a language level of 8.0 or higher.
<p>
<small>New in 13.1</small>
</body>
</html>
@@ -0,0 +1,51 @@
/*
* 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.siyeh.ig.classlayout;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
/**
* @author Bas Leijdekkers
*/
public class InterfaceMayBeAnnotatedFunctionalInspectionTest extends LightInspectionTestCase {
public void testSimple() {
doTest("interface /*Interface 'Simple' may be annotated with @FunctionalInterface*/Simple/**/ {" +
" void f();" +
"}");
}
public void testLessSimple() {
doTest("interface /*Interface 'F' may be annotated with @FunctionalInterface*/F/**/ {" +
" boolean equals(Object o);" +
" static void f00() {}\n" +
" default void g() {}\n" +
" void f();\n" +
"}");
}
public void testNotFunctional() {
doTest("interface G {" +
"<T> void f();" +
"}");
}
@Override
protected InspectionProfileEntry getInspection() {
return new InterfaceMayBeAnnotatedFunctionalInspection();
}
}