Refactoring code

This commit is contained in:
Valentin Kipyatkov
2015-10-05 13:27:59 +03:00
parent 058f41a28b
commit 488e6f7458
2 changed files with 116 additions and 120 deletions
@@ -16,26 +16,26 @@
package org.jetbrains.kotlin.idea.parameterInfo package org.jetbrains.kotlin.idea.parameterInfo
import com.google.common.collect.Iterables
import com.intellij.codeInsight.CodeInsightBundle import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.lang.ASTNode
import com.intellij.lang.parameterInfo.* import com.intellij.lang.parameterInfo.*
import com.intellij.openapi.util.Pair
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.ui.Gray import com.intellij.ui.Gray
import com.intellij.ui.JBColor import com.intellij.ui.JBColor
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.core.isVisible import org.jetbrains.kotlin.idea.core.isVisible
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
@@ -47,7 +47,7 @@ import org.jetbrains.kotlin.types.checker.JetTypeChecker
import java.awt.Color import java.awt.Color
import java.util.* import java.util.*
class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupport<JetValueArgumentList, Pair<out FunctionDescriptor, ResolutionFacade>, JetValueArgument> { class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupport<JetValueArgumentList, Pair<FunctionDescriptor, ResolutionFacade>, JetValueArgument> {
override fun getActualParameters(arguments: JetValueArgumentList) = arguments.arguments.toTypedArray() override fun getActualParameters(arguments: JetValueArgumentList) = arguments.arguments.toTypedArray()
@@ -65,7 +65,7 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
override fun getParametersForLookup(item: LookupElement, context: ParameterInfoContext) = emptyArray<Any>() //todo: ? override fun getParametersForLookup(item: LookupElement, context: ParameterInfoContext) = emptyArray<Any>() //todo: ?
override fun getParametersForDocumentation(p: Pair<out FunctionDescriptor, ResolutionFacade>, context: ParameterInfoContext) = emptyArray<Any>() //todo: ? override fun getParametersForDocumentation(p: Pair<FunctionDescriptor, ResolutionFacade>, context: ParameterInfoContext) = emptyArray<Any>() //todo: ?
override fun findElementForParameterInfo(context: CreateParameterInfoContext): JetValueArgumentList? { override fun findElementForParameterInfo(context: CreateParameterInfoContext): JetValueArgumentList? {
return findCall(context) return findCall(context)
@@ -80,22 +80,22 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
} }
override fun updateParameterInfo(argumentList: JetValueArgumentList, context: UpdateParameterInfoContext) { override fun updateParameterInfo(argumentList: JetValueArgumentList, context: UpdateParameterInfoContext) {
if (context.parameterOwner !== argumentList) context.removeHint() if (context.parameterOwner !== argumentList) {
val offset = context.offset context.removeHint()
var child: ASTNode? = argumentList.node.firstChildNode
var i = 0
while (child != null && child.startOffset < offset) {
if (child.elementType === JetTokens.COMMA) ++i
child = child.treeNext
} }
context.setCurrentParameter(i)
val offset = context.offset
val parameterIndex = argumentList.allChildren
.takeWhile { it.startOffset < offset }
.count { it.node.elementType == JetTokens.COMMA }
context.setCurrentParameter(parameterIndex)
} }
override fun getParameterCloseChars() = ParameterInfoUtils.DEFAULT_PARAMETER_CLOSE_CHARS override fun getParameterCloseChars() = ParameterInfoUtils.DEFAULT_PARAMETER_CLOSE_CHARS
override fun tracksParameterIndex() = true override fun tracksParameterIndex() = true
override fun updateUI(itemToShow: Pair<out FunctionDescriptor, ResolutionFacade>, context: ParameterInfoUIContext) { override fun updateUI(itemToShow: Pair<FunctionDescriptor, ResolutionFacade>, context: ParameterInfoUIContext) {
//todo: when we will have ability to pass Array as vararg, implement such feature here too? //todo: when we will have ability to pass Array as vararg, implement such feature here too?
if (context.parameterOwner == null || !context.parameterOwner.isValid) { if (context.parameterOwner == null || !context.parameterOwner.isValid) {
context.isUIComponentEnabled = false context.isUIComponentEnabled = false
@@ -129,111 +129,119 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
isGrey = true isGrey = true
} }
val builder = StringBuilder()
val owner = context.parameterOwner val owner = context.parameterOwner
val bindingContext = resolutionFacade.analyze(owner as JetElement, BodyResolveMode.FULL) val bindingContext = resolutionFacade.analyze(owner as JetElement, BodyResolveMode.FULL)
for (i in valueParameters.indices) { val text = StringBuilder {
if (i != 0) { for (i in valueParameters.indices) {
builder.append(", ") if (i != 0) {
} append(", ")
}
val highlightParameter = i == currentParameterIndex || (!namedMode && i < currentParameterIndex && Iterables.getLast(valueParameters).varargElementType != null) val highlightParameter = i == currentParameterIndex || (!namedMode && i < currentParameterIndex && valueParameters.last().varargElementType != null)
if (highlightParameter) { if (highlightParameter) {
boldStartOffset = builder.length() boldStartOffset = length()
} }
if (!namedMode) { if (!namedMode) {
if (valueArguments.size() > i) { if (valueArguments.size() > i) {
val argument = valueArguments.get(i) val argument = valueArguments.get(i)
if (argument.isNamed()) { if (argument.isNamed()) {
namedMode = true namedMode = true
}
else {
val param = valueParameters.get(i)
append(renderParameter(param, false))
if (i <= currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) {
isGrey = true
}
usedIndexes[i] = true
}
} }
else { else {
val param = valueParameters.get(i) val param = valueParameters.get(i)
builder.append(renderParameter(param, false)) append(renderParameter(param, false))
if (i <= currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) {
isGrey = true
}
usedIndexes[i] = true
} }
} }
else {
val param = valueParameters.get(i)
builder.append(renderParameter(param, false))
}
}
if (namedMode) { if (namedMode) {
var takeAnyArgument = true var takeAnyArgument = true
if (valueArguments.size() > i) { if (valueArguments.size() > i) {
val argument = valueArguments.get(i) val argument = valueArguments.get(i)
if (argument.isNamed()) { if (argument.isNamed()) {
for (j in valueParameters.indices) { for (j in valueParameters.indices) {
val referenceExpression = argument.getArgumentName()!!.getReferenceExpression() val referenceExpression = argument.getArgumentName()!!.getReferenceExpression()
val param = valueParameters[j] val param = valueParameters[j]
if (!usedIndexes[j] && param.name == referenceExpression.getReferencedNameAsName()) { if (!usedIndexes[j] && param.name == referenceExpression.getReferencedNameAsName()) {
takeAnyArgument = false takeAnyArgument = false
usedIndexes[j] = true usedIndexes[j] = true
builder.append(renderParameter(param, true)) append(renderParameter(param, true))
if (i < currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) { if (i < currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) {
isGrey = true isGrey = true
}
break
} }
}
}
}
if (takeAnyArgument) {
if (i < currentParameterIndex) {
isGrey = true
}
for (j in valueParameters.indices) {
val param = valueParameters.get(j)
if (!usedIndexes[j]) {
usedIndexes[j] = true
append(renderParameter(param, true))
break break
} }
} }
} }
} }
if (takeAnyArgument) { if (highlightParameter) {
if (i < currentParameterIndex) { boldEndOffset = length()
isGrey = true
}
for (j in valueParameters.indices) {
val param = valueParameters.get(j)
if (!usedIndexes[j]) {
usedIndexes[j] = true
builder.append(renderParameter(param, true))
break
}
}
} }
} }
if (highlightParameter) { if (valueParameters.size() == 0) {
boldEndOffset = builder.length() append(CodeInsightBundle.message("parameter.info.no.parameters"))
} }
} }.toString()
if (valueParameters.size() == 0) {
builder.append(CodeInsightBundle.message("parameter.info.no.parameters"))
}
assert(!builder.toString().isEmpty()) { "A message about 'no parameters' or some parameters should be present: " + functionDescriptor } assert(!text.isEmpty()) { "A message about 'no parameters' or some parameters should be present: $functionDescriptor" }
val color = if (isResolvedToDescriptor(parameterOwner, functionDescriptor, bindingContext)) GREEN_BACKGROUND else context.defaultParameterColor val color = if (isResolvedToDescriptor(parameterOwner, functionDescriptor, bindingContext))
context.setupUIComponentPresentation(builder.toString(), boldStartOffset, boldEndOffset, isGrey, isDeprecated, false, color) GREEN_BACKGROUND
else
context.defaultParameterColor
context.setupUIComponentPresentation(text, boldStartOffset, boldEndOffset, isGrey, isDeprecated, false, color)
} }
companion object { companion object {
val GREEN_BACKGROUND: Color = JBColor(Color(231, 254, 234), Gray._100) val GREEN_BACKGROUND: Color = JBColor(Color(231, 254, 234), Gray._100)
private fun renderParameter(parameter: ValueParameterDescriptor, named: Boolean): String { private fun renderParameter(parameter: ValueParameterDescriptor, named: Boolean): String {
val builder = StringBuilder() return StringBuilder {
if (named) builder.append("[") if (named) append("[")
if (parameter.varargElementType != null) { if (parameter.varargElementType != null) {
builder.append("vararg ") append("vararg ")
} }
builder.append(parameter.name).append(": ").append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getActualParameterType(parameter))) append(parameter.name)
if (parameter.hasDefaultValue()) { append(": ")
val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter) append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getActualParameterType(parameter)))
builder.append(" = ").append(getDefaultExpressionString(parameterDeclaration)) if (parameter.hasDefaultValue()) {
} val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter)
if (named) builder.append("]") append(" = ")
return builder.toString() append(getDefaultExpressionString(parameterDeclaration))
}
if (named) append("]")
}.toString()
} }
private fun getDefaultExpressionString(parameterDeclaration: PsiElement?): String { private fun getDefaultExpressionString(parameterDeclaration: PsiElement?): String {
@@ -270,21 +278,18 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
private fun isIndexValid(valueParameters: List<ValueParameterDescriptor>, index: Int): Boolean { private fun isIndexValid(valueParameters: List<ValueParameterDescriptor>, index: Int): Boolean {
// Index is within range of parameters or last parameter is vararg // Index is within range of parameters or last parameter is vararg
return index < valueParameters.size() || (valueParameters.size() > 0 && Iterables.getLast(valueParameters).varargElementType != null) return index < valueParameters.size() || (valueParameters.isNotEmpty() && valueParameters.last().varargElementType != null)
} }
private fun isResolvedToDescriptor( private fun isResolvedToDescriptor(
argumentList: JetValueArgumentList, argumentList: JetValueArgumentList,
functionDescriptor: FunctionDescriptor, functionDescriptor: FunctionDescriptor,
bindingContext: BindingContext): Boolean { bindingContext: BindingContext
val callNameExpression = getCallSimpleNameExpression(argumentList) ): Boolean {
val callNameExpression = getCallNameExpression(argumentList)
if (callNameExpression != null) { if (callNameExpression != null) {
val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, callNameExpression) val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, callNameExpression)
if (declarationDescriptor != null) { if (declarationDescriptor === functionDescriptor) return true
if (declarationDescriptor === functionDescriptor) {
return true
}
}
} }
return false return false
@@ -292,22 +297,17 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
private fun findCall(context: CreateParameterInfoContext): JetValueArgumentList? { private fun findCall(context: CreateParameterInfoContext): JetValueArgumentList? {
//todo: calls to this constructors, when we will have auxiliary constructors //todo: calls to this constructors, when we will have auxiliary constructors
val file = context.file val file = context.file as? JetFile ?: return null
if (file !is JetFile) {
return null
}
val argumentList = PsiTreeUtil.getParentOfType(file.findElementAt(context.offset), JetValueArgumentList::class.java) ?: return null val argumentList = file.findElementAt(context.offset)?.getStrictParentOfType<JetValueArgumentList>() ?: return null
val callNameExpression = getCallSimpleNameExpression(argumentList) ?: return null val callNameExpression = getCallNameExpression(argumentList) ?: return null
val references = callNameExpression.references val references = callNameExpression.references
if (references.size() == 0) { if (references.isEmpty()) return null
return null
}
val resolutionFacade = callNameExpression.getContainingJetFile().getResolutionFacade() val resolutionFacade = file.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(callNameExpression, BodyResolveMode.FULL) val bindingContext = callNameExpression.analyze(BodyResolveMode.FULL)
val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, callNameExpression) val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, callNameExpression)
val placeDescriptor = scope?.getContainingDeclaration() val placeDescriptor = scope?.getContainingDeclaration()
@@ -325,16 +325,16 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, visibilityFilter) val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, visibilityFilter)
.getReferenceVariants(callNameExpression, descriptorKindFilter, { it == refName }) .getReferenceVariants(callNameExpression, descriptorKindFilter, { it == refName })
val itemsToShow = ArrayList<Pair<out DeclarationDescriptor, ResolutionFacade>>() val itemsToShow = ArrayList<Pair<DeclarationDescriptor, ResolutionFacade>>()
for (variant in variants) { for (variant in variants) {
if (variant is FunctionDescriptor) { if (variant is FunctionDescriptor) {
//todo: renamed functions? //todo: renamed functions?
itemsToShow.add(Pair.create(variant, resolutionFacade)) itemsToShow.add(Pair(variant, resolutionFacade))
} }
else if (variant is ClassDescriptor) { else if (variant is ClassDescriptor) {
//todo: renamed classes? //todo: renamed classes?
for (constructorDescriptor in variant.constructors) { for (constructorDescriptor in variant.constructors) {
itemsToShow.add(Pair.create(constructorDescriptor, resolutionFacade)) itemsToShow.add(Pair(constructorDescriptor, resolutionFacade))
} }
} }
} }
@@ -343,23 +343,19 @@ class KotlinFunctionParameterInfoHandler : ParameterInfoHandlerWithTabActionSupp
return argumentList return argumentList
} }
private fun getCallSimpleNameExpression(argumentList: JetValueArgumentList): JetSimpleNameExpression? { private fun getCallNameExpression(argumentList: JetValueArgumentList): JetSimpleNameExpression? {
val argumentListParent = argumentList.parent return (argumentList.parent as? JetCallElement)?.getCallNameExpression()
return if ((argumentListParent is JetCallElement))
argumentListParent.getCallNameExpression()
else
null
} }
private fun findCallAndUpdateContext(context: UpdateParameterInfoContext): JetValueArgumentList? { private fun findCallAndUpdateContext(context: UpdateParameterInfoContext): JetValueArgumentList? {
val file = context.file var element = context.file.findElementAt(context.offset) ?: return null
var element = file.findElementAt(context.offset) ?: return null
var parent = element.parent var parent = element.parent
while (parent != null && parent !is JetValueArgumentList) { while (parent != null && parent !is JetValueArgumentList) {
element = element!!.parent element = element!!.parent
parent = parent.parent parent = parent.parent
} }
if (parent == null) return null if (parent == null) return null
val argumentList = parent as JetValueArgumentList val argumentList = parent as JetValueArgumentList
if (element is JetValueArgument) { if (element is JetValueArgument) {
val i = argumentList.arguments.indexOf(element) val i = argumentList.arguments.indexOf(element)
@@ -16,12 +16,12 @@
package org.jetbrains.kotlin.idea.parameterInfo; package org.jetbrains.kotlin.idea.parameterInfo;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import kotlin.Pair;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetValueArgumentList; import org.jetbrains.kotlin.psi.JetValueArgumentList;