J2K converter: automatic generation of 'open' modifier for classes and methods

This commit is contained in:
Valentin Kipyatkov
2014-10-24 18:05:22 +04:00
committed by valentin
parent 39cea5999c
commit 7e147d28c2
34 changed files with 206 additions and 86 deletions
@@ -47,7 +47,8 @@ enum class AccessorKind {
}
class ClassBodyConverter(private val psiClass: PsiClass,
private val converter: Converter) {
private val converter: Converter,
private val isOpenClass: Boolean) {
private val membersToRemove = HashSet<PsiMember>()
private val fieldCorrections = HashMap<PsiField, FieldCorrectionInfo>()
@@ -110,7 +111,7 @@ class ClassBodyConverter(private val psiClass: PsiClass,
membersToRemove: MutableSet<PsiMember>,
constructorConverter: ConstructorConverter?): Member? {
return when (member) {
is PsiMethod -> convertMethod(member, membersToRemove, constructorConverter)
is PsiMethod -> convertMethod(member, membersToRemove, constructorConverter, isOpenClass)
is PsiField -> convertField(member, fieldCorrections[member])
is PsiClass -> convertClass(member)
is PsiClassInitializer -> convertInitializer(member)
@@ -148,7 +148,7 @@ class CodeConverter(public val converter: Converter,
}
public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody {
return AnonymousClassBody(ClassBodyConverter(anonymousClass, converter).convertBody(),
return AnonymousClassBody(ClassBodyConverter(anonymousClass, converter, false).convertBody(),
anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass)
}
+41 -8
View File
@@ -95,7 +95,7 @@ class Converter private(private val elementToConvert: PsiElement,
private fun convertTopElement(element: PsiElement): Element? = when (element) {
is PsiJavaFile -> convertFile(element)
is PsiClass -> convertClass(element)
is PsiMethod -> convertMethod(element, null, null)
is PsiMethod -> convertMethod(element, null, null, false)
is PsiField -> convertField(element, null)
is PsiStatement -> createDefaultCodeConverter().convertStatement(element)
is PsiExpression -> createDefaultCodeConverter().convertExpression(element)
@@ -179,15 +179,19 @@ class Converter private(private val elementToConvert: PsiElement,
val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes())
val name = psiClass.declarationIdentifier()
var classBody = ClassBodyConverter(psiClass, this).convertBody()
return when {
psiClass.isInterface() -> Trait(name, annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody)
psiClass.isInterface() -> {
var classBody = ClassBodyConverter(psiClass, this, false).convertBody()
Trait(name, annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody)
}
psiClass.isEnum() -> Enum(name, annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody)
psiClass.isEnum() -> {
var classBody = ClassBodyConverter(psiClass, this, false).convertBody()
Enum(name, annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody)
}
else -> {
if (settings.openByDefault && !psiClass.hasModifierProperty(PsiModifier.FINAL)) {
if (needOpenModifier(psiClass)) {
modifiers = modifiers.with(Modifier.OPEN)
}
@@ -195,11 +199,20 @@ class Converter private(private val elementToConvert: PsiElement,
modifiers = modifiers.with(Modifier.INNER)
}
var classBody = ClassBodyConverter(psiClass, this, modifiers.contains(Modifier.OPEN)).convertBody()
Class(name, annotations, modifiers, typeParameters, extendsTypes, classBody.baseClassParams, implementsTypes, classBody)
}
}.assignPrototype(psiClass)
}
private fun needOpenModifier(psiClass: PsiClass): Boolean {
return if (settings.openByDefault)
!psiClass.hasModifierProperty(PsiModifier.FINAL) && !psiClass.hasModifierProperty(PsiModifier.ABSTRACT)
else
referenceSearcher.hasInheritors(psiClass)
}
private fun convertAnnotationType(psiClass: PsiClass): Class {
val paramModifiers = Modifiers(listOf(Modifier.PUBLIC)).assignNoPrototype()
val noBlankLinesInheritance = CommentsAndSpacesInheritance(blankLinesBefore = false)
@@ -224,7 +237,7 @@ class Converter private(private val elementToConvert: PsiElement,
val constructorSignature = PrimaryConstructorSignature(Annotations.Empty(), Modifiers.Empty(), parameterList).assignNoPrototype()
// to convert fields and nested types - they are not allowed in Kotlin but we convert them and let user refactor code
var classBody = ClassBodyConverter(psiClass, this).convertBody()
var classBody = ClassBodyConverter(psiClass, this, false).convertBody()
classBody = ClassBody(constructorSignature, classBody.baseClassParams, classBody.members, classBody.classObjectMembers, listOf(), classBody.lBrace, classBody.rBrace)
val annotationAnnotation = Annotation(Identifier("annotation").assignNoPrototype(), listOf(), false, false).assignNoPrototype()
@@ -299,11 +312,18 @@ class Converter private(private val elementToConvert: PsiElement,
return if (convertedType == initializerType) null else convertedType
}
public fun convertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>?, constructorConverter: ConstructorConverter?): Member? {
public fun convertMethod(method: PsiMethod,
membersToRemove: MutableSet<PsiMember>?,
constructorConverter: ConstructorConverter?,
isInOpenClass: Boolean): Member? {
val returnType = typeConverter.convertMethodReturnType(method)
val annotations = (convertAnnotations(method) + convertThrows(method)).assignNoPrototype()
var modifiers = convertModifiers(method)
if (needOpenModifier(method, isInOpenClass, modifiers)) {
modifiers = modifiers.with(Modifier.OPEN)
}
val statementsToInsert = ArrayList<Statement>()
for (parameter in method.getParameterList().getParameters()) {
@@ -392,6 +412,19 @@ class Converter private(private val elementToConvert: PsiElement,
return false
}
private fun needOpenModifier(method: PsiMethod, isInOpenClass: Boolean, modifiers: Modifiers): Boolean {
if (!isInOpenClass) return false
if (modifiers.contains(Modifier.OVERRIDE) || modifiers.contains(Modifier.ABSTRACT)) return false
if (settings.openByDefault) {
return !method.hasModifierProperty(PsiModifier.FINAL)
&& !method.hasModifierProperty(PsiModifier.PRIVATE)
&& !method.hasModifierProperty(PsiModifier.STATIC)
}
else {
return referenceSearcher.hasOverrides(method)
}
}
public fun convertCodeReferenceElement(element: PsiJavaCodeReferenceElement, hasExternalQualifier: Boolean, typeArgsConverted: List<Element>? = null): ReferenceElement {
val typeArgs = typeArgsConverted ?: typeConverter.convertTypes(element.getTypeParameters())
@@ -23,16 +23,22 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethodCallExpression
import java.util.Collections
import com.intellij.psi.PsiClass
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.search.searches.OverridingMethodsSearch
public trait ReferenceSearcher {
fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression>
fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression>
fun hasInheritors(`class`: PsiClass): Boolean
fun hasOverrides(method: PsiMethod): Boolean
}
public object EmptyReferenceSearcher: ReferenceSearcher {
override fun findVariableUsages(variable: PsiVariable, scope: PsiElement) = listOf<PsiReferenceExpression>()
override fun findMethodCalls(method: PsiMethod, scope: PsiElement) = listOf<PsiMethodCallExpression>()
override fun hasInheritors(`class`: PsiClass) = false
override fun hasOverrides(method: PsiMethod) = false
}
public object IdeaReferenceSearcher : ReferenceSearcher {
@@ -51,4 +57,8 @@ public object IdeaReferenceSearcher : ReferenceSearcher {
}
}.filterNotNull()
}
override fun hasInheritors(`class`: PsiClass) = ClassInheritorsSearch.search(`class`, false).any()
override fun hasOverrides(method: PsiMethod) = OverridingMethodsSearch.search(method, false).any()
}
@@ -2162,6 +2162,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/inheritance/classOneExtendsBaseWithZeroParamsNonEmptyConstructor.java");
doTest(fileName);
}
@TestMetadata("openModifier.java")
public void testOpenModifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/inheritance/openModifier.java");
doTest(fileName);
}
}
@TestMetadata("j2k/tests/testData/fileOrElement/isOperator")
@@ -2162,6 +2162,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/inheritance/classOneExtendsBaseWithZeroParamsNonEmptyConstructor.java");
doTest(fileName);
}
@TestMetadata("openModifier.java")
public void testOpenModifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/inheritance/openModifier.java");
doTest(fileName);
}
}
@TestMetadata("j2k/tests/testData/fileOrElement/isOperator")
@@ -1,4 +1,3 @@
// ERROR: This type is final, so it cannot be inherited from
class Base(o: Any, l: Int)
open class Base(o: Any, l: Int)
class C(private val string: String) : Base(string, string.length())
@@ -1,5 +1,4 @@
// ERROR: This type is final, so it cannot be inherited from
class Base(nested: Base.Nested) {
open class Base(nested: Base.Nested) {
class Nested(p: Int) {
class object {
@@ -1,5 +1,4 @@
// ERROR: This type is final, so it cannot be inherited from
public class Base(x: Int) {
public open class Base(x: Int) {
public var x: Int = 42
protected set
@@ -1,5 +1,4 @@
// ERROR: This type is final, so it cannot be inherited from
public class AAA {
public open class AAA {
public var x: Int = 42
protected set
@@ -1,5 +1,4 @@
// ERROR: This type is final, so it cannot be inherited from
class Base {
open class Base {
private val myFirst: String? = null
}
@@ -1,6 +1,3 @@
// ERROR: 'clone' in 'Base' is final and cannot be overridden
// ERROR: 'finalize' in 'Base' is final and cannot be overridden
// ERROR: This type is final, so it cannot be inherited from
// ERROR: Unresolved reference: clone
// ERROR: Unresolved reference: finalize
package test
@@ -29,7 +26,7 @@ class Test : Base() {
}
}
class Base {
open class Base {
override fun hashCode(): Int {
return super.hashCode()
}
@@ -39,7 +36,7 @@ class Base {
}
throws(javaClass<CloneNotSupportedException>())
protected fun clone(): Any {
protected open fun clone(): Any {
return super.clone()
}
@@ -48,7 +45,7 @@ class Base {
}
throws(javaClass<Throwable>())
protected fun finalize() {
protected open fun finalize() {
super.finalize()
}
}
@@ -1,7 +1,5 @@
// ERROR: 'a' in 'A' is final and cannot be overridden
// ERROR: This type is final, so it cannot be inherited from
class A {
fun a() {
open class A {
open fun a() {
}
}
@@ -1,12 +1,9 @@
// ERROR: 'foo' in 'A' is final and cannot be overridden
// ERROR: This type is final, so it cannot be inherited from
// ERROR: This type is final, so it cannot be inherited from
class A {
fun foo() {
open class A {
open fun foo() {
}
}
class B : A() {
open class B : A() {
override fun foo() {
}
}
@@ -1,6 +1,5 @@
// ERROR: This type is final, so it cannot be inherited from
// ERROR: Unresolved reference: clone
class Base
open class Base
class X : Base() {
override fun hashCode(): Int {
@@ -1,5 +1,4 @@
// ERROR: This type is final, so it cannot be inherited from
class Base {
open class Base {
override fun equals(o: Any?): Boolean {
return super.equals(o)
}
@@ -1,7 +1,6 @@
// ERROR: This type is final, so it cannot be inherited from
class `$$$$$`
class `$`
open class `$`
class `$$`(val `$$$`: `$$$$$`) : `$`() {
@@ -1,4 +1,3 @@
// ERROR: This type is final, so it cannot be inherited from
class Base<T>(name: T)
open class Base<T>(name: T)
class One<T, K>(name: T, private val mySecond: K) : Base<T>(name)
@@ -1,4 +1,3 @@
// ERROR: This type is final, so it cannot be inherited from
class Base(name: String)
open class Base(name: String)
class One(name: String, second: String) : Base(name)
@@ -1,4 +1,3 @@
// ERROR: This type is final, so it cannot be inherited from
class Base
open class Base
class One : Base()
@@ -1,4 +1,3 @@
// ERROR: This type is final, so it cannot be inherited from
class Base(name: String)
open class Base(name: String)
class One(name: String, private val mySecond: String) : Base(name)
@@ -0,0 +1,48 @@
import java.lang.Override;
import java.lang.Void;
class A {
public void f1(){}
public void f2(){}
private void f3(){}
}
class B extends A {
@Override
public void f1() {
super.f1();
}
}
class C extends B {
@Override
public void f1() {
super.f1();
}
}
interface I {
void f();
}
class D implements I {
@Override
public void f() { }
}
abstract class E {
abstract void f1();
void f2(){}
void f3(){}
}
class F extends E {
@Override
void f1() {
}
@Override
void f2() {
super.f2();
}
}
@@ -0,0 +1,51 @@
import java.lang.Void
open class A {
public open fun f1() {
}
public fun f2() {
}
private fun f3() {
}
}
open class B : A() {
override fun f1() {
super.f1()
}
}
class C : B() {
override fun f1() {
super.f1()
}
}
trait I {
public fun f()
}
class D : I {
override fun f() {
}
}
abstract class E {
abstract fun f1()
open fun f2() {
}
fun f3() {
}
}
class F : E() {
override fun f1() {
}
override fun f2() {
super.f2()
}
}
@@ -1,6 +1,5 @@
// ERROR: This type is final, so it cannot be inherited from
// ERROR: Property must be initialized or be abstract
class Base {
open class Base {
inner class Nested
}
@@ -1,7 +1,6 @@
// ERROR: This type is final, so it cannot be inherited from
package test
class Base {
open class Base {
override fun hashCode(): Int {
return super.hashCode()
}
@@ -1,5 +1,3 @@
// ERROR: 'test' in 'Base' is final and cannot be overridden
// ERROR: This type is final, so it cannot be inherited from
package com.voltvoodoo.saplo4j.model
import java.io.Serializable
@@ -12,8 +10,8 @@ public class Language(protected var code: String) : Serializable {
}
class Base {
fun test() {
open class Base {
open fun test() {
}
override fun toString(): String {
@@ -1,13 +1,11 @@
// ERROR: There's a cycle in the inheritance hierarchy for this type
// ERROR: There's a cycle in the inheritance hierarchy for this type
// ERROR: This type is final, so it cannot be inherited from
// ERROR: This type is final, so it cannot be inherited from
class A : B() {
public fun foo(s: String) {
open class A : B() {
public open fun foo(s: String) {
}
}
class B : A() {
public fun foo(s: String) {
open class B : A() {
public open fun foo(s: String) {
}
}
@@ -1,16 +1,13 @@
// ERROR: 'foo' in 'Base' is final and cannot be overridden
// ERROR: 'bar' in 'Base' is final and cannot be overridden
// ERROR: This type is final, so it cannot be inherited from
class Base {
public fun foo(s: String?): String? {
open class Base {
public open fun foo(s: String?): String? {
return ""
}
public fun bar(s: String?): String? {
public open fun bar(s: String?): String? {
return if (s != null) s + 1 else null
}
public fun zoo(o: Any): String {
public open fun zoo(o: Any): String {
return ""
}
}
@@ -1,18 +1,15 @@
// ERROR: This type is final, so it cannot be inherited from
// ERROR: This type is final, so it cannot be inherited from
// ERROR: This type is final, so it cannot be inherited from
package demo
trait WindowListener {
public fun windowClosing()
}
class WindowAdapter : WindowListener {
open class WindowAdapter : WindowListener {
override fun windowClosing() {
}
}
class Frame {
open class Frame {
public fun addWindowListener(listener: WindowListener) {
}
}
@@ -1,7 +1,7 @@
// !openByDefault: true
open class A {
open fun foo1() {
open open fun foo1() {
}
private fun foo2() {
@@ -1,7 +1,6 @@
// ERROR: This type is final, so it cannot be inherited from
package a.b
class Base {
open class Base {
fun foo() {
}
}
@@ -1,4 +1,3 @@
//class
class B {
B(int i) {}
int call() {return 1;}
@@ -1,5 +1,5 @@
class B(i: Int) {
fun call(): Int {
open class B(i: Int) {
open fun call(): Int {
return 1
}
}
@@ -1,7 +1,6 @@
// ERROR: This type is final, so it cannot be inherited from
package a.b
class Base {
open class Base {
fun foo() {
}
}