Extract Function: Type parameters inference
This commit is contained in:
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import kotlin.KotlinPackage;
|
||||
import kotlin.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -30,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -526,8 +528,10 @@ public class JetPsiFactory {
|
||||
static enum State {
|
||||
MODIFIERS,
|
||||
NAME,
|
||||
RECEIVER,
|
||||
FIRST_PARAM,
|
||||
REST_PARAMS,
|
||||
TYPE_CONSTRAINTS,
|
||||
BODY,
|
||||
DONE
|
||||
}
|
||||
@@ -543,7 +547,7 @@ public class JetPsiFactory {
|
||||
|
||||
sb.append(")");
|
||||
|
||||
state = State.BODY;
|
||||
state = State.TYPE_CONSTRAINTS;
|
||||
}
|
||||
|
||||
private void placeFun() {
|
||||
@@ -554,7 +558,7 @@ public class JetPsiFactory {
|
||||
}
|
||||
sb.append("fun ");
|
||||
|
||||
state = State.NAME;
|
||||
state = State.RECEIVER;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -567,23 +571,28 @@ public class JetPsiFactory {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionBuilder receiver(@NotNull String receiverType) {
|
||||
public FunctionBuilder typeParams(@NotNull Collection<String> values) {
|
||||
placeFun();
|
||||
sb.append(receiverType).append(".");
|
||||
if (!values.isEmpty()) {
|
||||
sb.append(KotlinPackage.makeString(values, ", ", "<", "> ", -1, ""));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionBuilder noReceiver() {
|
||||
placeFun();
|
||||
public FunctionBuilder receiver(@NotNull String receiverType) {
|
||||
assert state == State.RECEIVER;
|
||||
|
||||
sb.append(receiverType).append(".");
|
||||
state = State.NAME;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionBuilder name(@NotNull String name) {
|
||||
assert state == State.NAME;
|
||||
assert state == State.NAME || state == State.RECEIVER;
|
||||
|
||||
sb.append(name).append("(");
|
||||
state = State.FIRST_PARAM;
|
||||
@@ -621,9 +630,21 @@ public class JetPsiFactory {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionBuilder typeConstraints(@NotNull Collection<String> values) {
|
||||
assert state == State.TYPE_CONSTRAINTS;
|
||||
|
||||
if (!values.isEmpty()) {
|
||||
sb.append(KotlinPackage.makeString(values, ", ", " where ", "", -1, ""));
|
||||
}
|
||||
state = State.BODY;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionBuilder simpleBody(@NotNull String body) {
|
||||
assert state == State.BODY;
|
||||
assert state == State.BODY || state == State.TYPE_CONSTRAINTS;
|
||||
|
||||
sb.append(" = ").append(body);
|
||||
state = State.DONE;
|
||||
@@ -633,7 +654,7 @@ public class JetPsiFactory {
|
||||
|
||||
@NotNull
|
||||
public FunctionBuilder blockBody(@NotNull String body) {
|
||||
assert state == State.BODY;
|
||||
assert state == State.BODY || state == State.TYPE_CONSTRAINTS;
|
||||
|
||||
sb.append(" {\n").append(body).append("\n}");
|
||||
state = State.DONE;
|
||||
|
||||
@@ -125,17 +125,27 @@ public class DFS {
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class NodeHandlerWithListResult<N, R> extends AbstractNodeHandler<N, List<R>> {
|
||||
public static abstract class CollectingNodeHandler<N, R, C extends Iterable<R>> extends AbstractNodeHandler<N, C> {
|
||||
@NotNull
|
||||
protected final LinkedList<R> result = new LinkedList<R>();
|
||||
protected final C result;
|
||||
|
||||
protected CollectingNodeHandler(@NotNull C result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<R> result() {
|
||||
public C result() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class NodeHandlerWithListResult<N, R> extends CollectingNodeHandler<N, R, LinkedList<R>> {
|
||||
protected NodeHandlerWithListResult() {
|
||||
super(new LinkedList<R>());
|
||||
}
|
||||
}
|
||||
|
||||
public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
|
||||
@Override
|
||||
public void afterChildren(N current) {
|
||||
|
||||
@@ -29,6 +29,8 @@ import org.jetbrains.jet.lang.resolve.name.FqName
|
||||
import org.jetbrains.jet.plugin.references.JetSimpleNameReference.ShorteningMode
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
||||
import org.jetbrains.jet.lang.psi.JetTypeParameter
|
||||
import org.jetbrains.jet.lang.psi.JetTypeConstraint
|
||||
|
||||
data class Parameter(
|
||||
val argumentText: String,
|
||||
@@ -40,6 +42,11 @@ data class Parameter(
|
||||
val nameForRef: String get() = mirrorVarName ?: name
|
||||
}
|
||||
|
||||
data class TypeParameter(
|
||||
val originalDeclaration: JetTypeParameter,
|
||||
val originalConstraints: List<JetTypeConstraint>
|
||||
)
|
||||
|
||||
trait Replacement: Function1<JetElement, JetElement>
|
||||
|
||||
trait ParameterReplacement : Replacement {
|
||||
@@ -120,6 +127,7 @@ data class ExtractionDescriptor(
|
||||
val visibility: String,
|
||||
val parameters: List<Parameter>,
|
||||
val receiverParameter: Parameter?,
|
||||
val typeParameters: List<TypeParameter>,
|
||||
val replacementMap: Map<Int, Replacement>,
|
||||
val controlFlow: ControlFlow
|
||||
)
|
||||
|
||||
+89
-4
@@ -86,9 +86,20 @@ import java.util.Collections
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils
|
||||
import org.jetbrains.jet.lang.psi.JetTypeParameter
|
||||
import org.jetbrains.jet.lang.psi.JetTypeConstraint
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.jet.utils.DFS
|
||||
import org.jetbrains.jet.utils.DFS.Neighbors
|
||||
import org.jetbrains.jet.utils.DFS.VisitedWithSet
|
||||
import org.jetbrains.jet.utils.DFS.AbstractNodeHandler
|
||||
import org.jetbrains.jet.utils.DFS.CollectingNodeHandler
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
||||
import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors
|
||||
import org.jetbrains.jet.lang.psi.JetTypeReference
|
||||
import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
|
||||
private val DEFAULT_FUNCTION_NAME = "myFun"
|
||||
@@ -227,13 +238,75 @@ private fun ExtractionData.createTemporaryCodeBlock(): JetBlockExpression {
|
||||
return tmpFunction.getBodyExpression() as JetBlockExpression
|
||||
}
|
||||
|
||||
private fun JetType.collectReferencedTypes(): List<JetType> {
|
||||
return DFS.dfsFromNode(
|
||||
this,
|
||||
object: Neighbors<JetType> {
|
||||
override fun getNeighbors(current: JetType): Iterable<JetType> = current.getArguments().map { it.getType() }
|
||||
},
|
||||
VisitedWithSet(),
|
||||
object: CollectingNodeHandler<JetType, JetType, ArrayList<JetType>>(ArrayList()) {
|
||||
override fun afterChildren(current: JetType) {
|
||||
result.add(current)
|
||||
}
|
||||
}
|
||||
)!!
|
||||
}
|
||||
|
||||
fun JetTypeParameter.collectRelevantConstraints(): List<JetTypeConstraint> {
|
||||
val typeConstraints = getParentByType(javaClass<JetTypeParameterListOwner>())?.getTypeConstraints()
|
||||
if (typeConstraints == null) return Collections.emptyList()
|
||||
return typeConstraints.filter { it.getSubjectTypeParameterName()?.getReference()?.resolve() == this}
|
||||
}
|
||||
|
||||
fun TypeParameter.collectReferencedTypes(bindingContext: BindingContext): List<JetType> {
|
||||
val typeRefs = ArrayList<JetTypeReference>()
|
||||
originalDeclaration.getExtendsBound()?.let { typeRefs.add(it) }
|
||||
originalConstraints
|
||||
.map { it.getBoundTypeReference() }
|
||||
.filterNotNullTo(typeRefs)
|
||||
|
||||
return typeRefs
|
||||
.map { bindingContext[BindingContext.TYPE, it] }
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
private fun JetType.processTypeIfExtractable(
|
||||
bindingContext: BindingContext,
|
||||
typeParameters: MutableSet<TypeParameter>,
|
||||
nonDenotableTypes: HashSet<JetType>
|
||||
): Boolean {
|
||||
return collectReferencedTypes().fold(true) { (extractable, typeToCheck) ->
|
||||
val parameterTypeDescriptor = typeToCheck.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor
|
||||
val typeParameter = parameterTypeDescriptor?.let {
|
||||
BindingContextUtils.descriptorToDeclaration(bindingContext, it)
|
||||
} as? JetTypeParameter
|
||||
|
||||
when {
|
||||
typeParameter != null -> {
|
||||
typeParameters.add(TypeParameter(typeParameter, typeParameter.collectRelevantConstraints()))
|
||||
extractable
|
||||
}
|
||||
|
||||
typeToCheck.canBeReferencedViaImport() ->
|
||||
extractable
|
||||
|
||||
else -> {
|
||||
nonDenotableTypes.add(typeToCheck)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExtractionData.inferParametersInfo(
|
||||
commonParent: PsiElement,
|
||||
localInstructions: List<Instruction>,
|
||||
bindingContext: BindingContext,
|
||||
resultType: JetType?,
|
||||
replacementMap: MutableMap<Int, Replacement>,
|
||||
parameters: MutableSet<Parameter>
|
||||
parameters: MutableSet<Parameter>,
|
||||
typeParameters: MutableSet<TypeParameter>
|
||||
): MaybeError<ExtractionDescriptor, String>? {
|
||||
val varNameValidator = JetNameValidatorImpl(
|
||||
commonParent.getParentByType(javaClass<JetExpression>()),
|
||||
@@ -244,6 +317,7 @@ private fun ExtractionData.inferParametersInfo(
|
||||
|
||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, Parameter>()
|
||||
val nonDenotableTypes = HashSet<JetType>()
|
||||
|
||||
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
||||
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
||||
val ref = refInfo.refExpr
|
||||
@@ -439,8 +513,10 @@ fun ExtractionData.performAnalysis(): Maybe<ExtractionDescriptor, String> {
|
||||
|
||||
val replacementMap = HashMap<Int, Replacement>()
|
||||
val parameters = HashSet<Parameter>()
|
||||
val parameterError =
|
||||
inferParametersInfo(commonParent, localInstructions, bindingContext, inferredResultType, replacementMap, parameters)
|
||||
val typeParameters = HashSet<TypeParameter>()
|
||||
val parameterError = inferParametersInfo(
|
||||
commonParent, localInstructions, bindingContext, inferredResultType, replacementMap, parameters, typeParameters
|
||||
)
|
||||
if (parameterError != null) return parameterError
|
||||
|
||||
val controlFlowInfo = localInstructions.analyzeControlFlow(bindingContext, parameters, inferredResultType)
|
||||
@@ -465,7 +541,16 @@ fun ExtractionData.performAnalysis(): Maybe<ExtractionDescriptor, String> {
|
||||
receiverParameter?.let { parameters.remove(it) }
|
||||
|
||||
return MaybeValue(
|
||||
ExtractionDescriptor(this, functionName, "", parameters.sortBy { it.name }, receiverParameter, replacementMap, controlFlow)
|
||||
ExtractionDescriptor(
|
||||
this,
|
||||
functionName,
|
||||
"",
|
||||
parameters.sortBy { it.name },
|
||||
receiverParameter,
|
||||
typeParameters.sortBy { it.originalDeclaration.getName()!! },
|
||||
replacementMap,
|
||||
controlFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -212,6 +212,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
getVisibility(),
|
||||
ContainerUtil.newArrayList(oldToNewParameters.values()),
|
||||
descriptor.getReceiverParameter(),
|
||||
descriptor.getTypeParameters(),
|
||||
replacementMap,
|
||||
controlFlow
|
||||
);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// NEXT_SIBLING:
|
||||
fun foo() {
|
||||
open class X(val x: Int)
|
||||
|
||||
fun bar<T: X>(t: T): Int {
|
||||
return <selection>t.x + 1</selection>
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
Cannot extract method since following types are not denotable in the target scope: foo.X
|
||||
@@ -0,0 +1,8 @@
|
||||
// NEXT_SIBLING:
|
||||
fun foo() {
|
||||
open class X(val x: Int)
|
||||
|
||||
fun bar<T>(t: T): Int where T: X {
|
||||
return <selection>t.x + 1</selection>
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
Cannot extract method since following types are not denotable in the target scope: foo.X
|
||||
@@ -0,0 +1,8 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
class Pair<A, B>(val a: A, val b: B)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun foo<V: Data>(v: V): Pair<Int, V> {
|
||||
return <selection>Pair(v.x + 10, v)</selection>
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
class Pair<A, B>(val a: A, val b: B)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun <V : Data> pair(v: V): Pair<Int, V> {
|
||||
return Pair(v.x + 10, v)
|
||||
}
|
||||
|
||||
fun foo<V: Data>(v: V): Pair<Int, V> {
|
||||
return pair(v)
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
|
||||
class Pair<A, B>(val a: A, val b: B)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun foo<V: Data>(v: V): Pair<Int, V> where V: DataEx {
|
||||
return <selection>Pair(v.x + 10, v)</selection>
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
|
||||
class Pair<A, B>(val a: A, val b: B)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun <V : Data> pair(v: V): Pair<Int, V> where V : DataEx {
|
||||
return Pair(v.x + 10, v)
|
||||
}
|
||||
|
||||
fun foo<V: Data>(v: V): Pair<Int, V> where V: DataEx {
|
||||
return pair(v)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class Data<T>(val t: Int)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
class A<T> {
|
||||
fun foo(d: Data<T>): Int {
|
||||
return <selection>d.t + 1</selection>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class Data<T>(val t: Int)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun <T> i(d: Data<T>): Int {
|
||||
return d.t + 1
|
||||
}
|
||||
|
||||
class A<T> {
|
||||
fun foo(d: Data<T>): Int {
|
||||
return i(d)
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
trait DataExEx
|
||||
|
||||
// NEXT_SIBLING:
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
inner class B<U: Data>(val u: U) where U: DataExEx {
|
||||
fun foo<V: Data>(v: V): Int where V: DataEx {
|
||||
return <selection>t.x + u.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
trait DataExEx
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun <T : Data, U : Data, V : Data> i(a: A<T>, b: A.B<U>, v: V): Int where T : DataEx, U : DataExEx, V : DataEx {
|
||||
return a.t.x + b.u.x + v.x
|
||||
}
|
||||
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
inner class B<U: Data>(val u: U) where U: DataExEx {
|
||||
fun foo<V: Data>(v: V): Int where V: DataEx {
|
||||
return i(this@A, this@B, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
trait DataExEx
|
||||
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
// NEXT_SIBLING:
|
||||
inner class B<U: Data>(val u: U) where U: DataExEx {
|
||||
fun foo<V: Data>(v: V): Int where V: DataEx {
|
||||
return <selection>t.x + u.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
trait DataExEx
|
||||
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
// NEXT_SIBLING:
|
||||
fun <U : Data, V : Data> B<U>.i(v: V): Int where U : DataExEx, V : DataEx {
|
||||
return t.x + u.x + v.x
|
||||
}
|
||||
|
||||
inner class B<U: Data>(val u: U) where U: DataExEx {
|
||||
fun foo<V: Data>(v: V): Int where V: DataEx {
|
||||
return i(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
trait DataExEx
|
||||
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
inner class B<U: Data>(val u: U) where U: DataExEx {
|
||||
// NEXT_SIBLING:
|
||||
fun foo<V: Data>(v: V): Int where V: DataEx {
|
||||
return <selection>t.x + u.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
trait DataExEx
|
||||
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
inner class B<U: Data>(val u: U) where U: DataExEx {
|
||||
// NEXT_SIBLING:
|
||||
fun <V : Data> i(v: V): Int where V : DataEx {
|
||||
return t.x + u.x + v.x
|
||||
}
|
||||
|
||||
fun foo<V: Data>(v: V): Int where V: DataEx {
|
||||
return i(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
class A<T: Data>(val t: T) {
|
||||
inner class B<U: Data>(val u: U) {
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return <selection>t.x + u.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun <T : Data, U : Data, V : Data> i(a: A<T>, b: A.B<U>, v: V): Int {
|
||||
return a.t.x + b.u.x + v.x
|
||||
}
|
||||
|
||||
class A<T: Data>(val t: T) {
|
||||
inner class B<U: Data>(val u: U) {
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return i(this@A, this@B, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
class A<T: Data>(val t: T) {
|
||||
// NEXT_SIBLING:
|
||||
inner class B<U: Data>(val u: U) {
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return <selection>t.x + u.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
class A<T: Data>(val t: T) {
|
||||
// NEXT_SIBLING:
|
||||
fun <U : Data, V : Data> B<U>.i(v: V): Int {
|
||||
return t.x + u.x + v.x
|
||||
}
|
||||
|
||||
inner class B<U: Data>(val u: U) {
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return i(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
class A<T: Data>(val t: T) {
|
||||
inner class B<U: Data>(val u: U) {
|
||||
// NEXT_SIBLING:
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return <selection>t.x + u.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
open class Data(val x: Int)
|
||||
|
||||
class A<T: Data>(val t: T) {
|
||||
inner class B<U: Data>(val u: U) {
|
||||
// NEXT_SIBLING:
|
||||
fun <V : Data> i(v: V): Int {
|
||||
return t.x + u.x + v.x
|
||||
}
|
||||
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return i(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
|
||||
// NEXT_SIBLING:
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return <selection>t.x + v.x</selection>
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
open class Data(val x: Int)
|
||||
trait DataEx
|
||||
|
||||
// NEXT_SIBLING:
|
||||
fun <T : Data, V : Data> A<T>.i(v: V): Int where T : DataEx {
|
||||
return t.x + v.x
|
||||
}
|
||||
|
||||
class A<T: Data>(val t: T) where T: DataEx {
|
||||
fun foo<V: Data>(v: V): Int {
|
||||
return i(v)
|
||||
}
|
||||
}
|
||||
+70
-1
@@ -186,7 +186,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/extractFunction")
|
||||
@InnerTestClasses({ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.Parameters.class})
|
||||
@InnerTestClasses({ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.Parameters.class, ExtractFunction.TypeParameters.class})
|
||||
public static class ExtractFunction extends AbstractJetExtractionTest {
|
||||
public void testAllFilesPresentInExtractFunction() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -618,12 +618,81 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/extractFunction/typeParameters")
|
||||
public static class TypeParameters extends AbstractJetExtractionTest {
|
||||
public void testAllFilesPresentInTypeParameters() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/typeParameters"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("localClassInBound.kt")
|
||||
public void testLocalClassInBound() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/localClassInBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localClassInTypeConstraint.kt")
|
||||
public void testLocalClassInTypeConstraint() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/localClassInTypeConstraint.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleTypeParameter.kt")
|
||||
public void testSimpleTypeParameter() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleTypeParameterWithConstraint.kt")
|
||||
public void testSimpleTypeParameterWithConstraint() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParamInArgument.kt")
|
||||
public void testTypeParamInArgument() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersAndConstraintsCombined1.kt")
|
||||
public void testTypeParametersAndConstraintsCombined1() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersAndConstraintsCombined2.kt")
|
||||
public void testTypeParametersAndConstraintsCombined2() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersAndConstraintsCombined3.kt")
|
||||
public void testTypeParametersAndConstraintsCombined3() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersCombined1.kt")
|
||||
public void testTypeParametersCombined1() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersCombined2.kt")
|
||||
public void testTypeParametersCombined2() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersCombined3.kt")
|
||||
public void testTypeParametersCombined3() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersCombinedAndThis.kt")
|
||||
public void testTypeParametersCombinedAndThis() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("ExtractFunction");
|
||||
suite.addTestSuite(ExtractFunction.class);
|
||||
suite.addTestSuite(Basic.class);
|
||||
suite.addTest(ControlFlow.innerSuite());
|
||||
suite.addTest(Parameters.innerSuite());
|
||||
suite.addTestSuite(TypeParameters.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user