errorProne.atl 29.1 KB
Newer Older
1
2
3
4
library errorProne;

---------------------------------- Missing break in switch---------------------------------------------

5
--- Returns a set of measures for every switch statement without a break statement for each case option
6
7
8
helper def: missingBreakInSwitch(): Set(smm!Measure) = 
	java!SwitchStatement.allInstances()
		-> select (switchStatement | thisModule.switchStatementContainsMissingBreaks(switchStatement))
9
		-> collect (switchStatement | thisModule.MeasureMissingBreakInSwitch(switchStatement))
10
11
;

12
--- Returns true if the switch statement contains missing breaks, false otherwise 
13
14
15
16
helper def: switchStatementContainsMissingBreaks(ss: java!SwitchStatement): Boolean = 
	-- If the number of switch cases (omitting those that empty => indicates intentional fallout) is bigger than
	-- the number of break statements => we don't have a break statement for every switch case 
	-- in that case, return true, else false
17
18
	(thisModule.nbBranchesOfASwitchStatement(ss) - thisModule.nbEmptySwitchCasesOfASwitchStatement(ss)) > thisModule.nbBreakStatementOfASwitchStatement(ss)
	
19
20
;

21
22
23
24
25
26
--------------------------------------------- DoNotExtendJavaLangThrowable ---------------------------------------------

-- Rule for metrics DoNotExtendJavaLangThrowable
helper def: doNotExtendJavaLangThrowable() : Set(smm!Measure) =
	-- select all class with a superTyper
	java!ClassDeclaration.allInstances()->select(it | it.superClass <> OclUndefined)
27
28
		-- select all class create by the user
		->select(it2| it2.proxy = false)
29
		-- select all class who extend Throwable
30
		->select(it3| it3.superClass.type.name = 'Throwable' or it3.superClass.type.name = 'java.lang.Throwable')
31
		-- collect all results and send an error message
32
33
		->collect(it4|thisModule.MeasureDoNotExtendJavaLangThrowable(it4))
	;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
--------------------------------------------- SuspiciousEqualsMethodName---------------------------------------------

--Detects the declaration of methods whose name and parameters looks like the equals(Object) method, which denote an intention to override the equals(Object) method.
--A method that looks like equals(Object) is named 'equals', or 'equal' wich is a common typo, and  the parameters and return type can be wrong typed.
helper def: suspiciousEqualsMethodName() : Set(smm!Measure) =
	java!MethodDeclaration.allInstances() 
		-> select(method | method.hasParameters() and method.hasReturnType())
		-> select(method | thisModule.isWrongEqualsDeclaration(method)) 
		-> collect(method | thisModule.MeasureSuspiciousEqualsMethodName(method));

--Detects if a method looks like the equals(Object) method.
helper def: isWrongEqualsDeclaration(method : java!MethodDeclaration) : Boolean = 
	method.name = 'equals' or method.name = 'equal' and --'equal' method name can be a typo
	(
		(
			method.parameters.size() = 1 and --there is only one parameter and the type of this parameter is wrong, or the return type of the method is wrong, or both.
		 	not(method.parameters.first().type.type.name = 'Object') or 
			not(method.returnType.type.name = 'boolean')
		)
		or
		(
			method.parameters.size() = 2 and --there are two parameters, and everything is well typed
			method.parameters->forAll(param | param.type.type.name = 'Object') and
			method.returnType.type.name = 'boolean'
		)
	)
	or
	(
		method.name = 'equal' and --the method is well typed but there is a typo
		method.parameters.size() = 1 and 
		method.parameters.first().type.type.name = 'Object' and
		method.returnType.type.name = 'boolean'
	);
	
	

	
--Allows to have the signature of a method as a String.
helper context java!MethodDeclaration def: toString() : String = 
	if self.hasReturnType() then 
		self.returnType.type.name
	else
		''
	endif 
	+ ' ' + self.name + '(' + 
	if self.hasParameters() then
		let params : String = self.parameters->collect(param | param.type.type.name + ' ' + param.name).toString()
		in params.substring(12, params.size()-2).regexReplaceAll('\'', '') 
	else
		''
	endif
	+ ')';
			
--Indicates whether a MethodDeclaration has a return type.
helper context java!MethodDeclaration def: hasReturnType() : Boolean = 
	not self.returnType.oclIsUndefined();

--Indicates whether a MethodDeclaration has parameters.
helper context java!MethodDeclaration def: hasParameters() : Boolean = 
	not self.parameters.isEmpty();

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
--------------------------------------------- CompareObjectsWithEquals---------------------------------------------

--Detects a wrong usage of objects comparison, which use the '==' operator instead of 'equals' method.
helper def: compareObjectsWithEquals() : Set(smm!Measure) =
	java!InfixExpression.allInstances()
	->select(expression | expression.operator.name = '==')
	->select(expression | thisModule.isWrongCompareObjectsUse(expression))
	->collect(expression | thisModule.MeasureCompareObjectsWithEquals(expression));

--Detects if the right and left operands are Objects.
helper def: isWrongCompareObjectsUse(expression : java!InfixExpression) : Boolean = 
	thisModule.isObject(expression.leftOperand) and thisModule.isObject(expression.rightOperand);

	
----------isObject() helpers
--Indicates if an operand is an Object, using polymorphism, with various '<java!Expression>.isObject()' helpers.
helper def: isObject(operand : java!Expression) : Boolean = 
	operand.isObject();

--Default helper: an unrecognized type is evaluated.
helper context java!Expression def: isObject() : Boolean = 
	false;

helper context java!SingleVariableAccess def: isObject() : Boolean = 
	thisModule.variableIsObject(self.variable);

--An attribute 'this.xxx' of the class is evaluated
helper context java!FieldAccess def: isObject() : Boolean = 
	thisModule.variableIsObject(self.field.variable);

--The object 'this' is currently evaluated.
helper context java!ThisExpression def: isObject() : Boolean = 
	self.originalCompilationUnit.types
		->exists(typeInstance | (typeInstance.oclIsTypeOf(java!ClassDeclaration)));

--A constructor is used in the evaluation.
helper context java!ClassInstanceCreation def: isObject() : Boolean = 
	self.type.type.oclIsTypeOf(java!ClassDeclaration);
----------
----------variableIsObject() helpers
--Differents variables types.
helper def: variableIsObject(variable : java!VariableDeclaration) : Boolean = 
	variable.variableIsObject();

helper context java!SingleVariableDeclaration def: variableIsObject() : Boolean = 
	self.type.type.oclIsTypeOf(java!ClassDeclaration);

helper context java!VariableDeclarationFragment def: variableIsObject() : Boolean = 
	self.variablesContainer.type.type.oclIsTypeOf(java!ClassDeclaration);
----------


147
--------------------------------------------------------------------------------------------------------
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

------------------------------------------- AvoidCallingFinalize----------------------------------------------
-- Rule for metrics AvoidCallingFinalize
helper def: avoidCallingFinalize() : Set(smm!Measure) = 
	java!MethodInvocation.allInstances()
		->select(methode | methode.method.name = 'finalize')
		->collect(methode | thisModule.MeasureAvoidCallingFinalize(methode));

------------------------------------------- EmptyTryBlock----------------------------------------------
-- Rule for metrics EmptyTryBlock
helper def: emptyTryBlock() : Set(smm!Measure) =
	java!TryStatement.allInstances()
		->select( t | t.body.statements.size() = 0)
		->collect(t | thisModule.MeasureEmptyTryBlock(t));

------------------------------------------- EmptyWhileStmt----------------------------------------------
-- Rule for metrics EmptyWhileStmt
helper def: emptyWhileStmt() : Set(smm!Measure) =
	java!WhileStatement.allInstances()
Oussama EL KOURRI's avatar
Oussama EL KOURRI committed
167
168
		->select( w | w.body.oclIsTypeOf(java!Block))
		->select(w | w.body.statements.isEmpty())
169
170
171
172
173
174
175
176
177
178
179
180
		->collect(w | thisModule.MeasureEmptyWhileStmt(w));
------------------------------------------- MeasureDontImportSun----------------------------------------------
-- Rule for metrics DontImportSun
helper def: dontImportSun() : Set(smm!Measure) = 
	java!Package.allInstances()
		->select(p | p.name = 'sun' and p.ownedElements.size() = 0 and p.proxy = true)
		->collect(p | thisModule.MeasureDontImportSun(p.model.compilationUnits));

-------------------------------------------- FinalizeShouldBeProtected ---------------------------------------
-- Rule for metrics FinalizeShouldBeProtected
helper def: finalizeShouldBeProtected() : Set(smm!Measure) = 
	java!MethodDeclaration.allInstances()
181
182
		->select(m | m.modifier <> OclUndefined)
		->select(m | m.name = 'finalize' and m.modifier.visibility.toString() <> 'protected')
183
184
		->collect(m | thisModule.MesureFinalizeShouldBeProtected(m));

Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198

--------------------------------------------------------------------------------------------------------------
--------------------------------------------DontUseFloatTypeForLoopIndices------------------------------------

helper def: dontUseFloatTypeForLoopIndices() : Set(smm!Measure) = 
	java!ForStatement.allInstances()
		-> select(loop | loop.initializers.type.type = '//@orphanType.2')
		-> collect(loop | thisModule.MeasureDontUseFloatTypeForLoopIndices())
;
	
	
	
	
	
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
--------------------------------------------- EmptySwitchStatement ---------------------------------------------


--Detects the use of empty switch statements. These blocks serve no purpose and should be removed
helper def: emptySwitchStatement() : Set(smm!Measure) =
	java!SwitchStatement.allInstances()
		->select(switchStatement | switchStatement.statements.isEmpty())
		->collect(switchStatement | thisModule.MeasureEmptySwitchStatement(switchStatement));

------------------------------------------ EmptySynchronizedBlock ---------------------------------------------


--Detects the use of empty synchronized block. These blocks serve no purpose and should be removed
helper def: emptySynchronizedBlock() : Set(smm!Measure) =
	java!SynchronizedStatement.allInstances()
	   ->select(synchronizedBlock | synchronizedBlock.body.statements.isEmpty() )
	   ->collect(synchronizedBlock | thisModule.MeasureEmptySynchronizedBlock(synchronizedBlock));
		
---------------------------------------- EmptyFinallyBlock----------------------------------------------
-- Rule for metrics EmptyFinallyBlock
helper def: emptyFinallyBlock() : Set(smm!Measure) =
	java!TryStatement.allInstances()
		->select( finallyBlock | finallyBlock.finally.statements.isEmpty())
		->collect(finallyBlock| thisModule.MeasureEmptyFinallyBlock(finallyBlock));


----------------------------------------- EmptyFinalizer----------------------------------------------
-- Rule for metrics EmptyFinalizer
helper def: emptyfinalizeMethod() : Set(smm!Measure) =
	java!MethodDeclaration.allInstances()
		->select( finalizeMethod | finalizeMethod.name = 'finalize' and finalizeMethod.body.statements.isEmpty())
		->collect(finalizeMethod| thisModule. MeasureEmptyFinalizer(finalizeMethod));



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313

--- Issues #780, #784, #799, #819, #862, #871

--- helper AvoidCatchingNPE 
--- get all the catchClause inside the class
--- check if the name of type for the typeAccess is equals to 'NullPointerException'
--- if it is the case make collection and make a call for MeasureAvoidCatchingNPE rule
--- with the detected VariableDeclaration
helper def: AvoidCatchingNPE() : Set(smm!Measure) =
	java!CatchClause.allInstances()
		->select (w | w.exception.type.type.name = 'NullPointerException')
		->collect(w | thisModule.MeasureAvoidCatchingNPE(w));


--- helper AvoidEnumAsIdentifier 

-- modisco do not allow to convert a class with error
-- and a field with enum decleration is already detected by Java compiler
-- so we need at least to change the name of enum to Enum to work
--- get all the declared variable inside the class
--- check if their name are defined and 
--- if it's different than reserved key word 'enum''
--- if it is not the case make collection and make a call for MeasureAvoidEnumAsIdentifier rule
--- with the detected VariableDeclaration
helper def: AvoidEnumAsIdentifier() : Set(smm!Measure) =
	java!VariableDeclaration.allInstances()
		->select (w | w.name <> OclUndefined )
		->select (w | w.name = 'enum')
		->collect(w | thisModule.MeasureAvoidEnumAsIdentifier(w));


--- helper CloneMethodMustBePublic 
--- get all the declaredMethods inside the class
--- check if is clone methode or not
--- check if its modifier is defined 
--- check if its visibilty access is different from public
--- if it is the case make collection and make a call for MeasureExcessiveClassLength rule
--- with the detected MethodDeclaration
helper def: CloneMethodMustBePublic() : Set(smm!Measure) =
	java!MethodDeclaration.allInstances()
		->select (w | w.modifier <> OclUndefined )
		->select (w | w.name = 'clone')
		->select (w | w.modifier <> 'public')
		->collect(w | thisModule.MeasureCloneMethodMustBePublic(w));


--- helper EmptyInitializer 
--- get all the the used Initializer make a selection on all those that  
--- has nothing inside theire body (empty initialize), 
--- check if the contained statments size equals to 0 
--- if there is collect them and make a call for MeasureEmptyInitializer rule 
--- with the detected Initializer
helper def: EmptyInitializer() : Set(smm!Measure) = 
	java!Initializer.allInstances()
		->select( w | w.body.statements.size() = 0)
		->collect(w | thisModule.MeasureEmptyInitializer(w));

--- helper UnconditionalIfStatement 
--- get all the the used ifstatements and make a selection on all those that contains
--- an only expression in which its type is BooleanLiteral type like (true) or (false)
--- if there is collect them and make a call for MeasureUnconditionalIfStatement rule
--- with the detected ifstatments 

helper def: UnconditionalIfStatement() : Set(smm!Measure) =
	java!IfStatement.allInstances()
		->select( w | w.expression.oclIsTypeOf(java!BooleanLiteral))
		->collect(w | thisModule.MeasureUnconditionalIfStatement(w));


--- helper UseProperClassLoader 
--- get all the MethodInvocation inside the class
--- check if the invocked method name is equals to getClassLoader
--- if it is the case make collection and make a call for MeasureUseProperClassLoader rule
--- with the detected MethodInvocation
helper def: UseProperClassLoader() : Set(smm!Measure) =
	java!MethodInvocation.allInstances()
		->select (w | w.method.name='getClassLoader')
		->collect(w | thisModule.MeasureUseProperClassLoader(w));


314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
-----------------------------------------avoidCatchingThrowable----------------------------------------------
-- Rule for metrics avoidCatchingThrowable
helper def: avoidCatchingThrowable() : Set(smm!Measure) =
	java!CatchClause.allInstances()
		->select(catch | catch.exception.type.type.name = 'Throwable')
		->collect(catch | thisModule.MeasureAvoidCatchingThrowable(catch));

-----------------------------------------DoNotCallGarbageCollectionExplicitly----------------------------------------------
-- Rule for metrics DoNotCallGarbageCollectionExplicitly
helper def: doNotCallGarbageCollectionExplicitly() : Set(smm!Measure) =
	java!MethodInvocation.allInstances()
		->select(method | method.method.name = 'gc' and method.method.proxy)
		->collect(method | thisModule.MeasureDoNotCallGarbageCollectionExplicitly(method));

-----------------------------------------EmptyCatchBlock----------------------------------------------
-- Rule for metrics EmptyCatchBlock
helper def: emptyCatchBlock() : Set(smm!Measure) =
	java!CatchClause.allInstances()
		->select(catch | catch.body.statements.size() = 0)
		->collect(catch | thisModule.MeasureEmptyCatchBlock(catch));

-----------------------------------------ImportFromSamePackage----------------------------------------------
-- Rule for metrics ImportFromSamePackage
helper def: importFromSamePackage() : Set(smm!Measure) =
	java!ImportDeclaration.allInstances()
		->select(import | import.importedElement = import.originalCompilationUnit.package)
		->collect(import | thisModule.MeasureImportFromSamePackage(import));

Thorrigan's avatar
Thorrigan committed
342
343
344
345
346
347
348
349
-- ------------------------------------------- JUnitSpelling ---------------------------------------------
--- Helper for issue JUnitSpelling : Some JUnit framework methods are easy to misspell !("tearDown", "setUp").
helper def: junitSpelling() : Set(smm!Measure) = 
    java!MethodDeclaration.allInstances()
    -> select(i | ((i.name <> 'tearDown' and i.name <> 'setUp') and (i.name.toLower() = 'teardown' or i.name.toLower() = 'setup')))
	-> collect(i | thisModule.MeasureJUnitSpelling(i));


350
351
352
353
354
-----------------------------------------MethodWithSameNameAsEnclosingClass----------------------------------------------
-- Rule for metrics MethodWithSameNameAsEnclosingClass
helper def: methodWithSameNameAsEnclosingClass() : Set(smm!Measure) =
	java!MethodDeclaration.allInstances()
		->select(method | method.name = method.abstractTypeDeclaration.name)
Ronan GUEGUEN's avatar
Ronan GUEGUEN committed
355
		->collect(method | thisModule.MeasureMethodWithSameNameAsEnclosingClass(method));
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372

------------------------------------------- testClassWithoutTest ------------------------------------------------------------------------------------

helper def: testClassWithoutTest() : Set(smm!Measure) =
	java!ClassDeclaration.allInstances()
	-> reject(each | each.isProxy())
	-> reject(each| each.name.size() < 4)
	-> select(each | each.name.substring(each.name.size()-3, each.name.size()) = 'Test')
	-> select(each | each.nbTestMethod() = 0)
	-> collect(each | thisModule.MeasureTestClassWithoutTest(each.originalCompilationUnit));

helper context java!ClassDeclaration  def: nbTestMethod() : Integer  =
	self.bodyDeclarations
	-> select(bodyDeclaration | bodyDeclaration.oclIsTypeOf(java!MethodDeclaration))
	-> select(bodyDeclaration | bodyDeclaration.name.size() > 4)
	-> select(each | each.name.substring(1, 4) = 'test')
	-> size();
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
	
--------------------------------------------- DoNotCallSystemExit ---------------------------------------------

-- Detects if the method "exit" of the System or Runtime class is called
helper def: doNotCallSystemExit(): Set(smm!Measure) =
	java!MethodInvocation.allInstances()->select(invocation |
		invocation.isSystemExit() or invocation.isRuntimeExit()
	)->collect(invocation | 
		thisModule.MeasureDoNotCallSystemExit(invocation)
	);

-- Returns the name of the class in which the invocated method is defined
helper context java!MethodDeclaration def: getMethodClassName(): String =
	if self.abstractTypeDeclaration.oclIsUndefined() then
		'Object'
	else
		self.abstractTypeDeclaration.name
	endif;

-- Returns true if the called method is the method "exit" of the System class, false otherwise
helper context java!MethodInvocation def: isSystemExit(): Boolean =
	self.method.name = 'exit' and self.method.getMethodClassName() = 'System';

-- Returns true if the called method is the method "exit" of the Runtime class, false otherwise
helper context java!MethodInvocation def: isRuntimeExit(): Boolean =
	self.method.name = 'exit' and self.method.getMethodClassName() = 'Runtime';
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444

--------------------------------------------- NullAssignment  ---------------------------------------------

-- Helper for issue NullAssignment : return a Measure for each null assignment.
helper def: nullAssignment() : Set(smm!Measure) =
	-- Browse through all null assignement 
	java!NullLiteral.allInstances()
	->select(it | it.eContainer().oclIsTypeOf(java!Assignment))
	-> select(it | it.eContainer().eContainer().oclIsTypeOf(java!ExpressionStatement))
	-> select(it | it.eContainer().operator.toString() = '=')
	-> collect(it |thisModule.MesureNullAssignment(it))
;


--------------------------------------------- DetachedTestCase  ---------------------------------------------

-- Helper for issue DetachedTestCase : return a Measure for each detached test case.
helper def: detachedTestCase() : Set(smm!Measure) =
	java!CompilationUnit.allInstances()
	-> select(each | each.imports.size() > 0)
	-> select(each | each.hasJunitAnnotation().size()>0) 
	-> select(it | it.types <> OclUndefined)	
	->iterate(c; res : Set(smm!Measure) = Set{} |
	c.types
		->select(it1 | it1.oclIsTypeOf(java!ClassDeclaration))
		->iterate(c1; res1 : Set(smm!Measure) = Set{} |
	 		c1.bodyDeclarations 
			-- select method has public or default visibility, non-static access, no arguments, no return value, has no annotations
			-> select(bodyDeclaration | bodyDeclaration.oclIsTypeOf(java!MethodDeclaration))
			-> select(bodyDeclaration | bodyDeclaration.modifier.visibility.toString() = 'public' or bodyDeclaration.modifier.visibility.toString() = 'none')
			-> select(bodyDeclaration | bodyDeclaration.modifier.static.toString() = 'false')
			-> select(bodyDeclaration | bodyDeclaration.returnType.oclIsTypeOf(java!TypeAccess))
			-> select(bodyDeclaration | bodyDeclaration.returnType.type.oclIsTypeOf(java!PrimitiveTypeVoid))
			-> select(bodyDeclaration | bodyDeclaration.parameters.isEmpty())
			-> select(bodyDeclaration | bodyDeclaration.annotations.isEmpty())
			-> collect(bodyDeclaration | thisModule.MesureDetachedTestCase(c))
		)
	)
;

--Indicates whether a CompilationUnit has a Junit Annotation.
helper context java!CompilationUnit def: hasJunitAnnotation() : Boolean =
	self.imports
		-> select(it | it.oclIsTypeOf(java!ImportDeclaration))
		-> select(it | it.importedElement.oclIsTypeOf(java!AnnotationTypeDeclaration))
		-> select(it | it.importedElement.package.package.package.name = 'junit')		
445
446
447
448
449
450
451
452
;

--------------------------------------------- SuspiciousHashcodeMethodName ---------------------------------------------

helper def: suspiciousHashcodeMethodName(): Set(smm!Measure) =
	java!MethodDeclaration.allInstances()
		->select(md | md.name <> 'hashCode')
		->select(md | md.name.toLower() = 'hashcode')
453
		->collect(md | thisModule.MeasureSuspiciousHashcodeMethodName(md));
Matthieu Gayraud's avatar
Matthieu Gayraud committed
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594

-- Helpers for the UseEqualsToCompareString measure
--- Collect every utilisation of == or != that compares two strings
--- Return : A set of measures that contains each use of the aforementioned operator
helper def : useEqualsToCompareString() : Set(mm!Measure) =
	java!InfixExpression.allInstances()
	-> select(expression | expression.operator.name = '==' or expression.operator.name = '!=')
	-> select(expression | thisModule.stringComparison(expression))
	-> collect(expression | thisModule.MeasureUseEqualsToCompareStrings(expression));

--- Check if both operand of an infix expression are string
--- Param expression : A java infix expression
--- Return true : two strings are compared
--- else return false
helper def : stringComparison(expression : java!InfixExpression) : Boolean =
	thisModule.isString(expression.leftOperand) or thisModule.isString(expression.rightOperand);

--- Called by stringComparison
--- Dispatch the use of isString according to the context
--- Param operand : A java expression
--- Return true : operand is a string
--- false otherwise
helper def : isString(operand : java!Expression) : Boolean =
	operand.isString();

--- Called if an operand is an ArrayAccess
--- Return true : the element is a string,
--- return false otherwise
helper context java!ArrayAccess def: isString() : Boolean =
	thisModule.variableIsString(self.array);
	
--- Called if an operand is a CastExpression
--- Return true : the current element is casted as a string
--- return false otherwise
helper context java!CastExpression def: isString() : Boolean =
	thisModule.variableIsString(self.type);

--- Called if an operand is a field access 
--- Return true : the field access is a string
--- return false otherwise
helper context java!FieldAccess def: isString() : Boolean = 
	thisModule.variableIsString(self.field.variable);

--- Called if an operand is a method invocation
--- Return true : the return type is String
--- else return false
helper context java!MethodInvocation def : isString() : Boolean =
	thisModule.variableIsString(self.method);

--- Called if an operand is a parenthesized expression
--- Return true : the type of the expression is String
--- return false otherwise
helper context java!ParenthesizedExpression def : isString() : Boolean =
	thisModule.variableIsString(self.expression);
	
--- Called if an operand is a single variable access
--- Return true : the variable is a string
--- else return false
helper context java!SingleVariableAccess def : isString() : Boolean =
	thisModule.variableIsString(self);
	
--- Called if an operand is a string literal
--- Always return true
helper context java!StringLiteral def : isString() : Boolean = 
	true;

--- Called if the operand is 'this'
--- Return true : the expression is of type String
--- return false otherwise
helper context java!ThisExpression def: isString() : Boolean = 
	self.originalCompilationUnit.types
		->exists(name | name = 'String');

--- Called if the context is not one of the aforementioned one
--- when isString() is called. Always return false
helper context java!Expression def: isString() : Boolean =
	false;

-- ############################## variableIsString() helpers ##############################
--- Dispatch the call of variableIsString according to the context
--- Param variable : A java declaration of a variable
--- Return true : variable is a string
--- return false otherwise
helper def: variableIsString(variable : java!VariableDeclaration) : Boolean = 
	variable.variableIsString();

--- Called when the context is MethodDeclaration
--- See : variableIsString(variable : java!VariableDeclaration)
helper context java!AbstractMethodDeclaration def: variableIsString() : Boolean =
	thisModule.variableIsString(self.returnType) or self.name = 'toString';

--- Called when the context is an AbstractVariablesContainer
--- See : variableIsString(variable : java!VariableDeclaration)
helper context java!AbstractVariablesContainer def: variableIsString() : Boolean =
	thisModule.variableIsString(self.type);

--- Called when the context is a SingleVariableAccess
--- See : variableIsString(variable : java!VariableDeclaration)
helper context java!SingleVariableAccess def: variableIsString() : Boolean = 
	thisModule.variableIsString(self.variable);
	
--- Called when the context is a SingleVariableDeclaration
--- See : variableIsString(variable : java!VariableDeclaration)
helper context java!SingleVariableDeclaration def: variableIsString() : Boolean = 
	self.type.type.name = 'String';

--- Called when the context is AbstractMethodDeclaration
--- See : variableIsString(variable : java!VariableDeclaration)
helper context java!TypeAccess def: variableIsString() : Boolean =
	self.type.name = 'String';

--- Called when the context is a VariableDeclarationFragment
--- See : variableIsString(variable : java!VariableDeclaration)
helper context java!VariableDeclarationFragment def: variableIsString() : Boolean = 
	thisModule.variableIsString(self.variablesContainer);

--- Default case, allows to deal with OclUndefined
--- Always return false
helper context OclAny def: variableIsString() : Boolean =
	false;

-- ############################## getMethodName() helpers ##############################
--- Dispatch the call of getMethodName according  to the 
--- container context
--- Return the name of the method in which the expression is
helper def: getMethodName(expression : java!Expression) : String =
	--let expr : OclAny = expr.eContainer() in expression.eContainer().getMethodName();
	expression.getMethodName();
	
--- Called when the context is a MethodDeclaration
--- Return self.name : the name of the method
helper context java!MethodDeclaration def: getMethodName() : String = 
	self.name;

--- Called when the context is an ASTNode 
--- Return the name of the method where the ASTNode by looking at its container
helper context java!ASTNode def: getMethodName() : String = 
	thisModule.getMethodName(self.eContainer());

--- Default case, allows to deal with OclUndefined
helper context OclAny def : getMethodName() : String = 
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
	'';

--------------------------------------------- MissingSerialVersionUID ---------------------------------------------

--- Indicates if a VariableDeclarationFragment has no SerialVersion UID.
helper def: missingSerialVersionUID() : Set(smm!Measure) =
	java!VariableDeclarationFragment.allInstances() -> select(i | i.name = 'serialVersionUID')
		-> collect (i | thisModule.MeasureMissingSerialVersionUID(i));

--------------------------------------------- NonStaticInitializer ---------------------------------------------

--- Indicates if an initializer before the constructor is non-static. 
helper def: nonStaticInitializer() : Set(smm!Measure) =
	java!Initializer.allInstances() -> select(i | i.modifier <> OclUndefined)
		-> select(i | i.modifier.static = false)
		-> collect (i | thisModule.MeasureNonStaticInitializer(i));

--------------------------------------------- SimpleDateFormatNeedsLocale ---------------------------------------------

--- Indicates if a SimpleDateFormat variable has no Locale parameter
helper def: simpleDateFormatNeedsLocale() : Set(smm!Measure) =
	java!VariableDeclarationFragment.allInstances()
		-> select(i | i.initializer.oclIsTypeOf(java!ArrayCreation) = false and i.initializer.oclIsTypeOf(java!ArrayInitializer) = false and i.initializer.oclIsTypeOf(java!NumberLiteral) = false) --because ArrayCreation, ArrayInitializer and NumberLitteral don't have initializer.arguments
		-> select(i | i.initializer <> OclUndefined) -> select(i | i.initializer.arguments.size() <= 1 and i.initializer.type.type.name = 'SimpleDateFormat')
		-> collect (i | thisModule.MeasureSimpleDateFormatNeedsLocale(i));

--------------------------------------------- NonCaseLabelInSwitchStatement ---------------------------------------------

--- Indicates if a non-case label is present in a switch statement.
helper def: nonCaseLabelInSwitchStatement() : Set(smm!Measure) =
	java!LabeledStatement.allInstances()
		-> select(i | i.name <> OclUndefined)
		-> select(i | i.name <> 'case :' and i.name <> 'default:')
		-> collect (i | thisModule.MeasureNonCaseLabelInSwitchStatement(i));
629