Repository: checkstyle/checkstyle

Problem statement:
Indentation violation for lambda depends on tab symbols in code
ATTENTION: code with tab symbols.
```
/tmp $ javac Test.java

/tmp $ cat config.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
		"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
		"https://checkstyle.org/dtds/configuration_1_3.dtd">

<module name = "Checker">
    <module name="TreeWalker">
        <property name="tabWidth" value="4"/>
        <module name="Indentation"/>
    </module>
</module>

/tmp $ cat Test.java
import java.lang.*;
import java.util.*;
import java.util.stream.*;

class Test {
	List<Integer> test(List<String> input) {
		return input.stream()
				.flatMap(in -> Arrays.stream(in.split(""))) // only 2 char parameter has violation
				.map(Integer::valueOf)
				.collect(Collectors.toList());
	}

	String test2(String input) {
		return Optional.ofNullable(input)
				.filter(inp -> inp.contains("e")) // only 3 char parameter has violation
				.orElse(null);
	}
}

/tmp $ java -jar checkstyle-8.10.1-all.jar -c config.xml Test.java
Starting audit...
[ERROR] /tmp/Test.java:8: 'lambda' has incorrect indentation level 16, expected level should be 20. [Indentation]
[ERROR] /tmp/Test.java:15: 'lambda' has incorrect indentation level 16, expected level should be 20. [Indentation]
Audit done.
Checkstyle ends with 2 errors.
```

---------------

Expectation: lambda parameter name length should not affect the indentation rule, and the example code above should not have any violations.

If you change line 8's lamdba parameter to `i` or `inp` or any other name that is not 2 characters, the indentation violation goes away.
Likewise, line 15's lambda parameter can be changed to any name that is not 3 characters and the indentation violation goes away.

--------------

If tabs changed to spaces, no problems are reported, but we use tabs in code.
http://checkstyle.sourceforge.net/config_misc.html#Indentation no special property for tab size, tab should be taken from Treewalker.
Confusing violation of Indentation rule
Im having a problem with the https://checkstyle.sourceforge.io/config_misc.html#Indentation check.

```/home/serra/dev/cs-repro $ javac Test.java```
[no output here]
```/home/serra/dev/cs-repro $ cat my-checks.xml```
```xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
        "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
        "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
	<property name="charset" value="UTF-8" />
	<property name="tabWidth" value="3" />
	<module name="TreeWalker">
		<module name="Indentation">
			<property name="basicOffset" value="3" />
			<property name="caseIndent" value="0" />
			<property name="lineWrappingIndentation" value="6" />
		</module>
	</module>
</module>
```

```/home/serra/dev/cs-repro $ cat Test.java```
```java
import java.util.Arrays;
import java.util.stream.Stream;

public class Test {
	public void test(Stream<Inner<?>> stream) {
		stream
				.filter(ps -> ps instanceof Inner)
				.map(ps -> ((Inner<?>) ps).getPropertyNames())
				.forEach(System.out::println);
	}

	private static class Inner<T> {
		String[] getPropertyNames() {
			return new String[] {"a", "b"};
		}
	}
}
```
```/home/serra/dev/cs-repro $ java -Duser.language=en -Duser.country=us -jar checkstyle-8.29-all.jar -c my-checks.xml Test.java
Starting audit...
[ERROR] /home/serra/dev/cs-repro/Test.java:8: 'lambda' has incorrect indentation level 12, expected level should be 18. [Indentation]
Audit done.
```

---------------

I expected the code to be conforming to my rules.
As far as I can recognize I adhere to all the rules in the xml.

I am not sure if this is a bug or if I am just misunderstandung how the rule is working.


Hints:

This looks like a bug to me from the information I am seeing, but indentation is always tricky.

Lambda does not start the line and should not have been the one reporting the problem if the indentation was wrong. I would expect the `.` or referenced the message call to be where the failure message to be.
Duplicate of #5969.

Patch:
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java
@@ -66,7 +66,7 @@ protected IndentLevel getIndentImpl() {
         // If the start of the lambda is the first element on the line;
         // assume line wrapping with respect to its parent.
         final DetailAST firstChild = getMainAst().getFirstChild();
-        if (getLineStart(firstChild) == firstChild.getColumnNo()) {
+        if (getLineStart(firstChild) == expandedTabsColumnNo(firstChild)) {
             level = new IndentLevel(level, getIndentCheck().getLineWrappingIndentation());
         }
 
@@ -77,19 +77,19 @@ protected IndentLevel getIndentImpl() {
     public void checkIndentation() {
         // If the argument list is the first element on the line
         final DetailAST firstChild = getMainAst().getFirstChild();
-        if (getLineStart(firstChild) == firstChild.getColumnNo()) {
+        if (getLineStart(firstChild) == expandedTabsColumnNo(firstChild)) {
             final IndentLevel level = getIndent();
-            if (!level.isAcceptable(firstChild.getColumnNo())) {
-                logError(firstChild, "arguments", firstChild.getColumnNo(), level);
+            if (!level.isAcceptable(expandedTabsColumnNo(firstChild))) {
+                logError(firstChild, "arguments", expandedTabsColumnNo(firstChild), level);
             }
         }
 
         // If the "->" is the first element on the line, assume line wrapping.
-        if (getLineStart(getMainAst()) == getMainAst().getColumnNo()) {
+        if (getLineStart(getMainAst()) == expandedTabsColumnNo(getMainAst())) {
             final IndentLevel level =
                 new IndentLevel(getIndent(), getIndentCheck().getLineWrappingIndentation());
-            if (!level.isAcceptable(getMainAst().getColumnNo())) {
-                logError(getMainAst(), "", getMainAst().getColumnNo(), level);
+            if (!level.isAcceptable(expandedTabsColumnNo(getMainAst()))) {
+                logError(getMainAst(), "", expandedTabsColumnNo(getMainAst()), level);
             }
         }
     }


Test patch:
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheckTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheckTest.java
@@ -1759,6 +1759,47 @@ public void testLambda2() throws Exception {
         verifyWarns(checkConfig, getPath("InputIndentationLambda2.java"), expected);
     }
 
+    @Test
+    public void testLambda3() throws Exception {
+        final DefaultConfiguration checkConfig = createModuleConfig(IndentationCheck.class);
+        checkConfig.addAttribute("tabWidth", "4");
+        checkConfig.addAttribute("basicOffset", "4");
+        checkConfig.addAttribute("lineWrappingIndentation", "8");
+        final String[] expected = {
+            "15: " + getCheckMessage(MSG_CHILD_ERROR, "method def", 12, 8),
+            "23: " + getCheckMessage(MSG_ERROR_MULTI, "lambda arguments", 20, "12, 16"),
+            "29: " + getCheckMessage(MSG_CHILD_ERROR, "method def", 12, 8),
+            "30: " + getCheckMessage(MSG_CHILD_ERROR, "block", 12, 16),
+            "31: " + getCheckMessage(MSG_ERROR, "block rcurly", 8, 12),
+            "43: " + getCheckMessage(MSG_ERROR, "lambda arguments", 20, 16),
+            "65: " + getCheckMessage(MSG_CHILD_ERROR, "method def", 12, 8),
+            "67: " + getCheckMessage(MSG_ERROR, "lambda", 28, 24),
+            "87: " + getCheckMessage(MSG_ERROR, "method def rcurly", 12, 8),
+        };
+        verifyWarns(checkConfig, getPath("InputIndentationLambda3.java"), expected);
+    }
+
+    @Test
+    public void testLambda4() throws Exception {
+        final DefaultConfiguration checkConfig = createModuleConfig(IndentationCheck.class);
+        checkConfig.addAttribute("tabWidth", "4");
+        checkConfig.addAttribute("basicOffset", "4");
+        checkConfig.addAttribute("lineWrappingIndentation", "8");
+        final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
+        verifyWarns(checkConfig, getPath("InputIndentationLambda4.java"), expected);
+    }
+
+    @Test
+    public void testLambda5() throws Exception {
+        final DefaultConfiguration checkConfig = createModuleConfig(IndentationCheck.class);
+        checkConfig.addAttribute("tabWidth", "3");
+        checkConfig.addAttribute("basicOffset", "3");
+        checkConfig.addAttribute("caseIndent", "0");
+        checkConfig.addAttribute("lineWrappingIndentation", "6");
+        final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
+        verifyWarns(checkConfig, getPath("InputIndentationLambda5.java"), expected);
+    }
+
     @Test
     public void testSeparatedStatements() throws Exception {
         final DefaultConfiguration checkConfig = createModuleConfig(IndentationCheck.class);
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda3.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda3.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda3.java
@@ -0,0 +1,89 @@
+//a comment //indent:0 exp:0
+package com.puppycrawl.tools.checkstyle.checks.indentation.indentation; //indent:0 exp:0
+
+import java.util.Arrays; //indent:0 exp:0
+import java.util.List; //indent:0 exp:0
+import java.util.Optional; //indent:0 exp:0
+import java.util.function.BinaryOperator; //indent:0 exp:0
+import java.util.function.Consumer; //indent:0 exp:0
+import java.util.stream.Collectors; //indent:0 exp:0
+import java.util.stream.Stream; //indent:0 exp:0
+
+
+public class InputIndentationLambda3 { //indent:0 exp:0
+	public <T> Consumer<Integer> par(Consumer<Integer> f1, Consumer<Integer> f2) { //indent:4 exp:4
+			return f2; //indent:12 exp:8 warn
+	} //indent:4 exp:4
+
+	private void print(int i) { //indent:4 exp:4
+	} //indent:4 exp:4
+
+	public Consumer<Integer> returnFunctionOfLambda() { //indent:4 exp:4
+		return par( //indent:8 exp:8
+					(x) -> print(x * 1), //indent:20 exp:12,16 warn
+				(x) -> print(x * 2) //indent:16 exp:16
+		); //indent:8 exp:8
+	} //indent:4 exp:4
+
+	public static <T> BinaryOperator<T> returnLambda() { //indent:4 exp:4
+			return (t1, t2) -> { //indent:12 exp:8 warn
+			return t1; //indent:12 exp:16 warn
+		}; //indent:8 exp:12 warn
+	} //indent:4 exp:4
+
+	class TwoParams { //indent:4 exp:4
+		TwoParams(Consumer<Integer> c1, Consumer<Integer> c2) { //indent:8 exp:8
+		} //indent:8 exp:8
+	} //indent:4 exp:4
+
+	public void makeTwoParams() { //indent:4 exp:4
+		TwoParams t0 = new TwoParams( //indent:8 exp:8
+				intValueA //indent:16 exp:16
+						-> print(intValueA * 1), //indent:24 exp:24
+					(x) -> //indent:20 exp:16 warn
+						print(x * 2) //indent:24 exp:24
+		); //indent:8 exp:8
+
+		TwoParams t1 = new TwoParams( //indent:8 exp:8
+				x //indent:16 exp:16
+						-> print(x * 1), //indent:24 exp:24
+				(aggregateValue) -> //indent:16 exp:16
+						print(aggregateValue * 2)); //indent:24 exp:24
+	} //indent:4 exp:4
+
+	// see https://github.com/checkstyle/checkstyle/issues/5969 //indent:4 exp:4
+	List<Integer> test(List<String> input) { //indent:4 exp:4
+		return input.stream() //indent:8 exp:8
+				.flatMap(each -> Arrays.stream(each.split(""))) //indent:16 exp:16
+				.flatMap(in -> Arrays.stream(in.split(""))) //indent:16 exp:16
+				// only 2 char parameter has violation //indent:16 exp:16
+				.map(Integer::valueOf) //indent:16 exp:16
+				.collect(Collectors.toList()); //indent:16 exp:16
+	} //indent:4 exp:4
+
+	String test2(String input) { //indent:4 exp:4
+			return Optional.ofNullable(input) //indent:12 exp:8 warn
+				.filter(in //indent:16 exp:16
+							-> //indent:28 exp:24 warn
+					in.contains("e")) //indent:20 exp:20
+			.filter(inp -> inp.contains("e")) //indent:12 exp:12
+				// only 3 char parameter has violation //indent:16 exp:16
+				.orElse(null); //indent:16 exp:16
+	} //indent:4 exp:4
+
+	// see https://github.com/checkstyle/checkstyle/issues/7675 //indent:4 exp:4
+	public void test(Stream<Inner<?>> stream) { //indent:4 exp:4
+		stream //indent:8 exp:8
+.sorted() //indent:0 exp:0
+.filter(ps -> ps instanceof Inner) //indent:0 exp:0
+				.map(ps -> ((Inner<?>) ps).getPropertyNames()) //indent:16 exp:16
+				// This line above originally breaks //indent:16 exp:16
+				.forEach(System.out::println); //indent:16 exp:16
+	} //indent:4 exp:4
+
+	private static class Inner<T> { //indent:4 exp:4
+		String[] getPropertyNames() { //indent:8 exp:8
+			return new String[] {"a", "b"}; //indent:12 exp:12
+			} //indent:12 exp:8 warn
+	} //indent:4 exp:4
+} //indent:0 exp:0
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda4.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda4.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda4.java
@@ -0,0 +1,64 @@
+//a comment //indent:0 exp:0
+package com.puppycrawl.tools.checkstyle.checks.indentation.indentation; //indent:0 exp:0
+
+import java.util.Arrays; //indent:0 exp:0
+import java.util.List; //indent:0 exp:0
+import java.util.Optional; //indent:0 exp:0
+import java.util.function.BinaryOperator; //indent:0 exp:0
+import java.util.function.Consumer; //indent:0 exp:0
+import java.util.stream.Collectors; //indent:0 exp:0
+
+
+public class InputIndentationLambda4 { //indent:0 exp:0
+	public <T> Consumer<Integer> par(Consumer<Integer> f1, Consumer<Integer> f2) { //indent:4 exp:4
+		return f2; //indent:8 exp:8
+	} //indent:4 exp:4
+
+	private void print(int i) { //indent:4 exp:4
+	} //indent:4 exp:4
+
+	public Consumer<Integer> returnFunctionOfLambda() { //indent:4 exp:4
+		return par( //indent:8 exp:8
+				(x) -> print(x * 1), //indent:16 exp:16
+				(x) -> print(x * 2) //indent:16 exp:16
+		); //indent:8 exp:8
+	} //indent:4 exp:4
+
+	public static <T> BinaryOperator<T> returnLambda() { //indent:4 exp:4
+		return (t1, t2) -> { //indent:8 exp:8
+			return t1; //indent:12 exp:12
+		}; //indent:8 exp:8
+	} //indent:4 exp:4
+
+	class TwoParams { //indent:4 exp:4
+		TwoParams(Consumer<Integer> c1, Consumer<Integer> c2) { //indent:8 exp:8
+		} //indent:8 exp:8
+	} //indent:4 exp:4
+
+	public void makeTwoParams() { //indent:4 exp:4
+		TwoParams t0 = new TwoParams( //indent:8 exp:8
+				(x) -> print(x * 1), //indent:16 exp:16
+				(x) -> print(x * 2) //indent:16 exp:16
+		); //indent:8 exp:8
+
+		TwoParams t1 = new TwoParams( //indent:8 exp:8
+				(x) -> print(x * 1), //indent:16 exp:16
+				(x) -> print(x * 2)); //indent:16 exp:16
+	} //indent:4 exp:4
+
+	// see https://github.com/checkstyle/checkstyle/issues/5969 //indent:4 exp:4
+	List<Integer> test(List<String> input) { //indent:4 exp:4
+		return input.stream() //indent:8 exp:8
+				.flatMap(in -> Arrays.stream(in.split(""))) //indent:16 exp:16
+				// only 2 char parameter has violation //indent:16 exp:16
+				.map(Integer::valueOf) //indent:16 exp:16
+				.collect(Collectors.toList()); //indent:16 exp:16
+	} //indent:4 exp:4
+
+	String test2(String input) { //indent:4 exp:4
+		return Optional.ofNullable(input) //indent:8 exp:8
+				.filter(inp -> inp.contains("e")) //indent:16 exp:16
+				// only 3 char parameter has violation //indent:16 exp:16
+				.orElse(null); //indent:16 exp:16
+	} //indent:4 exp:4
+} //indent:0 exp:0
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda5.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda5.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/indentation/indentation/InputIndentationLambda5.java
@@ -0,0 +1,17 @@
+package com.puppycrawl.tools.checkstyle.checks.indentation.indentation; //indent:0 exp:0
+// see https://github.com/checkstyle/checkstyle/issues/7675 //indent:0 exp:0
+import java.util.stream.Stream; //indent:0 exp:0
+public class InputIndentationLambda5 { //indent:0 exp:0
+	public void test(Stream<Inner<?>> stream) { //indent:3 exp:3
+		stream //indent:6 exp:6
+				.filter(ps -> ps instanceof Inner) //indent:12 exp:12
+				.map(ps -> ((Inner<?>) ps).getPropertyNames()) //indent:12 exp:12
+				.forEach(System.out::println); //indent:12 exp:12
+	} //indent:3 exp:3
+
+	private static class Inner<T> { //indent:3 exp:3
+		String[] getPropertyNames() { //indent:6 exp:6
+			return new String[] {"a", "b"}; //indent:9 exp:9
+		} //indent:6 exp:6
+	} //indent:3 exp:3
+} //indent:0 exp:0