FIR Analysis API: reimplement KtFirCallResolver with new data model
This commit is contained in:
committed by
Ilya Kirillov
parent
c9f9ce99c1
commit
9b05019137
+28
-7
@@ -12,17 +12,22 @@ import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
|
||||
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KT_DIAGNOSTIC_CONVERTER
|
||||
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirGenericSubstitutor
|
||||
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirMapBackedSubstitutor
|
||||
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
@@ -77,24 +82,40 @@ internal interface KtFirAnalysisSessionComponent {
|
||||
)
|
||||
}
|
||||
|
||||
fun FirQualifiedAccessExpression.createSubstitutorFromTypeArguments(): KtSubstitutor? {
|
||||
fun FirQualifiedAccess.createSubstitutorFromTypeArguments(): KtSubstitutor? {
|
||||
return createConeSubstitutorFromTypeArguments()?.toKtSubstitutor()
|
||||
}
|
||||
|
||||
fun FirQualifiedAccess.createSubstitutorFromTypeArguments(callableSymbol: FirCallableSymbol<*>): KtSubstitutor {
|
||||
return createConeSubstitutorFromTypeArguments(callableSymbol).toKtSubstitutor()
|
||||
}
|
||||
|
||||
fun FirQualifiedAccess.createConeSubstitutorFromTypeArguments(): ConeSubstitutor? {
|
||||
val symbol = when (val calleeReference = calleeReference) {
|
||||
is FirResolvedNamedReference -> calleeReference.resolvedSymbol as? FirCallableSymbol<*>
|
||||
is FirErrorNamedReference -> calleeReference.candidateSymbol as? FirCallableSymbol<*>
|
||||
else -> null
|
||||
} ?: return null
|
||||
return createSubstitutorFromTypeArguments(symbol)
|
||||
return createConeSubstitutorFromTypeArguments(symbol)
|
||||
}
|
||||
|
||||
fun FirQualifiedAccessExpression.createSubstitutorFromTypeArguments(functionSymbol: FirCallableSymbol<*>): KtSubstitutor {
|
||||
fun FirQualifiedAccess.createConeSubstitutorFromTypeArguments(callableSymbol: FirCallableSymbol<*>): ConeSubstitutor {
|
||||
val typeArgumentMap = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
||||
for (i in typeArguments.indices) {
|
||||
val type = typeArguments[i].safeAs<FirTypeProjectionWithVariance>()?.typeRef?.coneType
|
||||
if (type != null) {
|
||||
typeArgumentMap[functionSymbol.typeParameterSymbols[i]] = type
|
||||
typeArgumentMap[callableSymbol.typeParameterSymbols[i]] = type
|
||||
}
|
||||
}
|
||||
val coneSubstitutor = substitutorByMap(typeArgumentMap, rootModuleSession)
|
||||
return firSymbolBuilder.typeBuilder.buildSubstitutor(coneSubstitutor)
|
||||
return coneSubstitutor
|
||||
}
|
||||
|
||||
fun ConeSubstitutor.toKtSubstitutor(): KtSubstitutor {
|
||||
return when (this) {
|
||||
ConeSubstitutor.Empty -> KtSubstitutor.Empty(analysisSession.token)
|
||||
is ConeSubstitutorByMap -> KtFirMapBackedSubstitutor(this, analysisSession.firSymbolBuilder, analysisSession.token)
|
||||
else -> KtFirGenericSubstitutor(this, analysisSession.firSymbolBuilder, analysisSession.token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+676
-260
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.idea.references
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtSimpleFunctionCall
|
||||
import org.jetbrains.kotlin.analysis.api.calls.calls
|
||||
import org.jetbrains.kotlin.analysis.api.calls.symbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
@@ -21,7 +23,7 @@ class KtFirInvokeFunctionReference(expression: KtCallExpression) : KtInvokeFunct
|
||||
return expression.resolveCall().calls.mapNotNull { call ->
|
||||
(call as? KtSimpleFunctionCall)
|
||||
?.takeIf { it.isImplicitInvoke }
|
||||
?.boundSymbol
|
||||
?.partiallyAppliedSymbol
|
||||
?.symbol
|
||||
?.takeUnless { it is KtFunctionSymbol && it.isBuiltinFunctionInvoke }
|
||||
}
|
||||
|
||||
+252
@@ -162,6 +162,108 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/arrayOfInAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("calleeExpressionOfImplicitInvoke.kt")
|
||||
public void testCalleeExpressionOfImplicitInvoke() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/calleeExpressionOfImplicitInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkNotNullCall.kt")
|
||||
public void testCheckNotNullCall() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/checkNotNullCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkNotNullCallAsCallee.kt")
|
||||
public void testCheckNotNullCallAsCallee() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/checkNotNullCallAsCallee.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("comparisonCall.kt")
|
||||
public void testComparisonCall() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/comparisonCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignOnVal.kt")
|
||||
public void testCompoundAssignOnVal() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignOnVal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignOnVal_lhs.kt")
|
||||
public void testCompoundAssignOnVal_lhs() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignOnVal_lhs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignOnVar.kt")
|
||||
public void testCompoundAssignOnVar() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignOnVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignOnVar_lhs.kt")
|
||||
public void testCompoundAssignOnVar_lhs() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignOnVar_lhs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignWithArrayAccessConvention.kt")
|
||||
public void testCompoundAssignWithArrayAccessConvention() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignWithArrayAccessConvention.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignWithArrayAccessConvention_complexReceivers.kt")
|
||||
public void testCompoundAssignWithArrayAccessConvention_complexReceivers() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignWithArrayAccessConvention_complexReceivers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignWithArrayAccessConvention_lhs.kt")
|
||||
public void testCompoundAssignWithArrayAccessConvention_lhs() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignWithArrayAccessConvention_lhs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignWithArrayGetConvention.kt")
|
||||
public void testCompoundAssignWithArrayGetConvention() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignWithArrayGetConvention.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compoundAssignWithArrayGetConvention_lhs.kt")
|
||||
public void testCompoundAssignWithArrayGetConvention_lhs() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/compoundAssignWithArrayGetConvention_lhs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("consecutiveImplicitInvoke1.kt")
|
||||
public void testConsecutiveImplicitInvoke1() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/consecutiveImplicitInvoke1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("consecutiveImplicitInvoke2.kt")
|
||||
public void testConsecutiveImplicitInvoke2() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/consecutiveImplicitInvoke2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("consecutiveImplicitInvoke3.kt")
|
||||
public void testConsecutiveImplicitInvoke3() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/consecutiveImplicitInvoke3.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("consecutiveImplicitInvoke_callee.kt")
|
||||
public void testConsecutiveImplicitInvoke_callee() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/consecutiveImplicitInvoke_callee.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegatedConstructorCall_super.kt")
|
||||
public void testDelegatedConstructorCall_super() throws Exception {
|
||||
@@ -192,6 +294,24 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/enumAsAnnotationValue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("eqEqCall_fromAny.kt")
|
||||
public void testEqEqCall_fromAny() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/eqEqCall_fromAny.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("eqEqCall_fromSuperType.kt")
|
||||
public void testEqEqCall_fromSuperType() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/eqEqCall_fromSuperType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("eqEqCall_overridden.kt")
|
||||
public void testEqEqCall_overridden() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/eqEqCall_overridden.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionCallInTheSameFile.kt")
|
||||
public void testFunctionCallInTheSameFile() throws Exception {
|
||||
@@ -240,6 +360,18 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/functionCallWithVarargArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionTypeVariableCall_dispatchReceiver.kt")
|
||||
public void testFunctionTypeVariableCall_dispatchReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/functionTypeVariableCall_dispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionTypeVariableCall_extensionReceiver.kt")
|
||||
public void testFunctionTypeVariableCall_extensionReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/functionTypeVariableCall_extensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionWithReceiverCall.kt")
|
||||
public void testFunctionWithReceiverCall() throws Exception {
|
||||
@@ -252,6 +384,18 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/functionWithReceiverSafeCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("hiddenConstructor.kt")
|
||||
public void testHiddenConstructor() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/hiddenConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("hiddenDeprecated.kt")
|
||||
public void testHiddenDeprecated() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/hiddenDeprecated.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("implicitConstructorDelegationCall.kt")
|
||||
public void testImplicitConstructorDelegationCall() throws Exception {
|
||||
@@ -390,6 +534,78 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/memberFunctionCallWithTypeArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("postfixUnaryOperatorOnVar.kt")
|
||||
public void testPostfixUnaryOperatorOnVar() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/postfixUnaryOperatorOnVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("postfixUnaryOperatorOnVar_base.kt")
|
||||
public void testPostfixUnaryOperatorOnVar_base() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/postfixUnaryOperatorOnVar_base.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("postfixUnaryOperatorWithArrayAccessConvention.kt")
|
||||
public void testPostfixUnaryOperatorWithArrayAccessConvention() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/postfixUnaryOperatorWithArrayAccessConvention.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("postfixUnaryOperatorWithArrayAccessConvention_base.kt")
|
||||
public void testPostfixUnaryOperatorWithArrayAccessConvention_base() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/postfixUnaryOperatorWithArrayAccessConvention_base.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("postfixUnaryOperatorWithArrayAccessConvention_complexDispatcher.kt")
|
||||
public void testPostfixUnaryOperatorWithArrayAccessConvention_complexDispatcher() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/postfixUnaryOperatorWithArrayAccessConvention_complexDispatcher.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("prefixUnaryOperatorOnVar.kt")
|
||||
public void testPrefixUnaryOperatorOnVar() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/prefixUnaryOperatorOnVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("prefixUnaryOperatorOnVar_base.kt")
|
||||
public void testPrefixUnaryOperatorOnVar_base() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/prefixUnaryOperatorOnVar_base.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("prefixUnaryOperatorWithArrayAccessConvention.kt")
|
||||
public void testPrefixUnaryOperatorWithArrayAccessConvention() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/prefixUnaryOperatorWithArrayAccessConvention.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("prefixUnaryOperatorWithArrayAccessConvention_base.kt")
|
||||
public void testPrefixUnaryOperatorWithArrayAccessConvention_base() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/prefixUnaryOperatorWithArrayAccessConvention_base.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("prefixUnaryOperatorWithArrayAccessConvention_complexDispatcher.kt")
|
||||
public void testPrefixUnaryOperatorWithArrayAccessConvention_complexDispatcher() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/prefixUnaryOperatorWithArrayAccessConvention_complexDispatcher.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateMember.kt")
|
||||
public void testPrivateMember() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/privateMember.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("qualifiedCalleeExpressionOfImplicitInvoke.kt")
|
||||
public void testQualifiedCalleeExpressionOfImplicitInvoke() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/qualifiedCalleeExpressionOfImplicitInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("resolveCallInSuperConstructorParam.kt")
|
||||
public void testResolveCallInSuperConstructorParam() throws Exception {
|
||||
@@ -408,6 +624,30 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/simpleCallWithNonMatchingArgs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastExplicitDispatchReceiver.kt")
|
||||
public void testSmartCastExplicitDispatchReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/smartCastExplicitDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastExplicitExtensionReceiver.kt")
|
||||
public void testSmartCastExplicitExtensionReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/smartCastExplicitExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastImplicitDispatchReceiver.kt")
|
||||
public void testSmartCastImplicitDispatchReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/smartCastImplicitDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastImplicitExtensionReceiver.kt")
|
||||
public void testSmartCastImplicitExtensionReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/smartCastImplicitExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unresolvedSuperReference.kt")
|
||||
public void testUnresolvedSuperReference() throws Exception {
|
||||
@@ -468,6 +708,18 @@ public class FirResolveCallTestGenerated extends AbstractFirResolveCallTest {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/variableWithExtensionInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("variableWithInvokeFunctionCall_dispatchReceiver.kt")
|
||||
public void testVariableWithInvokeFunctionCall_dispatchReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/variableWithInvokeFunctionCall_dispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("variableWithInvokeFunctionCall_extensionReceiver.kt")
|
||||
public void testVariableWithInvokeFunctionCall_extensionReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/variableWithInvokeFunctionCall_extensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("variableWithMemberInvoke.kt")
|
||||
public void testVariableWithMemberInvoke() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user