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)'>
|
<item name='com.intellij.psi.PsiElement com.intellij.psi.PsiElement replace(com.intellij.psi.PsiElement)'>
|
||||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
</item>
|
</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()'>
|
<item name='com.intellij.psi.PsiReference com.intellij.psi.PsiElement getElement()'>
|
||||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
</item>
|
</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)'>
|
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'/>
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
</item>
|
</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>
|
</root>
|
||||||
@@ -17,10 +17,11 @@
|
|||||||
package org.jetbrains.jet.lang.psi;
|
package org.jetbrains.jet.lang.psi;
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class JetTreeVisitorVoid extends JetVisitorVoid {
|
public class JetTreeVisitorVoid extends JetVisitorVoid {
|
||||||
@Override
|
@Override
|
||||||
public void visitElement(PsiElement element) {
|
public void visitElement(@NotNull PsiElement element) {
|
||||||
element.acceptChildren(this);
|
element.acceptChildren(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
<liveTemplateMacro implementation="org.jetbrains.jet.plugin.liveTemplates.macro.JetAnonymousSuperMacro"/>
|
<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.JetIterableVariableMacro"/>
|
||||||
<liveTemplateMacro implementation="org.jetbrains.jet.plugin.liveTemplates.macro.JetSuggestVariableNameMacro"/>
|
<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"/>
|
<annotator language="jet" implementationClass="org.jetbrains.jet.plugin.highlighter.JetPsiChecker"/>
|
||||||
<highlightRangeExtension implementation="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.plugin.quickfix.ImportInsertHelper;
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import java.util.ArrayList
|
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.descriptor.JavaPropertyDescriptor
|
||||||
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentForJavaClass
|
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentForJavaClass
|
||||||
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor
|
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.SmartPointerManager
|
||||||
|
|
||||||
public object ShortenReferences {
|
public object ShortenReferences {
|
||||||
public fun process(element: JetElement) {
|
public fun process(element: JetElement) {
|
||||||
process(Collections.singleton(element))
|
process(listOf(element))
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun process(elements: Iterable<JetElement>) {
|
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
|
// first resolve all qualified references - optimization
|
||||||
val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, visitShortNames = false)
|
val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, visitShortNames = false)
|
||||||
|
|
||||||
val shortenTypesVisitor = ShortenTypesVisitor(file, referenceToContext)
|
val shortenTypesVisitor = ShortenTypesVisitor(file, elementFilter, referenceToContext)
|
||||||
processElements(fileElements, shortenTypesVisitor)
|
processElements(fileElements, shortenTypesVisitor)
|
||||||
shortenTypesVisitor.finish()
|
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
|
private val resolveSession : ResolveSessionForBodies
|
||||||
get() = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
|
get() = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
|
||||||
|
|
||||||
@@ -57,10 +95,16 @@ public object ShortenReferences {
|
|||||||
|
|
||||||
private fun bindingContext(expression: JetReferenceExpression): BindingContext = resolveMap[expression]!!
|
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) {
|
override fun visitUserType(userType: JetUserType) {
|
||||||
userType.getTypeArgumentList()?.accept(this)
|
userType.getTypeArgumentList()?.accept(this)
|
||||||
|
|
||||||
if (canShortenType(userType)) {
|
if (elementFilter(userType) == FilterResult.PROCESS && canShortenType(userType)) {
|
||||||
typesToShorten.add(userType)
|
typesToShorten.add(userType)
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -73,13 +117,13 @@ public object ShortenReferences {
|
|||||||
val referenceExpression = userType.getReferenceExpression()
|
val referenceExpression = userType.getReferenceExpression()
|
||||||
if (referenceExpression == null) return false
|
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 (desc is ConstructorDescriptor) desc.getContainingDeclaration() else desc
|
||||||
}
|
}
|
||||||
if (target == null) return false
|
if (target == null) return false
|
||||||
|
|
||||||
val typeReference = PsiTreeUtil.getParentOfType(userType, javaClass<JetTypeReference>())!!
|
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 name = target.getName()
|
||||||
val targetByName = scope.getClassifier(name)
|
val targetByName = scope.getClassifier(name)
|
||||||
if (targetByName == null) {
|
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
|
private val resolveSession : ResolveSessionForBodies
|
||||||
get() = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
|
get() = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
|
||||||
|
|
||||||
private fun bindingContext(expression: JetReferenceExpression): BindingContext
|
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
|
= 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) {
|
override fun visitElement(element: PsiElement) {
|
||||||
acceptChildren(element)
|
if (elementFilter(element) != FilterResult.SKIP) {
|
||||||
|
acceptChildren(element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDotQualifiedExpression(expression: JetDotQualifiedExpression) {
|
override fun visitDotQualifiedExpression(expression: JetDotQualifiedExpression) {
|
||||||
val resultElement = processDotQualifiedExpression(expression)
|
val filterResult = elementFilter(expression)
|
||||||
acceptChildren(resultElement)
|
val resultElement = if (filterResult == FilterResult.PROCESS) processDotQualifiedExpression(expression) else expression
|
||||||
|
if (filterResult != FilterResult.SKIP) {
|
||||||
|
acceptChildren(resultElement)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processDotQualifiedExpression(qualifiedExpression: JetDotQualifiedExpression): PsiElement {
|
private fun processDotQualifiedExpression(qualifiedExpression: JetDotQualifiedExpression): PsiElement {
|
||||||
@@ -150,7 +201,7 @@ public object ShortenReferences {
|
|||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
): PsiElement {
|
): PsiElement {
|
||||||
val receiverExpression = qualifiedExpression.getReceiverExpression()
|
val receiverExpression = qualifiedExpression.getReceiverExpression()
|
||||||
val target = bindingContext.get(BindingContext.REFERENCE_TARGET, refExpression)
|
val target = bindingContext[BindingContext.REFERENCE_TARGET, refExpression]
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
if ((target is JavaPropertyDescriptor || target is JavaMethodDescriptor) && receiverExpression is JetDotQualifiedExpression) {
|
if ((target is JavaPropertyDescriptor || target is JavaMethodDescriptor) && receiverExpression is JetDotQualifiedExpression) {
|
||||||
val containingDescriptor = target.getContainingDeclaration()
|
val containingDescriptor = target.getContainingDeclaration()
|
||||||
@@ -166,14 +217,14 @@ public object ShortenReferences {
|
|||||||
|
|
||||||
private fun instantiatedClass(calleeExpression: JetReferenceExpression): ClassDescriptor? {
|
private fun instantiatedClass(calleeExpression: JetReferenceExpression): ClassDescriptor? {
|
||||||
val bindingContext = bindingContext(calleeExpression)
|
val bindingContext = bindingContext(calleeExpression)
|
||||||
val target = bindingContext.get(BindingContext.REFERENCE_TARGET, calleeExpression)
|
val target = bindingContext[BindingContext.REFERENCE_TARGET, calleeExpression]
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
if (target is ConstructorDescriptor) {
|
if (target is ConstructorDescriptor) {
|
||||||
return target.getContainingDeclaration()
|
return target.getContainingDeclaration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val targets = bindingContext.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, calleeExpression)
|
val targets = bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, calleeExpression]
|
||||||
if (targets != null && !targets.isEmpty()) {
|
if (targets != null && !targets.isEmpty()) {
|
||||||
var targetClass: ClassDescriptor? = null
|
var targetClass: ClassDescriptor? = null
|
||||||
for (descriptor in targets) {
|
for (descriptor in targets) {
|
||||||
@@ -220,10 +271,10 @@ public object ShortenReferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveState(referenceExpression: JetReferenceExpression, bindingContext: BindingContext): Any? {
|
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()
|
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()})
|
if (targets != null) return HashSet(targets.map{it.asString()})
|
||||||
|
|
||||||
return null
|
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.JetNameValidator
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
|
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
|
||||||
import com.intellij.openapi.project.Project
|
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) {
|
class LambdaItems(val project: Project) {
|
||||||
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
|
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
|
||||||
@@ -27,35 +33,104 @@ class LambdaItems(val project: Project) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (singleSignatureLength != 0) {
|
if (singleSignatureLength != 0) {
|
||||||
fun functionParameterTypes(functionType: JetType)
|
|
||||||
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
|
|
||||||
|
|
||||||
for (functionType in distinctTypes) {
|
for (functionType in distinctTypes) {
|
||||||
val parameterTypes = functionParameterTypes(functionType)
|
val parameterTypes = functionParameterTypes(functionType)
|
||||||
val parametersPresentation = parameterTypes.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
|
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 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 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 }))
|
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 {
|
val matchedExpectedInfos = expectedInfos.filter {
|
||||||
expectedInfo ->
|
expectedInfo ->
|
||||||
descriptor is CallableDescriptor && descriptor.getReturnType()?.let { it.isSubtypeOf(expectedInfo.`type`) } ?: false
|
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
|
if (matchedExpectedInfos.isEmpty()) return
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,7 @@ class ArtificialElementInsertHandler(
|
|||||||
|
|
||||||
fun shortenReferences(context: InsertionContext, startOffset: Int, endOffset: Int) {
|
fun shortenReferences(context: InsertionContext, startOffset: Int, endOffset: Int) {
|
||||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();
|
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();
|
||||||
val file = context.getFile() as JetFile
|
ShortenReferences.process(context.getFile() as JetFile, startOffset, endOffset)
|
||||||
val element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, javaClass<JetElement>())
|
|
||||||
if (element != null) {
|
|
||||||
ShortenReferences.process(element)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mergeTails(tails: Collection<Tail?>): Tail? {
|
fun mergeTails(tails: Collection<Tail?>): Tail? {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class KotlinImportOptimizer() : ImportOptimizer {
|
|||||||
private fun extractUsedQualifiedNames(jetFile: JetFile): Set<FqName> {
|
private fun extractUsedQualifiedNames(jetFile: JetFile): Set<FqName> {
|
||||||
val usedQualifiedNames = HashSet<FqName>()
|
val usedQualifiedNames = HashSet<FqName>()
|
||||||
jetFile.accept(object : JetVisitorVoid() {
|
jetFile.accept(object : JetVisitorVoid() {
|
||||||
override fun visitElement(element: PsiElement?) {
|
override fun visitElement(element: PsiElement) {
|
||||||
ProgressIndicatorProvider.checkCanceled()
|
ProgressIndicatorProvider.checkCanceled()
|
||||||
element?.acceptChildren(this)
|
element?.acceptChildren(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public abstract class IntentionBasedInspection<T: JetElement>(
|
|||||||
) : AbstractKotlinInspection() {
|
) : AbstractKotlinInspection() {
|
||||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||||
return object: PsiElementVisitor() {
|
return object: PsiElementVisitor() {
|
||||||
override fun visitElement(element: PsiElement?) {
|
override fun visitElement(element: PsiElement) {
|
||||||
if (!intention.elementType.isInstance(element)) return
|
if (!intention.elementType.isInstance(element)) return
|
||||||
|
|
||||||
[suppress("UNCHECKED_CAST")]
|
[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) {
|
public static JetNameValidator getCollectingValidator(final Project project) {
|
||||||
return new JetNameValidator(project) {
|
return new JetNameValidator(project) {
|
||||||
private final Set<String> suggestedSet = new HashSet<String>();
|
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: "{...}"
|
// ABSENT: "{...}"
|
||||||
// EXIST: "{ String -> ... }"
|
// EXIST: "{ (String) -> ... }"
|
||||||
// EXIST: "{ Int -> ... }"
|
// EXIST: "{ (Int) -> ... }"
|
||||||
|
|||||||
+5
@@ -221,6 +221,11 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
|||||||
doTest("idea/testData/completion/handlers/smart/Lambda5.kt");
|
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")
|
@TestMetadata("MergeTail1.kt")
|
||||||
public void testMergeTail1() throws Exception {
|
public void testMergeTail1() throws Exception {
|
||||||
doTest("idea/testData/completion/handlers/smart/MergeTail1.kt");
|
doTest("idea/testData/completion/handlers/smart/MergeTail1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user