1
2
3
4
5 package com.qulice.checkstyle;
6
7 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8 import com.puppycrawl.tools.checkstyle.api.DetailAST;
9 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public final class IfThenThrowElseCheck extends AbstractCheck {
41
42
43
44
45 public IfThenThrowElseCheck() {
46
47 }
48
49 @Override
50 public int[] getDefaultTokens() {
51 return this.getRequiredTokens();
52 }
53
54 @Override
55 public int[] getAcceptableTokens() {
56 return this.getRequiredTokens();
57 }
58
59 @Override
60 public int[] getRequiredTokens() {
61 return new int[] {TokenTypes.LITERAL_IF};
62 }
63
64 @Override
65 public void visitToken(final DetailAST ast) {
66 final DetailAST branch = ast.findFirstToken(TokenTypes.LITERAL_ELSE);
67 if (branch != null
68 && IfThenThrowElseCheck.alwaysThrows(IfThenThrowElseCheck.thenBranch(ast))) {
69 this.log(
70 ast.getLineNo(),
71 "Avoid ''else'' when ''then'' branch ends with ''throw''"
72 );
73 }
74 }
75
76 private static DetailAST thenBranch(final DetailAST ast) {
77 final DetailAST rparen = ast.findFirstToken(TokenTypes.RPAREN);
78 DetailAST result = null;
79 if (rparen != null) {
80 result = rparen.getNextSibling();
81 }
82 return result;
83 }
84
85 private static boolean alwaysThrows(final DetailAST node) {
86 final boolean result;
87 if (node == null) {
88 result = false;
89 } else if (node.getType() == TokenTypes.LITERAL_THROW) {
90 result = true;
91 } else if (node.getType() == TokenTypes.SLIST) {
92 result = IfThenThrowElseCheck.endsWithThrow(node);
93 } else {
94 result = false;
95 }
96 return result;
97 }
98
99 private static boolean endsWithThrow(final DetailAST slist) {
100 DetailAST last = slist.getLastChild();
101 while (last != null && last.getType() == TokenTypes.RCURLY) {
102 last = last.getPreviousSibling();
103 }
104 return last != null && last.getType() == TokenTypes.LITERAL_THROW;
105 }
106 }