Commit 0e03c7a0 authored by Matthieu Gayraud's avatar Matthieu Gayraud
Browse files

Fix issue #868

parent 27803354
This diff is collapsed.
...@@ -130,6 +130,7 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = ...@@ -130,6 +130,7 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
thisModule.suspiciousHashcodeMethodName(), thisModule.suspiciousHashcodeMethodName(),
thisModule.testClassWithoutTest(), thisModule.testClassWithoutTest(),
thisModule.UnconditionalIfStatement(), thisModule.UnconditionalIfStatement(),
thisModule.useEqualsToCompareString(),
thisModule.UseProperClassLoader(), thisModule.UseProperClassLoader(),
-- Best practices rules -- Best practices rules
...@@ -1542,6 +1543,31 @@ rule MeasureUseArraysAsList(w: java!CompilationUnit) { ...@@ -1542,6 +1543,31 @@ rule MeasureUseArraysAsList(w: java!CompilationUnit) {
} }
} }
-- UseEqualsToCompareStrings
--- Create a new measure to show a wrongful use of == or != to compare two Strings
--- Param - expression : an infix expression (i.e. LeftOperand operation RightOperand)
rule MeasureUseEqualsToCompareStrings(expression : java!InfixExpression) {
to
om: smm!ObservedMeasure (
measure <- noc,
measurements <- measurement
),
noc: smm!DimensionalMeasure(
name <- 'UseEqualsToCompareStrings',
shortDescription <- 'Use the methode equals() to compare strings.'
+'The use of == and != should be prohibited'
),
measurement : smm!DirectMeasurement(
error <- 'The method ' + thisModule.getMethodName(expression) +
' in the class' + expression.originalCompilationUnit.name +
' is using ' + expression.operator.toString() +
' instead of equals() to compare strings'
)
do {
noc;
}
}
--- 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 --- 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) { rule MeasureUseIndexOfChar(method : java!MethodInvocation) {
to to
......
...@@ -443,3 +443,145 @@ helper def: suspiciousHashcodeMethodName(): Set(smm!Measure) = ...@@ -443,3 +443,145 @@ helper def: suspiciousHashcodeMethodName(): Set(smm!Measure) =
->select(md | md.name <> 'hashCode') ->select(md | md.name <> 'hashCode')
->select(md | md.name.toLower() = 'hashcode') ->select(md | md.name.toLower() = 'hashcode')
->collect(md | thisModule.MeasureSuspiciousHashcodeMethodName(md)); ->collect(md | thisModule.MeasureSuspiciousHashcodeMethodName(md));
-- 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 =
'';
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment