1 package com.stateofflow.eclipse.metrics.calculators.linesofcode;
2
3 import java.util.Stack;
4
5 import org.eclipse.jdt.core.dom.ASTNode;
6 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
7 import org.eclipse.jdt.core.dom.ArrayAccess;
8 import org.eclipse.jdt.core.dom.AssertStatement;
9 import org.eclipse.jdt.core.dom.Assignment;
10 import org.eclipse.jdt.core.dom.Block;
11 import org.eclipse.jdt.core.dom.BooleanLiteral;
12 import org.eclipse.jdt.core.dom.BreakStatement;
13 import org.eclipse.jdt.core.dom.CastExpression;
14 import org.eclipse.jdt.core.dom.CatchClause;
15 import org.eclipse.jdt.core.dom.CharacterLiteral;
16 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
17 import org.eclipse.jdt.core.dom.ConditionalExpression;
18 import org.eclipse.jdt.core.dom.ConstructorInvocation;
19 import org.eclipse.jdt.core.dom.ContinueStatement;
20 import org.eclipse.jdt.core.dom.DoStatement;
21 import org.eclipse.jdt.core.dom.EnhancedForStatement;
22 import org.eclipse.jdt.core.dom.ExpressionStatement;
23 import org.eclipse.jdt.core.dom.ForStatement;
24 import org.eclipse.jdt.core.dom.IfStatement;
25 import org.eclipse.jdt.core.dom.InfixExpression;
26 import org.eclipse.jdt.core.dom.InstanceofExpression;
27 import org.eclipse.jdt.core.dom.Javadoc;
28 import org.eclipse.jdt.core.dom.LabeledStatement;
29 import org.eclipse.jdt.core.dom.MarkerAnnotation;
30 import org.eclipse.jdt.core.dom.MethodDeclaration;
31 import org.eclipse.jdt.core.dom.Modifier;
32 import org.eclipse.jdt.core.dom.NormalAnnotation;
33 import org.eclipse.jdt.core.dom.NullLiteral;
34 import org.eclipse.jdt.core.dom.NumberLiteral;
35 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
36 import org.eclipse.jdt.core.dom.PrimitiveType;
37 import org.eclipse.jdt.core.dom.QualifiedName;
38 import org.eclipse.jdt.core.dom.QualifiedType;
39 import org.eclipse.jdt.core.dom.ReturnStatement;
40 import org.eclipse.jdt.core.dom.SimpleName;
41 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
42 import org.eclipse.jdt.core.dom.StringLiteral;
43 import org.eclipse.jdt.core.dom.SwitchCase;
44 import org.eclipse.jdt.core.dom.SwitchStatement;
45 import org.eclipse.jdt.core.dom.SynchronizedStatement;
46 import org.eclipse.jdt.core.dom.ThisExpression;
47 import org.eclipse.jdt.core.dom.ThrowStatement;
48 import org.eclipse.jdt.core.dom.TryStatement;
49 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
50 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
51
52 import com.stateofflow.eclipse.metrics.calculators.AbstractASTVisitorCalculator;
53 import com.stateofflow.eclipse.metrics.configuration.MetricsConfiguration;
54 import com.stateofflow.eclipse.metrics.metric.MetricId;
55 import com.stateofflow.eclipse.metrics.metric.MetricPropertyKey;
56
57 public final class LinesOfCodeCalculator extends AbstractASTVisitorCalculator {
58 public static final MetricId METRIC_ID = MetricId.createMethodId(LinesOfCodeCalculator.class);
59 public static final MetricPropertyKey INCLUDE_METHOD_COMMENTS_KEY = new MetricPropertyKey(METRIC_ID, "includeComments");
60 public static final MetricPropertyKey IGNORE_COMMENTS_BLANKS_KEY = new MetricPropertyKey(METRIC_ID, "ignoreBlanks");
61
62 private final MetricsConfiguration configuration;
63 private final LinesOfCode linesOfCode = new LinesOfCode();
64 private final Stack<Integer> nestedClassesLinesOfCode = new Stack<Integer>();
65
66 public LinesOfCodeCalculator(final MetricsConfiguration configuration) {
67 this.configuration = configuration;
68 }
69
70 private void checkAndIncrementLocCount(final ASTNode node) {
71 linesOfCode.checkAndIncrement(getStartLineNumber(node));
72 }
73
74 private boolean checkAndRecurse(final ASTNode node) {
75 checkAndIncrementLocCount(node);
76 return getStartLineNumber(node) != getEndLineNumber(node);
77 }
78
79 private void measure(final ASTNode startNode, final ASTNode endNode) {
80 noteMethodValue(LinesOfCodeCalculator.METRIC_ID, getEndLineNumber(endNode) - getLineNumber(startNode.getStartPosition()) + 1);
81 }
82
83 private void measureConcreteMethod(final MethodDeclaration declaration) {
84 if (configuration.getBoolean(INCLUDE_METHOD_COMMENTS_KEY)) {
85 measureFromStartOfJavaDoc(declaration);
86 } else {
87 measureExcludingJavaDoc(declaration);
88 }
89 noteMethodValue(LinesOfCodeCalculator.METRIC_ID, linesOfCode.getCount());
90 }
91
92 private void measureExcludingJavaDoc(final MethodDeclaration declaration) {
93 if (declaration.getBody() != null) {
94 measureMethodBody(declaration);
95 } else {
96 measureNative();
97 }
98 }
99
100 private void measureNative() {
101 linesOfCode.initialise(0);
102 linesOfCode.setCount(1);
103 }
104
105 private void measureMethodBody(final MethodDeclaration declaration) {
106 linesOfCode.initialise(getStartLineNumber(declaration.getBody()));
107 declaration.getBody().accept(this);
108 }
109
110 private void measureFromStartOfJavaDoc(final MethodDeclaration declaration) {
111 linesOfCode.initialise(getStartLineNumber(declaration));
112 if (declaration.getJavadoc() != null) {
113 declaration.getJavadoc().accept(this);
114 }
115 }
116
117 private void measureSimpleMetric(final MethodDeclaration declaration) {
118 if (configuration.getBoolean(INCLUDE_METHOD_COMMENTS_KEY)) {
119 measure(declaration, declaration);
120 } else {
121 measure(declaration.getName(), declaration);
122 }
123 }
124
125 @Override
126 public boolean visit(final AnonymousClassDeclaration node) {
127 nestedClassesLinesOfCode.push(new Integer(linesOfCode.getCount()));
128 linesOfCode.setCount(0);
129 return super.visit(node);
130 }
131
132 @Override
133 public void endVisit(final AnonymousClassDeclaration node) {
134 linesOfCode.setCount((nestedClassesLinesOfCode.pop()).intValue());
135 super.endVisit(node);
136 }
137
138 @Override
139 public boolean visit(final ArrayAccess node) {
140 return checkAndRecurse(node);
141 }
142
143 @Override
144 public boolean visit(final AssertStatement node) {
145 return checkAndRecurse(node);
146 }
147
148 @Override
149 public boolean visit(final Assignment node) {
150 return checkAndRecurse(node);
151 }
152
153 @Override
154 public boolean visit(final Block node) {
155 return true;
156 }
157
158 @Override
159 public boolean visit(final BooleanLiteral node) {
160 return checkAndRecurse(node);
161 }
162
163 @Override
164 public boolean visit(final BreakStatement node) {
165 return checkAndRecurse(node);
166 }
167
168 @Override
169 public boolean visit(final CastExpression node) {
170 return checkAndRecurse(node);
171 }
172
173 @Override
174 public boolean visit(final CatchClause node) {
175 return checkAndRecurse(node);
176 }
177
178 @Override
179 public boolean visit(final CharacterLiteral node) {
180 return checkAndRecurse(node);
181 }
182
183 @Override
184 public boolean visit(final ClassInstanceCreation node) {
185 return checkAndRecurse(node);
186 }
187
188 @Override
189 public boolean visit(final ConditionalExpression node) {
190 return checkAndRecurse(node);
191 }
192
193 @Override
194 public boolean visit(final ConstructorInvocation node) {
195 return checkAndRecurse(node);
196 }
197
198 @Override
199 public boolean visit(final ContinueStatement node) {
200 return checkAndRecurse(node);
201 }
202
203 @Override
204 public boolean visit(final DoStatement node) {
205 return checkAndRecurse(node);
206 }
207
208 @Override
209 public boolean visit(final EnhancedForStatement node) {
210 return checkAndRecurse(node);
211 }
212
213 @Override
214 public boolean visit(final ExpressionStatement node) {
215 return checkAndRecurse(node);
216 }
217
218 @Override
219 public boolean visit(final ForStatement node) {
220 return checkAndRecurse(node);
221 }
222
223 @Override
224 public boolean visit(final IfStatement node) {
225 return checkAndRecurse(node);
226 }
227
228 @Override
229 public boolean visit(final InfixExpression node) {
230 return checkAndRecurse(node);
231 }
232
233 @Override
234 public boolean visit(final InstanceofExpression node) {
235 return checkAndRecurse(node);
236 }
237
238 @Override
239 public boolean visit(final Javadoc node) {
240 linesOfCode.increment(getEndLineNumber(node) - getStartLineNumber(node) + 1);
241 return false;
242 }
243
244 @Override
245 public boolean visit(final LabeledStatement node) {
246 return checkAndRecurse(node);
247 }
248
249 @Override
250 public boolean visit(final MarkerAnnotation node) {
251 return checkAndRecurse(node);
252 }
253
254 @Override
255 public boolean visit(final MethodDeclaration arg0) {
256 super.visit(arg0);
257 if (isConcrete(arg0)) {
258 if (configuration.getBoolean(IGNORE_COMMENTS_BLANKS_KEY)) {
259 measureConcreteMethod(arg0);
260 } else {
261 measureSimpleMetric(arg0);
262 }
263 }
264 return false;
265 }
266
267 @Override
268 public boolean visit(final Modifier node) {
269 return checkAndRecurse(node);
270 }
271
272 @Override
273 public boolean visit(final NormalAnnotation node) {
274 return checkAndRecurse(node);
275 }
276
277 @Override
278 public boolean visit(final NullLiteral node) {
279 return checkAndRecurse(node);
280 }
281
282 @Override
283 public boolean visit(final NumberLiteral node) {
284 return checkAndRecurse(node);
285 }
286
287 @Override
288 public boolean visit(final ParenthesizedExpression node) {
289 return true;
290 }
291
292 @Override
293 public boolean visit(final PrimitiveType node) {
294 return checkAndRecurse(node);
295 }
296
297 @Override
298 public boolean visit(final QualifiedName node) {
299 return checkAndRecurse(node);
300 }
301
302 @Override
303 public boolean visit(final QualifiedType node) {
304 return checkAndRecurse(node);
305 }
306
307 @Override
308 public boolean visit(final ReturnStatement node) {
309 return checkAndRecurse(node);
310 }
311
312 @Override
313 public boolean visit(final SimpleName node) {
314 return checkAndRecurse(node);
315 }
316
317 @Override
318 public boolean visit(final SingleMemberAnnotation node) {
319 return checkAndRecurse(node);
320 }
321
322 @Override
323 public boolean visit(final StringLiteral node) {
324 return checkAndRecurse(node);
325 }
326
327 @Override
328 public boolean visit(final SwitchCase node) {
329 return checkAndRecurse(node);
330 }
331
332 @Override
333 public boolean visit(final SwitchStatement node) {
334 return checkAndRecurse(node);
335 }
336
337 @Override
338 public boolean visit(final SynchronizedStatement node) {
339 return checkAndRecurse(node);
340 }
341
342 @Override
343 public boolean visit(final ThisExpression node) {
344 return checkAndRecurse(node);
345 }
346
347 @Override
348 public boolean visit(final ThrowStatement node) {
349 return checkAndRecurse(node);
350 }
351
352 @Override
353 public boolean visit(final TryStatement node) {
354 return checkAndRecurse(node);
355 }
356
357 @Override
358 public boolean visit(final VariableDeclarationFragment node) {
359 return checkAndRecurse(node);
360 }
361
362 @Override
363 public boolean visit(final VariableDeclarationStatement node) {
364 return checkAndRecurse(node);
365 }
366
367 }
368