From 49683779699796e6302ef3b1577401f92b1044ee Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 18 Apr 2014 19:26:39 +0400 Subject: [PATCH] Smart completion: lambda item uses template to allow change parameter names --- .../codeInsight/template/annotations.xml | 17 +++ .../codeInsight/template/impl/annotations.xml | 34 +++++ .../intellij/openapi/command/annotations.xml | 5 + annotations/com/intellij/psi/annotations.xml | 6 + .../jet/lang/psi/JetTreeVisitorVoid.java | 3 +- idea/src/META-INF/plugin.xml | 1 + .../plugin/codeInsight/ShortenReferences.kt | 89 ++++++++++--- .../plugin/completion/smart/LambdaItems.kt | 117 ++++++++++++++---- .../plugin/completion/smart/StaticMembers.kt | 2 +- .../jet/plugin/completion/smart/Utils.kt | 6 +- .../plugin/imports/KotlinImportOptimizer.kt | 2 +- .../inspections/IntentionBasedInspection.kt | 2 +- .../KotlinShortenFQNamesProcessor.kt | 38 ++++++ .../plugin/refactoring/JetNameValidator.java | 2 +- .../handlers/smart/LambdaInsertImport.kt | 8 ++ .../smart/LambdaInsertImport.kt.after | 10 ++ idea/testData/completion/smart/Lambda4.kt | 4 +- .../SmartCompletionHandlerTestGenerated.java | 5 + 18 files changed, 299 insertions(+), 52 deletions(-) create mode 100644 annotations/com/intellij/codeInsight/template/annotations.xml create mode 100644 annotations/com/intellij/codeInsight/template/impl/annotations.xml create mode 100644 annotations/com/intellij/openapi/command/annotations.xml create mode 100644 idea/src/org/jetbrains/jet/plugin/liveTemplates/KotlinShortenFQNamesProcessor.kt create mode 100644 idea/testData/completion/handlers/smart/LambdaInsertImport.kt create mode 100644 idea/testData/completion/handlers/smart/LambdaInsertImport.kt.after diff --git a/annotations/com/intellij/codeInsight/template/annotations.xml b/annotations/com/intellij/codeInsight/template/annotations.xml new file mode 100644 index 00000000000..49c52c9424a --- /dev/null +++ b/annotations/com/intellij/codeInsight/template/annotations.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/codeInsight/template/impl/annotations.xml b/annotations/com/intellij/codeInsight/template/impl/annotations.xml new file mode 100644 index 00000000000..76332fc8fde --- /dev/null +++ b/annotations/com/intellij/codeInsight/template/impl/annotations.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/openapi/command/annotations.xml b/annotations/com/intellij/openapi/command/annotations.xml new file mode 100644 index 00000000000..69318e5b241 --- /dev/null +++ b/annotations/com/intellij/openapi/command/annotations.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/psi/annotations.xml b/annotations/com/intellij/psi/annotations.xml index 9ebf450d9bf..325cc901c25 100644 --- a/annotations/com/intellij/psi/annotations.xml +++ b/annotations/com/intellij/psi/annotations.xml @@ -11,6 +11,9 @@ + + + @@ -18,4 +21,7 @@ name='com.intellij.psi.PsiReferenceService java.util.List<com.intellij.psi.PsiReference> getReferences(com.intellij.psi.PsiElement, com.intellij.psi.PsiReferenceService.Hints)'> + + + \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java index 7958bb906e6..608ae63e6ac 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java @@ -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); } } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 0ceff10bc59..4ec68bfe29b 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -257,6 +257,7 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt index d461c5e474e..8a905069cee 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt @@ -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) { - 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, 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) : JetTreeVisitorVoid() { + private class ShortenTypesVisitor(val file: JetFile, + val elementFilter: (PsiElement) -> FilterResult, + val resolveMap: Map) : 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())!! - 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) : JetVisitorVoid() { + private class ShortenQualifiedExpressionsVisitor(val file: JetFile, + val elementFilter: (PsiElement) -> FilterResult, + val resolveMap: Map) : 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 diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/LambdaItems.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/LambdaItems.kt index 14c28729ad4..f91f63b204e 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/smart/LambdaItems.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/LambdaItems.kt @@ -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, functionExpectedInfos: Collection) { @@ -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 })) } } } -} \ No newline at end of file + + private fun useParenthesis(useExplicitTypes: Boolean, parameterTypes: List) = useExplicitTypes || parameterTypes.size != 1 + + private inner class LambdaInsertHandler(val functionType: JetType, val useExplicitTypes: Boolean) : InsertHandler { + 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{ + 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 + = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() } + + private class ParameterNameExpression(val nameSuggestions: Array) : Expression() { + override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0]) + + override fun calculateQuickResult(context: ExpressionContext?): Result? = null + + override fun calculateLookupItems(context: ExpressionContext?) + = Array(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) }) + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/StaticMembers.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/StaticMembers.kt index 7384092d3f8..f5deeb827e6 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/smart/StaticMembers.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/StaticMembers.kt @@ -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 diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt index cb0331796fe..b9d9bbfa3bb 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt @@ -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()) - if (element != null) { - ShortenReferences.process(element) - } + ShortenReferences.process(context.getFile() as JetFile, startOffset, endOffset) } fun mergeTails(tails: Collection): Tail? { diff --git a/idea/src/org/jetbrains/jet/plugin/imports/KotlinImportOptimizer.kt b/idea/src/org/jetbrains/jet/plugin/imports/KotlinImportOptimizer.kt index 83d55c6b795..0a5b3f97f38 100644 --- a/idea/src/org/jetbrains/jet/plugin/imports/KotlinImportOptimizer.kt +++ b/idea/src/org/jetbrains/jet/plugin/imports/KotlinImportOptimizer.kt @@ -74,7 +74,7 @@ public class KotlinImportOptimizer() : ImportOptimizer { private fun extractUsedQualifiedNames(jetFile: JetFile): Set { val usedQualifiedNames = HashSet() jetFile.accept(object : JetVisitorVoid() { - override fun visitElement(element: PsiElement?) { + override fun visitElement(element: PsiElement) { ProgressIndicatorProvider.checkCanceled() element?.acceptChildren(this) } diff --git a/idea/src/org/jetbrains/jet/plugin/inspections/IntentionBasedInspection.kt b/idea/src/org/jetbrains/jet/plugin/inspections/IntentionBasedInspection.kt index 4802df3181b..60860553479 100644 --- a/idea/src/org/jetbrains/jet/plugin/inspections/IntentionBasedInspection.kt +++ b/idea/src/org/jetbrains/jet/plugin/inspections/IntentionBasedInspection.kt @@ -35,7 +35,7 @@ public abstract class IntentionBasedInspection( ) : 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")] diff --git a/idea/src/org/jetbrains/jet/plugin/liveTemplates/KotlinShortenFQNamesProcessor.kt b/idea/src/org/jetbrains/jet/plugin/liveTemplates/KotlinShortenFQNamesProcessor.kt new file mode 100644 index 00000000000..e0df888a5d7 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/liveTemplates/KotlinShortenFQNamesProcessor.kt @@ -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 +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.java index f4fa4ab4ae1..ee2dbabe95c 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.java @@ -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 suggestedSet = new HashSet(); diff --git a/idea/testData/completion/handlers/smart/LambdaInsertImport.kt b/idea/testData/completion/handlers/smart/LambdaInsertImport.kt new file mode 100644 index 00000000000..859d73a97b0 --- /dev/null +++ b/idea/testData/completion/handlers/smart/LambdaInsertImport.kt @@ -0,0 +1,8 @@ +fun foo(p: (java.util.Date) -> Unit){} +fun foo(p: (String) -> Unit){} + +fun bar() { + foo() +} + +// ELEMENT: "{ (Date) -> ... }" diff --git a/idea/testData/completion/handlers/smart/LambdaInsertImport.kt.after b/idea/testData/completion/handlers/smart/LambdaInsertImport.kt.after new file mode 100644 index 00000000000..3715f6d4194 --- /dev/null +++ b/idea/testData/completion/handlers/smart/LambdaInsertImport.kt.after @@ -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) -> }) +} + +// ELEMENT: "{ (Date) -> ... }" diff --git a/idea/testData/completion/smart/Lambda4.kt b/idea/testData/completion/smart/Lambda4.kt index 57e9058c189..4079b76b003 100644 --- a/idea/testData/completion/smart/Lambda4.kt +++ b/idea/testData/completion/smart/Lambda4.kt @@ -6,5 +6,5 @@ fun bar() { } // ABSENT: "{...}" -// EXIST: "{ String -> ... }" -// EXIST: "{ Int -> ... }" +// EXIST: "{ (String) -> ... }" +// EXIST: "{ (Int) -> ... }" diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java index 076bc1e17e7..7a2b55e0e46 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java @@ -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");