diff --git a/input/avoid-using-native-code.xmi b/input/avoid-using-native-code.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..6aa447c5fb3808e4fc8958cbc02428b64465c8ae
--- /dev/null
+++ b/input/avoid-using-native-code.xmi
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/missing-serial-version-uid.xmi b/input/missing-serial-version-uid.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..a0635a88a34bd3b8ca0cf0e5cb4f9a73ef3fe39a
--- /dev/null
+++ b/input/missing-serial-version-uid.xmi
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/non-case-label-in-switch-statement.xmi b/input/non-case-label-in-switch-statement.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..0a45ef9f23273a2910b5ad84e66dd67aed511d5a
--- /dev/null
+++ b/input/non-case-label-in-switch-statement.xmi
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/non-static-initializer.xmi b/input/non-static-initializer.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..cfbfe9752a265ac5ac019a7443eea2dab7e75dd9
--- /dev/null
+++ b/input/non-static-initializer.xmi
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/simple-date-format-needs-locale.xmi b/input/simple-date-format-needs-locale.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..a0cd1fa8fcc2f3ef9ada3cd97c0f01f4084a6117
--- /dev/null
+++ b/input/simple-date-format-needs-locale.xmi
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/uncommented-empty-constructor.xmi b/input/uncommented-empty-constructor.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..16044e121a513cb9ff78e15f6eefd5316b9b3d85
--- /dev/null
+++ b/input/uncommented-empty-constructor.xmi
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/uncommented-empty-method-body.xmi b/input/uncommented-empty-method-body.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..8592b3a045bee4012789382bb2279d010a9cfbe3
--- /dev/null
+++ b/input/uncommented-empty-method-body.xmi
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/use-short-array-initializer.xmi b/input/use-short-array-initializer.xmi
new file mode 100644
index 0000000000000000000000000000000000000000..d30385fb58cf68d72374c57a78084406b4fa8b67
--- /dev/null
+++ b/input/use-short-array-initializer.xmi
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/atl/analysis.atl b/src/main/atl/analysis.atl
index 86cc4213113c23fbb51ed99f1de26ca589239db9..fadb7da8cb6e240ea948bcbffcc361c69313c8b5 100644
--- a/src/main/atl/analysis.atl
+++ b/src/main/atl/analysis.atl
@@ -47,6 +47,7 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
thisModule.avoidDollarSigns(),
thisModule.avoidPrefixingMethodParameters(),
thisModule.duplicateImport(),
+ thisModule.avoidUsingNativeCode(),
thisModule.extendsObject(),
thisModule.fieldDeclarationsShouldBeAtStartOfClass(),
thisModule.genericsNaming(),
@@ -57,7 +58,11 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
thisModule.shortMethodName(),
thisModule.shortVariableName(),
thisModule.tooManyStaticImports(),
+ --thisModule.AvoidDollarSigns(),
+ thisModule.shortClassName(),
+ thisModule.extendsObject(),
thisModule.unnecessaryReturn(),
+ thisModule.useShortArrayInitializer(),
-- Design rules
--
@@ -108,6 +113,9 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
--
thisModule.commentContent(),
thisModule.commentRequired(),
+ thisModule.uncommentedEmptyConstructor(),
+ thisModule.uncommentedEmptyMethodBody(),
+
-- Error prone rules
--
@@ -132,7 +140,11 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
thisModule.importFromSamePackage(),
thisModule.junitSpelling(),
thisModule.missingBreakInSwitch(),
+ thisModule.missingSerialVersionUID(),
+ thisModule.nonCaseLabelInSwitchStatement(),
+ thisModule.nonStaticInitializer(),
thisModule.nullAssignment(),
+ thisModule.simpleDateFormatNeedsLocale(),
thisModule.suspiciousEqualsMethodName(),
thisModule.suspiciousHashcodeMethodName(),
thisModule.testClassWithoutTest(),
@@ -167,6 +179,10 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
-- thisModule.methodWithSameNameAsEnclosingClass(),
+ -- Best practicices rules
+ --
+ thisModule.avoidThrowingNewInstanceOfSameException(),
+ thisModule.switchDensity()
};
@@ -516,6 +532,27 @@ rule MeasureAvoidUsingShortType(typeShort : java!VariableDeclarationStatement) {
}
}
+-- ----------------------------------------- AvoidUsingNativeCode ------------------------------------------------------------------------------------
+
+---creates a new Measure when a Java Native Interface (JNI) calls unecessary reliance(s).
+rule MeasureAvoidUsingNativeCode(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'AvoidUsingNativeCode',
+ shortDescription <- 'Unnecessary reliance on Java Native Interface (JNI) calls directly reduces application portability and increases the maintenance burden.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The method '+ classDeclaration.method.name + ' violates the rule AvoidUsingNativeCode.'
+ )
+ do {
+ noc;
+ }
+}
+
-- ------------------------------------------- BigIntegerInstantiation ---------------------------------------------
--- creates a Measure when a BigInteger is instantiated with a "new BigInteger()" statement.
rule MeasureBigIntegerInstantiation(variable : java!CompilationUnit) {
@@ -573,7 +610,6 @@ rule MeasureByteInstantiation(variable : java!CompilationUnit) {
measurement: smm!DirectMeasurement (
error<-'In the Class '+ variable.name + ' an instantiation of Byte must be Byte.valueOf().'
)
-
do {
noc;
}
@@ -1369,6 +1405,69 @@ rule MeasureMisLeadingVariableName(variable :java!VariableDeclarationFragment) {
}
}
+-- ----------------------------------------- MissingSerialVersionUID ------------------------------------------------------------------------------------
+
+---creates a new Measure if a serializable class does not provide a serialVersionUID field.
+rule MeasureMissingSerialVersionUID(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'Missing Serial Version UID',
+ shortDescription <- 'Serializable classes should provide a serialVersionUID field. The serialVersionUID field is also needed for abstract base classes. Each individual class in the inheritance chain needs an own serialVersionUID field. See also Should an abstract class have a serialVersionUID.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The class '+ classDeclaration.name + ' violates the rule Missing Serial Version UID.'
+ )
+ do {
+ noc;
+ }
+}
+
+-- ----------------------------------------- NonCaseLabelInSwitchStatement ------------------------------------------------------------------------------------
+
+---creates a new Measure when a non-case label is present in a switch statement.
+rule MeasureNonCaseLabelInSwitchStatement(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'NonCaseLabelInSwitchStatement',
+ shortDescription <- 'A non-case label (e.g. a named break/continue label) was present in a switch statement. This legal, but confusing. It is easy to mix up the case labels and the non-case labels.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The label '+ classDeclaration.name + ' violates the rule NonCaseLabelInSwitchStatement.'
+ )
+ do {
+ noc;
+ }
+}
+
+-- ----------------------------------------- NonStaticInitializer ------------------------------------------------------------------------------------
+
+---creates a new Measure when a non-static initializer (just prior to invoking the constructor) is called.
+rule MeasureNonStaticInitializer(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'NonStaticInitializer',
+ shortDescription <- 'A non-static initializer block will be called any time a constructor is invoked (just prior to invoking the constructor). While this is a valid language construct, it is rarely used and is confusing.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The initializer '+ classDeclaration.name + ' violates the rule NonStaticInitializer.'
+ )
+ do {
+ noc;
+ }
+}
+
-- ----------------------------------------- OneDeclarationPerLine ----------------------------------------------
--- creates a measure when several variables are declared on the same line
rule MeasureOneDeclarationPerLine(s: java!VariableDeclarationStatement){
@@ -1472,6 +1571,27 @@ rule MeasureSignatureDeclareThrowsException(class : java!ClassDeclaration) {
}
}
+-- ----------------------------------------- SimpleDateFormatNeedsLocale ------------------------------------------------------------------------------------
+
+---creates a new Measure when a SimpleDateFormat's Locale parameter is missing (Locale.US for example).
+rule MeasureSimpleDateFormatNeedsLocale(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'SimpleDateFormatNeedsLocale',
+ shortDescription <- 'Be sure to specify a Locale when creating SimpleDateFormat instances to ensure that locale-appropriate formatting is used.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The variable '+ classDeclaration.name + ' violates the rule SimpleDateFormatNeedsLocale.'
+ )
+ do {
+ noc;
+ }
+}
+
-- ------------------------------------------- SimplifyBooleanAssertion ---------------------------------------------
--- creates a new Measure when a class contains a negation in an assertTrue or assertFalse.
rule MeasureSimplifyBooleanAssertion(i : java!PrefixExpression) {
@@ -1839,6 +1959,26 @@ rule MeasureUseProperClassLoader(w: java!MethodInvocation) {
}
}
+-- ----------------------------------------- UseShortArrayInitializer ------------------------------------------------------------------------------------
+
+---creates a new Measure when a new array is created using "new".
+rule MeasureUseShortArrayInitializer(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'UseShortArrayInitializer',
+ shortDescription <- 'When declaring and initializing array fields or variables, it is not necessary to explicitly create a new array using new. Instead one can simply define the initial content of the array as a expression in curly braces.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The variable '+ classDeclaration.name + ' violates the rule UseShortArrayInitializer.'
+ )
+ do {
+ noc;
+ }
+}
-- ----------------------------------------- AddEmptyString ------------------------------------------------------------------------------------
-- #TODO: Add comment
@@ -2152,6 +2292,47 @@ rule MesureTooManyStaticImports(class : java!CompilationUnit) {
noc;
}
}
+
+-- ------------------------------------------- UncommentedEmptyConstructor ---------------------------------------------
+--- A Measure instance if the class violates the rule UncommentedEmptyConstructor.
+rule MeasureUncommentedEmptyConstructor(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'Uncommented Empty Constructor',
+ shortDescription <- 'Uncommented Empty Constructor finds instances where a constructor does not contain statements, but there is no comment. By explicitly commenting empty constructors it is easier to distinguish between intentional (commented) and unintentional empty constructors.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The class '+ classDeclaration.name + ' violates the rule Uncommented Empty Constructor.'
+ )
+ do {
+ noc;
+ }
+}
+
+-- ----------------------------------------- UncommentedEmptyMethodBody ------------------------------------------------------------------------------------
+
+---creates a new Measure when an empty method doesn't have any comment in his body.
+rule MeasureUncommentedEmptyMethodBody(classDeclaration : java!ClassDeclaration) {
+ to
+ om: smm!ObservedMeasure (
+ measure <- noc,
+ measurements <- measurement
+ ),
+ noc: smm!DimensionalMeasure (
+ name <- 'Uncommented Empty Method Body',
+ shortDescription <- 'Uncommented Empty Method Body finds instances where a method body does not contain statements, but there is no comment. By explicitly commenting empty method bodies it is easier to distinguish between intentional (commented) and unintentional empty methods.'
+ ),
+ measurement: smm!DirectMeasurement (
+ error<- 'The method '+ classDeclaration.name + ' violates the rule Uncommented Empty Method Body.'
+ )
+ do {
+ noc;
+ }
+}
----------------------------------------- UnusedLocalVariable ------------------------------------------------------
diff --git a/src/main/atl/codestyle.atl b/src/main/atl/codestyle.atl
index fc9493251c21049433594fb0d015cb6b84091ba0..8ac892d744b3e8ed46c2b26eff0e9e64124308b9 100644
--- a/src/main/atl/codestyle.atl
+++ b/src/main/atl/codestyle.atl
@@ -101,9 +101,9 @@ helper context java!ClassDeclaration def: isNotAllFieldsDeclaredAtStartOfClass()
endif
endif
)
- endif
-;
+ endif;
+
--- GenericsNaming
-- Rule for metrics GenericsNaming
helper def: genericsNaming() : Set(smm!Measure) =
@@ -200,4 +200,21 @@ helper def: noPackageDeclaration() : Set(smm!Measure) =
java!CompilationUnit.allInstances()
->select(compUnit | compUnit.package.oclIsUndefined())
->collect(err | thisModule.MesureAvoidNoPackageDeclaration(err))
-;
\ No newline at end of file
+;
+
+-- ------------------------------------------- AvoidUsingNativeCode ---------------------------------------------
+
+--- Indicates if a JNI class has unecessary reliances.
+helper def: avoidUsingNativeCode() : Set(smm!Measure) =
+ java!MethodInvocation.allInstances()
+ -> select(i | i.expression = OclUndefined)
+ -> select(i | i.expression.type.name.startsWith('System') and i.method.name.startsWith('loadLibrary'))
+ -> collect (i | thisModule.MeasureAvoidUsingNativeCode(i));
+
+-- ------------------------------------------- UseShortArrayInitializer ---------------------------------------------
+
+--- Indicates if an array initializer contain a "new"
+helper def: useShortArrayInitializer() : Set(smm!Measure) =
+ java!VariableDeclarationFragment.allInstances()
+ -> select(i | i.initializer.oclIsTypeOf(java!ArrayCreation) = true)
+ -> collect (i | thisModule.MeasureUseShortArrayInitializer(i));
diff --git a/src/main/atl/documentation.atl b/src/main/atl/documentation.atl
index 35218b5cd3a0f667c84c201e55c0ea9baec458aa..708456d27d4e261767843a98b080037ab935259f 100644
--- a/src/main/atl/documentation.atl
+++ b/src/main/atl/documentation.atl
@@ -162,3 +162,19 @@ helper def: violatedCommentContent(node : java!ASTNode): Sequence(String) =
-> reject (words | words.isEmpty()) -> flatten()
;
+
+--------------------------------------------- UncommentedEmptyConstructor ---------------------------------------------
+
+--- Uncommented Empty Constructor finds instances where a constructor does not contain statements, but there is no comment.
+helper def: uncommentedEmptyConstructor() : Set(smm!Measure) =
+ java!ClassDeclaration.allInstances() -> select(i | i.bodyDeclarations.first().body.comments.size() = 0)
+ -> collect (i | thisModule.MeasureUncommentedEmptyConstructor(i));
+
+--------------------------------------------- UncommentedEmptyConstructor ---------------------------------------------
+
+--- Indicates if an empty contructor doesn't have any comment inside his body.
+helper def: uncommentedEmptyMethodBody() : Set(smm!Measure) =
+ java!MethodDeclaration.allInstances() -> select(i | i.body <> OclUndefined)
+ -> select(i | (i.body.comments.size() = 0 and i.body.statements.size() = 0))
+ -> collect (i | thisModule.MeasureUncommentedEmptyMethodBody(i));
+
\ No newline at end of file
diff --git a/src/main/atl/errorProne.atl b/src/main/atl/errorProne.atl
index fd7a29f3a2adea0cf2a51e18f714c6979d347ffa..4f9dd41f353300e2dc5b940a9ecaaf468c1e7357 100644
--- a/src/main/atl/errorProne.atl
+++ b/src/main/atl/errorProne.atl
@@ -592,4 +592,37 @@ helper context java!ASTNode def: getMethodName() : String =
--- Default case, allows to deal with OclUndefined
helper context OclAny def : getMethodName() : String =
- '';
\ No newline at end of file
+ '';
+
+--------------------------------------------- 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));