Smart completion: lambda item uses template to allow change parameter names

This commit is contained in:
Valentin Kipyatkov
2014-04-18 19:26:39 +04:00
parent 767eb04930
commit 4968377969
18 changed files with 299 additions and 52 deletions
@@ -0,0 +1,17 @@
<root>
<item name='com.intellij.codeInsight.template.Template'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.TemplateManager com.intellij.codeInsight.template.Template createTemplate(java.lang.String, java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.TemplateManager com.intellij.codeInsight.template.Template createTemplate(java.lang.String, java.lang.String, java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.TemplateManager com.intellij.codeInsight.template.TemplateManager getInstance(com.intellij.openapi.project.Project)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,34 @@
<root>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor boolean isEnabled(com.intellij.codeInsight.template.Template) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor boolean isVisible(com.intellij.codeInsight.template.Template) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor void processText(com.intellij.openapi.project.Project, com.intellij.codeInsight.template.Template, com.intellij.openapi.editor.Document, com.intellij.openapi.editor.RangeMarker, com.intellij.openapi.editor.Editor) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor void processText(com.intellij.openapi.project.Project, com.intellij.codeInsight.template.Template, com.intellij.openapi.editor.Document, com.intellij.openapi.editor.RangeMarker, com.intellij.openapi.editor.Editor) 1'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor void processText(com.intellij.openapi.project.Project, com.intellij.codeInsight.template.Template, com.intellij.openapi.editor.Document, com.intellij.openapi.editor.RangeMarker, com.intellij.openapi.editor.Editor) 2'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor void processText(com.intellij.openapi.project.Project, com.intellij.codeInsight.template.Template, com.intellij.openapi.editor.Document, com.intellij.openapi.editor.RangeMarker, com.intellij.openapi.editor.Editor) 3'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor void processText(com.intellij.openapi.project.Project, com.intellij.codeInsight.template.Template, com.intellij.openapi.editor.Document, com.intellij.openapi.editor.RangeMarker, com.intellij.openapi.editor.Editor) 4'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.template.impl.TemplateOptionalProcessor void setEnabled(com.intellij.codeInsight.template.Template, boolean) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,5 @@
<root>
<item name='com.intellij.openapi.command.CommandProcessor com.intellij.openapi.command.CommandProcessor getInstance()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -11,6 +11,9 @@
<item name='com.intellij.psi.PsiElement com.intellij.psi.PsiElement replace(com.intellij.psi.PsiElement)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.intellij.psi.PsiElementVisitor void visitElement(com.intellij.psi.PsiElement) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.intellij.psi.PsiReference com.intellij.psi.PsiElement getElement()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
@@ -18,4 +21,7 @@
name='com.intellij.psi.PsiReferenceService java.util.List&lt;com.intellij.psi.PsiReference&gt; getReferences(com.intellij.psi.PsiElement, com.intellij.psi.PsiReferenceService.Hints)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.intellij.psi.SmartPointerManager com.intellij.psi.SmartPointerManager getInstance(com.intellij.openapi.project.Project)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -17,10 +17,11 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
public class JetTreeVisitorVoid extends JetVisitorVoid {
@Override
public void visitElement(PsiElement element) {
public void visitElement(@NotNull PsiElement element) {
element.acceptChildren(this);
}
}
+1
View File
@@ -257,6 +257,7 @@
<liveTemplateMacro implementation="org.jetbrains.jet.plugin.liveTemplates.macro.JetAnonymousSuperMacro"/>
<liveTemplateMacro implementation="org.jetbrains.jet.plugin.liveTemplates.macro.JetIterableVariableMacro"/>
<liveTemplateMacro implementation="org.jetbrains.jet.plugin.liveTemplates.macro.JetSuggestVariableNameMacro"/>
<liveTemplateOptionalProcessor implementation="org.jetbrains.jet.plugin.liveTemplates.KotlinShortenFQNamesProcessor"/>
<annotator language="jet" implementationClass="org.jetbrains.jet.plugin.highlighter.JetPsiChecker"/>
<highlightRangeExtension implementation="org.jetbrains.jet.plugin.highlighter.JetPsiChecker"/>
@@ -10,7 +10,6 @@ import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.Collections;
import java.util.HashSet;
import com.intellij.psi.util.PsiTreeUtil
import java.util.ArrayList
@@ -18,22 +17,59 @@ import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentForJavaClass
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor
import com.intellij.openapi.util.TextRange
import com.intellij.psi.SmartPointerManager
public object ShortenReferences {
public fun process(element: JetElement) {
process(Collections.singleton(element))
process(listOf(element))
}
public fun process(elements: Iterable<JetElement>) {
for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) {
process(elements, { FilterResult.PROCESS })
}
public fun process(file: JetFile, startOffset: Int, endOffset: Int) {
val smartPointerManager = SmartPointerManager.getInstance(file.getProject())
val pointer = smartPointerManager.createSmartPsiFileRangePointer(file, TextRange(startOffset, endOffset))
try{
process(listOf(file), { element ->
val segment = pointer.getRange()
if (segment != null) {
val range = TextRange(segment.getStartOffset(), segment.getEndOffset())
val elementRange = element.getTextRange()!!
when {
range.contains(elementRange) -> FilterResult.PROCESS
range.intersects(elementRange) -> FilterResult.GO_INSIDE
else -> FilterResult.SKIP
}
}
else{
FilterResult.SKIP
}
})
}
finally {
smartPointerManager.removePointer(pointer)
}
}
private enum class FilterResult {
SKIP
GO_INSIDE
PROCESS
}
private fun process(elements: Iterable<JetElement>, elementFilter: (PsiElement) -> FilterResult) {
for ((file, fileElements) in elements.groupBy { element -> element.getContainingFile() as JetFile }) {
// first resolve all qualified references - optimization
val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, visitShortNames = false)
val shortenTypesVisitor = ShortenTypesVisitor(file, referenceToContext)
val shortenTypesVisitor = ShortenTypesVisitor(file, elementFilter, referenceToContext)
processElements(fileElements, shortenTypesVisitor)
shortenTypesVisitor.finish()
processElements(fileElements, ShortenQualifiedExpressionsVisitor(file, referenceToContext))
processElements(fileElements, ShortenQualifiedExpressionsVisitor(file, elementFilter, referenceToContext))
}
}
@@ -43,7 +79,9 @@ public object ShortenReferences {
}
}
private class ShortenTypesVisitor(val file: JetFile, val resolveMap: Map<JetReferenceExpression, BindingContext>) : JetTreeVisitorVoid() {
private class ShortenTypesVisitor(val file: JetFile,
val elementFilter: (PsiElement) -> FilterResult,
val resolveMap: Map<JetReferenceExpression, BindingContext>) : JetVisitorVoid() {
private val resolveSession : ResolveSessionForBodies
get() = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
@@ -57,10 +95,16 @@ public object ShortenReferences {
private fun bindingContext(expression: JetReferenceExpression): BindingContext = resolveMap[expression]!!
override fun visitElement(element: PsiElement) {
if (elementFilter(element) != FilterResult.SKIP) {
element.acceptChildren(this)
}
}
override fun visitUserType(userType: JetUserType) {
userType.getTypeArgumentList()?.accept(this)
if (canShortenType(userType)) {
if (elementFilter(userType) == FilterResult.PROCESS && canShortenType(userType)) {
typesToShorten.add(userType)
}
else{
@@ -73,13 +117,13 @@ public object ShortenReferences {
val referenceExpression = userType.getReferenceExpression()
if (referenceExpression == null) return false
val target = bindingContext(referenceExpression).get(BindingContext.REFERENCE_TARGET, referenceExpression)?.let { desc ->
val target = bindingContext(referenceExpression)[BindingContext.REFERENCE_TARGET, referenceExpression]?.let { desc ->
if (desc is ConstructorDescriptor) desc.getContainingDeclaration() else desc
}
if (target == null) return false
val typeReference = PsiTreeUtil.getParentOfType(userType, javaClass<JetTypeReference>())!!
val scope = resolveSession.resolveToElement(typeReference).get(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference)!!
val scope = resolveSession.resolveToElement(typeReference)[BindingContext.TYPE_RESOLUTION_SCOPE, typeReference]!!
val name = target.getName()
val targetByName = scope.getClassifier(name)
if (targetByName == null) {
@@ -107,20 +151,27 @@ public object ShortenReferences {
}
}
private class ShortenQualifiedExpressionsVisitor(val file: JetFile, val resolveMap: Map<JetReferenceExpression, BindingContext>) : JetVisitorVoid() {
private class ShortenQualifiedExpressionsVisitor(val file: JetFile,
val elementFilter: (PsiElement) -> FilterResult,
val resolveMap: Map<JetReferenceExpression, BindingContext>) : JetVisitorVoid() {
private val resolveSession : ResolveSessionForBodies
get() = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
private fun bindingContext(expression: JetReferenceExpression): BindingContext
= resolveMap[expression] ?: resolveSession.resolveToElement(expression) // binding context can be absent in the map if some references have been shortened already
override fun visitJetElement(element: JetElement) {
acceptChildren(element)
override fun visitElement(element: PsiElement) {
if (elementFilter(element) != FilterResult.SKIP) {
acceptChildren(element)
}
}
override fun visitDotQualifiedExpression(expression: JetDotQualifiedExpression) {
val resultElement = processDotQualifiedExpression(expression)
acceptChildren(resultElement)
val filterResult = elementFilter(expression)
val resultElement = if (filterResult == FilterResult.PROCESS) processDotQualifiedExpression(expression) else expression
if (filterResult != FilterResult.SKIP) {
acceptChildren(resultElement)
}
}
private fun processDotQualifiedExpression(qualifiedExpression: JetDotQualifiedExpression): PsiElement {
@@ -150,7 +201,7 @@ public object ShortenReferences {
bindingContext: BindingContext
): PsiElement {
val receiverExpression = qualifiedExpression.getReceiverExpression()
val target = bindingContext.get(BindingContext.REFERENCE_TARGET, refExpression)
val target = bindingContext[BindingContext.REFERENCE_TARGET, refExpression]
if (target != null) {
if ((target is JavaPropertyDescriptor || target is JavaMethodDescriptor) && receiverExpression is JetDotQualifiedExpression) {
val containingDescriptor = target.getContainingDeclaration()
@@ -166,14 +217,14 @@ public object ShortenReferences {
private fun instantiatedClass(calleeExpression: JetReferenceExpression): ClassDescriptor? {
val bindingContext = bindingContext(calleeExpression)
val target = bindingContext.get(BindingContext.REFERENCE_TARGET, calleeExpression)
val target = bindingContext[BindingContext.REFERENCE_TARGET, calleeExpression]
if (target != null) {
if (target is ConstructorDescriptor) {
return target.getContainingDeclaration()
}
}
else {
val targets = bindingContext.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, calleeExpression)
val targets = bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, calleeExpression]
if (targets != null && !targets.isEmpty()) {
var targetClass: ClassDescriptor? = null
for (descriptor in targets) {
@@ -220,10 +271,10 @@ public object ShortenReferences {
}
private fun resolveState(referenceExpression: JetReferenceExpression, bindingContext: BindingContext): Any? {
val target = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression)
val target = bindingContext[BindingContext.REFERENCE_TARGET, referenceExpression]
if (target != null) return target.asString()
val targets = bindingContext.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression)
val targets = bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression]
if (targets != null) return HashSet(targets.map{it.asString()})
return null
@@ -8,6 +8,12 @@ import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.plugin.refactoring.JetNameValidator
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
import com.intellij.openapi.project.Project
import com.intellij.codeInsight.completion.InsertHandler
import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.codeInsight.template.*
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
class LambdaItems(val project: Project) {
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
@@ -27,35 +33,104 @@ class LambdaItems(val project: Project) {
}
if (singleSignatureLength != 0) {
fun functionParameterTypes(functionType: JetType)
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
for (functionType in distinctTypes) {
val parameterTypes = functionParameterTypes(functionType)
val parametersPresentation = parameterTypes.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
val useExplicitTypes = distinctTypes.stream().any { it != functionType && functionParameterTypes(it).size == parameterTypes.size }
val nameValidator = JetNameValidator.getEmptyValidator(project)
fun parameterName(parameterType: JetType) = JetNameSuggester.suggestNames(parameterType, nameValidator, "p")[0]
fun parameterText(parameterType: JetType): String {
return if (useExplicitTypes)
parameterName(parameterType) + ": " + DescriptorRenderer.SOURCE_CODE.renderType(parameterType)
else
parameterName(parameterType)
}
val parametersText = parameterTypes.map(::parameterText).makeString(", ")
val useParenthesis = parameterTypes.size != 1
fun wrap(s: String) = if (useParenthesis) "($s)" else s
fun wrap(s: String) = if (useParenthesis(useExplicitTypes, parameterTypes)) "($s)" else s
val lookupString = "{ ${wrap(parametersPresentation)} -> ... }"
val lookupElement = createLookupElement(lookupString, "{ ${wrap(parametersText)} -> ", " }", shortenRefs = true)
val lookupElement = LookupElementBuilder.create(lookupString)
.withInsertHandler(LambdaInsertHandler(functionType, useExplicitTypes))
.suppressAutoInsertion()
collection.add(addTailToLookupElement(lookupElement, functionExpectedInfos.filter { it.`type` == functionType }))
}
}
}
}
private fun useParenthesis(useExplicitTypes: Boolean, parameterTypes: List<JetType>) = useExplicitTypes || parameterTypes.size != 1
private inner class LambdaInsertHandler(val functionType: JetType, val useExplicitTypes: Boolean) : InsertHandler<LookupElement> {
override fun handleInsert(context: InsertionContext, item: LookupElement) {
val document = context.getDocument()
val editor = context.getEditor()
val offset = context.getStartOffset()
val placeholder = "{}"
document.replaceString(offset, context.getTailOffset(), placeholder)
editor.getCaretModel().moveToOffset(offset + 1)
val rangeMarker = document.createRangeMarker(offset, offset + placeholder.length)
// we start template later to not interfere with insertion of tail type
val commandProcessor = CommandProcessor.getInstance()
val commandName = commandProcessor.getCurrentCommandName()
val commandGroupId = commandProcessor.getCurrentCommandGroupId()
context.setLaterRunnable{
commandProcessor.executeCommand(project, {
ApplicationManager.getApplication()!!.runWriteAction(Computable<Unit>{
try{
if (rangeMarker.isValid()) {
document.deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())
editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset())
TemplateManager.getInstance(project).startTemplate(editor, buildTemplate())
}
}
finally {
rangeMarker.dispose()
}
})
}, commandName, commandGroupId)
}
}
private fun buildTemplate(): Template {
val parameterTypes = functionParameterTypes(functionType)
val nameValidator = JetNameValidator.getEmptyValidator(project) //TODO: check for names in scope
val useParenthesis = useParenthesis(useExplicitTypes, parameterTypes)
val manager = TemplateManager.getInstance(project)
val template = manager.createTemplate("", "")
template.setToShortenLongNames(true)
//template.setToReformat(true) //TODO
template.addTextSegment("{ ")
if (useParenthesis) {
template.addTextSegment("(")
}
var i = 0
for (parameterType in parameterTypes) {
if (i++ > 0) {
template.addTextSegment(", ")
}
template.addVariable(ParameterNameExpression(JetNameSuggester.suggestNames(parameterType, nameValidator, "p")), true)
if (useExplicitTypes) {
template.addTextSegment(": " + DescriptorRenderer.SOURCE_CODE.renderType(parameterType))
}
}
if (useParenthesis) {
template.addTextSegment(")")
}
template.addTextSegment(" -> ")
template.addEndVariable()
template.addTextSegment(" }")
return template
}
}
private fun functionParameterTypes(functionType: JetType): List<JetType>
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
private class ParameterNameExpression(val nameSuggestions: Array<String>) : Expression() {
override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0])
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
override fun calculateLookupItems(context: ExpressionContext?)
= Array<LookupElement>(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) })
}
}
@@ -48,7 +48,7 @@ class StaticMembers(val bindingContext: BindingContext, val resolveSession: Reso
val matchedExpectedInfos = expectedInfos.filter {
expectedInfo ->
descriptor is CallableDescriptor && descriptor.getReturnType()?.let { it.isSubtypeOf(expectedInfo.`type`) } ?: false
|| descriptor is ClassDescriptor && descriptor.getKind() == ClassKind.ENUM_ENTRY
|| DescriptorUtils.isEnumEntry(descriptor) /* we do not need to check type of enum entry because it's taken from proper enum */
}
if (matchedExpectedInfos.isEmpty()) return
@@ -34,11 +34,7 @@ class ArtificialElementInsertHandler(
fun shortenReferences(context: InsertionContext, startOffset: Int, endOffset: Int) {
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();
val file = context.getFile() as JetFile
val element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, javaClass<JetElement>())
if (element != null) {
ShortenReferences.process(element)
}
ShortenReferences.process(context.getFile() as JetFile, startOffset, endOffset)
}
fun mergeTails(tails: Collection<Tail?>): Tail? {
@@ -74,7 +74,7 @@ public class KotlinImportOptimizer() : ImportOptimizer {
private fun extractUsedQualifiedNames(jetFile: JetFile): Set<FqName> {
val usedQualifiedNames = HashSet<FqName>()
jetFile.accept(object : JetVisitorVoid() {
override fun visitElement(element: PsiElement?) {
override fun visitElement(element: PsiElement) {
ProgressIndicatorProvider.checkCanceled()
element?.acceptChildren(this)
}
@@ -35,7 +35,7 @@ public abstract class IntentionBasedInspection<T: JetElement>(
) : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object: PsiElementVisitor() {
override fun visitElement(element: PsiElement?) {
override fun visitElement(element: PsiElement) {
if (!intention.elementType.isInstance(element)) return
[suppress("UNCHECKED_CAST")]
@@ -0,0 +1,38 @@
package org.jetbrains.jet.plugin.liveTemplates
import com.intellij.codeInsight.template.impl.TemplateOptionalProcessor
import com.intellij.openapi.project.Project
import com.intellij.codeInsight.template.Template
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.Editor
import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.psi.PsiDocumentManager
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
import com.intellij.psi.util.PsiUtilBase
import org.jetbrains.jet.lang.psi.JetFile
public class KotlinShortenFQNamesProcessor : TemplateOptionalProcessor {
override fun processText(project: Project, template: Template, document: Document, templateRange: RangeMarker, editor: Editor) {
if (!template.isToShortenLongNames()) return
PsiDocumentManager.getInstance(project).commitDocument(document)
val file = PsiUtilBase.getPsiFileInEditor(editor, project) as? JetFile ?: return
ShortenReferences.process(file, templateRange.getStartOffset(), templateRange.getEndOffset())
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document)
}
override fun getOptionName(): String {
return CodeInsightBundle.message("dialog.edit.template.checkbox.shorten.fq.names")!!
}
override fun isEnabled(template: Template) = template.isToShortenLongNames()
override fun setEnabled(template: Template, value: Boolean) {
template.setToShortenLongNames(value)
}
override fun isVisible(template: Template) = true
}
@@ -39,7 +39,7 @@ public abstract class JetNameValidator {
};
}
@NotNull
@NotNull //TODO: shouldn't it be "createCollectingValidator"?
public static JetNameValidator getCollectingValidator(final Project project) {
return new JetNameValidator(project) {
private final Set<String> suggestedSet = new HashSet<String>();
@@ -0,0 +1,8 @@
fun foo(p: (java.util.Date) -> Unit){}
fun foo(p: (String) -> Unit){}
fun bar() {
foo(<caret>)
}
// ELEMENT: "{ (Date) -> ... }"
@@ -0,0 +1,10 @@
import java.util.Date
fun foo(p: (java.util.Date) -> Unit){}
fun foo(p: (String) -> Unit){}
fun bar() {
foo({ (date: Date) -> <caret> })
}
// ELEMENT: "{ (Date) -> ... }"
+2 -2
View File
@@ -6,5 +6,5 @@ fun bar() {
}
// ABSENT: "{...}"
// EXIST: "{ String -> ... }"
// EXIST: "{ Int -> ... }"
// EXIST: "{ (String) -> ... }"
// EXIST: "{ (Int) -> ... }"
@@ -221,6 +221,11 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest("idea/testData/completion/handlers/smart/Lambda5.kt");
}
@TestMetadata("LambdaInsertImport.kt")
public void testLambdaInsertImport() throws Exception {
doTest("idea/testData/completion/handlers/smart/LambdaInsertImport.kt");
}
@TestMetadata("MergeTail1.kt")
public void testMergeTail1() throws Exception {
doTest("idea/testData/completion/handlers/smart/MergeTail1.kt");