Skip to content

Commit 33f4abd

Browse files
committed
add new SLF4J_GET_STACK_TRACE detector (fixes KengoTODA#70)
1 parent d1a2c62 commit 33f4abd

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package jp.skypencil.findbugs.slf4j;
2+
3+
import com.google.common.base.Objects;
4+
import edu.umd.cs.findbugs.BugReporter;
5+
import edu.umd.cs.findbugs.OpcodeStack.Item;
6+
import jp.skypencil.findbugs.slf4j.parameter.AbstractDetectorForParameterArray2;
7+
8+
/**
9+
* FindBugs (now SpotBugs) Detector for (ab)use of {@link Throwable#getStackTrace()} in SFL4j logger.
10+
*
11+
* @author Michael Vorburger.ch
12+
*/
13+
public class ManualGetStackTraceDetector extends AbstractDetectorForParameterArray2 {
14+
15+
@Item.SpecialKind
16+
private final int isGetStackTrace = Item.defineNewSpecialKind("use of throwable getStackTrace");
17+
18+
public ManualGetStackTraceDetector(BugReporter bugReporter) {
19+
super(bugReporter, "SLF4J_GET_STACK_TRACE");
20+
}
21+
22+
@Override
23+
protected int getIsOfInterestKind() {
24+
return isGetStackTrace;
25+
}
26+
27+
@Override
28+
protected boolean isWhatWeWantToDetect(int seen) {
29+
// return false;
30+
return seen == INVOKEVIRTUAL
31+
&& !stack.isTop()
32+
&& getThrowableHandler().checkThrowable(getStack().getStackItem(0))
33+
&& Objects.equal("getStackTrace", getNameConstantOperand());
34+
}
35+
36+
}

bug-pattern/src/main/resources/bugrank.txt

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
0 BugPattern SLF4J_ILLEGAL_PASSED_CLASS
88
0 BugPattern SLF4J_SIGN_ONLY_FORMAT
99
0 BugPattern SLF4J_MANUALLY_PROVIDED_MESSAGE
10+
0 BugPattern SLF4J_GET_STACK_TRACE

bug-pattern/src/main/resources/findbugs.xml

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<Detector class="jp.skypencil.findbugs.slf4j.StaticLoggerDetector" reports="SLF4J_LOGGER_SHOULD_BE_NON_STATIC" speed="fast" />
1212
<Detector class="jp.skypencil.findbugs.slf4j.IllegalPassedClassDetector" reports="SLF4J_ILLEGAL_PASSED_CLASS" speed="fast" />
1313
<Detector class="jp.skypencil.findbugs.slf4j.ManualMessageDetector" reports="SLF4J_MANUALLY_PROVIDED_MESSAGE,SLF4J_FORMAT_SHOULD_BE_CONST" speed="fast" />
14+
<Detector class="jp.skypencil.findbugs.slf4j.ManualGetStackTraceDetector" reports="SLF4J_GET_STACK_TRACE" speed="fast" />
15+
1416
<BugPattern type="SLF4J_PLACE_HOLDER_MISMATCH" abbrev="SLF4J" category="CORRECTNESS" />
1517
<BugPattern type="SLF4J_FORMAT_SHOULD_BE_CONST" abbrev="SLF4J" category="CORRECTNESS" />
1618
<BugPattern type="SLF4J_UNKNOWN_ARRAY" abbrev="SLF4J" category="CORRECTNESS" />
@@ -20,5 +22,6 @@
2022
<BugPattern type="SLF4J_ILLEGAL_PASSED_CLASS" abbrev="SLF4J" category="CORRECTNESS" />
2123
<BugPattern type="SLF4J_SIGN_ONLY_FORMAT" abbrev="SLF4J" category="BAD_PRACTICE" />
2224
<BugPattern type="SLF4J_MANUALLY_PROVIDED_MESSAGE" abbrev="SLF4J" category="BAD_PRACTICE" />
25+
<BugPattern type="SLF4J_GET_STACK_TRACE" abbrev="SLF4J" category="BAD_PRACTICE" />
2326

2427
</FindbugsPlugin>

bug-pattern/src/main/resources/messages.xml

+18
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
</Details>
4444
</Detector>
4545

46+
<Detector class="jp.skypencil.findbugs.slf4j.ManualGetStackTraceDetector">
47+
<Details>
48+
Finds log which uses Throwable#getStackTrace.
49+
</Details>
50+
</Detector>
51+
4652
<BugPattern type="SLF4J_PLACE_HOLDER_MISMATCH">
4753
<ShortDescription>Count of placeholder is not equal to count of parameter</ShortDescription>
4854
<LongDescription>Count of placeholder({5}) is not equal to count of parameter({4})</LongDescription>
@@ -146,5 +152,17 @@ You cannot use array which is provided as method argument or returned from other
146152
</Details>
147153
</BugPattern>
148154

155+
<BugPattern type="SLF4J_GET_STACK_TRACE">
156+
<ShortDescription>Do not use Throwable#getStackTrace.</ShortDescription>
157+
<LongDescription>
158+
Do not have use Throwable#getStackTrace. It is enough to provide throwable instance as the last argument, then binding will log its message.
159+
</LongDescription>
160+
<Details>
161+
<![CDATA[
162+
<p>Do not use Throwable#getStackTrace.</p>
163+
]]>
164+
</Details>
165+
</BugPattern>
166+
149167
<BugCode abbrev="SLF4J">SLF4J</BugCode>
150168
</MessageCollection>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package pkg;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
public class UsingGetStackTrace {
7+
8+
private final Logger logger = LoggerFactory.getLogger(getClass());
9+
10+
void method(RuntimeException ex) {
11+
logger.error("Failed to determine The Answer to Life, The Universe and Everything; {}", 27, ex.getStackTrace());
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package jp.skypencil.findbugs.slf4j;
2+
3+
import edu.umd.cs.findbugs.BugInstance;
4+
import java.util.function.Predicate;
5+
import org.hamcrest.BaseMatcher;
6+
import org.hamcrest.Description;
7+
8+
/**
9+
* Hamcrest matcher for FindBugs (now SpotBugs) {@link BugInstance}.
10+
*
11+
* @author Michael Vorburger.ch
12+
*/
13+
public final class BugInstanceMatcher extends BaseMatcher<BugInstance> {
14+
15+
private final Predicate<BugInstance> predicate;
16+
17+
public BugInstanceMatcher(Predicate<BugInstance> predicate) {
18+
this.predicate = predicate;
19+
}
20+
21+
@Override
22+
public final boolean matches(Object item) {
23+
return predicate.test((BugInstance) item);
24+
}
25+
26+
@Override
27+
public void describeTo(Description description) {
28+
description.appendText("BugInstance must match expected");
29+
}
30+
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package jp.skypencil.findbugs.slf4j;
2+
3+
import com.youdevise.fbplugins.tdd4fb.DetectorAssert;
4+
import edu.umd.cs.findbugs.BugReporter;
5+
import edu.umd.cs.findbugs.Detector;
6+
import org.junit.jupiter.api.Test;
7+
import pkg.UsingGetStackTrace;
8+
9+
/**
10+
* Test for {@link ManualGetStackTraceDetector}.
11+
*
12+
* @author Michael Vorburger.ch
13+
*/
14+
public class UsingGetStackTraceTest {
15+
16+
@Test
17+
public void testExceptionMethods() throws Exception {
18+
BugReporter bugReporter = DetectorAssert.bugReporterForTesting();
19+
Detector detector = new ManualGetStackTraceDetector(bugReporter);
20+
DetectorAssert.assertNoBugsReported(UsingGetStackTrace.class, detector, bugReporter);
21+
DetectorAssert.assertBugReported(UsingGetStackTrace.class, detector, bugReporter, new BugInstanceMatcher(
22+
bugInstance -> bugInstance.getBugPattern().getAbbrev().equals("SLF4J_GET_STACK_TRACE")));
23+
}
24+
25+
}

0 commit comments

Comments
 (0)