1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks.indentation;
21
22 import com.puppycrawl.tools.checkstyle.api.DetailAST;
23 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
25
26
27
28
29 public class NewHandler extends AbstractExpressionHandler {
30
31
32
33
34 private static final int[] LINE_WRAP_NEW_PARENT_TYPES = {
35 TokenTypes.ASSIGN,
36 TokenTypes.LITERAL_RETURN,
37 TokenTypes.LITERAL_THROW,
38 };
39
40
41 private final DetailAST mainAst;
42
43
44
45
46
47
48
49
50
51 public NewHandler(IndentationCheck indentCheck,
52 DetailAST ast,
53 AbstractExpressionHandler parent) {
54 super(indentCheck, "new", ast, parent);
55 mainAst = ast;
56 }
57
58 @Override
59 public void checkIndentation() {
60
61 if (isOnStartOfLine(mainAst)) {
62 final int columnNo = expandedTabsColumnNo(mainAst);
63 final IndentLevel level = getIndentImpl();
64
65 final boolean forceStrictCondition = getIndentCheck().isForceStrictCondition();
66 if (forceStrictCondition && !level.isAcceptable(columnNo)
67 || !forceStrictCondition && level.isGreaterThan(columnNo)) {
68 logError(mainAst, "", columnNo, level);
69 }
70 }
71
72 final DetailAST firstChild = mainAst.getFirstChild();
73 if (firstChild != null) {
74 checkExpressionSubtree(firstChild, getIndent(), false, false);
75 }
76
77 final DetailAST expression = mainAst.findFirstToken(TokenTypes.ELIST);
78 if (checkNestedNew(expression) && isOnStartOfLine(expression)) {
79 final IndentLevel indentLevel = new IndentLevel(getIndent(),
80 getLineWrappingIndent());
81 checkExpressionSubtree(expression, indentLevel, false, false);
82 }
83
84 final DetailAST lparen = mainAst.findFirstToken(TokenTypes.LPAREN);
85 checkLeftParen(lparen);
86 }
87
88
89
90
91
92
93
94
95 public boolean checkNestedNew(DetailAST expression) {
96 boolean result = false;
97 if (expression != null && expression.getFirstChild() != null) {
98 final boolean isNestedNewPresent = expression.getFirstChild()
99 .findFirstToken(TokenTypes.LITERAL_NEW) != null;
100 if (!isNestedNewPresent) {
101 result = true;
102 }
103 }
104 return result;
105 }
106
107 @Override
108 public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
109 final int offset;
110 if (TokenUtil.isOfType(child.getMainAst(), TokenTypes.OBJBLOCK)) {
111 offset = getBasicOffset();
112 }
113 else {
114 offset = getLineWrappingIndent();
115 }
116 return new IndentLevel(getIndent(), offset);
117 }
118
119 @Override
120 protected IndentLevel getIndentImpl() {
121 IndentLevel result;
122
123
124 if (getLineStart(mainAst) == mainAst.getColumnNo()) {
125 result = super.getIndentImpl();
126
127 final boolean isLineWrappedNew = TokenUtil.isOfType(mainAst.getParent().getParent(),
128 LINE_WRAP_NEW_PARENT_TYPES);
129
130 final int ternaryLevel = getTernaryNestingLevel();
131
132 if (isLineWrappedNew || doesNewNeedLineWrappingIndent()) {
133 result = new IndentLevel(result, getLineWrappingIndent());
134 }
135
136 if (ternaryLevel >= 2) {
137 for (int idx = 1; idx < ternaryLevel; idx++) {
138 result = new IndentLevel(result, getLineWrappingIndent());
139 }
140 }
141 }
142 else {
143 result = new IndentLevel(getLineStart(mainAst));
144 }
145
146 return result;
147 }
148
149
150
151
152
153
154
155 private int getLineWrappingIndent() {
156 return getIndentCheck().getLineWrappingIndentation();
157 }
158
159 @Override
160 protected boolean shouldIncreaseIndent() {
161 return false;
162 }
163
164
165
166
167
168
169
170
171 private boolean doesNewNeedLineWrappingIndent() {
172 DetailAST ast = mainAst.getParent();
173
174 while (TokenUtil.isOfType(ast, TokenTypes.DOT, TokenTypes.METHOD_CALL, TokenTypes.EXPR)) {
175 ast = ast.getParent();
176 }
177
178 return TokenUtil.isOfType(ast, LINE_WRAP_NEW_PARENT_TYPES)
179 || ast.getType() == TokenTypes.QUESTION && isParentAssignReturnOrThrow(ast);
180 }
181
182
183
184
185
186
187
188 private static boolean isParentAssignReturnOrThrow(DetailAST ast) {
189 DetailAST parent = ast.getParent();
190 while (TokenUtil.isOfType(parent, TokenTypes.EXPR, TokenTypes.QUESTION)) {
191 parent = parent.getParent();
192 }
193 return TokenUtil.isOfType(parent, LINE_WRAP_NEW_PARENT_TYPES);
194 }
195
196
197
198
199
200
201
202 private int getTernaryNestingLevel() {
203 DetailAST ast = mainAst.getParent();
204
205 while (TokenUtil.isOfType(ast, TokenTypes.DOT, TokenTypes.METHOD_CALL, TokenTypes.EXPR)) {
206 ast = ast.getParent();
207 }
208
209 int level = 0;
210 while (ast.getType() == TokenTypes.QUESTION) {
211 level++;
212 do {
213 ast = ast.getParent();
214 } while (ast.getType() == TokenTypes.EXPR);
215 }
216
217 int result = 0;
218 if (TokenUtil.isOfType(ast, LINE_WRAP_NEW_PARENT_TYPES)) {
219 result = level;
220 }
221
222 return result;
223 }
224
225 }