Add surrounder for cast to runtime type
This commit is contained in:
@@ -193,6 +193,7 @@ choose.target.class.or.trait.title=Choose target class or trait
|
|||||||
surround.with=Surround with
|
surround.with=Surround with
|
||||||
surround.with.string.template="${expr}"
|
surround.with.string.template="${expr}"
|
||||||
surround.with.when.template=when (expr) {}
|
surround.with.when.template=when (expr) {}
|
||||||
|
surround.with.runtime.type.cast.template=(expr as RuntimeType)
|
||||||
surround.with.function.template={ }
|
surround.with.function.template={ }
|
||||||
surround.with.cannot.perform.action=Cannot perform Surround With action to the current contextsurround.with.function.template={ }
|
surround.with.cannot.perform.action=Cannot perform Surround With action to the current contextsurround.with.function.template={ }
|
||||||
remove.variable.family.name=Remove variable
|
remove.variable.family.name=Remove variable
|
||||||
|
|||||||
+4
-1
@@ -30,9 +30,11 @@ public class KotlinExpressionSurroundDescriptor implements SurroundDescriptor {
|
|||||||
new KotlinNotSurrounder(),
|
new KotlinNotSurrounder(),
|
||||||
new KotlinStringTemplateSurrounder(),
|
new KotlinStringTemplateSurrounder(),
|
||||||
new KotlinParenthesesSurrounder(),
|
new KotlinParenthesesSurrounder(),
|
||||||
new KotlinWhenSurrounder()
|
new KotlinWhenSurrounder() ,
|
||||||
|
new KotlinRuntimeTypeCastSurrounder()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) {
|
public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) {
|
||||||
JetExpression expression = CodeInsightUtils.findExpression(file, startOffset, endOffset);
|
JetExpression expression = CodeInsightUtils.findExpression(file, startOffset, endOffset);
|
||||||
@@ -42,6 +44,7 @@ public class KotlinExpressionSurroundDescriptor implements SurroundDescriptor {
|
|||||||
return new PsiElement[] {expression};
|
return new PsiElement[] {expression};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public Surrounder[] getSurrounders() {
|
public Surrounder[] getSurrounders() {
|
||||||
return SURROUNDERS;
|
return SURROUNDERS;
|
||||||
|
|||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.plugin.codeInsight.surroundWith.expression
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.CodeInsightBundle
|
||||||
|
import com.intellij.debugger.DebuggerBundle
|
||||||
|
import com.intellij.debugger.DebuggerInvocationUtil
|
||||||
|
import com.intellij.debugger.DebuggerManagerEx
|
||||||
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
|
import com.intellij.openapi.application.Result
|
||||||
|
import com.intellij.openapi.command.WriteCommandAction
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.ScrollType
|
||||||
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
|
import com.intellij.openapi.progress.util.ProgressWindowWithNotification
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||||
|
import org.jetbrains.jet.plugin.debugger.evaluate.KotlinRuntimeTypeEvaluator
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||||
|
import org.jetbrains.jet.lang.psi.JetBinaryExpressionWithTypeRHS
|
||||||
|
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
|
||||||
|
import org.jetbrains.jet.lang.psi.JetParenthesizedExpression
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.jet.plugin.caches.resolve.analyzeFully
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
|
import org.jetbrains.jet.lang.types.TypeUtils
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||||
|
import org.jetbrains.jet.plugin.JetBundle
|
||||||
|
|
||||||
|
public class KotlinRuntimeTypeCastSurrounder: KotlinExpressionSurrounder() {
|
||||||
|
|
||||||
|
override fun isApplicable(expression: JetExpression): Boolean {
|
||||||
|
if (!expression.isPhysical()) return false
|
||||||
|
val file = expression.getContainingFile()
|
||||||
|
if (file !is JetCodeFragment) return false
|
||||||
|
|
||||||
|
val context = file.analyzeFully()
|
||||||
|
val type = context[BindingContext.EXPRESSION_TYPE, expression]
|
||||||
|
if (type == null) return false
|
||||||
|
|
||||||
|
return TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surroundExpression(project: Project, editor: Editor, expression: JetExpression): TextRange? {
|
||||||
|
val debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext()
|
||||||
|
val debuggerSession = debuggerContext.getDebuggerSession()
|
||||||
|
if (debuggerSession != null) {
|
||||||
|
val progressWindow = ProgressWindowWithNotification(true, expression.getProject())
|
||||||
|
val worker = SurroundWithCastWorker(editor, expression, debuggerContext, progressWindow)
|
||||||
|
progressWindow.setTitle(DebuggerBundle.message("title.evaluating"))
|
||||||
|
debuggerContext.getDebugProcess()?.getManagerThread()?.startProgress(worker, progressWindow)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTemplateDescription(): String {
|
||||||
|
return JetBundle.message("surround.with.runtime.type.cast.template")
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class SurroundWithCastWorker(
|
||||||
|
private val myEditor: Editor,
|
||||||
|
expression: JetExpression,
|
||||||
|
context: DebuggerContextImpl,
|
||||||
|
indicator: ProgressIndicator
|
||||||
|
): KotlinRuntimeTypeEvaluator(myEditor, expression, context, indicator) {
|
||||||
|
|
||||||
|
override fun typeCalculationFinished(type: JetType?) {
|
||||||
|
if (type == null) return
|
||||||
|
|
||||||
|
hold()
|
||||||
|
|
||||||
|
val project = myEditor.getProject()
|
||||||
|
DebuggerInvocationUtil.invokeLater(project, Runnable {
|
||||||
|
object : WriteCommandAction<Any>(project, CodeInsightBundle.message("command.name.surround.with.runtime.cast")) {
|
||||||
|
override fun run(result: Result<Any>) {
|
||||||
|
try {
|
||||||
|
val factory = JetPsiFactory(myElement.getProject())
|
||||||
|
|
||||||
|
val fqName = DescriptorUtils.getFqName(type.getConstructor().getDeclarationDescriptor())
|
||||||
|
val parentCast = factory.createExpression("(expr as " + fqName.asString() + ")") as JetParenthesizedExpression
|
||||||
|
val cast = parentCast.getExpression() as JetBinaryExpressionWithTypeRHS
|
||||||
|
cast.getLeft().replace(myElement)
|
||||||
|
val expr = myElement.replace(parentCast) as JetExpression
|
||||||
|
|
||||||
|
ShortenReferences.process(expr)
|
||||||
|
|
||||||
|
val range = expr.getTextRange()
|
||||||
|
myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset())
|
||||||
|
myEditor.getCaretModel().moveToOffset(range.getEndOffset())
|
||||||
|
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute()
|
||||||
|
}, myProgressIndicator.getModalityState())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.plugin.debugger.evaluate
|
||||||
|
|
||||||
|
import com.intellij.debugger.DebuggerBundle
|
||||||
|
import com.intellij.debugger.DebuggerInvocationUtil
|
||||||
|
import com.intellij.debugger.EvaluatingComputable
|
||||||
|
import com.intellij.debugger.engine.ContextUtil
|
||||||
|
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||||
|
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||||
|
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||||
|
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator
|
||||||
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
|
import com.intellij.debugger.ui.EditorEvaluationCommand
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.CommonClassNames
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.sun.jdi.ClassType
|
||||||
|
import com.sun.jdi.Value
|
||||||
|
import org.jetbrains.eval4j.jdi.*
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type as AsmType
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi
|
||||||
|
|
||||||
|
public abstract class KotlinRuntimeTypeEvaluator(
|
||||||
|
editor: Editor?,
|
||||||
|
expression: JetExpression,
|
||||||
|
context: DebuggerContextImpl,
|
||||||
|
indicator: ProgressIndicator
|
||||||
|
) : EditorEvaluationCommand<JetType>(editor, expression, context, indicator) {
|
||||||
|
|
||||||
|
override fun threadAction() {
|
||||||
|
var type: JetType? = null
|
||||||
|
try {
|
||||||
|
type = evaluate()
|
||||||
|
}
|
||||||
|
catch (ignored: ProcessCanceledException) {
|
||||||
|
}
|
||||||
|
catch (ignored: EvaluateException) {
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
typeCalculationFinished(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun typeCalculationFinished(type: JetType?)
|
||||||
|
|
||||||
|
override fun evaluate(evaluationContext: EvaluationContextImpl): JetType? {
|
||||||
|
val project = evaluationContext.getProject()
|
||||||
|
|
||||||
|
val evaluator = DebuggerInvocationUtil.commitAndRunReadAction<ExpressionEvaluator>(project, EvaluatingComputable {
|
||||||
|
val codeFragment = JetPsiFactory(myElement.getProject()).createExpressionCodeFragment(
|
||||||
|
myElement.getText(), myElement.getContainingFile().getContext())
|
||||||
|
KotlinEvaluationBuilder.build(codeFragment, ContextUtil.getSourcePosition(evaluationContext))
|
||||||
|
})
|
||||||
|
|
||||||
|
val value = evaluator.evaluate(evaluationContext)
|
||||||
|
if (value != null) {
|
||||||
|
return getCastableRuntimeType(project, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null"))
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
private fun getCastableRuntimeType(project: Project, value: Value): JetType? {
|
||||||
|
val myValue = value.asValue()
|
||||||
|
var psiClass = myValue.asmType.getClassDescriptor(project)
|
||||||
|
if (psiClass != null) {
|
||||||
|
return psiClass!!.getDefaultType()
|
||||||
|
}
|
||||||
|
|
||||||
|
val type = value.type()
|
||||||
|
if (type is ClassType) {
|
||||||
|
val superclass = type.superclass()
|
||||||
|
if (superclass != null && CommonClassNames.JAVA_LANG_OBJECT != superclass.name()) {
|
||||||
|
psiClass = AsmType.getType(superclass.signature()).getClassDescriptor(project)
|
||||||
|
if (psiClass != null) {
|
||||||
|
return psiClass!!.getDefaultType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (interfaceType in type.interfaces()) {
|
||||||
|
if (JvmAbi.K_OBJECT.asString() == interfaceType.name()) continue
|
||||||
|
|
||||||
|
psiClass = AsmType.getType(interfaceType.signature()).getClassDescriptor(project)
|
||||||
|
if (psiClass != null) {
|
||||||
|
return psiClass!!.getDefaultType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user