From 63b66f396461d2f77430eb2aee289db08d8e9050 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Wed, 30 Nov 2016 16:51:32 +0300 Subject: [PATCH] [name hints] option to show hints for multiple parameters with the same type --- .../hints/JavaInlayParameterHintsProvider.kt | 2 +- .../hints/JavaParameterHintManager.java | 88 ++++++++++++++----- .../inlays/JavaParameterNameHintsTest.kt | 17 ++++ .../codeInsight/hints/ParameterNameInlays.kt | 2 +- .../ParameterNameHintsConfigurable.java | 6 +- .../settings/ParameterNameHintsSettings.kt | 8 +- 6 files changed, 91 insertions(+), 32 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/JavaInlayParameterHintsProvider.kt b/java/java-impl/src/com/intellij/codeInsight/hints/JavaInlayParameterHintsProvider.kt index 8d05425af542..224e3a2a27e9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hints/JavaInlayParameterHintsProvider.kt +++ b/java/java-impl/src/com/intellij/codeInsight/hints/JavaInlayParameterHintsProvider.kt @@ -34,7 +34,7 @@ class JavaInlayParameterHintsProvider : InlayParameterHintsProvider { override fun getParameterHints(element: PsiElement): List { if (element is PsiCallExpression) { - return JavaParameterHintManager(element).descriptors + return JavaParameterHintManager(element).descriptors.toList() } return emptyList() } diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/JavaParameterHintManager.java b/java/java-impl/src/com/intellij/codeInsight/hints/JavaParameterHintManager.java index f8db4f105712..7e6c0e8477ba 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hints/JavaParameterHintManager.java +++ b/java/java-impl/src/com/intellij/codeInsight/hints/JavaParameterHintManager.java @@ -16,32 +16,39 @@ package com.intellij.codeInsight.hints; import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class JavaParameterHintManager { @NotNull - private final List myDescriptors; + private final Set myDescriptors; public JavaParameterHintManager(@NotNull PsiCallExpression callExpression) { PsiExpression[] callArguments = getArguments(callExpression); JavaResolveResult resolveResult = callExpression.resolveMethodGenerics(); + if (!(resolveResult.getElement() instanceof PsiMethod)) { + myDescriptors = Collections.emptySet(); + return; + } - List descriptors = Collections.emptyList(); - if (resolveResult.getElement() instanceof PsiMethod - && isMethodToShowParams(callExpression, resolveResult) - && hasUnclearExpressions(callArguments)) - { - PsiMethod method = (PsiMethod)resolveResult.getElement(); + final PsiMethod method = (PsiMethod)resolveResult.getElement(); + + Set descriptors = Collections.emptySet(); + if (isMethodToShowParams(callExpression, method)) { PsiParameter[] parameters = method.getParameterList().getParameters(); descriptors = buildDescriptorsForLiteralArguments(callArguments, parameters, resolveResult); } @@ -49,11 +56,7 @@ public class JavaParameterHintManager { myDescriptors = descriptors; } - private static boolean isMethodToShowParams(@NotNull PsiCallExpression callExpression, @NotNull JavaResolveResult resolveResult) { - PsiElement element = resolveResult.getElement(); - if (!(element instanceof PsiMethod)) return false; - - PsiMethod method = (PsiMethod)element; + private static boolean isMethodToShowParams(@NotNull PsiCallExpression callExpression, @NotNull PsiMethod method) { if (isSetter(method)) return false; PsiParameter[] parameters = method.getParameterList().getParameters(); @@ -70,6 +73,16 @@ public class JavaParameterHintManager { return true; } + private static Set getDuplicatedParamTypes(PsiParameter[] parameters) { + List duplicatedTypes = Arrays + .stream(parameters) + .map((p) -> p.getType().getCanonicalText()) + .collect(Collectors.toList()); + + ContainerUtil.newHashSet(duplicatedTypes).forEach((e) -> duplicatedTypes.remove(e)); + return ContainerUtil.newHashSet(duplicatedTypes); + } + private static boolean isParamNameContainedInMethodName(@NotNull PsiParameter parameter, @NotNull PsiMethod method) { String parameterName = parameter.getName(); if (parameterName != null && parameterName.length() > 1) { @@ -137,42 +150,71 @@ public class JavaParameterHintManager { } @NotNull - public List getDescriptors() { + public Set getDescriptors() { return myDescriptors; } @NotNull - private static List buildDescriptorsForLiteralArguments(@NotNull PsiExpression[] callArguments, - @NotNull PsiParameter[] parameters, - @NotNull JavaResolveResult resolveResult) { + private static Set buildDescriptorsForLiteralArguments(@NotNull PsiExpression[] callArguments, + @NotNull PsiParameter[] parameters, + @NotNull JavaResolveResult resolveResult) { + + final Set descriptors = ContainerUtil.newHashSet(); + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + + if (ParameterNameHintsSettings.getInstance().isShowForParamsWithSameType()) { + final List hintsForNonLiterals = getHintsForParamsWithSameType(callArguments, parameters, substitutor); + descriptors.addAll(hintsForNonLiterals); + } - List descriptors = ContainerUtil.newArrayList(); for (int i = 0; i < Math.min(callArguments.length, parameters.length); i++) { PsiExpression arg = callArguments[i]; PsiParameter param = parameters[i]; if (isVarargParam(param.getType(), arg.getType()) && hasUnclearExpressionStartingFrom(i, callArguments) - || shouldInlineParameterName(arg, param, resolveResult)) { + || isUnclearExpression(arg) && isAssignable(arg, param, substitutor)) { descriptors.add(createInlayInfo(arg, param)); } } + return descriptors; } + private static List getHintsForParamsWithSameType(@NotNull PsiExpression[] callArguments, + @NotNull PsiParameter[] parameters, + @NotNull PsiSubstitutor substitutor) + { + final Set duplicatedTypes = getDuplicatedParamTypes(parameters); + + final int minArraySize = Math.min(callArguments.length, parameters.length); + List args = ContainerUtil.list(callArguments).subList(0, minArraySize); + List params = ContainerUtil.list(parameters).subList(0, minArraySize); + + return StreamEx + .zip(args, params, (a, b) -> Pair.create(a, b)) + .filter((pair) -> { + PsiParameter param = pair.getSecond(); + return duplicatedTypes.contains(param.getType().getCanonicalText()); + }) + .filter((pair) -> isAssignable(pair.first, pair.second, substitutor)) + .map((pair) -> createInlayInfo(pair.first, pair.second)) + .collect(Collectors.toList()); + } + @NotNull private static InlayInfo createInlayInfo(@NotNull PsiExpression callArgument, @NotNull PsiParameter methodParam) { String paramName = ((methodParam.getType() instanceof PsiEllipsisType) ? "..." : "") + methodParam.getName(); return new InlayInfo(paramName, callArgument.getTextRange().getStartOffset()); } - private static boolean shouldInlineParameterName(@NotNull PsiExpression argument, - @NotNull PsiParameter parameter, - @NotNull JavaResolveResult resolveResult) { + private static boolean isAssignable(@NotNull PsiExpression argument, + @NotNull PsiParameter parameter, + @NotNull PsiSubstitutor substitutor) { PsiType argType = argument.getType(); PsiType paramType = parameter.getType(); - if (argType != null && isUnclearExpression(argument)) { - PsiType parameterType = resolveResult.getSubstitutor().substitute(paramType); + if (argType != null) { + PsiType parameterType = substitutor.substitute(paramType); return TypeConversionUtil.isAssignable(parameterType, argType); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt index 199d646d6ae3..5e6b20fafd8a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt @@ -789,4 +789,21 @@ class Test { .assertInlays("timeout->1000", "message->\"xxx\"") } + fun `test show same params`() { + ParameterNameHintsSettings.getInstance().isShowForParamsWithSameType = true + setup(""" +class Test { + void main() { + String c = "c"; + String d = "d"; + test(c, d); + } + void test(String parent, String child) { + } +} +""") + + onLineStartingWith("test").assertInlays("parent->c", "child->d") + } + } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/codeInsight/hints/ParameterNameInlays.kt b/platform/lang-api/src/com/intellij/codeInsight/hints/ParameterNameInlays.kt index c9e8f73de3fe..1fb42873938a 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/hints/ParameterNameInlays.kt +++ b/platform/lang-api/src/com/intellij/codeInsight/hints/ParameterNameInlays.kt @@ -15,7 +15,7 @@ */ package com.intellij.codeInsight.hints -class InlayInfo(val text: String, val offset: Int) +data class InlayInfo(val text: String, val offset: Int) open class MethodInfo(val fullyQualifiedName: String, val paramNames: List) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsConfigurable.java b/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsConfigurable.java index 928ee8def358..2761ba1de45a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsConfigurable.java @@ -73,7 +73,7 @@ public class ParameterNameHintsConfigurable extends DialogWrapper { setTitle("Configure Parameter Name Hints Blacklist"); init(); - myOptionsPanel.setVisible(false); + myOptionsPanel.setVisible(true); } private void updateOkEnabled() { @@ -103,7 +103,7 @@ public class ParameterNameHintsConfigurable extends DialogWrapper { ParameterNameHintsSettings settings = ParameterNameHintsSettings.getInstance(); settings.setShowParamNameContainedInMethodName(myShowIfParamNameContainedInMethod.isSelected()); - settings.setShowWhenMultipleParamsWithSameType(myShowWhenMultipleParamsWithSameType.isSelected()); + settings.setShowForParamsWithSameType(myShowWhenMultipleParamsWithSameType.isSelected()); } private static void storeBlackListDiff(@NotNull Language language, @NotNull String text) { @@ -147,7 +147,7 @@ public class ParameterNameHintsConfigurable extends DialogWrapper { ParameterNameHintsSettings settings = ParameterNameHintsSettings.getInstance(); myShowIfParamNameContainedInMethod.setSelected(settings.isShowParamNameContainedInMethodName()); - myShowWhenMultipleParamsWithSameType.setSelected(settings.getShowWhenMultipleParamsWithSameType()); + myShowWhenMultipleParamsWithSameType.setSelected(settings.isShowForParamsWithSameType()); initLanguageCombo(languages, selected); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsSettings.kt b/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsSettings.kt index ac96ea0c6dbb..1862dfcb4d29 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsSettings.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsSettings.kt @@ -50,7 +50,7 @@ class ParameterNameHintsSettings : PersistentStateComponent { private val myAddedPatterns = hashMapOf>() var isShowParamNameContainedInMethodName: Boolean = false - var showWhenMultipleParamsWithSameType: Boolean = false + var isShowForParamsWithSameType: Boolean = false fun addIgnorePattern(language: Language, pattern: String) { val patternsBefore = getAddedPatterns(language) @@ -85,7 +85,7 @@ class ParameterNameHintsSettings : PersistentStateComponent { .setAttribute("value", isShowParamNameContainedInMethodName.toString()) root.getOrCreateChild(XmlTagHelper.SHOW_WHEN_MULTIPLE_PARAMS_WITH_SAME_TYPE) - .setAttribute("value", showWhenMultipleParamsWithSameType.toString()) + .setAttribute("value", isShowForParamsWithSameType.toString()) return root } @@ -95,7 +95,7 @@ class ParameterNameHintsSettings : PersistentStateComponent { myRemovedPatterns.clear() isShowParamNameContainedInMethodName = false - showWhenMultipleParamsWithSameType = false + isShowForParamsWithSameType = false val allBlackLists = state .getChild(XmlTagHelper.BLACKLISTS) @@ -108,7 +108,7 @@ class ParameterNameHintsSettings : PersistentStateComponent { } isShowParamNameContainedInMethodName = state.getBooleanValue(XmlTagHelper.SHOW_IF_PARAM_NAME_CONTAINED, true) - showWhenMultipleParamsWithSameType = state.getBooleanValue(XmlTagHelper.SHOW_WHEN_MULTIPLE_PARAMS_WITH_SAME_TYPE, false) + isShowForParamsWithSameType = state.getBooleanValue(XmlTagHelper.SHOW_WHEN_MULTIPLE_PARAMS_WITH_SAME_TYPE, false) } private fun Element.getBooleanValue(childName: String, defaultValue: Boolean): Boolean {