Smart completion: lambda item uses template to allow change parameter names
This commit is contained in:
@@ -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<com.intellij.psi.PsiReference> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) -> ... }"
|
||||
@@ -6,5 +6,5 @@ fun bar() {
|
||||
}
|
||||
|
||||
// ABSENT: "{...}"
|
||||
// EXIST: "{ String -> ... }"
|
||||
// EXIST: "{ Int -> ... }"
|
||||
// EXIST: "{ (String) -> ... }"
|
||||
// EXIST: "{ (Int) -> ... }"
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user