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:
Yan Zhulanow
2019-07-16 18:20:37 +09:00
parent 25fb77e7ad
commit 780c0518e5
7 changed files with 97 additions and 4 deletions
@@ -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) {
@@ -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;
}
@@ -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
}
}