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.PsiFileFactory;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.util.LocalTimeCounter;
|
import com.intellij.util.LocalTimeCounter;
|
||||||
|
import kotlin.KotlinPackage;
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.lexer.JetKeywordToken;
|
||||||
import org.jetbrains.jet.plugin.JetFileType;
|
import org.jetbrains.jet.plugin.JetFileType;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -526,8 +528,10 @@ public class JetPsiFactory {
|
|||||||
static enum State {
|
static enum State {
|
||||||
MODIFIERS,
|
MODIFIERS,
|
||||||
NAME,
|
NAME,
|
||||||
|
RECEIVER,
|
||||||
FIRST_PARAM,
|
FIRST_PARAM,
|
||||||
REST_PARAMS,
|
REST_PARAMS,
|
||||||
|
TYPE_CONSTRAINTS,
|
||||||
BODY,
|
BODY,
|
||||||
DONE
|
DONE
|
||||||
}
|
}
|
||||||
@@ -543,7 +547,7 @@ public class JetPsiFactory {
|
|||||||
|
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
|
|
||||||
state = State.BODY;
|
state = State.TYPE_CONSTRAINTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void placeFun() {
|
private void placeFun() {
|
||||||
@@ -554,7 +558,7 @@ public class JetPsiFactory {
|
|||||||
}
|
}
|
||||||
sb.append("fun ");
|
sb.append("fun ");
|
||||||
|
|
||||||
state = State.NAME;
|
state = State.RECEIVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -567,23 +571,28 @@ public class JetPsiFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public FunctionBuilder receiver(@NotNull String receiverType) {
|
public FunctionBuilder typeParams(@NotNull Collection<String> values) {
|
||||||
placeFun();
|
placeFun();
|
||||||
sb.append(receiverType).append(".");
|
if (!values.isEmpty()) {
|
||||||
|
sb.append(KotlinPackage.makeString(values, ", ", "<", "> ", -1, ""));
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public FunctionBuilder noReceiver() {
|
public FunctionBuilder receiver(@NotNull String receiverType) {
|
||||||
placeFun();
|
assert state == State.RECEIVER;
|
||||||
|
|
||||||
|
sb.append(receiverType).append(".");
|
||||||
|
state = State.NAME;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public FunctionBuilder name(@NotNull String name) {
|
public FunctionBuilder name(@NotNull String name) {
|
||||||
assert state == State.NAME;
|
assert state == State.NAME || state == State.RECEIVER;
|
||||||
|
|
||||||
sb.append(name).append("(");
|
sb.append(name).append("(");
|
||||||
state = State.FIRST_PARAM;
|
state = State.FIRST_PARAM;
|
||||||
@@ -621,9 +630,21 @@ public class JetPsiFactory {
|
|||||||
return this;
|
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
|
@NotNull
|
||||||
public FunctionBuilder simpleBody(@NotNull String body) {
|
public FunctionBuilder simpleBody(@NotNull String body) {
|
||||||
assert state == State.BODY;
|
assert state == State.BODY || state == State.TYPE_CONSTRAINTS;
|
||||||
|
|
||||||
sb.append(" = ").append(body);
|
sb.append(" = ").append(body);
|
||||||
state = State.DONE;
|
state = State.DONE;
|
||||||
@@ -633,7 +654,7 @@ public class JetPsiFactory {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public FunctionBuilder blockBody(@NotNull String body) {
|
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}");
|
sb.append(" {\n").append(body).append("\n}");
|
||||||
state = State.DONE;
|
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
|
@NotNull
|
||||||
protected final LinkedList<R> result = new LinkedList<R>();
|
protected final C result;
|
||||||
|
|
||||||
|
protected CollectingNodeHandler(@NotNull C result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<R> result() {
|
public C result() {
|
||||||
return 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> {
|
public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
|
||||||
@Override
|
@Override
|
||||||
public void afterChildren(N current) {
|
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.plugin.references.JetSimpleNameReference.ShorteningMode
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
||||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
||||||
|
import org.jetbrains.jet.lang.psi.JetTypeParameter
|
||||||
|
import org.jetbrains.jet.lang.psi.JetTypeConstraint
|
||||||
|
|
||||||
data class Parameter(
|
data class Parameter(
|
||||||
val argumentText: String,
|
val argumentText: String,
|
||||||
@@ -40,6 +42,11 @@ data class Parameter(
|
|||||||
val nameForRef: String get() = mirrorVarName ?: name
|
val nameForRef: String get() = mirrorVarName ?: name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class TypeParameter(
|
||||||
|
val originalDeclaration: JetTypeParameter,
|
||||||
|
val originalConstraints: List<JetTypeConstraint>
|
||||||
|
)
|
||||||
|
|
||||||
trait Replacement: Function1<JetElement, JetElement>
|
trait Replacement: Function1<JetElement, JetElement>
|
||||||
|
|
||||||
trait ParameterReplacement : Replacement {
|
trait ParameterReplacement : Replacement {
|
||||||
@@ -120,6 +127,7 @@ data class ExtractionDescriptor(
|
|||||||
val visibility: String,
|
val visibility: String,
|
||||||
val parameters: List<Parameter>,
|
val parameters: List<Parameter>,
|
||||||
val receiverParameter: Parameter?,
|
val receiverParameter: Parameter?,
|
||||||
|
val typeParameters: List<TypeParameter>,
|
||||||
val replacementMap: Map<Int, Replacement>,
|
val replacementMap: Map<Int, Replacement>,
|
||||||
val controlFlow: ControlFlow
|
val controlFlow: ControlFlow
|
||||||
)
|
)
|
||||||
|
|||||||
+89
-4
@@ -86,9 +86,20 @@ import java.util.Collections
|
|||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor
|
||||||
import org.jetbrains.jet.lang.types.ErrorUtils
|
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.caches.resolve.getLazyResolveSession
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors
|
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
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||||
|
|
||||||
private val DEFAULT_FUNCTION_NAME = "myFun"
|
private val DEFAULT_FUNCTION_NAME = "myFun"
|
||||||
@@ -227,13 +238,75 @@ private fun ExtractionData.createTemporaryCodeBlock(): JetBlockExpression {
|
|||||||
return tmpFunction.getBodyExpression() as 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(
|
private fun ExtractionData.inferParametersInfo(
|
||||||
commonParent: PsiElement,
|
commonParent: PsiElement,
|
||||||
localInstructions: List<Instruction>,
|
localInstructions: List<Instruction>,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
resultType: JetType?,
|
resultType: JetType?,
|
||||||
replacementMap: MutableMap<Int, Replacement>,
|
replacementMap: MutableMap<Int, Replacement>,
|
||||||
parameters: MutableSet<Parameter>
|
parameters: MutableSet<Parameter>,
|
||||||
|
typeParameters: MutableSet<TypeParameter>
|
||||||
): MaybeError<ExtractionDescriptor, String>? {
|
): MaybeError<ExtractionDescriptor, String>? {
|
||||||
val varNameValidator = JetNameValidatorImpl(
|
val varNameValidator = JetNameValidatorImpl(
|
||||||
commonParent.getParentByType(javaClass<JetExpression>()),
|
commonParent.getParentByType(javaClass<JetExpression>()),
|
||||||
@@ -244,6 +317,7 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
|
|
||||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, Parameter>()
|
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, Parameter>()
|
||||||
val nonDenotableTypes = HashSet<JetType>()
|
val nonDenotableTypes = HashSet<JetType>()
|
||||||
|
|
||||||
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
||||||
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
||||||
val ref = refInfo.refExpr
|
val ref = refInfo.refExpr
|
||||||
@@ -439,8 +513,10 @@ fun ExtractionData.performAnalysis(): Maybe<ExtractionDescriptor, String> {
|
|||||||
|
|
||||||
val replacementMap = HashMap<Int, Replacement>()
|
val replacementMap = HashMap<Int, Replacement>()
|
||||||
val parameters = HashSet<Parameter>()
|
val parameters = HashSet<Parameter>()
|
||||||
val parameterError =
|
val typeParameters = HashSet<TypeParameter>()
|
||||||
inferParametersInfo(commonParent, localInstructions, bindingContext, inferredResultType, replacementMap, parameters)
|
val parameterError = inferParametersInfo(
|
||||||
|
commonParent, localInstructions, bindingContext, inferredResultType, replacementMap, parameters, typeParameters
|
||||||
|
)
|
||||||
if (parameterError != null) return parameterError
|
if (parameterError != null) return parameterError
|
||||||
|
|
||||||
val controlFlowInfo = localInstructions.analyzeControlFlow(bindingContext, parameters, inferredResultType)
|
val controlFlowInfo = localInstructions.analyzeControlFlow(bindingContext, parameters, inferredResultType)
|
||||||
@@ -465,7 +541,16 @@ fun ExtractionData.performAnalysis(): Maybe<ExtractionDescriptor, String> {
|
|||||||
receiverParameter?.let { parameters.remove(it) }
|
receiverParameter?.let { parameters.remove(it) }
|
||||||
|
|
||||||
return MaybeValue(
|
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(),
|
getVisibility(),
|
||||||
ContainerUtil.newArrayList(oldToNewParameters.values()),
|
ContainerUtil.newArrayList(oldToNewParameters.values()),
|
||||||
descriptor.getReceiverParameter(),
|
descriptor.getReceiverParameter(),
|
||||||
|
descriptor.getTypeParameters(),
|
||||||
replacementMap,
|
replacementMap,
|
||||||
controlFlow
|
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")
|
@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 static class ExtractFunction extends AbstractJetExtractionTest {
|
||||||
public void testAllFilesPresentInExtractFunction() throws Exception {
|
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);
|
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() {
|
public static Test innerSuite() {
|
||||||
TestSuite suite = new TestSuite("ExtractFunction");
|
TestSuite suite = new TestSuite("ExtractFunction");
|
||||||
suite.addTestSuite(ExtractFunction.class);
|
suite.addTestSuite(ExtractFunction.class);
|
||||||
suite.addTestSuite(Basic.class);
|
suite.addTestSuite(Basic.class);
|
||||||
suite.addTest(ControlFlow.innerSuite());
|
suite.addTest(ControlFlow.innerSuite());
|
||||||
suite.addTest(Parameters.innerSuite());
|
suite.addTest(Parameters.innerSuite());
|
||||||
|
suite.addTestSuite(TypeParameters.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user