IDEA-125863 Folding: inline parameter names for literal call arguments

This commit is contained in:
Yaroslav Lepenkin
2014-06-23 19:56:49 +04:00
parent f0b5577aea
commit b21cd3b491
6 changed files with 210 additions and 0 deletions
@@ -27,6 +27,7 @@ import com.intellij.openapi.options.BeanConfigurable;
public class JavaCodeFoldingOptionsProvider extends BeanConfigurable<JavaCodeFoldingSettings> implements CodeFoldingOptionsProvider {
public JavaCodeFoldingOptionsProvider() {
super(JavaCodeFoldingSettings.getInstance());
checkBox("INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS", ApplicationBundle.message("checkbox.collapse.boolean.parameters"));
checkBox("COLLAPSE_ONE_LINE_METHODS", ApplicationBundle.message("checkbox.collapse.one.line.methods"));
checkBox("COLLAPSE_ACCESSORS", ApplicationBundle.message("checkbox.collapse.simple.property.accessors"));
checkBox("COLLAPSE_INNER_CLASSES", ApplicationBundle.message("checkbox.collapse.inner.classes"));
@@ -64,4 +64,7 @@ public abstract class JavaCodeFoldingSettings {
public abstract boolean isCollapseEndOfLineComments();
public abstract void setCollapseEndOfLineComments(boolean value);
public abstract boolean isInlineParameterNamesForLiteralCallArguments();
public abstract void setInlineParameterNamesForLiteralCallArguments(boolean value);
}
@@ -14,6 +14,7 @@ public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings {
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_I18N_MESSAGES = true;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_SUPPRESS_WARNINGS = true;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_END_OF_LINE_COMMENTS = false;
@SuppressWarnings({"WeakerAccess"}) public boolean INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS = true;
@Override
public boolean isCollapseImports() {
@@ -148,4 +149,14 @@ public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings {
public void setCollapseEndOfLineComments(boolean value) {
COLLAPSE_END_OF_LINE_COMMENTS = value;
}
@Override
public boolean isInlineParameterNamesForLiteralCallArguments() {
return INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS;
}
@Override
public void setInlineParameterNamesForLiteralCallArguments(boolean value) {
INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS = value;
}
}
@@ -703,6 +703,12 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
else if (element instanceof PsiComment) {
return settings.isCollapseEndOfLineComments();
}
else if (element instanceof PsiLiteralExpression
&& element.getParent() instanceof PsiExpressionList
&& (element.getParent().getParent() instanceof PsiCallExpression
|| element.getParent().getParent() instanceof PsiAnonymousClass)) {
return settings.isInlineParameterNamesForLiteralCallArguments();
}
else {
LOG.error("Unknown element:" + element);
return false;
@@ -725,6 +731,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
if (!dumb) {
addMethodGenericParametersFolding(expression, foldElements, document, quick);
inlineLiteralArgumentsNames(expression, foldElements, quick);
}
super.visitMethodCallExpression(expression);
@@ -734,6 +741,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
public void visitNewExpression(PsiNewExpression expression) {
if (!dumb) {
addGenericParametersFolding(expression, foldElements, document, quick);
inlineLiteralArgumentsNames(expression, foldElements, quick);
}
super.visitNewExpression(expression);
@@ -747,6 +755,50 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
});
}
private static void inlineLiteralArgumentsNames(@NotNull PsiCallExpression expression,
@NotNull List<FoldingDescriptor> foldElements,
boolean quick)
{
if (quick || !JavaCodeFoldingSettings.getInstance().isInlineParameterNamesForLiteralCallArguments()) {
return;
}
PsiExpressionList callArgumentsList = expression.getArgumentList();
if (callArgumentsList == null) {
return;
}
PsiExpression[] callArguments = callArgumentsList.getExpressions();
if (callArguments.length > 1) {
PsiParameter[] parameters = null;
boolean isResolved = false;
for (int i = 0; i < callArguments.length; i++) {
PsiExpression callArgument = callArguments[i];
if (callArgument instanceof PsiLiteralExpression) {
if (!isResolved) {
PsiMethod method = expression.resolveMethod();
isResolved = true;
if (method == null) {
return;
}
parameters = method.getParameterList().getParameters();
if (parameters.length != callArguments.length) {
return;
}
}
PsiParameter methodParam = parameters[i];
if (PsiType.NULL.equals(callArgument.getType()) || methodParam.getType().equals(callArgument.getType())) {
TextRange range = callArgument.getTextRange();
String placeholderText = methodParam.getName() + ": " + callArgument.getText();
foldElements.add(new NamedFoldingDescriptor(callArgument, range.getStartOffset(), range.getEndOffset(), null, placeholderText));
}
}
}
}
}
private boolean addClosureFolding(final PsiClass aClass, final Document document, final List<FoldingDescriptor> foldElements,
@NotNull Set<PsiElement> processedComments, final boolean quick) {
if (!JavaCodeFoldingSettings.getInstance().isCollapseLambdas()) {
@@ -27,6 +27,7 @@ import com.intellij.openapi.editor.impl.FoldingModelImpl
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiLiteralExpression
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.testFramework.LightProjectDescriptor
@@ -592,6 +593,147 @@ class Test {
assert regions[0].placeholderText == '{...}'
}
public void "test insert boolean literal argument name"() {
def text = """class Groo {
public void test() {
boolean testNow = System.currentTimeMillis() > 34000;
int times = 1;
float pi = 4;
String title = "Testing..."
char ch = 'q'
File file;
configure(true, false, 555, 3.141f, "Huge Title", 'c', null);
configure(testNow, shouldIgnoreRoots(), fourteen, pi, title, c, file);
}
pubic void configure(boolean testNow, boolean shouldIgnoreRoots, int times, float pi, String title, char terminate, File file) {
System.out.println();
System.out.println();
}
}"""
configure text
PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Groo', GlobalSearchScope.allScope(project))
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
assert regions.size() == 9
def literals = fooClass.methods[0].body.statements[6].children[0].children[1].children.findAll { it instanceof PsiLiteralExpression }
def parameters = fooClass.methods[1].parameterList.parameters
for (int i = 0; i < literals.size(); i++) {
def currentElement = literals[i]
def correspondingFolding = regions[i + 1]
assert correspondingFolding.startOffset == currentElement.textRange.startOffset && correspondingFolding.endOffset == currentElement.textRange.endOffset
assert correspondingFolding.placeholderText == parameters[i].name + ": " + currentElement.text
}
}
public void "test do not inline name if setter"() {
def text = """class Groo {
public void test() {
setTestNow(false);
System.out.println("");
}
pubic void setTestNow(boolean testNow) {
System.out.println("");
System.out.println("");
}
}"""
configure text
def regions = myFixture.editor.foldingModel.allFoldRegions
assert regions.size() == 2
}
public void "test do not collapse varargs"() {
def text = """
public class VarArgTest {
public void main() {
System.out.println("AAA");
testBooleanVarargs(13, false);
}
public boolean testBooleanVarargs(int test, boolean... booleans) {
int temp = test;
return false;
}
}
"""
configure text
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
assert regions.size() == 3
checkRangeOffsetByPositionInText(regions[1], text, "13")
assert regions[1].placeholderText == "test: 13"
}
public void "test inline constructor literal arguments names"() {
def text = """
public class Test {
public void main() {
System.out.println("AAA");
Checker r = new Checker(true, false) {
@Override
void test() {
}
};
}
abstract class Checker {
Checker(boolean applyToFirst, boolean applyToSecond) {}
abstract void test();
}
}
"""
configure text
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
assert regions.length == 6
assert regions[1].placeholderText == "applyToFirst: true"
assert regions[2].placeholderText == "applyToSecond: false"
checkRangeOffsetByPositionInText(regions[1], text, "true")
checkRangeOffsetByPositionInText(regions[2], text, "false")
}
public void "test inline anonymous class constructor literal arguments names"() {
def text = """
public class Test {
Test(int counter, boolean shouldTest) {
System.out.println();
System.out.println();
}
public static void main() {
System.out.println();
Test t = new Test(10, false);
}
}
"""
configure text
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
assert regions.length == 4
assert regions[2].placeholderText == "counter: 10"
assert regions[3].placeholderText == "shouldTest: false"
checkRangeOffsetByPositionInText(regions[2], text, "10")
checkRangeOffsetByPositionInText(regions[3], text, "false")
}
private static def checkRangeOffsetByPositionInText(FoldRegion region, String text, String foldElement) {
assert region.startOffset == text.indexOf(foldElement) && region.endOffset == text.indexOf(foldElement) + foldElement.length()
}
private def changeFoldRegions(Closure op) {
myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op)
}
@@ -350,6 +350,7 @@ checkbox.collapse.annotations=<html>Annotations</html>
checkbox.collapse.inner.classes=Inner classes
checkbox.collapse.simple.property.accessors=<html>Simple property accessors<html>
checkbox.collapse.one.line.methods=<html>One-line methods<html>
checkbox.collapse.boolean.parameters=<html>Inline parameter names for literal call arguments</html>
checkbox.collapse.method.bodies=Method bodies
checkbox.collapse.javadoc.comments=Documentation comments
checkbox.collapse.title.imports=Imports