FIR: avoid resolve loop between accessor and other members
#KT-48634 Fixed
This commit is contained in:
committed by
teamcityserver
parent
72fa330576
commit
19a75b31f9
+73
@@ -0,0 +1,73 @@
|
||||
FILE: accessInSetter.kt
|
||||
public final class DrawableGrid : R|kotlin/Any| {
|
||||
public constructor(isEnabled: R|kotlin/Boolean|): R|DrawableGrid| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final var isEnabled: R|kotlin/Boolean| = R|<local>/isEnabled|
|
||||
public get(): R|kotlin/Boolean|
|
||||
public set(value: R|kotlin/Boolean|): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public final class My : R|kotlin/Any| {
|
||||
public constructor(): R|My| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val drawableGrid: R|DrawableGrid| = this@R|/My|.R|/My.createDrawableGrid|()
|
||||
private get(): R|DrawableGrid|
|
||||
|
||||
private final var useAll: R|kotlin/Boolean| = Boolean(false)
|
||||
private get(): R|kotlin/Boolean|
|
||||
private set(value: R|kotlin/Boolean|): R|kotlin/Unit| {
|
||||
this@R|/My|.R|/My.drawableGrid|.R|/DrawableGrid.isEnabled| = R|<local>/value|.R|kotlin/Boolean.not|()
|
||||
}
|
||||
|
||||
private final fun createDrawableGrid(): R|DrawableGrid| {
|
||||
^createDrawableGrid R|/DrawableGrid.DrawableGrid|(Boolean(false)).R|kotlin/apply|<R|DrawableGrid|>(<L> = apply@fun R|DrawableGrid|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
when () {
|
||||
this@R|/My|.R|/My.useAll| -> {
|
||||
Int(-1)
|
||||
}
|
||||
else -> {
|
||||
Int(0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
public final class Your : R|kotlin/Any| {
|
||||
public constructor(): R|Your| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val drawableGrid: R|DrawableGrid| = this@R|/Your|.R|/Your.createDrawableGrid|()
|
||||
private get(): R|DrawableGrid|
|
||||
|
||||
private final var useAll: R|kotlin/Boolean|
|
||||
private get(): R|kotlin/Boolean| {
|
||||
^ Boolean(false)
|
||||
}
|
||||
private set(value: R|kotlin/Boolean|): R|kotlin/Unit| {
|
||||
this@R|/Your|.R|/Your.drawableGrid|.R|/DrawableGrid.isEnabled| = R|<local>/value|.R|kotlin/Boolean.not|()
|
||||
}
|
||||
|
||||
private final fun createDrawableGrid(): R|DrawableGrid| {
|
||||
^createDrawableGrid R|/DrawableGrid.DrawableGrid|(Boolean(false)).R|kotlin/apply|<R|DrawableGrid|>(<L> = apply@fun R|DrawableGrid|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
when () {
|
||||
this@R|/Your|.R|/Your.useAll| -> {
|
||||
Int(-1)
|
||||
}
|
||||
else -> {
|
||||
Int(0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
class DrawableGrid(var isEnabled: Boolean)
|
||||
|
||||
class My {
|
||||
private val drawableGrid = createDrawableGrid()
|
||||
|
||||
private var useAll = false
|
||||
set(value) {
|
||||
drawableGrid.isEnabled = !value
|
||||
}
|
||||
|
||||
private fun createDrawableGrid() = DrawableGrid(false).apply {
|
||||
if (useAll) -1 else 0
|
||||
}
|
||||
}
|
||||
|
||||
class Your {
|
||||
private val drawableGrid = createDrawableGrid()
|
||||
|
||||
private var useAll
|
||||
get() = false
|
||||
set(value) {
|
||||
drawableGrid.isEnabled = !value
|
||||
}
|
||||
|
||||
private fun createDrawableGrid() = DrawableGrid(false).apply {
|
||||
if (useAll) -1 else 0
|
||||
}
|
||||
}
|
||||
+6
@@ -5034,6 +5034,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Intellij {
|
||||
@Test
|
||||
@TestMetadata("accessInSetter.kt")
|
||||
public void testAccessInSetter() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/accessInSetter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInIntellij() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
|
||||
+6
@@ -5034,6 +5034,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Intellij {
|
||||
@Test
|
||||
@TestMetadata("accessInSetter.kt")
|
||||
public void testAccessInSetter() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/accessInSetter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInIntellij() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
|
||||
+35
-14
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
|
||||
open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
|
||||
private val statusResolver: FirStatusResolver = FirStatusResolver(session, scopeSession)
|
||||
@@ -126,17 +125,23 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
}
|
||||
|
||||
val returnTypeRef = property.returnTypeRef
|
||||
if (property.initializerAndAccessorsAreResolved) return property
|
||||
val bodyResolveState = property.bodyResolveState
|
||||
if (bodyResolveState == FirPropertyBodyResolveState.EVERYTHING_RESOLVED) return property
|
||||
if (returnTypeRef !is FirImplicitTypeRef && implicitTypeOnly) return property
|
||||
|
||||
property.transformReceiverTypeRef(transformer, ResolutionMode.ContextIndependent)
|
||||
dataFlowAnalyzer.enterProperty(property)
|
||||
doTransformTypeParameters(property)
|
||||
val shouldResolveEverything = !implicitTypeOnly
|
||||
return withFullBodyResolve {
|
||||
val initializerIsAlreadyResolved = bodyResolveState >= FirPropertyBodyResolveState.INITIALIZER_RESOLVED
|
||||
context.withProperty(property) {
|
||||
context.forPropertyInitializer {
|
||||
property.transformDelegate(transformer, ResolutionMode.ContextDependentDelegate)
|
||||
property.transformChildrenWithoutAccessors(returnTypeRef)
|
||||
if (!initializerIsAlreadyResolved) {
|
||||
property.transformChildrenWithoutAccessors(returnTypeRef)
|
||||
property.replaceBodyResolveState(FirPropertyBodyResolveState.INITIALIZER_RESOLVED)
|
||||
}
|
||||
if (property.initializer != null) {
|
||||
storeVariableReturnType(property)
|
||||
}
|
||||
@@ -147,14 +152,26 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
if (property.delegateFieldSymbol != null) {
|
||||
replacePropertyReferenceTypeInDelegateAccessors(property)
|
||||
}
|
||||
property.replaceBodyResolveState(FirPropertyBodyResolveState.EVERYTHING_RESOLVED)
|
||||
} else {
|
||||
property.transformAccessors()
|
||||
val hasNonDefaultAccessors = property.getter != null && property.getter !is FirDefaultPropertyAccessor ||
|
||||
property.setter != null && property.setter !is FirDefaultPropertyAccessor
|
||||
val mayResolveSetter = shouldResolveEverything || !hasNonDefaultAccessors
|
||||
val mayResolveGetter = mayResolveSetter || property.initializer == null
|
||||
if (mayResolveGetter) {
|
||||
property.transformAccessors(mayResolveSetter)
|
||||
property.replaceBodyResolveState(
|
||||
if (mayResolveSetter) FirPropertyBodyResolveState.EVERYTHING_RESOLVED
|
||||
else FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
dataFlowAnalyzer.exitProperty(property)?.let {
|
||||
property.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(it))
|
||||
if (!initializerIsAlreadyResolved) {
|
||||
dataFlowAnalyzer.exitProperty(property)?.let {
|
||||
property.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(it))
|
||||
}
|
||||
}
|
||||
property.replaceInitializerAndAccessorsAreResolved(true)
|
||||
property
|
||||
}
|
||||
}
|
||||
@@ -293,10 +310,12 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
.transformOtherChildren(transformer, data)
|
||||
}
|
||||
|
||||
private fun FirProperty.transformAccessors() {
|
||||
private fun FirProperty.transformAccessors(mayResolveSetter: Boolean = true) {
|
||||
var enhancedTypeRef = returnTypeRef
|
||||
getter?.let {
|
||||
transformAccessor(it, enhancedTypeRef, this)
|
||||
if (bodyResolveState < FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED) {
|
||||
getter?.let {
|
||||
transformAccessor(it, enhancedTypeRef, this)
|
||||
}
|
||||
}
|
||||
if (returnTypeRef is FirImplicitTypeRef) {
|
||||
storeVariableReturnType(this)
|
||||
@@ -304,11 +323,13 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
// We need update type of getter for case when its type was approximated
|
||||
getter?.replaceReturnTypeRef(enhancedTypeRef)
|
||||
}
|
||||
setter?.let {
|
||||
if (it.valueParameters[0].returnTypeRef is FirImplicitTypeRef) {
|
||||
it.valueParameters[0].transformReturnTypeRef(StoreType, enhancedTypeRef)
|
||||
if (mayResolveSetter) {
|
||||
setter?.let {
|
||||
if (it.valueParameters[0].returnTypeRef is FirImplicitTypeRef) {
|
||||
it.valueParameters[0].transformReturnTypeRef(StoreType, enhancedTypeRef)
|
||||
}
|
||||
transformAccessor(it, enhancedTypeRef, this)
|
||||
}
|
||||
transformAccessor(it, enhancedTypeRef, this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class FirProperty : FirVariable(), FirTypeParametersOwner, FirControlFl
|
||||
abstract val backingFieldSymbol: FirBackingFieldSymbol
|
||||
abstract val delegateFieldSymbol: FirDelegateFieldSymbol?
|
||||
abstract val isLocal: Boolean
|
||||
abstract val initializerAndAccessorsAreResolved: Boolean
|
||||
abstract val bodyResolveState: FirPropertyBodyResolveState
|
||||
abstract override val typeParameters: List<FirTypeParameter>
|
||||
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitProperty(this, data)
|
||||
@@ -71,7 +71,7 @@ abstract class FirProperty : FirVariable(), FirTypeParametersOwner, FirControlFl
|
||||
|
||||
abstract override fun replaceControlFlowGraphReference(newControlFlowGraphReference: FirControlFlowGraphReference?)
|
||||
|
||||
abstract fun replaceInitializerAndAccessorsAreResolved(newInitializerAndAccessorsAreResolved: Boolean)
|
||||
abstract fun replaceBodyResolveState(newBodyResolveState: FirPropertyBodyResolveState)
|
||||
|
||||
abstract override fun <D> transformReturnTypeRef(transformer: FirTransformer<D>, data: D): FirProperty
|
||||
|
||||
|
||||
+4
-3
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyBodyResolveState
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.FirDeclarationBuilder
|
||||
@@ -61,7 +62,7 @@ class FirPropertyBuilder : FirDeclarationBuilder, FirTypeParametersOwnerBuilder,
|
||||
lateinit var symbol: FirPropertySymbol
|
||||
var delegateFieldSymbol: FirDelegateFieldSymbol? = null
|
||||
var isLocal: Boolean by kotlin.properties.Delegates.notNull<Boolean>()
|
||||
var initializerAndAccessorsAreResolved: Boolean = false
|
||||
var bodyResolveState: FirPropertyBodyResolveState = FirPropertyBodyResolveState.NOTHING_RESOLVED
|
||||
override val typeParameters: MutableList<FirTypeParameter> = mutableListOf()
|
||||
|
||||
override fun build(): FirProperty {
|
||||
@@ -87,7 +88,7 @@ class FirPropertyBuilder : FirDeclarationBuilder, FirTypeParametersOwnerBuilder,
|
||||
symbol,
|
||||
delegateFieldSymbol,
|
||||
isLocal,
|
||||
initializerAndAccessorsAreResolved,
|
||||
bodyResolveState,
|
||||
typeParameters,
|
||||
)
|
||||
}
|
||||
@@ -129,7 +130,7 @@ inline fun buildPropertyCopy(original: FirProperty, init: FirPropertyBuilder.()
|
||||
copyBuilder.symbol = original.symbol
|
||||
copyBuilder.delegateFieldSymbol = original.delegateFieldSymbol
|
||||
copyBuilder.isLocal = original.isLocal
|
||||
copyBuilder.initializerAndAccessorsAreResolved = original.initializerAndAccessorsAreResolved
|
||||
copyBuilder.bodyResolveState = original.bodyResolveState
|
||||
copyBuilder.typeParameters.addAll(original.typeParameters)
|
||||
return copyBuilder.apply(init).build()
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyBodyResolveState
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
@@ -55,7 +56,7 @@ internal class FirPropertyImpl(
|
||||
override val symbol: FirPropertySymbol,
|
||||
override val delegateFieldSymbol: FirDelegateFieldSymbol?,
|
||||
override val isLocal: Boolean,
|
||||
override var initializerAndAccessorsAreResolved: Boolean,
|
||||
override var bodyResolveState: FirPropertyBodyResolveState,
|
||||
override val typeParameters: MutableList<FirTypeParameter>,
|
||||
) : FirProperty() {
|
||||
override val isVal: Boolean get() = !isVar
|
||||
@@ -169,7 +170,7 @@ internal class FirPropertyImpl(
|
||||
controlFlowGraphReference = newControlFlowGraphReference
|
||||
}
|
||||
|
||||
override fun replaceInitializerAndAccessorsAreResolved(newInitializerAndAccessorsAreResolved: Boolean) {
|
||||
initializerAndAccessorsAreResolved = newInitializerAndAccessorsAreResolved
|
||||
override fun replaceBodyResolveState(newBodyResolveState: FirPropertyBodyResolveState) {
|
||||
bodyResolveState = newBodyResolveState
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.declarations
|
||||
|
||||
// Semantically all states here are parts of FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE and just BODY_RESOLVE
|
||||
enum class FirPropertyBodyResolveState {
|
||||
NOTHING_RESOLVED,
|
||||
INITIALIZER_RESOLVED,
|
||||
INITIALIZER_AND_GETTER_RESOLVED,
|
||||
EVERYTHING_RESOLVED
|
||||
}
|
||||
+3
-3
@@ -82,8 +82,8 @@ class FirSyntheticProperty(
|
||||
// ???
|
||||
override val backingFieldSymbol: FirBackingFieldSymbol = FirBackingFieldSymbol(symbol.callableId)
|
||||
|
||||
override val initializerAndAccessorsAreResolved: Boolean
|
||||
get() = true
|
||||
override val bodyResolveState: FirPropertyBodyResolveState
|
||||
get() = FirPropertyBodyResolveState.EVERYTHING_RESOLVED
|
||||
|
||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||
returnTypeRef.accept(visitor, data)
|
||||
@@ -158,7 +158,7 @@ class FirSyntheticProperty(
|
||||
throw AssertionError("Mutation of synthetic property isn't supported")
|
||||
}
|
||||
|
||||
override fun replaceInitializerAndAccessorsAreResolved(newInitializerAndAccessorsAreResolved: Boolean) {
|
||||
override fun replaceBodyResolveState(newBodyResolveState: FirPropertyBodyResolveState) {
|
||||
throw AssertionError("Mutation of synthetic property isn't supported")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
|
||||
parents += typeParametersOwnerBuilder
|
||||
defaultNull("getter", "setter", "containerSource", "delegateFieldSymbol")
|
||||
default("resolvePhase", "FirResolvePhase.RAW_FIR")
|
||||
defaultFalse("initializerAndAccessorsAreResolved")
|
||||
default("bodyResolveState", "FirPropertyBodyResolveState.NOTHING_RESOLVED")
|
||||
withCopy()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -318,7 +318,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
+field("backingFieldSymbol", backingFieldSymbolType)
|
||||
+field("delegateFieldSymbol", delegateFieldSymbolType, nullable = true)
|
||||
+booleanField("isLocal")
|
||||
+booleanField("initializerAndAccessorsAreResolved", withReplace = true)
|
||||
+field("bodyResolveState", propertyBodyResolveStateType, withReplace = true)
|
||||
+typeParameters
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ val implicitNothingTypeRefType = generatedType("types.impl", "FirImplicitNothing
|
||||
val implicitStringTypeRefType = generatedType("types.impl", "FirImplicitStringTypeRef")
|
||||
val implicitUnitTypeRefType = generatedType("types.impl", "FirImplicitUnitTypeRef")
|
||||
val resolvePhaseType = type("fir.declarations", "FirResolvePhase")
|
||||
val propertyBodyResolveStateType = type("fir.declarations", "FirPropertyBodyResolveState")
|
||||
val stubReferenceType = generatedType("references.impl", "FirStubReference")
|
||||
|
||||
val firBasedSymbolType = type("fir.symbols", "FirBasedSymbol")
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ internal object DeclarationCopyBuilder {
|
||||
setter = copySetter
|
||||
|
||||
if (propertyResolvePhase < FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
|
||||
initializerAndAccessorsAreResolved = false
|
||||
bodyResolveState = FirPropertyBodyResolveState.NOTHING_RESOLVED
|
||||
}
|
||||
|
||||
initDeclaration(this@withBodyFrom, propertyWithBody)
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ internal class ReanalyzablePropertyStructureElement(
|
||||
getter?.replaceResolvePhase(upgradedPhase)
|
||||
setter?.replaceResolvePhase(upgradedPhase)
|
||||
replaceResolvePhase(upgradedPhase)
|
||||
replaceInitializerAndAccessorsAreResolved(false)
|
||||
replaceBodyResolveState(FirPropertyBodyResolveState.NOTHING_RESOLVED)
|
||||
}
|
||||
|
||||
val resolvedDeclaration = firLazyDeclarationResolver.lazyResolveDeclaration(
|
||||
|
||||
+6
@@ -5034,6 +5034,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Intellij {
|
||||
@Test
|
||||
@TestMetadata("accessInSetter.kt")
|
||||
public void testAccessInSetter() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/accessInSetter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInIntellij() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
|
||||
Reference in New Issue
Block a user