[groovy] parameter hints (IDEA-163484)
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / codeInsight / hint / GroovyInlayParameterHintsProvider.kt
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.plugins.groovy.codeInsight.hint
17
18 import com.intellij.codeInsight.hints.InlayInfo
19 import com.intellij.codeInsight.hints.InlayParameterHintsProvider
20 import com.intellij.codeInsight.hints.MethodInfo
21 import com.intellij.lang.java.JavaLanguage
22 import com.intellij.openapi.util.text.StringUtil
23 import com.intellij.psi.PsiElement
24 import com.intellij.psi.PsiMethod
25 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument
26 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall
27 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod
28 import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil
29
30 class GroovyInlayParameterHintsProvider : InlayParameterHintsProvider {
31
32   private companion object {
33     val blackList = setOf(
34         "org.codehaus.groovy.runtime.DefaultGroovyMethods.*"
35     )
36   }
37
38   override fun getParameterHints(element: PsiElement) = (element as? GrCall)?.doGetParameterHints() ?: emptyList()
39
40   private fun GrCall.doGetParameterHints(): List<InlayInfo>? {
41     val signature = GrClosureSignatureUtil.createSignature(this) ?: return null
42     val infos = GrClosureSignatureUtil.mapParametersToArguments(signature, this) ?: return null
43     val original = signature.parameters.zip(infos)
44
45     // leave only parameters with names
46     val map = original.mapNotNull {
47       it.first.name?.let { name -> name to it.second }
48     }.toMap()
49
50     // leave only regular arguments and varargs
51     val nonNamedArguments = map.filterValues {
52       !it.isMultiArg || it.args.none { it is GrNamedArgument }
53     }
54
55     return nonNamedArguments.mapNotNull {
56       val (name, info) = it
57       info.args.firstOrNull()?.let { arg ->
58         val inlayText = if (info.isMultiArg) "...$name" else name
59         InlayInfo(inlayText, arg.textRange.startOffset)
60       }
61     }
62   }
63
64   override fun getMethodInfo(element: PsiElement): MethodInfo? {
65     val call = element as? GrCall
66     val resolved = call?.resolveMethod()
67     val method = (resolved as? GrGdkMethod)?.staticMethod ?: resolved
68     return method?.getMethodInfo()
69   }
70
71   private fun PsiMethod.getMethodInfo(): MethodInfo? {
72     val clazzName = containingClass?.qualifiedName ?: return null
73     val fullMethodName = StringUtil.getQualifiedName(clazzName, name)
74     val paramNames: List<String> = parameterList.parameters.map { it.name ?: "" }
75     return MethodInfo(fullMethodName, paramNames)
76   }
77
78   override val defaultBlackList: Set<String> get() = blackList
79
80   override fun getBlackListDependencyLanguage() = JavaLanguage.INSTANCE
81 }