errorProne.atl 6.55 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
library errorProne;

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

-- Returns a set of measures for each switch statement that violates the rule : missing break in switch
helper def: missingBreakInSwitch(): Set(smm!Measure) = 
	java!SwitchStatement.allInstances()
		-> select (switchStatement | thisModule.switchStatementContainsMissingBreaks(switchStatement))
		-> collect (switchStatement | thisModule.createMeasureForMissingBreakInSwitch(switchStatement))
;

-- Returns true if the switch statement contains missing breaks, false otherwise 
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
	(thisModule.nbBranchesOfASwitchStatement(ss) - thisModule.nbIntentionalFallThroughOfASwitchStatement(ss)) > thisModule.nbBreakStatementOfASwitchStatement(ss)
;

20
21
22
23
24
25
--------------------------------------------- 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)
26
27
		-- select all class create by the user
		->select(it2| it2.proxy = false)
28
		-- select all class who extend Throwable
29
		->select(it3| it3.superClass.type.name = 'Throwable' or it3.superClass.type.name = 'java.lang.Throwable')
30
		-- collect all results and send an error message
31
32
		->collect(it4|thisModule.MeasureDoNotExtendJavaLangThrowable(it4))
	;
33
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
--------------------------------------------- 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();

94
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
--------------------------------------------- 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);
----------


146
--------------------------------------------------------------------------------------------------------