Minor: KotlinCodeFragmentFactory.kt cleanup

This commit is contained in:
Nikolay Krasko
2018-01-11 17:49:42 +03:00
parent 4d6c83b5b9
commit 2a0b7e293f
@@ -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)
} }