Minor: KotlinCodeFragmentFactory.kt cleanup
This commit is contained in:
+61
-62
@@ -59,9 +59,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
class KotlinCodeFragmentFactory : CodeFragmentFactory() {
|
||||||
private val LOG = Logger.getInstance(this::class.java)
|
|
||||||
|
|
||||||
override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
||||||
val contextElement = getWrappedContextElement(project, context)
|
val contextElement = getWrappedContextElement(project, context)
|
||||||
if (contextElement == null) {
|
if (contextElement == null) {
|
||||||
@@ -69,36 +67,34 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
val codeFragment = if (item.kind == CodeFragmentKind.EXPRESSION) {
|
val codeFragment = if (item.kind == CodeFragmentKind.EXPRESSION) {
|
||||||
KtExpressionCodeFragment(
|
KtExpressionCodeFragment(
|
||||||
project,
|
project,
|
||||||
"fragment.kt",
|
"fragment.kt",
|
||||||
item.text,
|
item.text,
|
||||||
initImports(item.imports),
|
initImports(item.imports),
|
||||||
contextElement
|
contextElement
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
KtBlockCodeFragment(
|
KtBlockCodeFragment(
|
||||||
project,
|
project,
|
||||||
"fragment.kt",
|
"fragment.kt",
|
||||||
item.text,
|
item.text,
|
||||||
initImports(item.imports),
|
initImports(item.imports),
|
||||||
contextElement
|
contextElement
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
codeFragment.putCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR, {
|
codeFragment.putCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR, { expression: KtExpression ->
|
||||||
expression: KtExpression ->
|
|
||||||
|
|
||||||
val debuggerContext = DebuggerManagerEx.getInstanceEx(project).context
|
val debuggerContext = DebuggerManagerEx.getInstanceEx(project).context
|
||||||
val debuggerSession = debuggerContext.debuggerSession
|
val debuggerSession = debuggerContext.debuggerSession
|
||||||
if (debuggerSession == null || debuggerContext.suspendContext == null) {
|
if (debuggerSession == null || debuggerContext.suspendContext == null) {
|
||||||
null
|
null
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val semaphore = Semaphore()
|
val semaphore = Semaphore()
|
||||||
semaphore.down()
|
semaphore.down()
|
||||||
val nameRef = AtomicReference<KotlinType>()
|
val nameRef = AtomicReference<KotlinType>()
|
||||||
val worker = object : KotlinRuntimeTypeEvaluator(null, expression, debuggerContext, ProgressManager.getInstance().progressIndicator) {
|
val worker = object : KotlinRuntimeTypeEvaluator(
|
||||||
|
null, expression, debuggerContext, ProgressManager.getInstance().progressIndicator
|
||||||
|
) {
|
||||||
override fun typeCalculationFinished(type: KotlinType?) {
|
override fun typeCalculationFinished(type: KotlinType?) {
|
||||||
nameRef.set(type)
|
nameRef.set(type)
|
||||||
semaphore.up()
|
semaphore.up()
|
||||||
@@ -133,10 +129,12 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
return@putCopyableUserData emptyFile
|
return@putCopyableUserData emptyFile
|
||||||
}
|
}
|
||||||
|
|
||||||
val receiverTypeReference = frameDescriptor.thisObject?.let { createKotlinProperty(project, "this_0", it.type().name(), it) }?.typeReference
|
val receiverTypeReference =
|
||||||
|
frameDescriptor.thisObject?.let { createKotlinProperty(project, "this_0", it.type().name(), it) }?.typeReference
|
||||||
val receiverTypeText = receiverTypeReference?.let { "${it.text}." } ?: ""
|
val receiverTypeText = receiverTypeReference?.let { "${it.text}." } ?: ""
|
||||||
|
|
||||||
val kotlinVariablesText = frameDescriptor.visibleVariables.entries.associate { it.key.name() to it.value }.kotlinVariablesAsText(project)
|
val kotlinVariablesText =
|
||||||
|
frameDescriptor.visibleVariables.entries.associate { it.key.name() to it.value }.kotlinVariablesAsText(project)
|
||||||
|
|
||||||
val fakeFunctionText = "fun ${receiverTypeText}_java_locals_debug_fun_() {\n$kotlinVariablesText\n}"
|
val fakeFunctionText = "fun ${receiverTypeText}_java_locals_debug_fun_() {\n$kotlinVariablesText\n}"
|
||||||
|
|
||||||
@@ -145,7 +143,6 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
val fakeContext = (fakeFunction?.bodyExpression as? KtBlockExpression)?.statements?.lastOrNull()
|
val fakeContext = (fakeFunction?.bodyExpression as? KtBlockExpression)?.statements?.lastOrNull()
|
||||||
|
|
||||||
return@putCopyableUserData wrapContextIfNeeded(project, contextElement, fakeContext) ?: emptyFile
|
return@putCopyableUserData wrapContextIfNeeded(project, contextElement, fakeContext) ?: emptyFile
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,11 +169,9 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
|
|
||||||
frameInfo = FrameInfo(frame?.thisObject(), visibleVariables)
|
frameInfo = FrameInfo(frame?.thisObject(), visibleVariables)
|
||||||
}
|
} catch (ignored: AbsentInformationException) {
|
||||||
catch(ignored: AbsentInformationException) {
|
|
||||||
// Debug info unavailable
|
// Debug info unavailable
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
semaphore.up()
|
semaphore.up()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,8 +191,8 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
private fun initImports(imports: String?): String? {
|
private fun initImports(imports: String?): String? {
|
||||||
if (imports != null && !imports.isEmpty()) {
|
if (imports != null && !imports.isEmpty()) {
|
||||||
return imports.split(KtCodeFragment.IMPORT_SEPARATOR)
|
return imports.split(KtCodeFragment.IMPORT_SEPARATOR)
|
||||||
.mapNotNull { fixImportIfNeeded(it) }
|
.mapNotNull { fixImportIfNeeded(it) }
|
||||||
.joinToString(KtCodeFragment.IMPORT_SEPARATOR)
|
.joinToString(KtCodeFragment.IMPORT_SEPARATOR)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -226,19 +221,17 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
if (PsiTreeUtil.hasErrorElements(kotlinCodeFragment) && kotlinCodeFragment is KtExpressionCodeFragment) {
|
if (PsiTreeUtil.hasErrorElements(kotlinCodeFragment) && kotlinCodeFragment is KtExpressionCodeFragment) {
|
||||||
val javaExpression = try {
|
val javaExpression = try {
|
||||||
PsiElementFactory.SERVICE.getInstance(project).createExpressionFromText(item.text, context)
|
PsiElementFactory.SERVICE.getInstance(project).createExpressionFromText(item.text, context)
|
||||||
}
|
} catch (e: IncorrectOperationException) {
|
||||||
catch(e: IncorrectOperationException) {
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val importList = try {
|
val importList = try {
|
||||||
kotlinCodeFragment.importsAsImportList()?.let {
|
kotlinCodeFragment.importsAsImportList()?.let {
|
||||||
(PsiFileFactory.getInstance(project).createFileFromText(
|
(PsiFileFactory.getInstance(project).createFileFromText(
|
||||||
"dummy.java", JavaFileType.INSTANCE, it.text
|
"dummy.java", JavaFileType.INSTANCE, it.text
|
||||||
) as? PsiJavaFile)?.importList
|
) as? PsiJavaFile)?.importList
|
||||||
}
|
}
|
||||||
}
|
} catch (e: IncorrectOperationException) {
|
||||||
catch(e: IncorrectOperationException) {
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,17 +243,16 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
val newImports = importList?.j2kText()
|
val newImports = importList?.j2kText()
|
||||||
if (newText != null) {
|
if (newText != null) {
|
||||||
convertedFragment = KtExpressionCodeFragment(
|
convertedFragment = KtExpressionCodeFragment(
|
||||||
project,
|
project,
|
||||||
kotlinCodeFragment.name,
|
kotlinCodeFragment.name,
|
||||||
newText,
|
newText,
|
||||||
newImports,
|
newImports,
|
||||||
kotlinCodeFragment.context
|
kotlinCodeFragment.context
|
||||||
)
|
)
|
||||||
|
|
||||||
AfterConversionPass(project, J2kPostProcessor(formatCode = false)).run(convertedFragment!!, range = null)
|
AfterConversionPass(project, J2kPostProcessor(formatCode = false)).run(convertedFragment!!, range = null)
|
||||||
}
|
}
|
||||||
}
|
} catch (e: Throwable) {
|
||||||
catch (e: Throwable) {
|
|
||||||
// ignored because text can be invalid
|
// ignored because text can be invalid
|
||||||
LOG.error("Couldn't convert expression:\n`${javaExpression.text}`", e)
|
LOG.error("Couldn't convert expression:\n`${javaExpression.text}`", e)
|
||||||
}
|
}
|
||||||
@@ -284,14 +276,19 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFileType() = KotlinFileType.INSTANCE
|
override fun getFileType(): KotlinFileType = KotlinFileType.INSTANCE
|
||||||
|
|
||||||
override fun getEvaluatorBuilder() = KotlinEvaluationBuilder
|
override fun getEvaluatorBuilder() = KotlinEvaluationBuilder
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val LOG = Logger.getInstance(this::class.java)
|
||||||
|
|
||||||
val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
||||||
val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
|
||||||
@TestOnly val DEBUG_CONTEXT_FOR_TESTS: Key<DebuggerContextImpl> = Key.create("DEBUG_CONTEXT_FOR_TESTS")
|
private const val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
||||||
|
|
||||||
|
@TestOnly
|
||||||
|
val DEBUG_CONTEXT_FOR_TESTS: Key<DebuggerContextImpl> = Key.create("DEBUG_CONTEXT_FOR_TESTS")
|
||||||
|
|
||||||
fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
||||||
if (elementAt == null) return null
|
if (elementAt == null) return null
|
||||||
@@ -310,7 +307,8 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
|
|
||||||
// elementAt can be PsiWhiteSpace when codeFragment is created from line start offset (in case of first opening EE window)
|
// elementAt can be PsiWhiteSpace when codeFragment is created from line start offset (in case of first opening EE window)
|
||||||
val lineStartOffset = if (elementAt is PsiWhiteSpace || elementAt is PsiComment) {
|
val lineStartOffset = if (elementAt is PsiWhiteSpace || elementAt is PsiComment) {
|
||||||
PsiTreeUtil.skipSiblingsForward(elementAt, PsiWhiteSpace::class.java, PsiComment::class.java)?.textOffset ?: elementAt.textOffset
|
PsiTreeUtil.skipSiblingsForward(elementAt, PsiWhiteSpace::class.java, PsiComment::class.java)?.textOffset
|
||||||
|
?: elementAt.textOffset
|
||||||
} else {
|
} else {
|
||||||
elementAt.textOffset
|
elementAt.textOffset
|
||||||
}
|
}
|
||||||
@@ -318,12 +316,12 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
fun KtElement.takeIfAcceptedAsCodeFragmentContext() = takeIf { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) }
|
fun KtElement.takeIfAcceptedAsCodeFragmentContext() = takeIf { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) }
|
||||||
|
|
||||||
PsiTreeUtil.findElementOfClassAtOffset(containingFile, lineStartOffset, KtExpression::class.java, false)
|
PsiTreeUtil.findElementOfClassAtOffset(containingFile, lineStartOffset, KtExpression::class.java, false)
|
||||||
?.takeIfAcceptedAsCodeFragmentContext()
|
?.takeIfAcceptedAsCodeFragmentContext()
|
||||||
?.let { return CodeInsightUtils.getTopmostElementAtOffset(it, lineStartOffset, KtExpression::class.java) }
|
?.let { return CodeInsightUtils.getTopmostElementAtOffset(it, lineStartOffset, KtExpression::class.java) }
|
||||||
|
|
||||||
KotlinEditorTextProvider.findExpressionInner(elementAt, true)
|
KotlinEditorTextProvider.findExpressionInner(elementAt, true)
|
||||||
?.takeIfAcceptedAsCodeFragmentContext()
|
?.takeIfAcceptedAsCodeFragmentContext()
|
||||||
?.let { return it }
|
?.let { return it }
|
||||||
|
|
||||||
return containingFile
|
return containingFile
|
||||||
}
|
}
|
||||||
@@ -374,7 +372,8 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
else
|
else
|
||||||
className).addArraySuffix()
|
className).addArraySuffix()
|
||||||
|
|
||||||
val field = PsiElementFactory.SERVICE.getInstance(project).createField(variableName, PsiType.getTypeByName(type, project, GlobalSearchScope.allScope(project)))
|
val field = PsiElementFactory.SERVICE.getInstance(project)
|
||||||
|
.createField(variableName, PsiType.getTypeByName(type, project, GlobalSearchScope.allScope(project)))
|
||||||
val ktField = field.j2k() as? KtProperty
|
val ktField = field.j2k() as? KtProperty
|
||||||
ktField?.modifierList?.delete()
|
ktField?.modifierList?.delete()
|
||||||
return ktField
|
return ktField
|
||||||
@@ -383,10 +382,10 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
|
|
||||||
private fun wrapContextIfNeeded(project: Project, originalContext: PsiElement?, newContext: KtElement?): KtElement? {
|
private fun wrapContextIfNeeded(project: Project, originalContext: PsiElement?, newContext: KtElement?): KtElement? {
|
||||||
val markupMap: Map<*, ValueMarkup>? =
|
val markupMap: Map<*, ValueMarkup>? =
|
||||||
if (ApplicationManager.getApplication().isUnitTestMode)
|
if (ApplicationManager.getApplication().isUnitTestMode)
|
||||||
NodeDescriptorImpl.getMarkupMap(originalContext?.getCopyableUserData(DEBUG_CONTEXT_FOR_TESTS)?.debugProcess)
|
NodeDescriptorImpl.getMarkupMap(originalContext?.getCopyableUserData(DEBUG_CONTEXT_FOR_TESTS)?.debugProcess)
|
||||||
else
|
else
|
||||||
(XDebuggerManager.getInstance(project).currentSession as? XDebugSessionImpl)?.valueMarkers?.allMarkers
|
(XDebuggerManager.getInstance(project).currentSession as? XDebugSessionImpl)?.valueMarkers?.allMarkers
|
||||||
|
|
||||||
if (markupMap == null || markupMap.isEmpty()) return newContext
|
if (markupMap == null || markupMap.isEmpty()) return newContext
|
||||||
|
|
||||||
@@ -413,17 +412,17 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// internal for test
|
// internal for test
|
||||||
fun createWrappingContext(
|
private fun createWrappingContext(
|
||||||
newFragmentText: String,
|
newFragmentText: String,
|
||||||
labels: Map<String, Value>,
|
labels: Map<String, Value>,
|
||||||
originalContext: KtElement?,
|
originalContext: KtElement?,
|
||||||
project: Project
|
project: Project
|
||||||
): KtElement? {
|
): KtElement? {
|
||||||
val codeFragment = KtPsiFactory(project).createBlockCodeFragment(newFragmentText, originalContext)
|
val codeFragment = KtPsiFactory(project).createBlockCodeFragment(newFragmentText, originalContext)
|
||||||
|
|
||||||
codeFragment.accept(object : KtTreeVisitorVoid() {
|
codeFragment.accept(object : KtTreeVisitorVoid() {
|
||||||
override fun visitProperty(property: KtProperty) {
|
override fun visitProperty(property: KtProperty) {
|
||||||
val reference = labels.get(property.name)
|
val reference = labels[property.name]
|
||||||
if (reference != null) {
|
if (reference != null) {
|
||||||
property.putUserData(LABEL_VARIABLE_VALUE_KEY, reference)
|
property.putUserData(LABEL_VARIABLE_VALUE_KEY, reference)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user