Debugger: Disallow breakpoints for @InlineOnly function bodies (KT-32687, KT-24408)
Kotlin compiler strips all debug information for @InlineOnly functions, making them non-debuggable. This commit disables breakpoints inside @InlineOnly functions to prevent false expectations.
This commit is contained in:
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly")
|
||||
val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly")
|
||||
|
||||
/**
|
||||
* @return true if it's impossible to observe a call instruction referencing this member in the bytecode.
|
||||
|
||||
+1
-2
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
@@ -315,8 +316,6 @@ private tailrec fun isInlineOrContainedInInline(declaration: IrDeclaration?): Bo
|
||||
|
||||
/* Borrowed from inlineOnly.kt */
|
||||
|
||||
private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly")
|
||||
|
||||
fun IrDeclarationWithVisibility.isInlineOnlyOrReifiable(): Boolean =
|
||||
this is IrFunction && (isReifiable() || isInlineOnly())
|
||||
|
||||
|
||||
+5
-1
@@ -153,7 +153,11 @@ public class KotlinFunctionBreakpointType
|
||||
|
||||
if (element instanceof KtFunction) {
|
||||
KtFunction function = (KtFunction) element;
|
||||
return ApplicabilityResult.maybe(function.hasBody() && !KtPsiUtil.isLocal(function));
|
||||
return ApplicabilityResult.maybe(
|
||||
function.hasBody()
|
||||
&& !KtPsiUtil.isLocal(function)
|
||||
&& !BreakpointTypeUtilsKt.isInlineOnly(function)
|
||||
);
|
||||
}
|
||||
|
||||
if (element instanceof KtPropertyAccessor) {
|
||||
|
||||
+8
@@ -135,6 +135,14 @@ public class KotlinLineBreakpointType extends JavaLineBreakpointType implements
|
||||
return ApplicabilityResult.MAYBE_YES;
|
||||
}
|
||||
|
||||
PsiElement containingMethod = getContainingMethod(element);
|
||||
if (containingMethod instanceof KtCallableDeclaration) {
|
||||
KtCallableDeclaration callable = (KtCallableDeclaration) containingMethod;
|
||||
if (BreakpointTypeUtilsKt.isInlineOnly(callable)) {
|
||||
return ApplicabilityResult.DEFINITELY_NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (isClosingBraceInMethod(element)) {
|
||||
return ApplicabilityResult.MAYBE_YES;
|
||||
}
|
||||
|
||||
+24
@@ -31,11 +31,17 @@ import com.intellij.xdebugger.XDebuggerUtil
|
||||
import com.intellij.xdebugger.XSourcePosition
|
||||
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.core.util.getLineNumber
|
||||
import org.jetbrains.kotlin.idea.debugger.findElementAtLine
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import java.util.*
|
||||
|
||||
@@ -55,6 +61,9 @@ class ApplicabilityResult(val isApplicable: Boolean, val shouldStop: Boolean) {
|
||||
@JvmField
|
||||
val DEFINITELY_YES = ApplicabilityResult(isApplicable = true, shouldStop = true)
|
||||
|
||||
@JvmField
|
||||
val DEFINITELY_NO = ApplicabilityResult(isApplicable = false, shouldStop = true)
|
||||
|
||||
@JvmField
|
||||
val MAYBE_YES = ApplicabilityResult(isApplicable = true, shouldStop = false)
|
||||
}
|
||||
@@ -181,3 +190,18 @@ fun getLambdasAtLineIfAny(file: KtFile, line: Int): List<KtFunction> {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KtCallableDeclaration.isInlineOnly(): Boolean {
|
||||
if (!hasModifier(KtTokens.INLINE_KEYWORD)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val inlineOnlyAnnotation = annotationEntries
|
||||
.firstOrNull { it.shortName == INLINE_ONLY_ANNOTATION_FQ_NAME.shortName() }
|
||||
?: return false
|
||||
|
||||
return runReadAction f@{
|
||||
val bindingContext = inlineOnlyAnnotation.analyze(BodyResolveMode.PARTIAL)
|
||||
val annotationDescriptor = bindingContext[BindingContext.ANNOTATION, inlineOnlyAnnotation] ?: return@f false
|
||||
return@f annotationDescriptor.fqName == INLINE_ONLY_ANNOTATION_FQ_NAME
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
fun foo() {
|
||||
require(true) { "foo" } /// *, L, λ
|
||||
|
||||
require(true) { val a = 5 } /// *, L, λ
|
||||
|
||||
require(true) { /// L
|
||||
val a = 5 /// L
|
||||
} /// L
|
||||
|
||||
block { val a = 5 } /// *, L, λ
|
||||
|
||||
block { /// L
|
||||
val a = 5 /// L
|
||||
} /// L
|
||||
|
||||
inlineBlock { val a = 5} /// *, L, λ
|
||||
|
||||
inlineBlock { /// L
|
||||
val a = 5 /// L
|
||||
} /// L
|
||||
|
||||
inlineOnlyBlock { val a = 5 } /// *, L, λ
|
||||
|
||||
inlineOnlyBlock { /// L
|
||||
val a = 5 /// L
|
||||
} /// L
|
||||
|
||||
inlineOnlyBlock2 { val a = 5 } /// *, L, λ
|
||||
|
||||
inlineOnlyBlock2 { /// L
|
||||
val a = 5 /// L
|
||||
} /// L
|
||||
} /// L
|
||||
|
||||
private fun block(block: () -> Unit) { /// M
|
||||
block() /// L
|
||||
} /// L
|
||||
|
||||
private inline fun inlineBlock(block: () -> Unit) { /// M
|
||||
block() /// L
|
||||
} /// L
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
@kotlin.internal.InlineOnly
|
||||
private inline fun inlineOnlyBlock(block: () -> Unit) {
|
||||
block()
|
||||
}
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
@kotlin.internal.InlineOnly
|
||||
private inline fun inlineOnlyBlock2(noinline block: () -> Unit) {
|
||||
block()
|
||||
}
|
||||
+5
@@ -39,6 +39,11 @@ public class BreakpointApplicabilityTestGenerated extends AbstractBreakpointAppl
|
||||
runTest("idea/testData/debugger/breakpointApplicability/functions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineOnly.kt")
|
||||
public void testInlineOnly() throws Exception {
|
||||
runTest("idea/testData/debugger/breakpointApplicability/inlineOnly.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("locals.kt")
|
||||
public void testLocals() throws Exception {
|
||||
runTest("idea/testData/debugger/breakpointApplicability/locals.kt");
|
||||
|
||||
Reference in New Issue
Block a user