Support retrieving class of enum entry in ultra-light classes
This commit is contained in:
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
||||
|
||||
internal open class KtUltraLightField(
|
||||
private val declaration: KtNamedDeclaration,
|
||||
protected val declaration: KtNamedDeclaration,
|
||||
name: String,
|
||||
private val containingClass: KtUltraLightClass,
|
||||
private val support: UltraLightSupport,
|
||||
@@ -126,15 +126,24 @@ internal open class KtUltraLightField(
|
||||
}
|
||||
|
||||
internal class KtUltraLightEnumEntry(
|
||||
declaration: KtNamedDeclaration,
|
||||
declaration: KtEnumEntry,
|
||||
name: String,
|
||||
containingClass: KtUltraLightClass,
|
||||
support: UltraLightSupport,
|
||||
modifiers: Set<String>
|
||||
) : KtUltraLightField(declaration, name, containingClass, support, modifiers), PsiEnumConstant {
|
||||
override fun getInitializingClass(): PsiEnumConstantInitializer? = null
|
||||
private val enumEntry get() = declaration as KtEnumEntry
|
||||
|
||||
private val _initializingClass by lazyPub {
|
||||
if (enumEntry.body != null)
|
||||
KtUltraLightClassForEnumEntry(enumEntry, containingClass.support, this)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
override fun getInitializingClass(): PsiEnumConstantInitializer? = _initializingClass
|
||||
override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer =
|
||||
error("cannot create initializing class in light enum constant")
|
||||
_initializingClass ?: error("cannot create initializing class in light enum constant")
|
||||
|
||||
override fun getArgumentList(): PsiExpressionList? = null
|
||||
override fun resolveMethod(): PsiMethod? = null
|
||||
@@ -145,3 +154,31 @@ internal class KtUltraLightEnumEntry(
|
||||
override fun hasInitializer() = true
|
||||
override fun computeConstantValue(visitedVars: MutableSet<PsiVariable>?) = this
|
||||
}
|
||||
|
||||
internal class KtUltraLightClassForEnumEntry(
|
||||
enumEntry: KtEnumEntry, support: UltraLightSupport,
|
||||
private val enumConstant: PsiEnumConstant
|
||||
) : KtUltraLightClass(enumEntry, support), PsiEnumConstantInitializer {
|
||||
|
||||
private val baseClassReferenceAndType: Pair<PsiJavaCodeReferenceElement, PsiClassType> by lazyPub {
|
||||
// It should not be null for not-too-complex classes and that is not the case because
|
||||
// the containing class is not too complex (since we created KtUltraLightClassForEnumEntry instance)
|
||||
val extendsList =
|
||||
super.getExtendsList() ?: error("KtUltraLightClass::getExtendsList is null for ${enumEntry.fqName}")
|
||||
|
||||
Pair(
|
||||
extendsList.referenceElements.getOrNull(0) ?: error("No referenceElements found for ${enumEntry.fqName}"),
|
||||
extendsList.referencedTypes.getOrNull(0) ?: error("No referencedTypes found for ${enumEntry.fqName}")
|
||||
)
|
||||
}
|
||||
|
||||
override fun getBaseClassType() = baseClassReferenceAndType.second
|
||||
|
||||
override fun getBaseClassReference() = baseClassReferenceAndType.first
|
||||
|
||||
override fun getArgumentList(): PsiExpressionList? = null
|
||||
|
||||
override fun getEnumConstant() = enumConstant
|
||||
|
||||
override fun isInQualifiedNew() = false
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_N
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
|
||||
class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: UltraLightSupport) :
|
||||
open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val support: UltraLightSupport) :
|
||||
KtLightClassImpl(classOrObject) {
|
||||
companion object {
|
||||
|
||||
@@ -316,8 +316,11 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
|
||||
|
||||
private fun defaultConstructor(): KtUltraLightMethod {
|
||||
val visibility =
|
||||
if (classOrObject is KtObjectDeclaration || classOrObject.hasModifier(SEALED_KEYWORD) || isEnum) PsiModifier.PRIVATE
|
||||
else PsiModifier.PUBLIC
|
||||
when {
|
||||
classOrObject is KtObjectDeclaration || classOrObject.hasModifier(SEALED_KEYWORD) || isEnum -> PsiModifier.PRIVATE
|
||||
classOrObject is KtEnumEntry -> PsiModifier.PACKAGE_LOCAL
|
||||
else -> PsiModifier.PUBLIC
|
||||
}
|
||||
return noArgConstructor(visibility, classOrObject)
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,16 @@ object UltraLightChecker {
|
||||
} +
|
||||
";"
|
||||
|
||||
private fun PsiEnumConstant.renderEnumConstant(): String {
|
||||
val initializingClass = initializingClass ?: return name
|
||||
|
||||
return buildString {
|
||||
appendln("$name {")
|
||||
append(initializingClass.renderMembers())
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiClass.renderClass(): String {
|
||||
val classWord = when {
|
||||
isAnnotationType -> "@interface"
|
||||
@@ -118,18 +128,51 @@ object UltraLightChecker {
|
||||
else -> "class"
|
||||
}
|
||||
|
||||
return renderModifiers() +
|
||||
classWord + " " +
|
||||
name + " /* " + qualifiedName + "*/" +
|
||||
renderTypeParams() +
|
||||
extendsList.renderRefList("extends") +
|
||||
implementsList.renderRefList("implements") +
|
||||
" {\n" +
|
||||
(if (isEnum) fields.filterIsInstance<PsiEnumConstant>().joinToString(",\n") { it.name } + ";\n\n" else "") +
|
||||
fields.filterNot { it is PsiEnumConstant }.map { it.renderVar().prependIndent(" ") + ";\n\n" }.sorted().joinToString("") +
|
||||
methods.map { it.renderMethod().prependIndent(" ") + "\n\n" }.sorted().joinToString("") +
|
||||
innerClasses.map { "class ${it.name} ...\n\n".prependIndent(" ") }.sorted().joinToString("") +
|
||||
"}"
|
||||
return buildString {
|
||||
append(renderModifiers())
|
||||
append("$classWord ")
|
||||
append("$name /* $qualifiedName*/")
|
||||
append(renderTypeParams())
|
||||
append(extendsList.renderRefList("extends"))
|
||||
append(implementsList.renderRefList("implements"))
|
||||
appendln(" {")
|
||||
|
||||
if (isEnum) {
|
||||
append(
|
||||
fields
|
||||
.filterIsInstance<PsiEnumConstant>()
|
||||
.joinToString(",\n") { it.renderEnumConstant() }.prependDefaultIndent()
|
||||
)
|
||||
append(";\n\n")
|
||||
}
|
||||
|
||||
append(renderMembers())
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiClass.renderMembers(): String {
|
||||
return buildString {
|
||||
appendSorted(
|
||||
fields
|
||||
.filterNot { it is PsiEnumConstant }
|
||||
.map { it.renderVar().prependDefaultIndent() + ";\n\n" }
|
||||
)
|
||||
|
||||
appendSorted(
|
||||
methods
|
||||
.map { it.renderMethod().prependDefaultIndent() + "\n\n" }
|
||||
)
|
||||
|
||||
appendSorted(
|
||||
innerClasses.map { "class ${it.name} ...\n\n".prependDefaultIndent() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendSorted(list: List<String>) {
|
||||
append(list.sorted().joinToString(""))
|
||||
}
|
||||
|
||||
private fun String.prependDefaultIndent() = prependIndent(" ")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package test;
|
||||
|
||||
public interface <lineMarker>OverrideInEnumEntry</lineMarker> {
|
||||
void <lineMarker>foo</lineMarker>();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
enum class E : OverrideInEnumEntry {
|
||||
X {
|
||||
override fun foo() {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
// LINE_MARKERS
|
||||
@@ -29,6 +29,7 @@ import com.siyeh.ig.bugs.StaticCallOnSubclassInspection;
|
||||
import com.siyeh.ig.bugs.StaticFieldReferenceOnSubclassInspection;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.KotlinDaemonAnalyzerTestCase;
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
|
||||
@@ -64,7 +65,11 @@ public abstract class AbstractJavaAgainstKotlinCheckerTest extends KotlinDaemonA
|
||||
|
||||
@Nullable
|
||||
protected String getConfigFileText() {
|
||||
File configureFile = new File(PluginTestCaseBase.getTestDataPathBase() + "/kotlinAndJavaChecker/javaAgainstKotlin/" + getTestName(false) + ".txt");
|
||||
String className = getClass().getName();
|
||||
|
||||
boolean isJavaWithKotlin = className.contains("JavaWithKotlin");
|
||||
|
||||
File configureFile = new File(configPath(isJavaWithKotlin ? "javaWithKotlin" : "javaAgainstKotlin"));
|
||||
if (!configureFile.exists()) return null;
|
||||
|
||||
try {
|
||||
@@ -75,6 +80,11 @@ public abstract class AbstractJavaAgainstKotlinCheckerTest extends KotlinDaemonA
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String configPath(String testKind) {
|
||||
return PluginTestCaseBase.getTestDataPathBase() + "/kotlinAndJavaChecker/" + testKind + "/" + getTestName(false) + ".txt";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
String configFileText = getConfigFileText();
|
||||
@@ -90,6 +100,14 @@ public abstract class AbstractJavaAgainstKotlinCheckerTest extends KotlinDaemonA
|
||||
}), LocalInspectionTool.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doTestLineMarkers() {
|
||||
String configFileText = getConfigFileText();
|
||||
if (configFileText == null) return super.doTestLineMarkers();
|
||||
|
||||
return InTextDirectivesUtils.isDirectiveDefined(configFileText, "LINE_MARKERS");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Module createMainModule() throws IOException {
|
||||
Module module = super.createMainModule();
|
||||
|
||||
+5
@@ -213,5 +213,10 @@ public class JavaAgainstKotlinSourceCheckerTestGenerated extends AbstractJavaAga
|
||||
public void testNoNotNullOnParameterInOverride() throws Exception {
|
||||
runTest("idea/testData/kotlinAndJavaChecker/javaWithKotlin/NoNotNullOnParameterInOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("OverrideInEnumEntry.kt")
|
||||
public void testOverrideInEnumEntry() throws Exception {
|
||||
runTest("idea/testData/kotlinAndJavaChecker/javaWithKotlin/OverrideInEnumEntry.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -213,5 +213,10 @@ public class JavaAgainstKotlinSourceCheckerWithUltraLightTestGenerated extends A
|
||||
public void testNoNotNullOnParameterInOverride() throws Exception {
|
||||
runTest("idea/testData/kotlinAndJavaChecker/javaWithKotlin/NoNotNullOnParameterInOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("OverrideInEnumEntry.kt")
|
||||
public void testOverrideInEnumEntry() throws Exception {
|
||||
runTest("idea/testData/kotlinAndJavaChecker/javaWithKotlin/OverrideInEnumEntry.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user