Skip to content

GH-48 Add default value to lambda arguments #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## [Unreleased]
### Added
- arguments of type lambda filled with lambda stub and
- if lambda has 2+ parameters: add also parameter with guessed names

### Changed
- rebased on latest [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@ import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtValueArgumentList
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.types.KotlinType

@Suppress("Detekt.ComplexMethod", "Detekt.ReturnCount")
class AddArgumentsQuickFix(
Expand Down Expand Up @@ -44,7 +49,7 @@ class AddArgumentsQuickFix(
if (withoutDefaultArguments && parameter.declaresDefaultValue()) return@forEachIndexed
val added = addArgument(createDefaultValueArgument(parameter, factory))
val argumentExpression = added.getArgumentExpression()
if (argumentExpression is KtQualifiedExpression) {
if (argumentExpression is KtQualifiedExpression || argumentExpression is KtLambdaExpression) {
ShortenReferences.DEFAULT.process(argumentExpression)
}
}
Expand All @@ -59,21 +64,7 @@ class AddArgumentsQuickFix(
}

val type = parameter.type
val defaultValue = when {
KotlinBuiltIns.isBoolean(type) -> "false"
KotlinBuiltIns.isChar(type) -> "''"
KotlinBuiltIns.isDouble(type) -> "0.0"
KotlinBuiltIns.isFloat(type) -> "0.0f"
KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isLong(type) || KotlinBuiltIns.isShort(type) -> "0"
KotlinBuiltIns.isCollectionOrNullableCollection(type) -> "arrayOf()"
KotlinBuiltIns.isNullableAny(type) -> "null"
KotlinBuiltIns.isString(type) -> "\"\""
KotlinBuiltIns.isListOrNullableList(type) -> "listOf()"
KotlinBuiltIns.isSetOrNullableSet(type) -> "setOf()"
KotlinBuiltIns.isMapOrNullableMap(type) -> "mapOf()"
type.isMarkedNullable -> "null"
else -> null
}
val defaultValue = calculateDefaultValue(type)
if (defaultValue != null) {
return factory.createArgument(factory.createExpression(defaultValue), parameter.name)
}
Expand All @@ -97,4 +88,40 @@ class AddArgumentsQuickFix(
}
return factory.createArgument(argumentExpression, parameter.name)
}

private fun calculateDefaultValue(type: KotlinType) = when {
KotlinBuiltIns.isBoolean(type) -> "false"
KotlinBuiltIns.isChar(type) -> "''"
KotlinBuiltIns.isDouble(type) -> "0.0"
KotlinBuiltIns.isFloat(type) -> "0.0f"
KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isLong(type) || KotlinBuiltIns.isShort(type) -> "0"
KotlinBuiltIns.isCollectionOrNullableCollection(type) -> "arrayOf()"
KotlinBuiltIns.isNullableAny(type) -> "null"
KotlinBuiltIns.isString(type) -> "\"\""
KotlinBuiltIns.isListOrNullableList(type) -> "listOf()"
KotlinBuiltIns.isSetOrNullableSet(type) -> "setOf()"
KotlinBuiltIns.isMapOrNullableMap(type) -> "mapOf()"
type.isFunctionType -> calculateLambdaDefaultvalue(type)
type.isMarkedNullable -> "null"
else -> null
}

private fun calculateLambdaDefaultvalue(ktType: KotlinType): String =
buildString {
append("{")
if (ktType.arguments.size > 2) {
val validator = CollectingNameValidator()
val lambdaParameters = ktType.arguments.dropLast(1).joinToString(postfix = "->") {
val type = it.type
val name = KotlinNameSuggester.suggestNamesByType(type, validator, "param")[0]
validator.addName(name)
val typeText =
type.constructor.declarationDescriptor?.importableFqName?.asString() ?: type.toString()
val nullable = if (type.isMarkedNullable) "?" else ""
"$name: $typeText$nullable"
}
append(lambdaParameters)
}
append("}")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,31 @@ class KotlinFunctionArgumentsHelperInspectionTest : BasePlatformTestCase() {
)
}

fun `test fill lambda arguments`() {
val dependency = """
package foo
class A
class B(f1: () -> Unit, f2: (Int) -> String, f3: (Int, String?, A) -> String)
""".trimIndent()

doAvailableTest(
"""
import foo.B

fun test() {
B(<caret>)
}
""", """
import foo.A
import foo.B

fun test() {
B(f1 = {}, f2 = {}, f3 = { i: Int, s: String?, a: A -> })
}
""", withoutDefaultArguments = true, dependencies = listOf(dependency)
)
}

private fun doAvailableTest(
before: String,
after: String,
Expand Down