diff --git a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt index 32f687a476b..b2c1d84478d 100644 --- a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt +++ b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt @@ -1,251 +1,55 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package org.jetbrains.kotlin.idea.debugger.stepping +package org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto import com.intellij.debugger.SourcePosition import com.intellij.debugger.actions.JvmSmartStepIntoHandler -import com.intellij.debugger.actions.MethodSmartStepTarget import com.intellij.debugger.actions.SmartStepTarget import com.intellij.debugger.engine.MethodFilter import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiMethod import com.intellij.util.Range import com.intellij.util.containers.OrderedSet -import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor -import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType -import org.jetbrains.kotlin.builtins.isSuspendFunctionType -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods -import org.jetbrains.kotlin.config.JvmTarget -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks -import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde -import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils -import org.jetbrains.kotlin.idea.util.application.runReadAction -import org.jetbrains.kotlin.load.java.isFromJava +import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils.getTopmostElementAtOffset +import org.jetbrains.kotlin.idea.debugger.stepping.KotlinBasicStepMethodFilter +import org.jetbrains.kotlin.idea.debugger.stepping.KotlinLambdaMethodFilter +import org.jetbrains.kotlin.idea.debugger.stepping.KotlinLambdaSmartStepTarget +import org.jetbrains.kotlin.idea.debugger.stepping.KotlinMethodSmartStepTarget import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall -import org.jetbrains.kotlin.resolve.inline.InlineUtil class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { - override fun isAvailable(position: SourcePosition?) = position?.file is KtFile override fun findSmartStepTargets(position: SourcePosition): List { val file = position.file + val element = position.elementAt ?: return emptyList() + val ktElement = getTopmostElementAtOffset(element, element.textRange.startOffset) as? KtElement + val elementTextRange = ktElement?.textRange ?: return emptyList() + val document = PsiDocumentManager.getInstance(file.project).getDocument(file) ?: return emptyList() + val lines = Range(document.getLineNumber(elementTextRange.startOffset), document.getLineNumber(elementTextRange.endOffset)) - val elementAtOffset = position.elementAt ?: return emptyList() + val consumer = OrderedSet() + val visitor = SmartStepTargetVisitor(ktElement, lines, consumer) + ktElement.accept(visitor, null) - val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset) as? KtElement - ?: return emptyList() - - val elementTextRange = element.textRange ?: return emptyList() - - val doc = PsiDocumentManager.getInstance(file.project).getDocument(file) ?: return emptyList() - - val lines = Range(doc.getLineNumber(elementTextRange.startOffset), doc.getLineNumber(elementTextRange.endOffset)) - @Suppress("DEPRECATION") - val bindingContext = element.analyzeWithAllCompilerChecks().bindingContext - val result = OrderedSet() - - // TODO support class initializers, local functions, delegated properties with specified type, setter for properties - element.accept(object : KtTreeVisitorVoid() { - override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) { - recordFunctionLiteral(lambdaExpression.functionLiteral) - } - - override fun visitNamedFunction(function: KtNamedFunction) { - if (!recordFunctionLiteral(function)) { - super.visitNamedFunction(function) - } - } - - private fun recordFunctionLiteral(function: KtFunction): Boolean { - val context = function.analyze() - val resolvedCall = function.getParentCall(context).getResolvedCall(context) - if (resolvedCall != null) { - val arguments = resolvedCall.valueArguments - for ((param, argument) in arguments) { - if (argument.arguments.any { getArgumentExpression(it) == function }) { - val resultingDescriptor = resolvedCall.resultingDescriptor - val label = KotlinLambdaSmartStepTarget.calcLabel(resultingDescriptor, param.name) - result.add( - KotlinLambdaSmartStepTarget( - label, function, lines, InlineUtil.isInline(resultingDescriptor), param.type.isSuspendFunctionType - ) - ) - return true - } - } - } - return false - } - - private fun getArgumentExpression(it: ValueArgument) = - (it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression() - - override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) { - // skip calls in object declarations - } - - override fun visitIfExpression(expression: KtIfExpression) { - expression.condition?.accept(this) - } - - override fun visitWhileExpression(expression: KtWhileExpression) { - expression.condition?.accept(this) - } - - override fun visitDoWhileExpression(expression: KtDoWhileExpression) { - expression.condition?.accept(this) - } - - override fun visitForExpression(expression: KtForExpression) { - expression.loopRange?.accept(this) - } - - override fun visitWhenExpression(expression: KtWhenExpression) { - expression.subjectExpression?.accept(this) - } - - override fun visitArrayAccessExpression(expression: KtArrayAccessExpression) { - recordFunction(expression) - super.visitArrayAccessExpression(expression) - } - - override fun visitUnaryExpression(expression: KtUnaryExpression) { - recordFunction(expression.operationReference) - super.visitUnaryExpression(expression) - } - - override fun visitBinaryExpression(expression: KtBinaryExpression) { - recordFunction(expression.operationReference) - super.visitBinaryExpression(expression) - } - - override fun visitCallExpression(expression: KtCallExpression) { - val calleeExpression = expression.calleeExpression - if (calleeExpression != null) { - recordFunction(calleeExpression) - } - super.visitCallExpression(expression) - } - - override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { - recordGetter(expression) - super.visitSimpleNameExpression(expression) - } - - private fun recordGetter(expression: KtSimpleNameExpression) { - val resolvedCall = expression.getResolvedCall(bindingContext) ?: return - val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return - - val getterDescriptor = propertyDescriptor.getter - if (getterDescriptor == null || getterDescriptor.isDefault) return - - val ktDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, getterDescriptor) as? KtDeclaration ?: return - - val delegatedResolvedCall = bindingContext[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor] - if (delegatedResolvedCall != null) { - val delegatedPropertyGetterDescriptor = delegatedResolvedCall.resultingDescriptor - val label = "${propertyDescriptor.name}." + KotlinMethodSmartStepTarget.calcLabel(delegatedPropertyGetterDescriptor) - result.add(KotlinMethodSmartStepTarget(delegatedPropertyGetterDescriptor, ktDeclaration, label, expression, lines)) - } else { - if (ktDeclaration is KtPropertyAccessor && ktDeclaration.hasBody()) { - val label = KotlinMethodSmartStepTarget.calcLabel(getterDescriptor) - result.add(KotlinMethodSmartStepTarget(getterDescriptor, ktDeclaration, label, expression, lines)) - } - } - } - - private fun recordFunction(expression: KtExpression) { - val resolvedCall = expression.getResolvedCall(bindingContext) ?: return - - val descriptor = resolvedCall.resultingDescriptor - if (descriptor !is FunctionDescriptor || isIntrinsic(descriptor)) return - - val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) - if (descriptor.isFromJava) { - if (declaration is PsiMethod) { - result.add(MethodSmartStepTarget(declaration, null, expression, false, lines)) - } - } else { - if (declaration == null && !isInvokeInBuiltinFunction(descriptor)) { - return - } - - if (declaration !is KtDeclaration?) return - - if (descriptor is ConstructorDescriptor && descriptor.isPrimary) { - if (declaration is KtClass && declaration.getAnonymousInitializers().isEmpty()) { - // There is no constructor or init block, so do not show it in smart step into - return - } - } - - val callLabel = KotlinMethodSmartStepTarget.calcLabel(descriptor) - val label = when (descriptor) { - is FunctionInvokeDescriptor -> { - when (expression) { - is KtSimpleNameExpression -> "${runReadAction { expression.text }}.$callLabel" - else -> callLabel - } - } - else -> callLabel - } - - result.add(KotlinMethodSmartStepTarget(descriptor, declaration, label, expression, lines)) - } - } - }, null) - - return result + return consumer } override fun createMethodFilter(stepTarget: SmartStepTarget?): MethodFilter? { return when (stepTarget) { - is KotlinMethodSmartStepTarget -> - KotlinBasicStepMethodFilter( - stepTarget.declaration?.createSmartPointer(), - stepTarget.isInvoke, - stepTarget.targetMethodName, - stepTarget.callingExpressionLines!! - ) - is KotlinLambdaSmartStepTarget -> - KotlinLambdaMethodFilter( - stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline, stepTarget.isSuspend - ) + is KotlinMethodSmartStepTarget -> { + val declarationPtr = stepTarget.declaration?.createSmartPointer() + val lines = stepTarget.callingExpressionLines ?: return null + KotlinBasicStepMethodFilter(declarationPtr, stepTarget.isInvoke, stepTarget.targetMethodName, lines) + } + is KotlinLambdaSmartStepTarget -> { + val lines = stepTarget.callingExpressionLines ?: return null + KotlinLambdaMethodFilter(stepTarget.getLambda(), lines, stepTarget.isInline, stepTarget.isSuspend) + } else -> super.createMethodFilter(stepTarget) } } - - - private val methods = IntrinsicMethods(JvmTarget.JVM_1_6) - - private fun isIntrinsic(descriptor: CallableMemberDescriptor): Boolean { - return methods.getIntrinsic(descriptor) != null - } - - private fun isInvokeInBuiltinFunction(descriptor: DeclarationDescriptor): Boolean { - if (descriptor !is FunctionInvokeDescriptor) return false - val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return false - return classDescriptor.defaultType.isBuiltinFunctionalType - } } diff --git a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/smartStepInto/SmartStepTargetVisitor.kt b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/smartStepInto/SmartStepTargetVisitor.kt new file mode 100644 index 00000000000..88999fa5e4b --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/smartStepInto/SmartStepTargetVisitor.kt @@ -0,0 +1,208 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto + +import com.intellij.debugger.actions.MethodSmartStepTarget +import com.intellij.debugger.actions.SmartStepTarget +import com.intellij.psi.PsiMethod +import com.intellij.util.Range +import com.intellij.util.containers.OrderedSet +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor +import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType +import org.jetbrains.kotlin.builtins.isSuspendFunctionType +import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods +import org.jetbrains.kotlin.config.JvmTarget +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall +import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde +import org.jetbrains.kotlin.idea.debugger.stepping.KotlinLambdaSmartStepTarget +import org.jetbrains.kotlin.idea.debugger.stepping.KotlinMethodSmartStepTarget +import org.jetbrains.kotlin.idea.project.platform +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.load.java.isFromJava +import org.jetbrains.kotlin.platform.jvm.JdkPlatform +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.inline.InlineUtil +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull + +// TODO support class initializers, local functions, delegated properties with specified type, setter for properties +class SmartStepTargetVisitor( + private val element: KtElement, + private val lines: Range, + private val consumer: OrderedSet +) : KtTreeVisitorVoid() { + private fun append(target: SmartStepTarget) { + consumer += target + } + + private val intrinsicMethods = run { + val jvmTarget = element.platform.firstIsInstanceOrNull()?.targetVersion ?: JvmTarget.DEFAULT + IntrinsicMethods(jvmTarget) + } + + override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) { + recordFunction(lambdaExpression.functionLiteral) + } + + override fun visitNamedFunction(function: KtNamedFunction) { + if (!recordFunction(function)) { + super.visitNamedFunction(function) + } + } + + private fun recordFunction(function: KtFunction): Boolean { + val context = function.analyze() + val resolvedCall = function.getParentCall(context).getResolvedCall(context) ?: return false + val arguments = resolvedCall.valueArguments + + for ((param, argument) in arguments) { + if (argument.arguments.any { getArgumentExpression(it) == function }) { + val resultingDescriptor = resolvedCall.resultingDescriptor + val label = KotlinLambdaSmartStepTarget.calcLabel(resultingDescriptor, param.name) + val isInline = InlineUtil.isInline(resultingDescriptor) + val isSuspend = param.type.isSuspendFunctionType + val target = KotlinLambdaSmartStepTarget(label, function, lines, isInline, isSuspend) + append(target) + return true + } + } + + return false + } + + private fun getArgumentExpression(it: ValueArgument): KtExpression? { + return (it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression() + } + + override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) { + // Skip calls in object declarations + } + + override fun visitIfExpression(expression: KtIfExpression) { + expression.condition?.accept(this) + } + + override fun visitWhileExpression(expression: KtWhileExpression) { + expression.condition?.accept(this) + } + + override fun visitDoWhileExpression(expression: KtDoWhileExpression) { + expression.condition?.accept(this) + } + + override fun visitForExpression(expression: KtForExpression) { + expression.loopRange?.accept(this) + } + + override fun visitWhenExpression(expression: KtWhenExpression) { + expression.subjectExpression?.accept(this) + } + + override fun visitArrayAccessExpression(expression: KtArrayAccessExpression) { + recordFunctionCall(expression) + super.visitArrayAccessExpression(expression) + } + + override fun visitUnaryExpression(expression: KtUnaryExpression) { + recordFunctionCall(expression.operationReference) + super.visitUnaryExpression(expression) + } + + override fun visitBinaryExpression(expression: KtBinaryExpression) { + recordFunctionCall(expression.operationReference) + super.visitBinaryExpression(expression) + } + + override fun visitCallExpression(expression: KtCallExpression) { + val calleeExpression = expression.calleeExpression + if (calleeExpression != null) { + recordFunctionCall(calleeExpression) + } + super.visitCallExpression(expression) + } + + override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { + recordGetter(expression) + super.visitSimpleNameExpression(expression) + } + + private fun recordGetter(expression: KtSimpleNameExpression) { + val bindingContext = expression.analyze() + val resolvedCall = expression.getResolvedCall(bindingContext) ?: return + val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return + + val getterDescriptor = propertyDescriptor.getter + if (getterDescriptor == null || getterDescriptor.isDefault) return + + val ktDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, getterDescriptor) as? KtDeclaration ?: return + + val delegatedResolvedCall = bindingContext[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor] + if (delegatedResolvedCall != null) { + val delegatedPropertyGetterDescriptor = delegatedResolvedCall.resultingDescriptor + val label = "${propertyDescriptor.name}." + KotlinMethodSmartStepTarget.calcLabel(delegatedPropertyGetterDescriptor) + append(KotlinMethodSmartStepTarget(delegatedPropertyGetterDescriptor, ktDeclaration, label, expression, lines)) + } else { + if (ktDeclaration is KtPropertyAccessor && ktDeclaration.hasBody()) { + val label = KotlinMethodSmartStepTarget.calcLabel(getterDescriptor) + append(KotlinMethodSmartStepTarget(getterDescriptor, ktDeclaration, label, expression, lines)) + } + } + } + + private fun recordFunctionCall(expression: KtExpression) { + val resolvedCall = expression.resolveToCall() ?: return + + val descriptor = resolvedCall.resultingDescriptor + if (descriptor !is FunctionDescriptor || isIntrinsic(descriptor)) return + + val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, descriptor) + if (descriptor.isFromJava) { + if (declaration is PsiMethod) { + append(MethodSmartStepTarget(declaration, null, expression, false, lines)) + } + } else { + if (declaration == null && !isInvokeInBuiltinFunction(descriptor)) { + return + } + + if (declaration !is KtDeclaration?) return + + if (descriptor is ConstructorDescriptor && descriptor.isPrimary) { + if (declaration is KtClass && declaration.getAnonymousInitializers().isEmpty()) { + // There is no constructor or init block, so do not show it in smart step into + return + } + } + + val callLabel = KotlinMethodSmartStepTarget.calcLabel(descriptor) + val label = when (descriptor) { + is FunctionInvokeDescriptor -> { + when (expression) { + is KtSimpleNameExpression -> "${runReadAction { expression.text }}.$callLabel" + else -> callLabel + } + } + else -> callLabel + } + + append(KotlinMethodSmartStepTarget(descriptor, declaration, label, expression, lines)) + } + } + + private fun isIntrinsic(descriptor: CallableMemberDescriptor): Boolean { + return intrinsicMethods.getIntrinsic(descriptor) != null + } + + private fun isInvokeInBuiltinFunction(descriptor: DeclarationDescriptor): Boolean { + if (descriptor !is FunctionInvokeDescriptor) return false + val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return false + return classDescriptor.defaultType.isBuiltinFunctionalType + } +} \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/AbstractSmartStepIntoTest.kt b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/AbstractSmartStepIntoTest.kt index b6c68a58db1..29bc986d8d8 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/AbstractSmartStepIntoTest.kt +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/AbstractSmartStepIntoTest.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.debugger.test import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils -import org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler +import org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto.KotlinSmartStepIntoHandler import org.jetbrains.kotlin.idea.debugger.test.mock.MockSourcePosition import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinDescriptorTestCaseWithStepping.kt b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinDescriptorTestCaseWithStepping.kt index eb8e8abfa72..caa818157b0 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinDescriptorTestCaseWithStepping.kt +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinDescriptorTestCaseWithStepping.kt @@ -14,6 +14,7 @@ import com.intellij.debugger.impl.PositionUtil import com.intellij.execution.process.ProcessOutputTypes import com.sun.jdi.request.StepRequest import org.jetbrains.kotlin.idea.debugger.stepping.* +import org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto.KotlinSmartStepIntoHandler import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstructionKind import org.jetbrains.kotlin.idea.debugger.test.util.renderSourcePosition diff --git a/idea/resources/META-INF/jvm.xml b/idea/resources/META-INF/jvm.xml index 47b9eb8b00a..7ad320b160b 100644 --- a/idea/resources/META-INF/jvm.xml +++ b/idea/resources/META-INF/jvm.xml @@ -83,7 +83,7 @@ - + diff --git a/idea/resources/META-INF/jvm.xml.183 b/idea/resources/META-INF/jvm.xml.183 index 3b3c723d1ea..144e9db1a83 100644 --- a/idea/resources/META-INF/jvm.xml.183 +++ b/idea/resources/META-INF/jvm.xml.183 @@ -88,7 +88,7 @@ - +