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.string.template="${expr}"
|
||||
surround.with.when.template=when (expr) {}
|
||||
surround.with.runtime.type.cast.template=(expr as RuntimeType)
|
||||
surround.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
|
||||
|
||||
+4
-1
@@ -30,9 +30,11 @@ public class KotlinExpressionSurroundDescriptor implements SurroundDescriptor {
|
||||
new KotlinNotSurrounder(),
|
||||
new KotlinStringTemplateSurrounder(),
|
||||
new KotlinParenthesesSurrounder(),
|
||||
new KotlinWhenSurrounder()
|
||||
new KotlinWhenSurrounder() ,
|
||||
new KotlinRuntimeTypeCastSurrounder()
|
||||
};
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiElement[] getElementsToSurround(PsiFile file, int startOffset, int endOffset) {
|
||||
JetExpression expression = CodeInsightUtils.findExpression(file, startOffset, endOffset);
|
||||
@@ -42,6 +44,7 @@ public class KotlinExpressionSurroundDescriptor implements SurroundDescriptor {
|
||||
return new PsiElement[] {expression};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Surrounder[] getSurrounders() {
|
||||
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