openrewrite / openrewrite/rewrite

TabsAndIndents is not handling the indentation correctly on a lambda inside another lambda

Open
#3,362 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Java
Stars
3.7k
Forks
571
Avg merge
13h 12m
Merged PRs (30d)
261

Description

I am using

  • OpenRewrite v8.1.3
  • Maven plugin v5.2.4

I am using the Maven plugin on a single module project using the following YAML configuration:

---
type: specs.openrewrite.org/v1beta/recipe
name: myRecipe
recipeList:
  - org.openrewrite.java.format.TabsAndIndents
---
type: specs.openrewrite.org/v1beta/style
name: myStyle
styleConfigs:
  - org.openrewrite.java.style.TabsAndIndentsStyle:
      useTabCharacter: false
      tabSize: 4
      indentSize: 4
      continuationIndent: 8
      indentsRelativeToExpressionStart: false
      methodDeclarationParameters:
        alignWhenMultiple: false

N.B. Don't look into the logic of the code since it's just to reproduce the issue.
When processing the following class that is formatted correctly with the Google formatting style in Eclipse:

public class MyClass {
    public static void handleCollection(List<List<Object>> theList, Set<String> validIds, Set<String> validStates) {
        theList.forEach(element -> {
            // Filter internal elements to keep only valid and desired ones
            element.stream().filter(internalElement -> validIds.contains(internalElement.toString())
                    && validStates.contains(internalElement.toString())).forEach(internalElement -> {
                        internalElement.hashCode();
                        internalElement.equals(new Object());
                    });
        });
    }
}

It result in this undesired indentation change that gets flagged as a violation by Checkstyle:

public class MyClass {
    public static void handleCollection(List<List<Object>> theList, Set<String> validIds, Set<String> validStates) {
        theList.forEach(element -> {
            // Filter internal elements to keep only valid and desired ones
            element.stream().filter(internalElement -> validIds.contains(internalElement.toString())
                    && validStates.contains(internalElement.toString())).forEach(internalElement -> {
                internalElement.hashCode();
                internalElement.equals(new Object());
            });
        });
    }
}

My first thought was that indentsRelativeToExpressionStart would control this behavior. However, it seems like this parameter is never actually used in the code!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with rewrite-java/src/main/java/org/openrewrite/java/style/TabsAndIndentsStyle.java at the indentsRelativeToExpressionStart definition, then trace how TabsAndIndents formats nested lambdas. Done means the shown nested-lambda example retains the expected inner-body indentation while the configured style continues to apply elsewhere.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.