consider static and non-static methods when language level is 8.0 or higher

This commit is contained in:
Bas Leijdekkers
2014-04-01 15:11:05 +02:00
parent 2f2db4c182
commit a513885898
6 changed files with 151 additions and 12 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import com.intellij.psi.*;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -88,6 +89,21 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
}
private static void changeClassToInterface(PsiClass aClass) {
for (PsiMethod method : aClass.getMethods()) {
PsiUtil.setModifierProperty(method, PsiModifier.PUBLIC, false);
if (method.hasModifierProperty(PsiModifier.STATIC) || method.hasModifierProperty(PsiModifier.ABSTRACT)) {
continue;
}
PsiUtil.setModifierProperty(method, PsiModifier.DEFAULT, true);
}
for (PsiField field : aClass.getFields()) {
PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, false);
PsiUtil.setModifierProperty(field, PsiModifier.STATIC, false);
PsiUtil.setModifierProperty(field, PsiModifier.FINAL, false);
}
for (PsiClass innerClass : aClass.getInnerClasses()) {
PsiUtil.setModifierProperty(innerClass, PsiModifier.PUBLIC, false);
}
final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
if (nameIdentifier == null) {
return;
@@ -99,11 +115,8 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
if (classKeyword == null) {
return;
}
final PsiModifierList modifierList = aClass.getModifierList();
if (modifierList != null) {
modifierList.setModifierProperty(PsiModifier.ABSTRACT, false);
modifierList.setModifierProperty(PsiModifier.FINAL, false);
}
PsiUtil.setModifierProperty(aClass, PsiModifier.ABSTRACT, false);
PsiUtil.setModifierProperty(aClass, PsiModifier.FINAL, false);
classKeyword.replace(interfaceKeyword);
}
@@ -124,7 +137,7 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
}
private static void moveSubClassExtendsToImplements(List<PsiClass> inheritors) {
PsiClass oldClass = inheritors.get(0);
final PsiClass oldClass = inheritors.get(0);
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(oldClass.getProject()).getElementFactory();
final PsiJavaCodeReferenceElement classReference = elementFactory.createClassReferenceElement(oldClass);
for (int i = 1; i < inheritors.size(); i++) {
@@ -170,6 +183,9 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
if (aClass instanceof PsiTypeParameter || aClass instanceof PsiAnonymousClass) {
return;
}
if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
return;
}
if (!mayBeInterface(aClass)) {
return;
}
@@ -206,7 +222,10 @@ public class ClassMayBeInterfaceInspection extends BaseInspection {
private static boolean allMethodsPublicAbstract(PsiClass aClass) {
final PsiMethod[] methods = aClass.getMethods();
for (final PsiMethod method : methods) {
if (!(method.hasModifierProperty(PsiModifier.ABSTRACT) && method.hasModifierProperty(PsiModifier.PUBLIC))) {
if (!PsiUtil.isLanguageLevel8OrHigher(aClass) && !method.hasModifierProperty(PsiModifier.ABSTRACT)) {
return false;
}
else if (!method.hasModifierProperty(PsiModifier.PUBLIC) || method.hasModifierProperty(PsiModifier.FINAL)) {
return false;
}
}
@@ -1,10 +1,10 @@
<html>
<body>
Reports any concrete or abstract classes
which may be simplified to be interfaces. This occurs if the class has no superclass (other
Reports <b>abstract</b> classes which can be converted to interfaces.
A class may be converted to an interface if it has no superclass (other
than Object), has no fields declared that are not <b>static</b>, <b>final</b>, and <b>public</b>, and has no
methods declared that are not <b>public</b> and <b>abstract</b>, and no inner classes
that cannot themselves be interfaces.
methods declared that are not <b>public</b> and <b>abstract</b> and no inner classes that are not <b>public</b>.
When using a language level of 8.0 or higher classes containing static and non-static methods will also be reported.
<!-- tooltip end -->
<p>
@@ -0,0 +1,15 @@
package com.siyeh.igfixes.classlayout.class_may_be_interface;
interface ConvertMe {
String S = "";
default void m() {}
static void n() {
new ConvertMe() {};
class X implements ConvertMe {}
}
class A {}
}
@@ -0,0 +1,15 @@
package com.siyeh.igfixes.classlayout.class_may_be_interface;
abstract class <caret>ConvertMe {
public static final String S = "";
public void m() {}
public static void n() {
new ConvertMe() {};
class X extends ConvertMe {}
}
public class A {}
}
@@ -0,0 +1,53 @@
/*
* 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 ClassMayBeInterfaceInspectionTest extends LightInspectionTestCase {
public void testOne() {
doTest("abstract class /*'ConvertMe' may be interface*/ConvertMe/**/ {\n" +
" public static final String S = \"\";\n" +
" public void m() {}\n" +
" public static void n() {\n" +
" new ConvertMe() {};\n" +
" class X extends ConvertMe {}\n" +
" }\n" +
" public class A {}\n" +
"}");
}
public void testOnTwo() {
doTest("class ConvertMe {\n" +
" public static final String S = \"\";\n" +
" public void m() {}\n" +
" public static void n() {\n" +
" new ConvertMe() {};\n" +
" class X extends ConvertMe {}\n" +
" }\n" +
" public class A {}\n" +
"}");
}
@Override
protected InspectionProfileEntry getInspection() {
return new ClassMayBeInterfaceInspection();
}
}
@@ -0,0 +1,37 @@
/*
* 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.fixes.classlayout;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.classlayout.ClassMayBeInterfaceInspection;
/**
* @author Bas Leijdekkers
*/
public class ClassMayBeInterfaceFixTest extends IGQuickFixesTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(new ClassMayBeInterfaceInspection());
myRelativePath = "classlayout/class_may_be_interface";
myDefaultHint = InspectionGadgetsBundle.message("class.may.be.interface.convert.quickfix");
}
public void testConvertMe() { doTest(); }
}