analysis.atl 36.8 KB
Newer Older
Gerson Sunyé's avatar
Gerson Sunyé committed
1
2
3
-- @nsURI smm=http://www.eclipse.org/MoDisco/SMM/1.0.Beta2/smm
-- @nsURI java=http://www.eclipse.org/MoDisco/Java/0.2.incubation/java

Gerson Sunyé's avatar
Gerson Sunyé committed
4
5

module analysis;
Gerson Sunyé's avatar
Gerson Sunyé committed
6
7
create OUT: smm from IN: java;

8
uses design;
9
uses codestyle;
Gerson Sunyé's avatar
Gerson Sunyé committed
10
uses multithreading;
11
uses performance;
12
uses bestPractices;
Roxane MARECHAL's avatar
Roxane MARECHAL committed
13
uses documentation;
14
uses errorProne;
15

Roxane MARECHAL's avatar
Roxane MARECHAL committed
16

Gerson Sunyé's avatar
Gerson Sunyé committed
17
18
19
20
21
22
23
24
25
26
27
28
29
30
rule Java2SMM {
	from
		project: java!Model
	to
		model: smm!SmmModel (
			name <- project.name,
			librairies <- lib
		),
		lib: smm!MeasureLibrary (
			name <- 'Java metrics',
			measureElements <- thisModule.allMeasures(project)
		)
}

E19C506H's avatar
E19C506H committed
31
32
helper def: allMeasures(project: java!Model): Set(smm!Measure) =
	Set{-- Example rule
33
34
		--
		thisModule.numberOfClasses(),
E19C506H's avatar
E19C506H committed
35
			-- Multithreading rules
36
37
		--
		thisModule.dontCallThreadRun(),
E19C506H's avatar
E19C506H committed
38
39
40
			thisModule.avoidThreadGroup(),
			thisModule.useNotifyAllInsteadOfNotify(),
			-- Code Style rules
41
42
		--
		thisModule.shortMethodName(),
E19C506H's avatar
E19C506H committed
43
44
45
46
47
48
49
50
51
			thisModule.tooManyStaticImports(),
			thisModule.avoidDollarSigns(),
			thisModule.shortClassName(),
			thisModule.extendsObject(),
			thisModule.unnecessaryReturn(),
			thisModule.longVariable(),
			
			thisModule.noPackageDeclaration(),
			-- Design rules
52
53
		--
		thisModule.tooManyFields(),
E19C506H's avatar
E19C506H committed
54
55
56
57
58
			thisModule.tooManyMethods(),
			thisModule.returnFromFinallyBlock(),
			thisModule.longInstantiation(),
			thisModule.shortInstantiation(),
			--thisModule.returnEmptyArrayRatherThanNull(),
59
		thisModule.excessiveParameterList(),
E19C506H's avatar
E19C506H committed
60
61
62
63
			thisModule.finalFieldCouldBeStatic(),
			thisModule.signatureDeclareThrowsException(),
			thisModule.avoidThrowingNullPointerException(),
			-- Performance rules
64
		--
Raphael PAGE's avatar
Raphael PAGE committed
65
		thisModule.uselessStringValueOf(),
E19C506H's avatar
E19C506H committed
66
67
68
69
70
71
72
73
			thisModule.tooFewBranchesForASwitchStatement(),
			thisModule.useIndexOfChar(),
			thisModule.avoidPrintStackTrace(),
			thisModule.avoidUsingShortType(),
			thisModule.emptyStatementBlock(),
			thisModule.avoidRethrowingException(),
			thisModule.integerInstantiation(),
			-- Documentation rules
Roxane MARECHAL's avatar
Roxane MARECHAL committed
74
		--
Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
75
		thisModule.commentContent(),
E19C506H's avatar
E19C506H committed
76
77
			thisModule.commentRequired(),
			-- Error prone rules
78
		--
79
		thisModule.missingBreakInSwitch(),
E19C506H's avatar
E19C506H committed
80
81
82
83
84
85
86
87
88
			thisModule.suspiciousEqualsMethodName(),
			thisModule.doNotExtendJavaLangThrowable(),
			thisModule.doNotExtendJavaLangError(),
			thisModule.compareObjectsWithEquals(),
			thisModule.avoidCallingFinalize(),
			thisModule.emptyTryBlock(),
			thisModule.emptyWhileStmt(),
			thisModule.dontImportSun(),
			--thisModule.finalizeShouldBeProtected(),
89
		
90
91
		-- Best practices rules
		thisModule.avoidThrowingNewInstanceOfSameException(),
E19C506H's avatar
E19C506H committed
92
93
			thisModule.switchDensity() --thisModule.avoidStringBufferField()
		};
Raphael PAGE's avatar
Raphael PAGE committed
94
95

-- creates a new Measure when String.valueOf is called to append its argument to a string
E19C506H's avatar
E19C506H committed
96
rule MeasureUselessStringValueOf(method: java!MethodInvocation) {
Raphael PAGE's avatar
Raphael PAGE committed
97
98
99
100
101
102
103
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Useless string value of',
E19C506H's avatar
E19C506H committed
104
105
			shortDescription <- 'No need to call String.valueOf to append to a string;'
					+ ' just use the valueOf() argument directly.'
Raphael PAGE's avatar
Raphael PAGE committed
106
		),
E19C506H's avatar
E19C506H committed
107
108
109
110
		measurement: smm!DirectMeasurement (
			error <- 'The class ' + method.originalCompilationUnit.name + ' violates the'
					+ ' rule useless string value of.'
		)
Raphael PAGE's avatar
Raphael PAGE committed
111
112
113
114
115
116
	do {
		noc; 
	}
}

------------------------------------------------------------------------------------------
Yannis LE BARS's avatar
Yannis LE BARS committed
117
-- A Measure instance if the class violates the rule 'AvoidDollarSigns'.
E19C506H's avatar
E19C506H committed
118
rule MesureAvoidDollarSigns(node: java!ASTNode) {
Yannis LE BARS's avatar
Yannis LE BARS committed
119
120
121
122
123
124
125
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'AvoidDollarSigns',
E19C506H's avatar
E19C506H committed
126
127
			shortDescription <- 'Avoid using dollar signs in'
					+ ' variable/method/class/interface names.'
Yannis LE BARS's avatar
Yannis LE BARS committed
128
129
130
131
132
133
134
135
136
		),
		measurement: smm!DirectMeasurement (
			error <- node.name + ' has dollar in ' + node.originalCompilationUnit.name
		)
	do {
		noc; 
	}
}

Yannis LE BARS's avatar
Yannis LE BARS committed
137
-- A Measure instance if the class violates the rule 'ShortMethodName'.
E19C506H's avatar
E19C506H committed
138
rule MesureShortMethodName(method: java!MethodDeclaration) {
Yannis LE BARS's avatar
Yannis LE BARS committed
139
140
141
142
143
144
145
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'ShortMethodName',
E19C506H's avatar
E19C506H committed
146
147
			shortDescription <- 'Method names names that are very short are not helpful'
					+ ' to the reader.'
Yannis LE BARS's avatar
Yannis LE BARS committed
148
149
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
150
151
			error <- method.name + ' is too short in ' + method.originalCompilationUnit.
					name
Yannis LE BARS's avatar
Yannis LE BARS committed
152
153
154
155
156
		)
	do {
		noc; 
	}
}
Raphael PAGE's avatar
Raphael PAGE committed
157

Marion HUNAULT's avatar
Marion HUNAULT committed
158
-- A Measure instance if the class violates the rule 'ShortClassName'.
E19C506H's avatar
E19C506H committed
159
rule MesureShortClassName(class: java!ClassDeclaration) {
Marion HUNAULT's avatar
Marion HUNAULT committed
160
161
162
163
164
165
166
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'ShortClassName',
E19C506H's avatar
E19C506H committed
167
168
			shortDescription <- 'Short Classnames with fewer than e.g. five characters'
					+ ' are not recommended.'
Marion HUNAULT's avatar
Marion HUNAULT committed
169
170
171
172
173
174
175
176
177
		),
		measurement: smm!DirectMeasurement (
			error <- 'The Class ' + class.name + ' is too short.'
		)
	do {
		noc; 
	}
}

Raphael's avatar
Raphael committed
178
-- creates a new Measure when Thread.run() is used instead of Thread.start()
E19C506H's avatar
E19C506H committed
179
rule MeasureDontCallThreadRun(method: java!MethodInvocation) {
Raphael's avatar
Raphael committed
180
181
182
183
184
185
186
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Don t call Thread.run()',
E19C506H's avatar
E19C506H committed
187
188
189
			shortDescription <- 'Explicitly calling Thread.run() method will execute in'
					+ ' the caller s thread of control. Instead, call Thread.start() for'
					+ ' the intended behavior.'
Raphael's avatar
Raphael committed
190
		),
E19C506H's avatar
E19C506H committed
191
192
193
		measurement: smm!DirectMeasurement (
			error <- 'The class ' + method.originalCompilationUnit.name + ' violates the'
					+ ' rule don t call Thread.run().'
Raphael's avatar
Raphael committed
194
		)
Raphael's avatar
Raphael committed
195
196
197
198
199
	do {
		noc; 
	}
}

Astlo's avatar
Astlo committed
200
-- A Measure instance if the class violates the rule 'TooManyFields'.
E19C506H's avatar
E19C506H committed
201
rule MesureTooManyFields(class: java!ClassDeclaration) {
Gerson Sunyé's avatar
Gerson Sunyé committed
202
203
204
205
206
207
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
Astlo's avatar
Astlo committed
208
			name <- 'TooManyFields',
E19C506H's avatar
E19C506H committed
209
210
			shortDescription <- 'Classes that have too many fields can become unwieldy'
					+ ' and could be redesigned to have fewer field.'
Gerson Sunyé's avatar
Gerson Sunyé committed
211
212
		),
		measurement: smm!DirectMeasurement (
Astlo's avatar
Astlo committed
213
			error <- class.originalCompilationUnit.name + ' have too many fields'
Gerson Sunyé's avatar
Gerson Sunyé committed
214
		)
Raphael's avatar
Raphael committed
215
216
217
218
219
	do {
		noc; 
	}
}

E19C506H's avatar
E19C506H committed
220
221
222
-- creates a new Measure when the parameter of String.indexOf(char) is not of type char
		-- when checking for the index of a single character
rule MeasureUseIndexOfChar(method: java!MethodInvocation) {
Raphael's avatar
Raphael committed
223
224
225
226
227
228
229
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Use index of char',
E19C506H's avatar
E19C506H committed
230
231
			shortDescription <- 'Use String.indexOf(char) when checking for the index of'
					+ ' a single character; it executes faster.'
Raphael's avatar
Raphael committed
232
		),
E19C506H's avatar
E19C506H committed
233
234
235
		measurement: smm!DirectMeasurement (
			error <- 'The class ' + method.originalCompilationUnit.name + ' violates the'
					+ ' rule index of char.'
Raphael's avatar
Raphael committed
236
237
238
239
240
		)
	do {
		noc; 
	}
}
Gerson Sunyé's avatar
Gerson Sunyé committed
241

Raphael PAGE's avatar
Raphael PAGE committed
242
------------------------------------------------------------------------------------------
Gerson Sunyé's avatar
Gerson Sunyé committed
243
244
245
246
247
248
249
250
251
252
rule numberOfClasses() {
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Number of Classes'
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
253
254
			value <- java!ClassDeclaration.allInstances() -> reject(each | each.
					isProxy()) -> size()
Gerson Sunyé's avatar
Gerson Sunyé committed
255
		)
Gerson Sunyé's avatar
Gerson Sunyé committed
256

Gerson Sunyé's avatar
Gerson Sunyé committed
257
258
259
260
	do {
		noc; 
	}
}
261

E19C506H's avatar
E19C506H committed
262
263
-- Rule that creates an instance of Measure for the switch statement with too few
		-- branches passed in parameter
264
rule MeasureTooFewBranchesForASwitchStatement(switchStatement: java!SwitchStatement) {
265
266
267
268
269
270
	to
		om: smm!ObservedMeasure (
			measure <- tooFewBranchesForASwitchStatement,
			measurements <- measurement
		),
		tooFewBranchesForASwitchStatement: smm!DimensionalMeasure (
271
			name <- 'TooFewBranchesForASwitchStatement',
E19C506H's avatar
E19C506H committed
272
273
274
275
276
			shortDescription <- 'Switch statements are intended to be used to support'
					+ ' complex branching behaviour. Using a switch for only a few cases'
					+ ' is ill-advised, since switches are not as easy to understand as'
					+ ' if-then statements. In these cases use the if-then statement to'
					+ ' increase code readability.'
277
278
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
279
280
			error <- 'Too few branches for SwitchStatement in Class : ' + switchStatement.
					originalCompilationUnit.name,
281
282
283
284
285
286
			value <- thisModule.nbBranchesOfASwitchStatement(switchStatement)
		)
	do {
		tooFewBranchesForASwitchStatement; 
	}
}
287

E19C506H's avatar
E19C506H committed
288
289
--------------------------------------------- ShortInstantiation
--- ---------------------------------------------
290
-- A Measure instance if the class violates the rule 'ShortInstantiation'.
E19C506H's avatar
E19C506H committed
291
rule MeasureShortInstantiation(variable: java!CompilationUnit) {
292
293
294
295
296
297
298
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'ShortInstantiation',
E19C506H's avatar
E19C506H committed
299
300
301
302
303
			shortDescription <- 'Calling new Short() causes memory allocation that can be'
					+ ' avoided by the static Short.valueOf(). It makes use of an'
					+ ' internal cache that recycles earlier instances making it more'
					+ ' memory efficient. Note that new Short() is deprecated since JDK 9'
					+ ' for that reason.'
304
		),
E19C506H's avatar
E19C506H committed
305
306
307
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + variable.name + ' an instantiation of Short must'
					+ ' be Short.ValueOf().'
308
309
310
311
312
313
314
		)
		
	do {
		noc; 
	}
}

E19C506H's avatar
E19C506H committed
315
316
--------------------------------------------- LongInstantiation
--- ---------------------------------------------
317
-- A Measure instance if the class violates the rule 'LongInstantiation'.
E19C506H's avatar
E19C506H committed
318
rule MeasureLongInstantiation(variable: java!CompilationUnit) {
319
320
321
322
323
324
325
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'LongInstantiation',
E19C506H's avatar
E19C506H committed
326
327
328
329
330
			shortDescription <- 'Calling new Long() causes memory allocation that can be'
					+ ' avoided by the static Long.valueOf(). It makes use of an internal'
					+ ' cache that recycles earlier instances making it more memory'
					+ ' efficient. Note that new Long() is deprecated since JDK 9 for'
					+ ' that reason.'
331
		),
E19C506H's avatar
E19C506H committed
332
333
334
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + variable.name + ' an instantiation of Long must be'
					+ ' Long.ValueOf().'
335
336
337
338
339
340
341
		)
		
	do {
		noc; 
	}
}

E19C506H's avatar
E19C506H committed
342
343
--------------------------------------------- DoNotExtendJavaLangThrowable 
--- ---------------------------------------------
344
-- A Measure instance if the class violates the rule DoNotExtendJavaLangThrowable.
E19C506H's avatar
E19C506H committed
345
rule MeasureDoNotExtendJavaLangThrowable(variable: java!ClassDeclaration) {
346
347
348
349
350
351
352
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'DoNotExtendJavaLangThrowable ',
E19C506H's avatar
E19C506H committed
353
354
			shortDescription <- 'Extend Exception or RuntimeException instead of'
					+ ' Throwable.'
355
		),
E19C506H's avatar
E19C506H committed
356
357
358
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + variable.name + ' should not extend Throwable but'
					+ ' RuntimeException or Exception .'
359
360
361
362
363
364
		)
		
	do {
		noc; 
	}
}
E19C506H's avatar
E19C506H committed
365

366
-- Returns the number of branches in the switch statement passed in parameter
E19C506H's avatar
E19C506H committed
367
368
helper def: nbBranchesOfASwitchStatement(switchStatement: java!SwitchStatement): Integer =
	switchStatement.statements -> select(each | each.oclIsTypeOf(java!SwitchCase)).size();
369

370
-- Returns the number of Fields in Class
E19C506H's avatar
E19C506H committed
371
helper def: numberFieldsInClasse(s: java!ClassDeclaration): Integer =
372
	-- Return the number of FieldDeclaration in a class.
E19C506H's avatar
E19C506H committed
373
	s.bodyDeclarations -> select(r | r.oclIsTypeOf(java!FieldDeclaration)) -> size();
Martin's avatar
Martin committed
374

375
-- Returns the number of breaks of the switch statement passed in parameter
E19C506H's avatar
E19C506H committed
376
377
helper def: nbBreakStatementOfASwitchStatement(ss: java!SwitchStatement): Integer =
	ss.statements -> select(each | each.oclIsTypeOf(java!BreakStatement)).size();
378
379

-- Returns the number of expressions of the switch statement passed in parameter
E19C506H's avatar
E19C506H committed
380
381
382
383
384
385
386
387
388
389
390
391
helper def: nbExpressionsStatementOfASwitchStatement(ss: java!SwitchStatement): Integer =
	ss.statements -> select(each | each.oclIsTypeOf(java!ExpressionStatement)).size();

-- Returns the number of intentional fall-through (empty switch cases) of a
		-- switchStatement
helper def: nbIntentionalFallThroughOfASwitchStatement(ss: java!SwitchStatement): Integer
		=
	thisModule.nbBranchesOfASwitchStatement(ss) - thisModule.
			nbExpressionsStatementOfASwitchStatement(ss);

-- Creates an instance of Measure for the switch statement missing one or more break
		-- statements
392
393
394
395
396
397
398
399
400
-- To test, use input model : missing-break-in-switch.xmi
rule createMeasureForMissingBreakInSwitch(ss: java!SwitchStatement) {
	to
		om: smm!ObservedMeasure (
			measure <- missingBreakInSwitch,
			measurements <- measurement
		),
		missingBreakInSwitch: smm!DimensionalMeasure (
			name <- 'Missing break in Switch',
E19C506H's avatar
E19C506H committed
401
402
403
			shortDescription <- 'Switch statements without break or return statements for'
					+ ' each case option may indicate problematic behaviour. Empty cases'
					+ ' are ignored as these indicate an intentional fall-through.'
404
405
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
406
407
			error <- 'Missing breaks in Switch in Class : ' + ss.originalCompilationUnit.
					name + '',
408
			-- Indicates the number of breaks missing in the switch statement
E19C506H's avatar
E19C506H committed
409
410
411
			value <- (thisModule.nbBranchesOfASwitchStatement(ss) - thisModule.
					nbIntentionalFallThroughOfASwitchStatement(ss)) - thisModule.
					nbBreakStatementOfASwitchStatement(ss)
412
413
414
415
416
417
		)
	do {
		missingBreakInSwitch; 
	}
}

Martin's avatar
Martin committed
418
-- A Measure instance if the class violates the rule 'TooManyMethods'.
E19C506H's avatar
E19C506H committed
419
rule MesureTooManyMethods(class: java!ClassDeclaration) {
Martin's avatar
Martin committed
420
421
422
423
424
425
426
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'TooManyMethods',
E19C506H's avatar
E19C506H committed
427
428
429
			shortDescription <- 'A class with too many methods is probably a good suspect'
					+ ' for refactoring, in order to reduce its complexity and find a way'
					+ ' to have more fine grained objects.'
Martin's avatar
Martin committed
430
431
		),
		measurement: smm!DirectMeasurement (
Martin ARS's avatar
Martin ARS committed
432
			error <- class.originalCompilationUnit.name + ' has too many methods'
Martin's avatar
Martin committed
433
434
435
436
437
438
		)

	do {
		noc; 
	}
}
Martin ARS's avatar
Martin ARS committed
439

440
-- A Measure instance if the class violates the rule ReturnFromFinallyBlock.
E19C506H's avatar
E19C506H committed
441
rule MesureReturnFromFinallyBlock(method: java!MethodDeclaration) {
442
443
444
445
446
447
448
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'returnFromFinallyBlock',
E19C506H's avatar
E19C506H committed
449
450
			shortDescription <- 'Avoid returning from a finally block, this can discard'
					+ ' exceptions.'
451
452
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
453
454
455
			error <- 'The method ' + method.name + ' in the class ' + method.
					originalCompilationUnit.name + ' has a return statement in a finally'
					+ ' block.'
456
457
458
459
460
		)
	do {
		noc; 
	}
}
Martin ARS's avatar
Martin ARS committed
461
462

-- A Measure instance if the class violates the rule 'TooManyStaticImports'.
E19C506H's avatar
E19C506H committed
463
rule MesureTooManyStaticImports(class: java!CompilationUnit) {
Martin ARS's avatar
Martin ARS committed
464
465
466
467
468
469
470
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'TooManyStaticImports',
E19C506H's avatar
E19C506H committed
471
472
473
474
475
476
			shortDescription <- 'If you overuse the static import feature, it can make'
					+ ' your program unreadable and unmaintainable, polluting its'
					+ ' namespace with all the static members you import. Readers of your'
					+ ' code (including you, a few months after you wrote it) will not'
					+ ' know which class a static member comes from (Sun 1.5 Language'
					+ ' Guide).'
Martin ARS's avatar
Martin ARS committed
477
478
479
480
481
482
483
		),
		measurement: smm!DirectMeasurement (
			error <- class.name + ' has too many static imports'
		)
	do {
		noc; 
	}
Raphael's avatar
Raphael committed
484
485
}

Raphael PAGE's avatar
Raphael PAGE committed
486
-- creates a new Measure when the method printStackTrace is used
E19C506H's avatar
E19C506H committed
487
rule MeasureAvoidPrintStackTrace(method: java!MethodInvocation) {
Raphael PAGE's avatar
Raphael PAGE committed
488
489
490
491
492
493
494
		to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Avoid print stack trace',
E19C506H's avatar
E19C506H committed
495
			shortDescription <- 'Avoid printStackTrace(); use a logger call instead.'
Raphael PAGE's avatar
Raphael PAGE committed
496
		),
E19C506H's avatar
E19C506H committed
497
498
499
		measurement: smm!DirectMeasurement (
			error <- 'The class ' + method.originalCompilationUnit.name + ' violates the'
					+ ' rule avoid print stack trace.'
Raphael PAGE's avatar
Raphael PAGE committed
500
501
502
503
504
		)
	do {
		noc; 
	}
}
Raphael's avatar
Raphael committed
505
506

-- creates a new Measure when Thread.run() is used instead of Thread.start()
E19C506H's avatar
E19C506H committed
507
rule measureAvoidThreadGroup(variable: java!VariableDeclarationFragment) {
Raphael's avatar
Raphael committed
508
509
510
511
512
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
513
		noc: smm!DimensionalMeasure (
Raphael's avatar
Raphael committed
514
			name <- 'Avoid Thread Group',
E19C506H's avatar
E19C506H committed
515
516
517
			shortDescription <- 'Avoid using java.lang.ThreadGroup; although it is'
					+ ' intended to be used in a threaded environment it contains methods'
					+ ' that are not thread-safe.'
Raphael's avatar
Raphael committed
518
		),
E19C506H's avatar
E19C506H committed
519
520
521
		measurement: smm!DirectMeasurement (
			error <- 'The class ' + variable.originalCompilationUnit.name + ' violates'
					+ ' the rule avoid thread group.'
Raphael's avatar
Raphael committed
522
523
		)
		
Martin ARS's avatar
Martin ARS committed
524
525
526
	do {
		noc; 
	}
Raphael PAGE's avatar
Raphael PAGE committed
527
}
528

E19C506H's avatar
E19C506H committed
529
530
531
532
533
--------------------------------------------- AvoidThrowingNewInstanceOfSameException
--- ---------------------------------------------
-- A Measure instance if the class violates the rule
		-- 'AvoidThrowingNewInstanceOfSameException'.
rule MeasureAvoidThrowingNewInstanceOfSameException(catch: java!CatchClause) {
534
535
536
537
538
539
540
    to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'AvoidThrowingNewInstanceOfSameException',
E19C506H's avatar
E19C506H committed
541
542
543
			shortDescription <- 'Catch blocks that merely rethrow a caught exception'
					+ ' wrapped inside a new instance of the same type only add to code'
					+ ' size and runtime complexity.'
544
		),
E19C506H's avatar
E19C506H committed
545
546
547
548
		measurement: smm!DirectMeasurement (
			error <- 'The class ' + catch.originalCompilationUnit.name + ' has a method'
					+ ' that rethrows a caught exception wrapped inside a new instance of'
					+ ' the same type.'
549
550
551
552
553
554
		)
	do {
		noc; 
	}
}

E19C506H's avatar
E19C506H committed
555
556
--------------------------------------------- ReturnEmptyArrayRatherThanNull
--- ---------------------------------------------
557
-- creates a new Measure when a method returns an empty method rather than null
E19C506H's avatar
E19C506H committed
558
rule MesureReturnEmptyArrayRatherThanNull(method: java!ReturnStatement) {
559
560
561
562
563
564
565
    to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'ReturnEmptyArrayRatherThanNull',
E19C506H's avatar
E19C506H committed
566
567
			shortDescription <- 'For any method that returns an array, it is a better to'
					+ ' return an empty array rather than a null reference.'
568
569
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
570
571
			error <- 'A method in the class ' + method.originalCompilationUnit.name + ''
					+ ' returns null instead of an empty array.'
572
573
574
575
576
		)
	do {
		noc; 
	}
}
577

E19C506H's avatar
E19C506H committed
578
579
--------------------------------------------- ExcessiveParameterList
--- ---------------------------------------------
580
-- creates a new Measure when a method has more than 10 parameters
E19C506H's avatar
E19C506H committed
581
rule MesureExcessiveParameterList(method: java!MethodDeclaration) {
582
583
584
585
586
587
588
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'ExcessiveParameterList',
E19C506H's avatar
E19C506H committed
589
590
			shortDescription <- 'Methods with numerous parameters are a challenge to'
					+ ' maintain, especially if most of them share the same datatype.'
591
		),
E19C506H's avatar
E19C506H committed
592
593
594
		measurement: smm!DirectMeasurement (
			error <- 'The method ' + method.name + ' in the class ' + method.
					originalCompilationUnit.name + ' has an excessive parameter list.'
595
596
597
598
599
600
		)
	do {
		noc; 
	}
}

601
-- A Measure instance if the class violates the rule 'AvoidFieldNameMatchingMethodName'.
E19C506H's avatar
E19C506H committed
602
603
rule MesureAvoidFieldNameMatchingMethodName(class: java!ClassDeclaration, method:
		java!MethodDeclaration) {
604
605
606
607
608
609
610
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'AvoidFieldNameMatchingMethodName',
E19C506H's avatar
E19C506H committed
611
612
613
614
615
			shortDescription <- 'It can be confusing to have a field name with the same'
					+ ' name as a method. While this is permitted, having information'
					+ ' (field) and actions (method) is not clear naming. Developers'
					+ ' versed in Smalltalk often prefer this approach as the methods'
					+ ' denote accessor methods.'
616
617
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
618
619
			error <- 'In the ' + class.name + ' class you have an field and an method'
					+ ' with the same name : ' + method.name
620
621
622
623
624
		)
	do {
		noc; 
	}
}
625
626
627
628
629
630
631
632
633
634

-- Creates a measure instance when rule 'UseNotifyAllInsteadOfNotify' is violated
rule MeasureUseNotifyAllInsteadOfNotify(method: java!MethodInvocation) {
	to
		om: smm!ObservedMeasure (
			measure <- useNotifyAllInsteadOfNotify,
			measurements <- measurement
		),
		useNotifyAllInsteadOfNotify: smm!DimensionalMeasure (
			name <- 'UseNotifyAllInsteadOfNotify',
E19C506H's avatar
E19C506H committed
635
636
637
638
			shortDescription <- 'Thread.notify() awakens a thread monitoring the object.'
					+ ' If more than one thread is monitoring, then only one is chosen.'
					+ ' The thread chosen is arbitrary; thus its usually safer to call'
					+ ' notifyAll() instead.'
639
640
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
641
642
			error <- 'Used notify() instead of notifyAll() in Class : ' + method.
					originalCompilationUnit.name
643
644
645
646
647
		)
	do {
		useNotifyAllInsteadOfNotify; 
	}
}
Roxane MARECHAL's avatar
Roxane MARECHAL committed
648

649
--- Creates a measure instance for each element that violates the rule : CommentRequired
E19C506H's avatar
E19C506H committed
650
651
rule MeasureCommentRequired(element: java!BodyDeclaration, violatedProperties:
		Set(String)) {
Roxane MARECHAL's avatar
Roxane MARECHAL committed
652
653
654
655
656
657
658
	to
		om: smm!ObservedMeasure (
			measure <- commentRequired,
			measurements <- measurement
		),
		commentRequired: smm!DimensionalMeasure (
			name <- 'CommentRequired',
E19C506H's avatar
E19C506H committed
659
660
			shortDescription <- 'Denotes whether comments are required (or unwanted) for'
					+ ' specific language elements.'
Roxane MARECHAL's avatar
Roxane MARECHAL committed
661
662
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
663
664
665
666
			error <- 'Violated the properties  ' + violatedProperties + ' in Class: ' +
					element.originalCompilationUnit.name + ' -> ' + element.oclType().
					name + ': ' + element.modifier.visibility + ' ' + element.
					getBodyDeclarationName()
Roxane MARECHAL's avatar
Roxane MARECHAL committed
667
668
669
		)
		do {
		commentRequired; 
E19C506H's avatar
E19C506H committed
670
	}
Roxane MARECHAL's avatar
Roxane MARECHAL committed
671
672
}

Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
673
674
675
676
677
678
679
680
rule MeasureCommentContent(element: Sequence(String)){
	to
		om: smm!ObservedMeasure (
			measure <- commentContent,
			measurements <- measurement
		),
		commentContent: smm!DimensionalMeasure (
			name <- 'CommentContent',
E19C506H's avatar
E19C506H committed
681
682
			shortDescription <- 'A rule for the politically correct… we don’t want to'
					+ ' offend anyone.'
Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
683
684
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
685
			error <- 'The words ' + element + ' were found in a comment '
Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
686
687
		)
		do {
E19C506H's avatar
E19C506H committed
688
689
		commentContent; 
	}
Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
690
691
692
	
}

693
--- Returns the name of a BodyDeclaration
E19C506H's avatar
E19C506H committed
694
695
helper context java!BodyDeclaration def: getBodyDeclarationName(): String =
	self.name;
696

E19C506H's avatar
E19C506H committed
697
698
699
700
--- In FielDeclaration, the attribute 'name' is NULL, this information is contained in
--- "fragments" instead
helper context java!FieldDeclaration def: getBodyDeclarationName(): String =
	self.fragments.first().name;
Roxane MARECHAL's avatar
Roxane MARECHAL committed
701

702
--- Returns the AnnotationTypeDeclaration corresponding to the given BodyDeclaration
Roxane MARECHAL's avatar
Roxane MARECHAL committed
703
-- This is necessary because BodyDeclaration.annotations returns Sequence(!IN<unamed>)
E19C506H's avatar
E19C506H committed
704
705
706
707
708
709
710
helper def: getAnnotationTypeDeclarationsFromBodyDeclaration(elem: java!BodyDeclaration):
		Set(java!AnnotationTypeDeclaration) =
	java!AnnotationTypeDeclaration.allInstances() -> select(annotTypeDec | annotTypeDec.
			usagesInTypeAccess -> exists(usage | (usage.eContainer().eContainer().name =
			elem.name).and(usage.eContainer().eContainer().modifier.visibility = elem.
			modifier.visibility).and(usage.eContainer().eContainer().
			originalCompilationUnit.name = elem.originalCompilationUnit.name)));
Glenn PLOUHINEC's avatar
Glenn PLOUHINEC committed
711

712
-- A Measure instance if the class violates the rule 'SuspiciousEqualsMethodName'
E19C506H's avatar
E19C506H committed
713
rule MeasureSuspiciousEqualsMethodName(method: java!MethodDeclaration) {
714
715
716
717
718
719
720
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Suspicious Equals Method Name',
E19C506H's avatar
E19C506H committed
721
722
723
			shortDescription <- 'The method name and parameter number are suspiciously'
					+ ' close to equals(Object), which can denote an intention to'
					+ ' override the equals(Object) method.'
724
725
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
726
727
			error <- 'The class ' + method.originalCompilationUnit.name + ' has a'
					+ ' suspicious \'equals\' method name : ' + method.toString()
728
729
		)
	do {
E19C506H's avatar
E19C506H committed
730
		noc; 
731
732
733
	}
}

Glenn PLOUHINEC's avatar
Glenn PLOUHINEC committed
734
-- A Measure instance if the class violates the rule 'AvoidUsingShortType'
E19C506H's avatar
E19C506H committed
735
rule MeasureAvoidUsingShortType(typeShort: java!VariableDeclarationStatement) {
Glenn PLOUHINEC's avatar
Glenn PLOUHINEC committed
736
737
738
739
740
741
742
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Avoid using short type',
E19C506H's avatar
E19C506H committed
743
744
745
746
747
748
749
			shortDescription <- 'Java uses the \'short\' type to reduce memory usage, not'
					+ ' to optimize calculation.' + ' In fact, the JVM does not have any'
					+ ' arithmetic capabilities for the short type:' + ' the JVM must'
					+ ' convert the short into an int, do the proper calculation and'
					+ ' convert' + ' the int back to a short. Thus any storage gains'
					+ ' found through use of the \'short\' type' + ' may be offset by'
					+ ' adverse impacts on performance.'
Glenn PLOUHINEC's avatar
Glenn PLOUHINEC committed
750
751
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
752
753
			error <- 'The class ' + typeShort.originalCompilationUnit.name + ' has'
					+ ' \'short\' type variable.'
Glenn PLOUHINEC's avatar
Glenn PLOUHINEC committed
754
755
		)
	do {
E19C506H's avatar
E19C506H committed
756
		noc; 
Glenn PLOUHINEC's avatar
Glenn PLOUHINEC committed
757
758
	}
}
759
760

-- A Measure instance if the class violates the rule 'EmptyStatementBlock'
E19C506H's avatar
E19C506H committed
761
rule MeasureEmptyStatementBlock(block: java!Block) {
762
763
764
765
766
767
768
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'Empty Statement Block',
E19C506H's avatar
E19C506H committed
769
770
			shortDescription <- 'Empty block statements serve no purpose and should be'
					+ ' removed.'
771
772
		),
		measurement: smm!DirectMeasurement (
E19C506H's avatar
E19C506H committed
773
774
			error <- 'The class ' + block.originalCompilationUnit.name + ' has an empty'
					+ ' statement block.'
775
776
		)
	do {
E19C506H's avatar
E19C506H committed
777
		noc; 
778
779
	}
}
780

E19C506H's avatar
E19C506H committed
781
782
--------------------------------------------- DoNotExtendJavaLangError 
--- ---------------------------------------------
783
-- A Measure instance if the class violates the rule DoNotExtendJavaLangError.
E19C506H's avatar
E19C506H committed
784
rule MeasureDoNotExtendJavaLangError(variable: java!ClassDeclaration) {
785
786
787
788
789
790
791
792
793
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'DoNotExtendJavaLangError ',
			shortDescription <- 'Errors are system exceptions. Do not extend them.'
		),
E19C506H's avatar
E19C506H committed
794
795
796
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + variable.name + ' Do not extend Error, Errors are'
					+ ' system exceptions.'
797
798
799
800
801
802
		)
		
	do {
		noc; 
	}
}
803

E19C506H's avatar
E19C506H committed
804
805
--------------------------------------------- MeasureFinalFieldCouldBeStatic 
--- ---------------------------------------------
806
-- A Measure instance if the class violates the rule MeasureFinalFieldCouldBeStatic.
E19C506H's avatar
E19C506H committed
807
rule MeasureFinalFieldCouldBeStatic(field: java!FieldDeclaration) {
808
809
810
811
812
813
814
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'FinalFieldCouldBeStatic',
E19C506H's avatar
E19C506H committed
815
816
817
			shortDescription <- 'If a final field is assigned to a compile-time constant,'
					+ ' it could be made static, thus saving overhead in each object at'
					+ ' runtime.'
818
		),
E19C506H's avatar
E19C506H committed
819
820
821
822
		measurement: smm!DirectMeasurement (
			error <- 'The field ' + field.fragments -> collect(i | i.name) -> first() + ''
					+ ' could be static in the class ' + field.originalCompilationUnit.
					name + '.'
823
824
825
826
827
828
		)
		
	do {
		noc; 
	}
}
Louis QUESTEL's avatar
Louis QUESTEL committed
829

E19C506H's avatar
E19C506H committed
830
831
--------------------------------------------- MeasureExtendsObject 
--- ---------------------------------------------
Louis QUESTEL's avatar
Louis QUESTEL committed
832
-- A Measure instance if the class violates the rule ExtendsObject.
E19C506H's avatar
E19C506H committed
833
rule MeasureExtendsObject(variable: java!ClassDeclaration) {
Louis QUESTEL's avatar
Louis QUESTEL committed
834
835
836
837
838
839
840
841
842
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'ExtendsObject',
			shortDescription <- 'No need to explicitly extend Object.'
		),
E19C506H's avatar
E19C506H committed
843
844
845
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + variable.name + ' No need to explicitly extend'
					+ ' Object.'
Louis QUESTEL's avatar
Louis QUESTEL committed
846
847
848
849
850
851
		)
		
	do {
		noc; 
	}
}
852

E19C506H's avatar
E19C506H committed
853
854
--------------------------------------------- SwitchDensity 
--- ---------------------------------------------
855
-- A Measure instance if the class violates the rule SwitchDensity.
E19C506H's avatar
E19C506H committed
856
rule MeasureSwitchDensity(switch: java!SwitchStatement) {
857
858
859
860
861
862
863
864
865
866
	
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'SwitchDensity ',
			shortDescription <- 'Statement to label ratio is too high (> 10)'
		),
E19C506H's avatar
E19C506H committed
867
868
869
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + switch.originalCompilationUnit.name + ' a switch'
					+ ' case contains too many statements.'
870
871
872
873
		)
	do {
		noc; 
	}
E19C506H's avatar
E19C506H committed
874
875
876
877
}

--------------------------------------------- SignatureDeclareThrowsException 
--- ---------------------------------------------
878
-- A Measure instance if the class violates the rule SignatureDeclareThrowsException.
E19C506H's avatar
E19C506H committed
879
rule MeasureSignatureDeclareThrowsException(class: java!ClassDeclaration) {
880
881
882
883
884
885
886
887
	
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'SignatureDeclareThrowsException ',
E19C506H's avatar
E19C506H committed
888
889
			shortDescription <- 'A method/constructor should not explicitly throw the'
					+ ' generic java.lang.Exception'
890
		),
E19C506H's avatar
E19C506H committed
891
892
893
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + class.name + ' a method/constructor explicitly'
					+ ' throws the generic java.lang.Exception.'
894
895
896
897
		)
	do {
		noc; 
	}
E19C506H's avatar
E19C506H committed
898
}
899

E19C506H's avatar
E19C506H committed
900
901
--------------------------------------------- UnnecessaryReturn 
--- ---------------------------------------------
902
-- A Measure instance if the class violates the rule UnnecessaryReturn.
E19C506H's avatar
E19C506H committed
903
rule MeasureUnnecessaryReturn(state: java!ReturnStatement) {
904
905
906
907
908
909
910
911
912
913
	
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'UnnecessaryReturn ',
			shortDescription <- 'Avoid the use of unnecessary return statements.'
		),
E19C506H's avatar
E19C506H committed
914
915
916
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + state.originalCompilationUnit.name + ' an'
					+ ' unnecessary return was used.'
917
918
919
920
		)
	do {
		noc; 
	}
921
922
}

E19C506H's avatar
E19C506H committed
923
924
--------------------------------------------- MeasureCompareObjectsWithEquals 
--- ---------------------------------------------
925
--A measure instance if the class violates the rule MeasureCompareObjectsWithEquals.
E19C506H's avatar
E19C506H committed
926
rule MeasureCompareObjectsWithEquals(expression: java!InfixExpression) {
927
928
929
930
931
932
933
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'CompareObjectsWithEquals',
E19C506H's avatar
E19C506H committed
934
935
			shortDescription <- 'Use equals() to compare object references; avoid'
					+ ' comparing them with ==.'
936
		),
E19C506H's avatar
E19C506H committed
937
938
939
		measurement: smm!DirectMeasurement (
			error <- 'The Class ' + expression.originalCompilationUnit.name + ' is using'
					+ ' == instead of equals() to compare objects.'
940
941
942
943
944
		)
		
	do {
		noc; 
	}
E19C506H's avatar
E19C506H committed
945
}
946

E19C506H's avatar
E19C506H committed
947
948
949
950
--------------------------------------------- AvoidRethrowingException 
--- ---------------------------------------------
--A Measure instance if the class violates the rule AvoidRethrowingException.
rule MeasureAvoidRethrowingException(statement: java!TryStatement) {
951
952
953
954
955
956
957
958
959
 		to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'AvoidRethrowingException ',
			shortDescription <- 'Avoid merely rethrowing an exception.'
		),
E19C506H's avatar
E19C506H committed
960
961
962
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + statement.originalCompilationUnit.name + ' an'
					+ ' exception was caught and merely rethrown.'
963
964
965
966
		)
	do {
		noc; 
	}
E19C506H's avatar
E19C506H committed
967
968
969
970
}

--------------------------------------------- IntegerInstantiation
--- ---------------------------------------------
Alexis Pineau's avatar
Alexis Pineau committed
971
-- A Measure instance if the class violates the rule 'IntegerInstantiation'.
E19C506H's avatar
E19C506H committed
972
rule MeasureIntegerInstantiation(variable: java!CompilationUnit) {
Alexis Pineau's avatar
Alexis Pineau committed
973
974
975
976
977
978
979
	to
		om: smm!ObservedMeasure (
			measure <- noc,
			measurements <- measurement
		),
		noc: smm!DimensionalMeasure (
			name <- 'IntegerInstantiation',
E19C506H's avatar
E19C506H committed
980
981
982
983
984
			shortDescription <- 'Calling new Integer() causes memory allocation that can'
					+ ' be avoided by the static Integer.valueOf(). It makes use of an'
					+ ' internal cache that recycles earlier instances making it more'
					+ ' memory efficient. Note that new Integer() is deprecated since JDK'
					+ ' 9 for that reason.'
Alexis Pineau's avatar
Alexis Pineau committed
985
		),
E19C506H's avatar
E19C506H committed
986
987
988
		measurement: smm!DirectMeasurement (
			error <- 'In the Class ' + variable.name + ' an instantiation of Integer must'
					+ ' be Integer.ValueOf().'
Alexis Pineau's avatar
Alexis Pineau committed
989
990
991
992
993
994
995
		)
		
	do {
		noc; 
	}
}

E19C506H's avatar
E19C506H committed
996
997
--------------------------------------------- LongVariable 
--- ---------------------------------------------
998
-- A Measure instance if the variable violates the rule LongVariable.
E19C506H's avatar
E19C506H committed
999
rule MeasureLongVariable(variable: java!VariableDeclarationFragment) {
1000
	to