summaryrefslogtreecommitdiff
path: root/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java')
-rw-r--r--java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java153
1 files changed, 153 insertions, 0 deletions
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java
new file mode 100644
index 000000000000..aca4357f7e49
--- /dev/null
+++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.folding.impl;
+
+import com.intellij.lang.folding.FoldingDescriptor;
+import com.intellij.lang.folding.NamedFoldingDescriptor;
+import com.intellij.openapi.util.Couple;
+import com.intellij.openapi.util.TextRange;
+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 org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class ParameterNameFoldingManager {
+ private static final int MIN_NAME_LENGTH_THRESHOLD = 3;
+ private static final int MIN_ARGS_TO_FOLD = 2;
+
+ private static final List<Couple<String>> COMMONLY_USED_PARAMETER_PAIR = ContainerUtil.newArrayList(
+ Couple.of("begin", "end"),
+ Couple.of("start", "end"),
+ Couple.of("first", "last"),
+ Couple.of("first", "second"),
+ Couple.of("from", "to"),
+ Couple.of("key", "value")
+ );
+
+ private final PsiCallExpression myCallExpression;
+
+ private PsiExpression[] myCallArguments;
+ private PsiParameter[] myParameters;
+
+ public ParameterNameFoldingManager(@NotNull PsiCallExpression callExpression) {
+ myCallExpression = callExpression;
+ }
+
+ public static boolean isLiteralExpression(@Nullable PsiElement callArgument) {
+ if (callArgument instanceof PsiLiteralExpression)
+ return true;
+
+ if (callArgument instanceof PsiPrefixExpression) {
+ PsiPrefixExpression expr = (PsiPrefixExpression)callArgument;
+ IElementType tokenType = expr.getOperationTokenType();
+ return JavaTokenType.MINUS.equals(tokenType) && expr.getOperand() instanceof PsiLiteralExpression;
+ }
+
+ return false;
+ }
+
+ @Nullable
+ public PsiExpression[] getArguments(@NotNull PsiCallExpression call) {
+ PsiExpressionList callArgumentsList = call.getArgumentList();
+ return callArgumentsList != null ? callArgumentsList.getExpressions() : null;
+ }
+
+ @NotNull
+ public List<FoldingDescriptor> buildDescriptors() {
+ myCallArguments = getArguments(myCallExpression);
+
+ if (myCallArguments != null && myCallArguments.length >= MIN_ARGS_TO_FOLD && hasLiteralExpression(myCallArguments)) {
+ PsiMethod method = myCallExpression.resolveMethod();
+
+ if (method != null) {
+ myParameters = method.getParameterList().getParameters();
+ if (myParameters.length == myCallArguments.length) {
+ return buildDescriptorsForLiteralArguments();
+ }
+ }
+ }
+
+ return ContainerUtil.emptyList();
+ }
+
+ @NotNull
+ private List<FoldingDescriptor> buildDescriptorsForLiteralArguments() {
+ List<FoldingDescriptor> descriptors = ContainerUtil.newArrayList();
+
+ int i = 0;
+ while (i < myCallArguments.length) {
+ if (i + 1 < myCallArguments.length && isCommonlyNamedParameterPair(i, i + 1)) {
+ i += 2;
+ continue;
+ }
+
+ if (shouldInlineParameterName(i)) {
+ descriptors.add(createFoldingDescriptor(myCallArguments[i], myParameters[i]));
+ }
+ i++;
+ }
+
+ return descriptors;
+ }
+
+ @NotNull
+ private static NamedFoldingDescriptor createFoldingDescriptor(@NotNull PsiExpression callArgument, @NotNull PsiParameter methodParam) {
+ TextRange range = callArgument.getTextRange();
+ String placeholderText = methodParam.getName() + ": " + callArgument.getText();
+ return new NamedFoldingDescriptor(callArgument, range.getStartOffset(), range.getEndOffset(), null, placeholderText);
+ }
+
+ private boolean isCommonlyNamedParameterPair(int first, int second) {
+ assert first < myParameters.length && second < myParameters.length;
+
+ String firstParamName = myParameters[first].getName();
+ String secondParamName = myParameters[second].getName();
+ if (firstParamName == null || secondParamName == null) return false;
+
+ for (Couple<String> knownPair : COMMONLY_USED_PARAMETER_PAIR) {
+ if (StringUtil.containsIgnoreCase(firstParamName, knownPair.first)
+ && StringUtil.containsIgnoreCase(secondParamName, knownPair.second)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean shouldInlineParameterName(int paramIndex) {
+ PsiExpression argument = myCallArguments[paramIndex];
+ if (isLiteralExpression(argument) && argument.getType() != null) {
+ PsiParameter parameter = myParameters[paramIndex];
+ String paramName = parameter.getName();
+ if (paramName != null && paramName.length() >= MIN_NAME_LENGTH_THRESHOLD) {
+ return TypeConversionUtil.isAssignable(parameter.getType(), argument.getType());
+ }
+ }
+ return false;
+ }
+
+ private static boolean hasLiteralExpression(@NotNull PsiExpression[] arguments) {
+ for (PsiExpression argument : arguments) {
+ if (isLiteralExpression(argument)) return true;
+ }
+ return false;
+ }
+}