From 0391fbd7647fb0ea6c68a0000b6d9db5078dbb4b Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 11 Feb 2015 15:45:55 +0300 Subject: [PATCH] Evaluate Expression: support anonymous objects evaluation --- .../jetbrains/kotlin/psi/codeFragmentUtil.kt | 17 +- .../jetbrains/kotlin/resolve/TypeResolver.kt | 7 + .../evaluate/KotlinEvaluationBuilder.kt | 158 +++++++++++------- .../extractFunctionForDebuggerUtil.kt | 2 +- .../ExtractableCodeDescriptor.kt | 8 +- .../extractFunction/ExtractionData.kt | 5 +- .../extractableAnalysisUtil.kt | 33 +++- .../extractFunction/extractorUtil.kt | 88 +++++----- .../ui/KotlinParameterTablePanel.java | 6 +- .../tinyApp/outs/ceAnonymousObject.out | 13 ++ .../ceAnonymousObjectCapturedInClosure.out | 9 + .../outs/ceAnonymousObjectThisAsReceiver.out | 9 + .../debugger/tinyApp/outs/ceObject.out | 2 + .../compilingEvaluator/ceAnonymousObject.kt | 45 +++++ .../ceAnonymousObjectCapturedInClosure.kt | 16 ++ .../ceAnonymousObjectThisAsReceiver.kt | 20 +++ .../compilingEvaluator/ceObject.kt | 7 +- .../singleBreakpoint/errors.kt.fragment2 | 3 - .../outputValues/tooManyOutputValuesAsList.kt | 2 +- .../tooManyOutputValuesAsList.kt.after | 2 +- .../AbstractKotlinEvaluateExpressionTest.kt | 7 +- ...KotlinEvaluateExpressionTestGenerated.java | 18 ++ .../AbstractJetExtractionTest.kt | 7 +- 23 files changed, 355 insertions(+), 129 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/outs/ceAnonymousObject.out create mode 100644 idea/testData/debugger/tinyApp/outs/ceAnonymousObjectCapturedInClosure.out create mode 100644 idea/testData/debugger/tinyApp/outs/ceAnonymousObjectThisAsReceiver.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObject.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectCapturedInClosure.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectThisAsReceiver.kt delete mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/codeFragmentUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/codeFragmentUtil.kt index 337cc070b7b..b6c5a013fd8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/codeFragmentUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/codeFragmentUtil.kt @@ -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 = Key.create("SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE") @@ -30,4 +32,15 @@ public var JetFile.suppressDiagnosticsInDebugMode: Boolean } set(skip: Boolean) { putUserData(SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE, skip) - } \ No newline at end of file + } + +public val DEBUG_TYPE_REFERENCE_STRING: String = "DebugTypeKotlinRulezzzz" + +public val DEBUG_TYPE_INFO: Key = Key.create("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) + } + } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index 3ad3ceb12ef..82139a7934c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -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 { diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt index 5faef7b7f3f..9cdf1337e62 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt index be9de56bb58..8c39e25e231 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -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)) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt index 157d14fa1cd..b9b9e75c89b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt @@ -63,10 +63,12 @@ trait Parameter { val originalDescriptor: DeclarationDescriptor val name: String val mirrorVarName: String? - val parameterType: JetType - val parameterTypeCandidates: List val receiverCandidate: Boolean + fun getParameterType(allowSpecialClassNames: Boolean): JetType + + fun getParameterTypeCandidates(allowSpecialClassNames: Boolean): List + fun copy(name: String, parameterType: JetType): Parameter } @@ -143,7 +145,7 @@ trait OutputValue { val parameter: Parameter, override val originalExpressions: List ): OutputValue { - override val valueType: JetType get() = parameter.parameterType + override val valueType: JetType get() = parameter.getParameterType(false) } class Initializer( diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractionData.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractionData.kt index 89a72ffb486..df24c2651fb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractionData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractionData.kt @@ -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) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt index 14e2be1147a..fb5278d92e7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt @@ -441,6 +441,7 @@ private fun JetType.isExtractable(): Boolean { private fun JetType.processTypeIfExtractable( typeParameters: MutableSet, nonDenotableTypes: MutableSet, + 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 by Delegates.lazy { + private val parameterTypeCandidates: List 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 { + 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()) { 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() diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt index f6354a7ad32..1135b0abb35 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt @@ -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 { val map = HashMap() @@ -172,7 +170,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List { 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 }) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ui/KotlinParameterTablePanel.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ui/KotlinParameterTablePanel.java index 0d4c97c6fce..38cc9cf9193 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ui/KotlinParameterTablePanel.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ui/KotlinParameterTablePanel.java @@ -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() { @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; } diff --git a/idea/testData/debugger/tinyApp/outs/ceAnonymousObject.out b/idea/testData/debugger/tinyApp/outs/ceAnonymousObject.out new file mode 100644 index 00000000000..9cc48095e18 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/ceAnonymousObject.out @@ -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 diff --git a/idea/testData/debugger/tinyApp/outs/ceAnonymousObjectCapturedInClosure.out b/idea/testData/debugger/tinyApp/outs/ceAnonymousObjectCapturedInClosure.out new file mode 100644 index 00000000000..fb434b91131 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/ceAnonymousObjectCapturedInClosure.out @@ -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 diff --git a/idea/testData/debugger/tinyApp/outs/ceAnonymousObjectThisAsReceiver.out b/idea/testData/debugger/tinyApp/outs/ceAnonymousObjectThisAsReceiver.out new file mode 100644 index 00000000000..f5baf1d0f4a --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/ceAnonymousObjectThisAsReceiver.out @@ -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 diff --git a/idea/testData/debugger/tinyApp/outs/ceObject.out b/idea/testData/debugger/tinyApp/outs/ceObject.out index 41c5d94ab80..3b86403374d 100644 --- a/idea/testData/debugger/tinyApp/outs/ceObject.out +++ b/idea/testData/debugger/tinyApp/outs/ceObject.out @@ -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 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObject.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObject.kt new file mode 100644 index 00000000000..d68cbf77571 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObject.kt @@ -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) { + 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 + diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectCapturedInClosure.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectCapturedInClosure.kt new file mode 100644 index 00000000000..6870af5b319 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectCapturedInClosure.kt @@ -0,0 +1,16 @@ +package ceAnonymousObjectCapturedInClosure + +fun main(args: Array) { + 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 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectThisAsReceiver.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectThisAsReceiver.kt new file mode 100644 index 00000000000..629a775b568 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceAnonymousObjectThisAsReceiver.kt @@ -0,0 +1,20 @@ +package ceAnonymousObjectThisAsReceiver + +fun main(args : Array) { + 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 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt index d60ce9f995b..c40c516b416 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt @@ -9,5 +9,8 @@ trait T { fun test() = 1 } -//- EXPRESSION: (object: T {}).test() -//- RESULT: 1: I \ No newline at end of file +// 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; \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 deleted file mode 100644 index 0a73e90849b..00000000000 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 +++ /dev/null @@ -1,3 +0,0 @@ -object {} - -// RESULT: Cannot perform an action because following types are unavailable from debugger scope: \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt index 959ae017971..d006b101a41 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt @@ -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 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after index 0809754d63a..2cf7e10ddea 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt index e0072342756..6bc6e0bf614 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt @@ -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())!! @@ -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]+)"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index d4f1594fcaf..645cb7f10c3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -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"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt index 77b57aec2f8..dc84f6b5edc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt @@ -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 - javaClass().getConstructors()[0].newInstance(*args) as ExtractionOptions + val constructor = javaClass().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.")