Evaluate Expression: support anonymous objects evaluation
This commit is contained in:
@@ -17,8 +17,10 @@
|
||||
package org.jetbrains.kotlin.psi.codeFragmentUtil
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetCodeFragment
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetTypeReference
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
|
||||
public val SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE: Key<Boolean> = Key.create<Boolean>("SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE")
|
||||
|
||||
@@ -30,4 +32,15 @@ public var JetFile.suppressDiagnosticsInDebugMode: Boolean
|
||||
}
|
||||
set(skip: Boolean) {
|
||||
putUserData(SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE, skip)
|
||||
}
|
||||
}
|
||||
|
||||
public val DEBUG_TYPE_REFERENCE_STRING: String = "DebugTypeKotlinRulezzzz"
|
||||
|
||||
public val DEBUG_TYPE_INFO: Key<JetType> = Key.create<JetType>("DEBUG_TYPE_INFO")
|
||||
public var JetTypeReference.debugTypeInfo: JetType?
|
||||
get() = getUserData(DEBUG_TYPE_INFO)
|
||||
set(type: JetType?) {
|
||||
if (type != null && this.getText() == DEBUG_TYPE_REFERENCE_STRING) {
|
||||
putUserData(DEBUG_TYPE_INFO, type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.lazy.LazyEntity
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.psi.debugText.getDebugText
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo
|
||||
|
||||
public class TypeResolver(
|
||||
private val annotationResolver: AnnotationResolver,
|
||||
@@ -67,6 +68,12 @@ public class TypeResolver(
|
||||
val cachedType = c.trace.getBindingContext().get(BindingContext.TYPE, typeReference)
|
||||
if (cachedType != null) return type(cachedType)
|
||||
|
||||
if (typeReference.debugTypeInfo != null) {
|
||||
val debugType = typeReference.debugTypeInfo
|
||||
c.trace.record(BindingContext.TYPE, typeReference, debugType)
|
||||
return type(debugType)
|
||||
}
|
||||
|
||||
if (!c.allowBareTypes && lazinessToken.isLazy()) {
|
||||
// Bare types can be allowed only inside expressions; lazy type resolution is only relevant for declarations
|
||||
class LazyKotlinType : DelegatingType(), LazyEntity {
|
||||
|
||||
@@ -16,69 +16,63 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.evaluate
|
||||
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.*
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.evaluation.*
|
||||
import com.intellij.debugger.engine.SuspendContext
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.engine.evaluation.expression.*
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import org.jetbrains.kotlin.idea.JetLanguage
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.openapi.diagnostic.Attachment
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import com.sun.jdi.*
|
||||
import com.sun.jdi.request.EventRequest
|
||||
import org.jetbrains.eval4j.*
|
||||
import org.jetbrains.eval4j.Value
|
||||
import org.jetbrains.eval4j.jdi.JDIEval
|
||||
import org.jetbrains.eval4j.jdi.asJdiValue
|
||||
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.eval4j.jdi.asValue
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.codegen.ClassFileFactory
|
||||
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.psi.JetCodeFragment
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import com.sun.jdi.request.EventRequest
|
||||
import com.sun.jdi.ObjectReference
|
||||
import com.intellij.debugger.engine.SuspendContext
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import com.sun.jdi.VirtualMachine
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import com.sun.jdi.InvalidStackFrameException
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.analysisContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.idea.JetLanguage
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.JavaResolveExtension
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.types.Flexibility
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile
|
||||
import com.intellij.openapi.diagnostic.Attachment
|
||||
import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments
|
||||
import com.sun.jdi.ClassType
|
||||
import com.sun.jdi.InvocationException
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.CompiledDataDescriptor
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.ParametersDescriptor
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.loadClasses
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile
|
||||
import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.types.Flexibility
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
private val RECEIVER_NAME = "\$receiver"
|
||||
private val THIS_NAME = "this"
|
||||
@@ -126,7 +120,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
val compiledData = KotlinEvaluateExpressionCache.getOrCreateCompiledData(codeFragment, sourcePosition, context) {
|
||||
fragment, position ->
|
||||
isCompiledDataFromCache = false
|
||||
extractAndCompile(fragment, position)
|
||||
extractAndCompile(fragment, position, context)
|
||||
}
|
||||
val result = runEval4j(context, compiledData)
|
||||
|
||||
@@ -134,7 +128,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
|
||||
// If bytecode was taken from cache and exception was thrown - recompile bytecode and run eval4j again
|
||||
if (isCompiledDataFromCache && result is ExceptionThrown && result.kind == ExceptionThrown.ExceptionKind.BROKEN_CODE) {
|
||||
return runEval4j(context, extractAndCompile(codeFragment, sourcePosition)).toJdiValue(virtualMachine)
|
||||
return runEval4j(context, extractAndCompile(codeFragment, sourcePosition, context)).toJdiValue(virtualMachine)
|
||||
}
|
||||
|
||||
return result.toJdiValue(virtualMachine)
|
||||
@@ -159,7 +153,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
}
|
||||
|
||||
class object {
|
||||
private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition): CompiledDataDescriptor {
|
||||
private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition, context: EvaluationContextImpl): CompiledDataDescriptor {
|
||||
codeFragment.checkForErrors()
|
||||
|
||||
val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine())
|
||||
@@ -167,7 +161,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
throw IllegalStateException("Code fragment cannot be extracted to function")
|
||||
}
|
||||
|
||||
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction)
|
||||
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context)
|
||||
|
||||
// KT-4509
|
||||
val outputFiles = (classFileFactory : OutputFileCollection).asList()
|
||||
@@ -273,7 +267,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
return parameterNames.zip(parameterTypes).map { this.findLocalVariable(it.first, it.second, checkType = false, failIfNotFound = true)!! }
|
||||
}
|
||||
|
||||
private fun createClassFileFactory(codeFragment: JetCodeFragment, extractedFunction: JetNamedFunction): ClassFileFactory {
|
||||
private fun createClassFileFactory(codeFragment: JetCodeFragment, extractedFunction: JetNamedFunction, context: EvaluationContextImpl): ClassFileFactory {
|
||||
return runReadAction {
|
||||
val file = createFileForDebugger(codeFragment, extractedFunction)
|
||||
|
||||
@@ -287,12 +281,44 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
listOf(file)
|
||||
)
|
||||
|
||||
extractedFunction.getReceiverTypeReference()?.let {
|
||||
state.recordAnonymousType(it, THIS_NAME, context)
|
||||
}
|
||||
|
||||
for (param in extractedFunction.getValueParameters()) {
|
||||
val paramRef = param.getTypeReference()
|
||||
val paramName = param.getName()
|
||||
if (paramRef == null || paramName == null) {
|
||||
logger.error("Each parameter for extracted function should have a name and a type reference",
|
||||
Attachment("codeFragment.txt", codeFragment.getText()),
|
||||
Attachment("extractedFunction.txt", extractedFunction.getText()))
|
||||
|
||||
exception("An exception occurs during Evaluate Expression Action")
|
||||
}
|
||||
|
||||
state.recordAnonymousType(paramRef, paramName, context)
|
||||
}
|
||||
|
||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION)
|
||||
|
||||
state.getFactory()
|
||||
}
|
||||
}
|
||||
|
||||
private fun GenerationState.recordAnonymousType(typeReference: JetTypeReference, localVariableName: String, context: EvaluationContextImpl) {
|
||||
val paramAnonymousType = typeReference.debugTypeInfo
|
||||
if (paramAnonymousType != null) {
|
||||
val declarationDescriptor = paramAnonymousType.getConstructor().getDeclarationDescriptor()
|
||||
if (declarationDescriptor is ClassDescriptor) {
|
||||
val localVariable = context.findLocalVariable(localVariableName, asmType = null, checkType = false, failIfNotFound = false)
|
||||
if (localVariable == null) {
|
||||
exception("Couldn't find local variable this in current frame to get classType for anonymous type ${paramAnonymousType}}")
|
||||
}
|
||||
getBindingTrace().record(CodegenBinding.ASM_TYPE, declarationDescriptor, localVariable.asmType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg)
|
||||
|
||||
private fun exception(e: Throwable): Nothing {
|
||||
@@ -351,6 +377,18 @@ private fun createFileForDebugger(codeFragment: JetCodeFragment,
|
||||
|
||||
val jetFile = codeFragment.createJetFile("debugFile.kt", fileText)
|
||||
jetFile.suppressDiagnosticsInDebugMode = true
|
||||
|
||||
val list = jetFile.getDeclarations()
|
||||
val function = list.get(0) as JetNamedFunction
|
||||
|
||||
function.getReceiverTypeReference()?.debugTypeInfo = extractedFunction.getReceiverTypeReference()?.debugTypeInfo
|
||||
|
||||
for ((newParam, oldParam) in function.getValueParameters().zip(extractedFunction.getValueParameters())) {
|
||||
newParam.getTypeReference()?.debugTypeInfo = oldParam.getTypeReference()?.debugTypeInfo
|
||||
}
|
||||
|
||||
function.getTypeReference()?.debugTypeInfo = extractedFunction.getTypeReference()?.debugTypeInfo
|
||||
|
||||
return jetFile
|
||||
}
|
||||
|
||||
@@ -451,8 +489,8 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT
|
||||
}
|
||||
}
|
||||
|
||||
fun Value.isSharedVar(expectedType: Type?): Boolean {
|
||||
return expectedType != null && this.asmType == StackValue.sharedTypeForType(expectedType)
|
||||
fun Value.isSharedVar(): Boolean {
|
||||
return this.asmType.getSort() == Type.OBJECT && this.asmType.getInternalName().startsWith(AsmTypes.REF_TYPE_PREFIX)
|
||||
}
|
||||
|
||||
fun getValueForSharedVar(value: Value, expectedType: Type?, checkType: Boolean): Value? {
|
||||
@@ -466,7 +504,7 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT
|
||||
val localVariable = frame.visibleVariableByName(name)
|
||||
if (localVariable != null) {
|
||||
val eval4jValue = frame.getValue(localVariable).asValue()
|
||||
if (eval4jValue.isSharedVar(asmType)) {
|
||||
if (eval4jValue.isSharedVar()) {
|
||||
val sharedVarValue = getValueForSharedVar(eval4jValue, asmType, checkType)
|
||||
if (sharedVarValue != null) {
|
||||
return sharedVarValue
|
||||
@@ -493,7 +531,7 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT
|
||||
val capturedValName = getCapturedFieldName(name)
|
||||
val capturedVal = findCapturedVal(capturedValName)
|
||||
if (capturedVal != null) {
|
||||
if (capturedVal.isSharedVar(asmType)) {
|
||||
if (capturedVal.isSharedVar()) {
|
||||
val sharedVarValue = getValueForSharedVar(capturedVal, asmType, checkType)
|
||||
if (sharedVarValue != null) {
|
||||
return sharedVarValue
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ fun getFunctionForExtractedFragment(
|
||||
if (targetSibling == null) return null
|
||||
|
||||
val analysisResult = ExtractionData(
|
||||
tmpFile, newDebugExpression.toRange(), targetSibling, ExtractionOptions(false, true)
|
||||
tmpFile, newDebugExpression.toRange(), targetSibling, ExtractionOptions(false, true, true)
|
||||
).performAnalysis()
|
||||
if (analysisResult.status != Status.SUCCESS) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||
|
||||
+5
-3
@@ -63,10 +63,12 @@ trait Parameter {
|
||||
val originalDescriptor: DeclarationDescriptor
|
||||
val name: String
|
||||
val mirrorVarName: String?
|
||||
val parameterType: JetType
|
||||
val parameterTypeCandidates: List<JetType>
|
||||
val receiverCandidate: Boolean
|
||||
|
||||
fun getParameterType(allowSpecialClassNames: Boolean): JetType
|
||||
|
||||
fun getParameterTypeCandidates(allowSpecialClassNames: Boolean): List<JetType>
|
||||
|
||||
fun copy(name: String, parameterType: JetType): Parameter
|
||||
}
|
||||
|
||||
@@ -143,7 +145,7 @@ trait OutputValue {
|
||||
val parameter: Parameter,
|
||||
override val originalExpressions: List<JetExpression>
|
||||
): OutputValue {
|
||||
override val valueType: JetType get() = parameter.parameterType
|
||||
override val valueType: JetType get() = parameter.getParameterType(false)
|
||||
}
|
||||
|
||||
class Initializer(
|
||||
|
||||
@@ -55,10 +55,11 @@ import org.jetbrains.kotlin.idea.refactoring.compareDescriptors
|
||||
|
||||
data class ExtractionOptions(
|
||||
val inferUnitTypeForUnusedValues: Boolean,
|
||||
val enableListBoxing: Boolean
|
||||
val enableListBoxing: Boolean,
|
||||
val allowSpecialClassNames: Boolean
|
||||
) {
|
||||
class object {
|
||||
val DEFAULT = ExtractionOptions(true, false)
|
||||
val DEFAULT = ExtractionOptions(true, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-9
@@ -441,6 +441,7 @@ private fun JetType.isExtractable(): Boolean {
|
||||
private fun JetType.processTypeIfExtractable(
|
||||
typeParameters: MutableSet<TypeParameter>,
|
||||
nonDenotableTypes: MutableSet<JetType>,
|
||||
options: ExtractionOptions,
|
||||
processTypeArguments: Boolean = true
|
||||
): Boolean {
|
||||
return collectReferencedTypes(processTypeArguments).fold(true) { (extractable, typeToCheck) ->
|
||||
@@ -458,6 +459,9 @@ private fun JetType.processTypeIfExtractable(
|
||||
typeToCheck.canBeReferencedViaImport() ->
|
||||
extractable
|
||||
|
||||
options.allowSpecialClassNames && typeToCheck.isSpecial() ->
|
||||
extractable
|
||||
|
||||
typeToCheck.isError() ->
|
||||
false
|
||||
|
||||
@@ -501,7 +505,7 @@ private class MutableParameter(
|
||||
CommonSupertypes.commonSupertype(defaultTypes)
|
||||
}
|
||||
|
||||
override val parameterTypeCandidates: List<JetType> by Delegates.lazy {
|
||||
private val parameterTypeCandidates: List<JetType> by Delegates.lazy {
|
||||
writable = false
|
||||
|
||||
val typePredicate = and(typePredicates)
|
||||
@@ -522,10 +526,20 @@ private class MutableParameter(
|
||||
typeList.add(superType)
|
||||
}
|
||||
|
||||
typeList.filter { it.isExtractable() }
|
||||
typeList
|
||||
}
|
||||
|
||||
override val parameterType: JetType by Delegates.lazy { parameterTypeCandidates.firstOrNull() ?: defaultType }
|
||||
override fun getParameterTypeCandidates(allowSpecialClassNames: Boolean): List<JetType> {
|
||||
return if (!allowSpecialClassNames) {
|
||||
parameterTypeCandidates.filter { it.isExtractable() }
|
||||
} else {
|
||||
parameterTypeCandidates
|
||||
}
|
||||
}
|
||||
|
||||
override fun getParameterType(allowSpecialClassNames: Boolean): JetType {
|
||||
return getParameterTypeCandidates(allowSpecialClassNames).firstOrNull() ?: defaultType
|
||||
}
|
||||
|
||||
override fun copy(name: String, parameterType: JetType): Parameter = DelegatingParameter(this, name, parameterType)
|
||||
}
|
||||
@@ -533,9 +547,10 @@ private class MutableParameter(
|
||||
private class DelegatingParameter(
|
||||
val original: Parameter,
|
||||
override val name: String,
|
||||
override val parameterType: JetType
|
||||
val parameterType: JetType
|
||||
): Parameter by original {
|
||||
override fun copy(name: String, parameterType: JetType): Parameter = DelegatingParameter(original, name, parameterType)
|
||||
override fun getParameterType(allowSpecialClassNames: Boolean) = parameterType
|
||||
}
|
||||
|
||||
private class ParametersInfo {
|
||||
@@ -596,7 +611,7 @@ private fun ExtractionData.inferParametersInfo(
|
||||
|
||||
if (referencedClassDescriptor != null) {
|
||||
if (!referencedClassDescriptor.getDefaultType().processTypeIfExtractable(
|
||||
info.typeParameters, info.nonDenotableTypes, false
|
||||
info.typeParameters, info.nonDenotableTypes, options, false
|
||||
)) continue
|
||||
|
||||
info.replacementMap[refInfo.offsetInBody] = FqNameReplacement(originalDescriptor.importableFqNameSafe)
|
||||
@@ -657,11 +672,11 @@ private fun ExtractionData.inferParametersInfo(
|
||||
)
|
||||
|
||||
for ((descriptorToExtract, parameter) in extractedDescriptorToParameter) {
|
||||
if (!parameter.parameterType.processTypeIfExtractable(info.typeParameters, info.nonDenotableTypes)) continue
|
||||
if (!parameter.getParameterType(options.allowSpecialClassNames).processTypeIfExtractable(info.typeParameters, info.nonDenotableTypes, options)) continue
|
||||
|
||||
with (parameter) {
|
||||
if (currentName == null) {
|
||||
currentName = JetNameSuggester.suggestNames(parameterType, varNameValidator, "p").first()
|
||||
currentName = JetNameSuggester.suggestNames(getParameterType(options.allowSpecialClassNames), varNameValidator, "p").first()
|
||||
}
|
||||
mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors) varNameValidator.validateName(name) else null
|
||||
info.parameters.add(this)
|
||||
@@ -669,7 +684,7 @@ private fun ExtractionData.inferParametersInfo(
|
||||
}
|
||||
|
||||
for (typeToCheck in info.typeParameters.flatMapTo(HashSet<JetType>()) { it.collectReferencedTypes(bindingContext) }) {
|
||||
typeToCheck.processTypeIfExtractable(info.typeParameters, info.nonDenotableTypes)
|
||||
typeToCheck.processTypeIfExtractable(info.typeParameters, info.nonDenotableTypes, options)
|
||||
}
|
||||
|
||||
|
||||
@@ -763,7 +778,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
controlFlowMessage?.let { messages.add(it) }
|
||||
|
||||
val returnType = controlFlow.outputValueBoxer.returnType
|
||||
returnType.processTypeIfExtractable(paramsInfo.typeParameters, paramsInfo.nonDenotableTypes)
|
||||
returnType.processTypeIfExtractable(paramsInfo.typeParameters, paramsInfo.nonDenotableTypes, options)
|
||||
|
||||
if (paramsInfo.nonDenotableTypes.isNotEmpty()) {
|
||||
val typeStr = paramsInfo.nonDenotableTypes.map {it.renderForMessage()}.sort()
|
||||
|
||||
@@ -16,49 +16,39 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.extractFunction
|
||||
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import java.util.HashMap
|
||||
import org.jetbrains.kotlin.psi.JetTreeVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder.Target
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||
import java.util.LinkedHashMap
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteralArgument
|
||||
import org.jetbrains.kotlin.idea.util.psiModificationUtil.moveInsideParenthesesAndReplaceWith
|
||||
import org.jetbrains.kotlin.psi.psiUtil.appendElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.replaced
|
||||
import org.jetbrains.kotlin.psi.JetBlockExpression
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.ParameterUpdate
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.Jump
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.Initializer
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.ExpressionValue
|
||||
import org.jetbrains.kotlin.psi.JetReturnExpression
|
||||
import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.refactoring.JetNameSuggester
|
||||
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
|
||||
import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.ExpressionValue
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.Initializer
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.Jump
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValue.ParameterUpdate
|
||||
import org.jetbrains.kotlin.idea.refactoring.extractFunction.OutputValueBoxer.AsTuple
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.UnifierParameter
|
||||
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiRange
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiRange.Match
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.UnificationResult.WeaklyMatched
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.UnificationResult.StronglyMatched
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.UnificationResult.WeaklyMatched
|
||||
import org.jetbrains.kotlin.idea.util.psi.patternMatching.UnifierParameter
|
||||
import org.jetbrains.kotlin.idea.util.psiModificationUtil.moveInsideParenthesesAndReplaceWith
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder.Target
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.DEBUG_TYPE_REFERENCE_STRING
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import java.util.Collections
|
||||
import java.util.HashMap
|
||||
import java.util.LinkedHashMap
|
||||
|
||||
fun ExtractableCodeDescriptor.getDeclarationText(
|
||||
options: ExtractionGeneratorOptions = ExtractionGeneratorOptions.DEFAULT,
|
||||
@@ -77,16 +67,20 @@ fun ExtractableCodeDescriptor.getDeclarationText(
|
||||
|
||||
builder.typeParams(typeParameters.map { it.originalDeclaration.getText()!! })
|
||||
|
||||
receiverParameter?.let { builder.receiver(descriptorRenderer.renderType(it.parameterType)) }
|
||||
fun JetType.typeAsString(): String {
|
||||
return if (isSpecial()) DEBUG_TYPE_REFERENCE_STRING else descriptorRenderer.renderType(this)
|
||||
}
|
||||
|
||||
receiverParameter?.let { builder.receiver(it.getParameterType(extractionData.options.allowSpecialClassNames).typeAsString()) }
|
||||
|
||||
builder.name(if (name != "") name else DEFAULT_FUNCTION_NAME)
|
||||
|
||||
parameters.forEach { parameter ->
|
||||
builder.param(parameter.name, descriptorRenderer.renderType(parameter.parameterType))
|
||||
builder.param(parameter.name, parameter.getParameterType(extractionData.options.allowSpecialClassNames).typeAsString())
|
||||
}
|
||||
|
||||
with(controlFlow.outputValueBoxer.returnType) {
|
||||
if (isDefault() || isError()) builder.noReturnType() else builder.returnType(descriptorRenderer.renderType(this))
|
||||
if (isDefault() || isError()) builder.noReturnType() else builder.returnType(this.typeAsString())
|
||||
}
|
||||
|
||||
builder.typeConstraints(typeParameters.flatMap { it.originalConstraints }.map { it.getText()!! })
|
||||
@@ -99,6 +93,10 @@ fun ExtractableCodeDescriptor.getDeclarationText(
|
||||
}
|
||||
}
|
||||
|
||||
fun JetType.isSpecial(): Boolean {
|
||||
return this.getConstructor().getDeclarationDescriptor()?.getName()?.isSpecial() ?: false
|
||||
}
|
||||
|
||||
fun createNameCounterpartMap(from: JetElement, to: JetElement): Map<JetSimpleNameExpression, JetSimpleNameExpression> {
|
||||
val map = HashMap<JetSimpleNameExpression, JetSimpleNameExpression>()
|
||||
|
||||
@@ -172,7 +170,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
|
||||
return if (matched) newControlFlow else null
|
||||
}
|
||||
|
||||
val unifierParameters = parameters.map { UnifierParameter(it.originalDescriptor, it.parameterType) }
|
||||
val unifierParameters = parameters.map { UnifierParameter(it.originalDescriptor, it.getParameterType(extractionData.options.allowSpecialClassNames)) }
|
||||
|
||||
val unifier = JetPsiUnifier(unifierParameters, true)
|
||||
|
||||
@@ -527,6 +525,18 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
val declaration = createDeclaration().let { if (options.inTempFile) it else insertDeclaration(it, anchor) }
|
||||
adjustDeclarationBody(declaration)
|
||||
|
||||
if (declaration is JetNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) {
|
||||
declaration.getReceiverTypeReference()?.debugTypeInfo = receiverParameter?.getParameterType(true)
|
||||
|
||||
for ((i, param) in declaration.getValueParameters().withIndex()) {
|
||||
param.getTypeReference()?.debugTypeInfo = parameters[i].getParameterType(true)
|
||||
}
|
||||
|
||||
if (declaration.getTypeReference() != null) {
|
||||
declaration.getTypeReference()?.debugTypeInfo = KotlinBuiltIns.getInstance().getAnyType()
|
||||
}
|
||||
}
|
||||
|
||||
if (options.inTempFile) return ExtractionResult(declaration, Collections.emptyMap(), nameByOffset)
|
||||
|
||||
makeCall(this, declaration, controlFlow, extractionData.originalRange, parameters.map { it.argumentText })
|
||||
|
||||
+3
-3
@@ -55,7 +55,7 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
public ParameterInfo(Parameter originalParameter) {
|
||||
this.originalParameter = originalParameter;
|
||||
this.name = originalParameter.getName();
|
||||
this.type = originalParameter.getParameterType();
|
||||
this.type = originalParameter.getParameterType(false);
|
||||
}
|
||||
|
||||
public Parameter getOriginalParameter() {
|
||||
@@ -176,7 +176,7 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
ParameterInfo info = parameterInfos.get(row);
|
||||
|
||||
myEditorComponent.setCell(table, row, column);
|
||||
myEditorComponent.setOptions(info.getOriginalParameter().getParameterTypeCandidates().toArray());
|
||||
myEditorComponent.setOptions(info.getOriginalParameter().getParameterTypeCandidates(false).toArray());
|
||||
myEditorComponent.setDefaultValue(info.getType());
|
||||
myEditorComponent.setToString(new Function<Object, String>() {
|
||||
@Override
|
||||
@@ -360,7 +360,7 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
case PARAMETER_NAME_COLUMN:
|
||||
return isEnabled() && info.isEnabled();
|
||||
case PARAMETER_TYPE_COLUMN:
|
||||
return isEnabled() && info.isEnabled() && info.getOriginalParameter().getParameterTypeCandidates().size() > 1;
|
||||
return isEnabled() && info.isEnabled() && info.getOriginalParameter().getParameterTypeCandidates(false).size() > 1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
LineBreakpoint created at ceAnonymousObject.kt:18
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ceAnonymousObject.CeAnonymousObjectPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
ceAnonymousObject.kt:18
|
||||
Compile bytecode for publicTopLevelObject
|
||||
Compile bytecode for privateTopLevelObject
|
||||
Compile bytecode for publicObject
|
||||
Compile bytecode for protectedObject
|
||||
Compile bytecode for localObject
|
||||
Compile bytecode for localObject.test()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at ceAnonymousObjectCapturedInClosure.kt:7
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ceAnonymousObjectCapturedInClosure.CeAnonymousObjectCapturedInClosurePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
ceAnonymousObjectCapturedInClosure.kt:7
|
||||
Compile bytecode for lambda { localObject.test() }
|
||||
Compile bytecode for lambda { localObjectVar.test() }
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at ceAnonymousObjectThisAsReceiver.kt:9
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ceAnonymousObjectThisAsReceiver.CeAnonymousObjectThisAsReceiverPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
ceAnonymousObjectThisAsReceiver.kt:9
|
||||
Compile bytecode for test()
|
||||
Compile bytecode for this.test()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -2,6 +2,8 @@ LineBreakpoint created at ceObject.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ceObject.CeObjectPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
ceObject.kt:5
|
||||
Compile bytecode for (object: T {}).test()
|
||||
Compile bytecode for object: T {}
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package ceAnonymousObject
|
||||
|
||||
public val publicTopLevelObject: Any = object { fun test() = 1 }
|
||||
private val privateTopLevelObject = object { fun test() = 1 }
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
MyClass().foo()
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
public val publicObject: Any = object { fun test() = 1 }
|
||||
protected val protectedObject: Any = object { fun test() = 1 }
|
||||
private val privateObject = object { fun test() = 1 }
|
||||
|
||||
fun foo() {
|
||||
val localObject = object { fun test() = 1 }
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
}
|
||||
}
|
||||
|
||||
// EXPRESSION: publicTopLevelObject
|
||||
// RESULT: instance of ceAnonymousObject.CeAnonymousObjectPackage$ceAnonymousObject$@packagePartHASH$publicTopLevelObject$1(id=ID): LceAnonymousObject/CeAnonymousObjectPackage$ceAnonymousObject$@packagePartHASH$publicTopLevelObject$1;
|
||||
|
||||
// EXPRESSION: privateTopLevelObject
|
||||
// RESULT: instance of ceAnonymousObject.CeAnonymousObjectPackage$ceAnonymousObject$@packagePartHASH$privateTopLevelObject$1(id=ID): LceAnonymousObject/CeAnonymousObjectPackage$ceAnonymousObject$@packagePartHASH$privateTopLevelObject$1;
|
||||
|
||||
// EXPRESSION: publicObject
|
||||
// RESULT: instance of ceAnonymousObject.MyClass$publicObject$1(id=ID): LceAnonymousObject/MyClass$publicObject$1;
|
||||
|
||||
// EXPRESSION: protectedObject
|
||||
// RESULT: instance of ceAnonymousObject.MyClass$protectedObject$1(id=ID): LceAnonymousObject/MyClass$protectedObject$1;
|
||||
|
||||
// -EXPRESSION: privateObject
|
||||
// -RESULT: 1
|
||||
|
||||
// -EXPRESSION: privateObject.test()
|
||||
// -RESULT: 1: I
|
||||
|
||||
// EXPRESSION: localObject
|
||||
// RESULT: instance of ceAnonymousObject.MyClass$foo$localObject$1(id=ID): LceAnonymousObject/MyClass$foo$localObject$1;
|
||||
|
||||
// EXPRESSION: localObject.test()
|
||||
// RESULT: 1: I
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package ceAnonymousObjectCapturedInClosure
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val localObject = object { fun test() = 1 }
|
||||
var localObjectVar = object { fun test() = 1 }
|
||||
//Breakpoint!
|
||||
lambda { localObjectVar.test() }
|
||||
}
|
||||
|
||||
fun lambda(f: () -> Int) = f()
|
||||
|
||||
// EXPRESSION: lambda { localObject.test() }
|
||||
// RESULT: 1: I
|
||||
|
||||
// EXPRESSION: lambda { localObjectVar.test() }
|
||||
// RESULT: 1: I
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package ceAnonymousObjectThisAsReceiver
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
val localObject = object {
|
||||
fun test() = 1
|
||||
|
||||
fun foo() {
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
}
|
||||
}
|
||||
|
||||
localObject.foo()
|
||||
}
|
||||
|
||||
// EXPRESSION: test()
|
||||
// RESULT: 1: I
|
||||
|
||||
// EXPRESSION: this.test()
|
||||
// RESULT: 1: I
|
||||
+5
-2
@@ -9,5 +9,8 @@ trait T {
|
||||
fun test() = 1
|
||||
}
|
||||
|
||||
//- EXPRESSION: (object: T {}).test()
|
||||
//- RESULT: 1: I
|
||||
// EXPRESSION: (object: T {}).test()
|
||||
// RESULT: 1: I
|
||||
|
||||
// EXPRESSION: object: T {}
|
||||
// RESULT: instance of packageForDebugger.PackageForDebuggerPackage$debugFile$@packagePartHASH$myFun$1(id=ID): LpackageForDebugger/PackageForDebuggerPackage$debugFile$@packagePartHASH$myFun$1;
|
||||
@@ -1,3 +0,0 @@
|
||||
object {}
|
||||
|
||||
// RESULT: Cannot perform an action because following types are unavailable from debugger scope: <no name provided>
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// OPTIONS: true, true
|
||||
// OPTIONS: true, true, false
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// OPTIONS: true, true
|
||||
// OPTIONS: true, true, false
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
|
||||
+6
-1
@@ -63,6 +63,8 @@ import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.SourcePositionProvider
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImports
|
||||
import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
||||
private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!!
|
||||
@@ -353,8 +355,11 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
|
||||
|
||||
private fun Value.asString(): String {
|
||||
if (this is ObjectValue && this.value is ObjectReference) {
|
||||
return this.toString().replaceFirst("id=[0-9]*", "id=ID")
|
||||
val regexMatcher = PACKAGE_PART_PATTERN.matcher(this.toString())
|
||||
return regexMatcher.replaceAll("$1@packagePartHASH").replaceFirst("id=[0-9]*", "id=ID")
|
||||
}
|
||||
return this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private val PACKAGE_PART_PATTERN = Pattern.compile("(Package\\$[\\w]*\\$)([0-9a-f]+)");
|
||||
|
||||
+18
@@ -243,6 +243,24 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ceAnonymousObject.kt")
|
||||
public void testCeAnonymousObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObject.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ceAnonymousObjectCapturedInClosure.kt")
|
||||
public void testCeAnonymousObjectCapturedInClosure() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectCapturedInClosure.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ceAnonymousObjectThisAsReceiver.kt")
|
||||
public void testCeAnonymousObjectThisAsReceiver() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectThisAsReceiver.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ceLambda.kt")
|
||||
public void testCeLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceLambda.kt");
|
||||
|
||||
+5
-2
@@ -44,6 +44,7 @@ import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.psi.JetPackageDirective
|
||||
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTestCase() {
|
||||
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
||||
@@ -96,7 +97,9 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
if (it.isNotEmpty()) {
|
||||
[suppress("CAST_NEVER_SUCCEEDS")]
|
||||
val args = it.map { it.toBoolean() }.copyToArray() as Array<Any?>
|
||||
javaClass<ExtractionOptions>().getConstructors()[0].newInstance(*args) as ExtractionOptions
|
||||
val constructor = javaClass<ExtractionOptions>().getConstructors()[0]
|
||||
assertTrue(constructor.getParameterTypes().size() == args.size(), "Wrong number of parameters was passed for ExtractOptions constructor: expected = ${constructor.getParameterTypes().size()}, actual = ${args.size()}. \nTest directive: // OPTIONS: $it")
|
||||
constructor.newInstance(*args) as ExtractionOptions
|
||||
} else ExtractionOptions.DEFAULT
|
||||
}
|
||||
|
||||
@@ -118,7 +121,7 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
val allParameters = emptyOrSingletonList(descriptor.receiverParameter) + descriptor.parameters
|
||||
val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString()
|
||||
val actualTypes = allParameters.map {
|
||||
it.parameterTypeCandidates.map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
||||
it.getParameterTypeCandidates(extractionOptions.allowSpecialClassNames).map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
||||
}.joinToString()
|
||||
|
||||
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
|
||||
|
||||
Reference in New Issue
Block a user