Skip to content

Commit 4aad239

Browse files
java-team-github-botError Prone Team
authored and
Error Prone Team
committed
Discourage public Foo stream() where Foo does _not_ end with "Stream"
PiperOrigin-RevId: 390684609
1 parent ba12995 commit 4aad239

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2021 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.errorprone.bugpatterns;
18+
19+
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
20+
import static com.google.errorprone.matchers.Matchers.allOf;
21+
import static com.google.errorprone.matchers.Matchers.methodHasVisibility;
22+
import static com.google.errorprone.matchers.Matchers.methodIsNamed;
23+
24+
import com.google.errorprone.BugPattern;
25+
import com.google.errorprone.VisitorState;
26+
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
27+
import com.google.errorprone.matchers.Description;
28+
import com.google.errorprone.matchers.Matcher;
29+
import com.google.errorprone.matchers.MethodVisibility;
30+
import com.google.errorprone.util.ASTHelpers;
31+
import com.sun.source.tree.MethodTree;
32+
import com.sun.tools.javac.code.Type;
33+
34+
/**
35+
* Checks if public APIs named "stream" returns a type whose name ends with Stream.
36+
*
37+
* @author [email protected] (Saurav Tiwary)
38+
*/
39+
@BugPattern(
40+
name = "PublicApiNamedStreamShouldReturnStream",
41+
summary =
42+
"Public methods named stream() are generally expected to return a type whose name ends with"
43+
+ " Stream. Consider choosing a different method name instead.",
44+
severity = SUGGESTION)
45+
public class PublicApiNamedStreamShouldReturnStream extends BugChecker
46+
implements MethodTreeMatcher {
47+
private static final String STREAM = "stream";
48+
49+
private static final Matcher<MethodTree> CONFUSING_PUBLIC_API_STREAM_MATCHER =
50+
allOf(
51+
methodIsNamed(STREAM),
52+
methodHasVisibility(MethodVisibility.Visibility.PUBLIC),
53+
PublicApiNamedStreamShouldReturnStream::returnTypeDoesNotEndsWithStream);
54+
55+
private static boolean returnTypeDoesNotEndsWithStream(
56+
MethodTree methodTree, VisitorState state) {
57+
Type returnType = ASTHelpers.getSymbol(methodTree).getReturnType();
58+
59+
// Constructors have no return type.
60+
return returnType != null && !returnType.tsym.getSimpleName().toString().endsWith("Stream");
61+
}
62+
63+
@Override
64+
public Description matchMethod(MethodTree tree, VisitorState state) {
65+
if (!CONFUSING_PUBLIC_API_STREAM_MATCHER.matches(tree, state)) {
66+
return Description.NO_MATCH;
67+
}
68+
69+
return describeMatch(tree);
70+
}
71+
}

core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@
278278
import com.google.errorprone.bugpatterns.ProtoTruthMixedDescriptors;
279279
import com.google.errorprone.bugpatterns.ProtocolBufferOrdinal;
280280
import com.google.errorprone.bugpatterns.ProtosAsKeyOfSetOrMap;
281+
import com.google.errorprone.bugpatterns.PublicApiNamedStreamShouldReturnStream;
281282
import com.google.errorprone.bugpatterns.PublicConstructorForAbstractClass;
282283
import com.google.errorprone.bugpatterns.RandomCast;
283284
import com.google.errorprone.bugpatterns.RandomModInteger;
@@ -1036,6 +1037,7 @@ public static ScannerSupplier errorChecks() {
10361037
PrivateConstructorForNoninstantiableModule.class,
10371038
PrivateConstructorForUtilityClass.class,
10381039
ProtosAsKeyOfSetOrMap.class,
1040+
PublicApiNamedStreamShouldReturnStream.class,
10391041
PublicConstructorForAbstractClass.class,
10401042
QualifierWithTypeUse.class,
10411043
RedundantCondition.class,
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2021 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.errorprone.bugpatterns;
18+
19+
import com.google.errorprone.CompilationTestHelper;
20+
import org.junit.Before;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.junit.runners.JUnit4;
24+
25+
/** Unit tests for {@link PublicApiNamedStreamShouldReturnStream}. */
26+
@RunWith(JUnit4.class)
27+
public class PublicApiNamedStreamShouldReturnStreamTest {
28+
29+
private CompilationTestHelper compilationHelper;
30+
31+
@Before
32+
public void setup() {
33+
compilationHelper =
34+
CompilationTestHelper.newInstance(PublicApiNamedStreamShouldReturnStream.class, getClass());
35+
}
36+
37+
@Test
38+
public void abstractMethodPositiveCase() {
39+
compilationHelper
40+
.addSourceLines(
41+
"in/Test.java",
42+
"public abstract class Test {",
43+
" // BUG: Diagnostic contains: PublicApiNamedStreamShouldReturnStream",
44+
" public abstract int stream();",
45+
"}")
46+
.doTest();
47+
}
48+
49+
@Test
50+
public void regularMethodPositiveCase() {
51+
compilationHelper
52+
.addSourceLines(
53+
"in/Test.java",
54+
"public class Test {",
55+
" // BUG: Diagnostic contains: PublicApiNamedStreamShouldReturnStream",
56+
" public String stream() { return \"hello\";}",
57+
"}")
58+
.doTest();
59+
}
60+
61+
@Test
62+
public void compliantNegativeCase() {
63+
compilationHelper
64+
.addSourceLines(
65+
"in/Test.java",
66+
"import java.util.stream.Stream;",
67+
"public abstract class Test {",
68+
" public abstract Stream<Integer> stream();",
69+
"}")
70+
.doTest();
71+
}
72+
73+
@Test
74+
public void differentNameNegativeCase() {
75+
compilationHelper
76+
.addSourceLines(
77+
"in/Test.java",
78+
"public class Test {",
79+
" public int differentMethodName() { return 0; }",
80+
"}")
81+
.doTest();
82+
}
83+
84+
@Test
85+
public void privateMethodNegativeCase() {
86+
compilationHelper
87+
.addSourceLines(
88+
"in/Test.java",
89+
"public class Test {",
90+
" private String stream() { return \"hello\"; }",
91+
"}")
92+
.doTest();
93+
}
94+
95+
@Test
96+
public void returnTypeEndingWithStreamNegativeCase() {
97+
compilationHelper
98+
.addSourceLines(
99+
"in/Test.java",
100+
"public class Test {",
101+
" private static class TestStream {}",
102+
" public TestStream stream() { return new TestStream(); }",
103+
"}")
104+
.doTest();
105+
}
106+
107+
@Test
108+
public void returnTypeNotEndingWithStreamPositiveCase() {
109+
compilationHelper
110+
.addSourceLines(
111+
"in/Test.java",
112+
"public class Test {",
113+
" private static class TestStreamRandomSuffix {}",
114+
" // BUG: Diagnostic contains: PublicApiNamedStreamShouldReturnStream",
115+
" public TestStreamRandomSuffix stream() { return new TestStreamRandomSuffix(); }",
116+
"}")
117+
.doTest();
118+
}
119+
}

0 commit comments

Comments
 (0)