bestPractices.atl 7.31 KB
Newer Older
Raphael PAGE's avatar
Raphael PAGE committed
1
2
3
4
5
6
7
library bestPractices;

--------------------------------------------- AvoidPrintStackTrace ---------------------------------------------

--Goes through all the methods to check if the following rule is followed:
--Avoid printStackTrace()
helper def: avoidPrintStackTrace() : Set(smm!Measure) =
8
9
10
11
	java!MethodInvocation.allInstances()
		-> select (m | m.method.name = 'printStackTrace')
		-> collect (m | thisModule.MeasureAvoidPrintStackTrace(m))
;
12
13
14
15
16
17
18

--------------------------------------------- AvoidFieldNameMatchingMethodName ---------------------------------------------

-- Rule for metrics AvoidFieldNameMatchingMethodName : return the set of class Measures that violates the rule.
helper def: avoidFieldNameMatchingMethodName() : Set(smm!Measure) =
	-- Browse through all class
	java!ClassDeclaration.allInstances()->iterate(i; res : Set(smm!Measure) = Set{} |
19
		-- Foreach FieldDeclaration, check all methods
20
21
		i.bodyDeclarations->iterate(field; resIter : Set(smm!Measure) = Set{} | 
		if field.oclIsTypeOf(java!FieldDeclaration)
22
23
24
25
		then i.bodyDeclarations
			-- Check if the name method and the name field is the same
			->select(method | method.oclIsTypeOf(java!MethodDeclaration) and method.name = field.fragments.first().name)
			->collect(method | thisModule.MesureAvoidFieldNameMatchingMethodName(i, method))
26
27
28
		else res
		endif
	)
29
30
31
32
33
34
35
36
37
38
);

--------------------------------------------- EmptyStatementBlock ---------------------------------------------


--Detects the use of empty statements blocks. These blocks serve no purpose and should be removed
helper def: emptyStatementBlock() : Set(smm!Measure) =
	java!Block.allInstances()
		->select(block | block.statements.isEmpty())
		->collect(block | thisModule.MeasureEmptyStatementBlock(block));
39
40
41
42
43
44
45
46
47
48
49
50

--------------------------------------------- SwitchDensity  ---------------------------------------------
-- Rule for metrics SwitchDensity :
helper def: switchDensity() : Set (smm!Measure) = 
	-- Browse through all Switch Statements
	java!SwitchStatement.allInstances()->iterate(switchCase; res : Set(smm!Measure) = Set{} |
	switchCase.statements
		->select(switchStatement | switchStatement.oclIsTypeOf(java!Block))
		->select(switchStatement | switchStatement.statements <> OclUndefined)
		->select(switchStatement | switchStatement.statements.size() -1 >= 10)
		->collect(switchStatement | thisModule.MeasureSwitchDensity(switchCase))
	);
51
52
53
54
55
56

--------------------------------------------- useAssertTrueInsteadOfAssertEquals  ---------------------------------------------
helper def: useAssertTrueInsteadOfAssertEquals() : Set(smm!Measure) =
	-- Browse through all methods use 
	java!MethodInvocation.allInstances()
	--Check if the method use is assertEqual and a Boolean is used
57
58
		->select(assert | assert.method.name = 'assertEquals')
		->select(assert | thisModule.isWrongUseAssertTrueInsteadOfAssertEquals(assert))
59
60
61
62
63
64
		->collect(assert | thisModule.MesureUseAssertTrueInsteadOfAssertEquals(assert));


helper def: isWrongUseAssertTrueInsteadOfAssertEquals(m:java!MethodInvocation) : Boolean = 
    --Shorten the path m.arguments.last() to lastArgument and check if it's a boolean
	let lastArgument : java!Expression = m.arguments.last() in lastArgument.isBoolean();
65
	
66
67
68
69
70
71
72
73
74
75
76
77
	 --Checks if it's a BooleanLiteral
helper context java!BooleanLiteral def: isBoolean() : Boolean = true;
 --Checks if the type of a Expression is Boolean
helper context java!Expression def: isBoolean() : Boolean =
    self.variable.variablesContainer.isBoolean();
 --Checks if the type of a VariableDeclarationStatement is Boolean
helper context java!VariableDeclarationStatement def: isBoolean() : Boolean =
    self.type.type.name= 'boolean';
 --Use in case of Boolean.TRUE or Boolean.FALSE
helper context java!FieldDeclaration def: isBoolean() : Boolean =
    self.abstractTypeDeclaration.name = 'Boolean';

78
79
80
81
82

--------------------------------------------- AvoidStringBufferField  ---------------------------------------------
-- Rule for metrics AvoidStringBufferField
helper def: avoidStringBufferField() : Set(smm!Measure) =
	java!FieldDeclaration.allInstances()
Oussama EL KOURRI's avatar
Oussama EL KOURRI committed
83
84
		->select(dec | dec.type <> OclUndefined )
		->select(dec | ( dec.type.type.name = 'StringBuffer' or dec.type.type.name = 'StringBuilder'))
85
		->collect(dec | thisModule.MeasureAvoidStringBufferField(dec));
86
87
88
89
90
91
92
93
94
95
96
97
---------------------------------------------UseAssertSameInsteadOfAssertTrue---------------------------------------------
helper def: useAssertSameInsteadOfAssertTrue() : Set(smm!Measure) =
	-- Browse through all methods use 
	java!MethodInvocation.allInstances()
	--Check if the method use is assertTrue and check if == is used
		->select(assert | assert.method.name = 'assertTrue')
		->select(assert | thisModule.isWrongUseAssertSameInsteadOfAssertTrue(assert))
		->collect(assert | thisModule.MesureUseAssertSameInsteadOfAssertTrue(assert));

helper def: isWrongUseAssertSameInsteadOfAssertTrue(m:java!MethodInvocation) : Boolean = 
    --Browse through all arguments of the method assertTrue and see if == is used
	(m.arguments->select(t|t.oclIsTypeOf(java!InfixExpression))->select(t|t.operator.toString() = '==')->collect(t|t).notEmpty());
Hanane HADJI's avatar
Hanane HADJI committed
98
	
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
--------------------------------------------- ForLoopVariableCount ---------------------------------------------

-- Rule for metrics ForLoopVariableCount
helper def: forLoopVariableCount(): Set(smm!Measure) =
	java!ForStatement.allInstances()->select(forStatement |
		forStatement.nbLocalVariableDeclarations() > 1
	)->collect(forStatement | thisModule.MeasureForLoopVariableCount(forStatement));

-- Returns the number of declared local variables in the for loop
helper context java!ForStatement def: nbLocalVariableDeclarations(): Integer =
	self.initializers->iterate(expression; acc: Integer = 0 | 
		acc + expression.nbLocalVariableDeclarations()
	);

-- A loop initializer can contains any Expression but we care about only VariableDeclarationExpression
helper context java!Expression def: nbLocalVariableDeclarations(): Integer =
	0;

helper context java!VariableDeclarationExpression def: nbLocalVariableDeclarations(): Integer =
	self.fragments.size(); -- The fragments collection contains all the variable declarations of an initializer*
						   -- Initializer* : for(int x = 0; ...), "int x = 0" is the initializer part of the for loop
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

--------------------------------------------- AvoidReassigningParameters ---------------------------------------------

helper def: avoidReassigningParameters(): Set(smm!Measure) =
	java!AbstractMethodDeclaration.allInstances()->select(method |
		method.parameters.size() > 0 -- need at least 1 parameter
	)->collect(method |
		method.body.statements->select(statement |
			statement.oclIsTypeOf(java!ExpressionStatement) -- statement must be an expression
		)->collect(expressionStatement |
			expressionStatement.expression
		)->select(expression |
			expression.oclIsTypeOf(java!Assignment) -- the expression must be an assignment
		)->select(assignment |
			assignment.leftHandSide.oclIsTypeOf(java!SingleVariableAccess) -- the receiving end of the assignment must be a variable access
		)->select(assignment |
			method.parameters->collect(singleVariableDeclaration |
				singleVariableDeclaration.name -- for each parameter of the method we retrieve its name
			)->includes(assignment.leftHandSide.variable.name) -- one of the parameter is on the receiving of an assignment
		)->collect(assignment |
			thisModule.MeasureAvoidReassigningParameters(assignment)
		)
		
	)->flatten();