From e7ed3b5bbd90a24932c921f3bfed01d3cc107adc Mon Sep 17 00:00:00 2001 From: chanez Date: Sat, 21 Dec 2019 15:53:29 +0100 Subject: [PATCH] Fix #664 AvoidFinalLocalVariable --- input/avoid-final-local-variable.xmi | 41 ++++ src/main/atl/analysis.atl | 341 ++++++++++++++------------- src/main/atl/codestyle.atl | 30 ++- 3 files changed, 245 insertions(+), 167 deletions(-) create mode 100644 input/avoid-final-local-variable.xmi diff --git a/input/avoid-final-local-variable.xmi b/input/avoid-final-local-variable.xmi new file mode 100644 index 0000000..86ad9ee --- /dev/null +++ b/input/avoid-final-local-variable.xmi @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/atl/analysis.atl b/src/main/atl/analysis.atl index d1db3d3..4ae6465 100644 --- a/src/main/atl/analysis.atl +++ b/src/main/atl/analysis.atl @@ -13,7 +13,7 @@ uses bestPractices; uses documentation; uses errorProne; - + rule Java2SMM { from project: java!Model @@ -34,15 +34,16 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = -- Example rule -- thisModule.numberOfClasses(), - + -- Multithreading rules -- thisModule.avoidThreadGroup(), thisModule.useNotifyAllInsteadOfNotify(), - - + + -- Code Style rules -- + thisModule.AvoidFinalLocalVariable(), thisModule.extendsObject(), thisModule.genericsNaming(), thisModule.longVariable(), @@ -54,6 +55,7 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = thisModule.tooManyStaticImports(), thisModule.unnecessaryReturn(), + -- Design rules -- thisModule.ExcessiveClassLength(), @@ -83,7 +85,7 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = thisModule.uselessStringValueOf(), thisModule.startsWith(), thisModule.tooFewBranchesForASwitchStatement(), - + -- Documentation rules -- thisModule.commentContent(), @@ -100,7 +102,7 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = thisModule.doNotExtendJavaLangThrowable(), thisModule.dontImportSun(), thisModule.emptyCatchBlock(), - thisModule.EmptyInitializer(), + thisModule.EmptyInitializer(), thisModule.emptySwitchStatement(), thisModule.emptySynchronizedBlock(), thisModule.emptyTryBlock(), @@ -110,12 +112,12 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = thisModule.testClassWithoutTest(), thisModule.UnconditionalIfStatement(), thisModule.UseProperClassLoader(), - + -- Best practices rules thisModule.switchDensity(), thisModule.useAssertSameInsteadOfAssertTrue(), thisModule.useAssertTrueInsteadOfAssertEquals() - + -- Bugged rules: -- -- thisModule.avoidThrowingNullPointerException(), @@ -138,8 +140,8 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) = -- thisModule.methodWithSameNameAsEnclosingClass(), -- thisModule.dontUseFloatTypeForLoopIndices(), -- thisModule.methodWithSameNameAsEnclosingClass(), - - + + }; @@ -152,13 +154,13 @@ rule MeasureUselessStringValueOf(method : java!MethodInvocation) { ), noc: smm!DimensionalMeasure ( name <- 'Useless string value of', - shortDescription <- 'No need to call String.valueOf to append to a string; just use the valueOf() argument directly.' + shortDescription <- 'No need to call String.valueOf to append to a string; just use the valueOf() argument directly.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<- 'The class '+ method.originalCompilationUnit.name + ' violates the rule useless string value of.' ) do { - noc; + noc; } } @@ -179,7 +181,7 @@ rule MesureAvoidDollarSigns(node : java!ASTNode) { error <- node.name + ' has dollar in ' + node.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -200,7 +202,7 @@ rule MesureShortMethodName(method : java!MethodDeclaration) { error <- method.name + ' is too short in ' + method.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -220,7 +222,7 @@ rule MesureShortClassName(class : java!ClassDeclaration) { error <- 'The Class ' + class.name + ' is too short.' ) do { - noc; + noc; } } @@ -239,7 +241,7 @@ rule MesureShortVariableName(variable : java!VariableDeclaration) { error <- 'The Variable ' + variable.name + ' is too short.' ) do { - noc; + noc; } } @@ -258,7 +260,7 @@ rule MeasureStringToString(method : java!MethodInvocation) { error <- 'The Object ' + method.expression.variable.name + ' is already a String in ' + method.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -271,13 +273,13 @@ rule MeasureDontCallThreadRun(method : java!MethodInvocation) { ), noc: smm!DimensionalMeasure ( name <- 'Don t call Thread.run()', - shortDescription <- 'Explicitly calling Thread.run() method will execute in the caller s thread of control. Instead, call Thread.start() for the intended behavior.' + shortDescription <- 'Explicitly calling Thread.run() method will execute in the caller s thread of control. Instead, call Thread.start() for the intended behavior.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The class '+ method.originalCompilationUnit.name + ' violates the rule don t call Thread.run().' ) do { - noc; + noc; } } @@ -297,7 +299,7 @@ rule MesureTooManyFields(class : java!ClassDeclaration) { error <- class.originalCompilationUnit.name + ' have too many fields' ) do { - noc; + noc; } } @@ -311,13 +313,13 @@ rule MeasureUseIndexOfChar(method : java!MethodInvocation) { ), noc: smm!DimensionalMeasure ( name <- 'Use index of char', - shortDescription <- 'Use String.indexOf(char) when checking for the index of a single character; it executes faster.' + shortDescription <- 'Use String.indexOf(char) when checking for the index of a single character; it executes faster.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<- 'The class '+ method.originalCompilationUnit.name + ' violates the rule index of char.' ) do { - noc; + noc; } } @@ -337,12 +339,12 @@ rule numberOfClasses() { ) do { - noc; + noc; } } --- Rule that creates an instance of Measure for the switch statement with too few branches passed in parameter +-- Rule that creates an instance of Measure for the switch statement with too few branches passed in parameter rule MeasureTooFewBranchesForASwitchStatement(switchStatement: java!SwitchStatement) { to om: smm!ObservedMeasure ( @@ -358,7 +360,7 @@ rule MeasureTooFewBranchesForASwitchStatement(switchStatement: java!SwitchStatem value <- thisModule.nbBranchesOfASwitchStatement(switchStatement) ) do { - tooFewBranchesForASwitchStatement; + tooFewBranchesForASwitchStatement; } } @@ -372,14 +374,14 @@ rule MeasureShortInstantiation(variable : java!CompilationUnit) { ), noc: smm!DimensionalMeasure ( name <- 'ShortInstantiation', - shortDescription <- 'Calling new Short() causes memory allocation that can be avoided by the static Short.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Short() is deprecated since JDK 9 for that reason.' + shortDescription <- 'Calling new Short() causes memory allocation that can be avoided by the static Short.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Short() is deprecated since JDK 9 for that reason.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ variable.name + ' an instantiation of Short must be Short.ValueOf().' ) - + do { - noc; + noc; } } @@ -394,14 +396,14 @@ rule MeasureLongInstantiation(variable : java!CompilationUnit) { ), noc: smm!DimensionalMeasure ( name <- 'LongInstantiation', - shortDescription <- 'Calling new Long() causes memory allocation that can be avoided by the static Long.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Long() is deprecated since JDK 9 for that reason.' + shortDescription <- 'Calling new Long() causes memory allocation that can be avoided by the static Long.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Long() is deprecated since JDK 9 for that reason.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ variable.name + ' an instantiation of Long must be Long.ValueOf().' ) - + do { - noc; + noc; } } @@ -416,17 +418,17 @@ rule MeasureDoNotExtendJavaLangThrowable(variable : java!ClassDeclaration) { noc: smm!DimensionalMeasure ( name <- 'DoNotExtendJavaLangThrowable ', shortDescription <- 'Extend Exception or RuntimeException instead of Throwable.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ variable.name + ' should not extend Throwable but RuntimeException or Exception .' ) - + do { - noc; + noc; } } - + -- Returns the number of branches in the switch statement passed in parameter helper def: nbBranchesOfASwitchStatement(switchStatement:java!SwitchStatement) : Integer = switchStatement.statements->select(each | each.oclIsTypeOf(java!SwitchCase)).size() @@ -470,7 +472,7 @@ rule createMeasureForMissingBreakInSwitch(ss: java!SwitchStatement) { value <- (thisModule.nbBranchesOfASwitchStatement(ss) - thisModule.nbIntentionalFallThroughOfASwitchStatement(ss)) - thisModule.nbBreakStatementOfASwitchStatement(ss) ) do { - missingBreakInSwitch; + missingBreakInSwitch; } } @@ -490,7 +492,7 @@ rule MesureTooManyMethods(class : java!ClassDeclaration) { ) do { - noc; + noc; } } @@ -509,7 +511,7 @@ rule MesureReturnFromFinallyBlock(method : java!MethodDeclaration) { error <- 'The method ' + method.name + ' in the class ' + method.originalCompilationUnit.name + ' has a return statement in a finally block.' ) do { - noc; + noc; } } @@ -528,7 +530,7 @@ rule MesureTooManyStaticImports(class : java!CompilationUnit) { error <- class.name + ' has too many static imports' ) do { - noc; + noc; } } @@ -541,13 +543,13 @@ rule MeasureAvoidPrintStackTrace(method : java!MethodInvocation) { ), noc: smm!DimensionalMeasure ( name <- 'Avoid print stack trace', - shortDescription <- 'Avoid printStackTrace(); use a logger call instead.' + shortDescription <- 'Avoid printStackTrace(); use a logger call instead.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<- 'The class '+ method.originalCompilationUnit.name + ' violates the rule avoid print stack trace.' ) do { - noc; + noc; } } @@ -560,14 +562,14 @@ rule measureAvoidThreadGroup(variable : java!VariableDeclarationFragment) { ), noc: smm!DimensionalMeasure ( name <- 'Avoid Thread Group', - shortDescription <- 'Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread-safe.' + shortDescription <- 'Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread-safe.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The class '+ variable.originalCompilationUnit.name + ' violates the rule avoid thread group.' ) - + do { - noc; + noc; } } @@ -581,17 +583,17 @@ rule MeasureAvoidThrowingNewInstanceOfSameException(catch : java!CatchClause) { ), noc: smm!DimensionalMeasure ( name <- 'AvoidThrowingNewInstanceOfSameException', - shortDescription <- 'Catch blocks that merely rethrow a caught exception wrapped inside a new instance of the same type only add to code size and runtime complexity.' + shortDescription <- 'Catch blocks that merely rethrow a caught exception wrapped inside a new instance of the same type only add to code size and runtime complexity.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error <-'The class '+ catch.originalCompilationUnit.name + ' has a method that rethrows a caught exception wrapped inside a new instance of the same type.' ) do { - noc; + noc; } } ---------------------------------------------- ReturnEmptyArrayRatherThanNull --------------------------------------------- +--------------------------------------------- ReturnEmptyArrayRatherThanNull --------------------------------------------- -- creates a new Measure when a method returns an empty method rather than null rule MesureReturnEmptyArrayRatherThanNull(method : java!ReturnStatement) { to @@ -607,7 +609,7 @@ rule MesureReturnEmptyArrayRatherThanNull(method : java!ReturnStatement) { error <- 'A method in the class ' + method.originalCompilationUnit.name + ' returns null instead of an empty array.' ) do { - noc; + noc; } } @@ -621,13 +623,13 @@ rule MesureExcessiveParameterList(method : java!MethodDeclaration) { ), noc: smm!DimensionalMeasure ( name <- 'ExcessiveParameterList', - shortDescription <- 'Methods with numerous parameters are a challenge to maintain, especially if most of them share the same datatype.' + shortDescription <- 'Methods with numerous parameters are a challenge to maintain, especially if most of them share the same datatype.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The method '+ method.name + ' in the class ' + method.originalCompilationUnit.name + ' has an excessive parameter list.' ) do { - noc; + noc; } } @@ -646,7 +648,7 @@ rule MesureAvoidFieldNameMatchingMethodName(class : java!ClassDeclaration, metho error <- 'In the ' + class.name + ' class you have an field and an method with the same name : '+ method.name ) do { - noc; + noc; } } @@ -665,7 +667,7 @@ rule MeasureUseNotifyAllInsteadOfNotify(method: java!MethodInvocation) { error <- 'Used notify() instead of notifyAll() in Class : ' + method.originalCompilationUnit.name ) do { - useNotifyAllInsteadOfNotify; + useNotifyAllInsteadOfNotify; } } @@ -684,7 +686,7 @@ rule MeasureCommentRequired(element: java!BodyDeclaration, violatedProperties: S error <- 'Violated the properties ' + violatedProperties + ' in Class: ' + element.originalCompilationUnit.name + ' -> ' + element.oclType().name + ': ' + element.modifier.visibility + ' ' + element.getBodyDeclarationName() ) do { - commentRequired; + commentRequired; } } -- Creates a measure instance when a bad word is found in a comment @@ -699,15 +701,15 @@ rule MeasureCommentContent(element: Sequence(String)){ shortDescription <- 'A rule for the politically correct… we don’t want to offend anyone.' ), measurement: smm!DirectMeasurement ( - error <- 'The words ' + element +' were found in a comment ' + error <- 'The words ' + element +' were found in a comment ' ) do { commentContent; } - + } --- Creates a measure instance when a for loop uses a float as loop indice +-- Creates a measure instance when a for loop uses a float as loop indice rule MeasureDontUseFloatTypeForLoopIndices(){ to om: smm!ObservedMeasure ( @@ -719,12 +721,12 @@ rule MeasureDontUseFloatTypeForLoopIndices(){ shortDescription <- 'Don’t use floating point for loop indices.' ), measurement: smm!DirectMeasurement ( - error <- 'Use integer instead of floats as loop indice' + error <- 'Use integer instead of floats as loop indice' ) do { dontUseFloatTypeForLoopIndices; } - + } --- Returns the name of a BodyDeclaration @@ -739,8 +741,8 @@ helper context java!FieldDeclaration def: getBodyDeclarationName() : String = -- This is necessary because BodyDeclaration.annotations returns Sequence(!IN) helper def: getAnnotationTypeDeclarationsFromBodyDeclaration(elem: java!BodyDeclaration): Set(java!AnnotationTypeDeclaration) = java!AnnotationTypeDeclaration.allInstances() - ->select(annotTypeDec | - annotTypeDec.usagesInTypeAccess->exists(usage | + ->select(annotTypeDec | + annotTypeDec.usagesInTypeAccess->exists(usage | (usage.eContainer().eContainer().name = elem.name) .and(usage.eContainer().eContainer().modifier.visibility = elem.modifier.visibility) .and(usage.eContainer().eContainer().originalCompilationUnit.name = elem.originalCompilationUnit.name)) @@ -775,10 +777,10 @@ rule MeasureAvoidUsingShortType(typeShort : java!VariableDeclarationStatement) { ), noc: smm!DimensionalMeasure ( name <- 'Avoid using short type', - shortDescription <- 'Java uses the \'short\' type to reduce memory usage, not to optimize calculation.' - + ' In fact, the JVM does not have any arithmetic capabilities for the short type:' - + ' the JVM must convert the short into an int, do the proper calculation and convert' - + ' the int back to a short. Thus any storage gains found through use of the \'short\' type' + shortDescription <- 'Java uses the \'short\' type to reduce memory usage, not to optimize calculation.' + + ' In fact, the JVM does not have any arithmetic capabilities for the short type:' + + ' the JVM must convert the short into an int, do the proper calculation and convert' + + ' the int back to a short. Thus any storage gains found through use of the \'short\' type' + ' may be offset by adverse impacts on performance.' ), measurement: smm!DirectMeasurement ( @@ -819,14 +821,14 @@ rule MeasureDoNotExtendJavaLangError(variable : java!ClassDeclaration) { noc: smm!DimensionalMeasure ( name <- 'DoNotExtendJavaLangError ', shortDescription <- 'Errors are system exceptions. Do not extend them.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ variable.name + ' Do not extend Error, Errors are system exceptions.' ) - + do { - noc; + noc; } } @@ -841,14 +843,14 @@ rule MeasureFinalFieldCouldBeStatic(field : java!FieldDeclaration) { noc: smm!DimensionalMeasure ( name <- 'FinalFieldCouldBeStatic', shortDescription <- 'If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead in each object at runtime.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The field '+ field.fragments->collect(i | i.name)->first() + ' could be static in the class ' + field.originalCompilationUnit.name +'.' ) - + do { - noc; + noc; } } @@ -864,82 +866,82 @@ rule MeasureExtendsObject(variable : java!ClassDeclaration) { noc: smm!DimensionalMeasure ( name <- 'ExtendsObject', shortDescription <- 'No need to explicitly extend Object.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ variable.name + ' No need to explicitly extend Object.' ) - + do { - noc; + noc; } } --------------------------------------------- SwitchDensity --------------------------------------------- -- A Measure instance if the class violates the rule SwitchDensity. rule MeasureSwitchDensity(switch : java!SwitchStatement) { - + to om: smm!ObservedMeasure ( measure <- noc, measurements <- measurement ), noc: smm!DimensionalMeasure ( - + name <- 'SwitchDensity ', shortDescription <- 'Statement to label ratio is too high (> 10)' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ switch.originalCompilationUnit.name + ' a switch case contains too many statements.' ) do { - noc; + noc; } -} +} --------------------------------------------- SignatureDeclareThrowsException --------------------------------------------- -- A Measure instance if the class violates the rule SignatureDeclareThrowsException. rule MeasureSignatureDeclareThrowsException(class : java!ClassDeclaration) { - + to om: smm!ObservedMeasure ( measure <- noc, measurements <- measurement ), noc: smm!DimensionalMeasure ( - + name <- 'SignatureDeclareThrowsException ', shortDescription <- 'A method/constructor should not explicitly throw the generic java.lang.Exception' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ class.name + ' a method/constructor explicitly throws the generic java.lang.Exception.' ) do { - noc; + noc; } -} +} --------------------------------------------- UnnecessaryReturn --------------------------------------------- -- A Measure instance if the class violates the rule UnnecessaryReturn. rule MeasureUnnecessaryReturn(state : java!ReturnStatement) { - + to om: smm!ObservedMeasure ( measure <- noc, measurements <- measurement ), noc: smm!DimensionalMeasure ( - + name <- 'UnnecessaryReturn ', shortDescription <- 'Avoid the use of unnecessary return statements.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ state.originalCompilationUnit.name + ' an unnecessary return was used.' ) do { - noc; + noc; } } @@ -955,22 +957,22 @@ rule MeasureCompareObjectsWithEquals(expression : java!InfixExpression) { noc: smm!DimensionalMeasure ( name <- 'CompareObjectsWithEquals', shortDescription <- 'Use equals() to compare object references; avoid comparing them with ==.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The Class '+ expression.originalCompilationUnit.name + ' is using == instead of equals() to compare objects.' ) - + do { - noc; + noc; } -} +} --------------------------------------------- UseAssertTrueInsteadOfAssertEquals --------------------------------------------- -- A Measure instance if the class violates the rule UseAssertTrueInsteadOfAssertEquals. rule MesureUseAssertTrueInsteadOfAssertEquals(class : java!MethodInvocation) { - + to om: smm!ObservedMeasure ( measure <- noc, @@ -978,14 +980,14 @@ rule MesureUseAssertTrueInsteadOfAssertEquals(class : java!MethodInvocation) { ), noc: smm!DimensionalMeasure ( name <- 'UseAssertTrueInsteadOfAssertEquals', - shortDescription <- 'Use AssertTrue instead of AssertEquals' + shortDescription <- 'Use AssertTrue instead of AssertEquals' ), measurement: smm!DirectMeasurement ( - error <- class.originalCompilationUnit.name + ' Use AssertTrue instead of AssertEquals ' + error <- class.originalCompilationUnit.name + ' Use AssertTrue instead of AssertEquals ' ) do { - noc; + noc; } } --------------------------------------------- AvoidRethrowingException --------------------------------------------- @@ -997,19 +999,19 @@ rule MeasureAvoidRethrowingException(statement : java!TryStatement) { measurements <- measurement ), noc: smm!DimensionalMeasure ( - + name <- 'AvoidRethrowingException ', shortDescription <- 'Avoid merely rethrowing an exception.' - + ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ statement.originalCompilationUnit.name + ' an exception was caught and merely rethrown.' ) do { - noc; + noc; } -} - +} + --------------------------------------------- IntegerInstantiation --------------------------------------------- -- A Measure instance if the class violates the rule 'IntegerInstantiation'. rule MeasureIntegerInstantiation(variable : java!CompilationUnit) { @@ -1020,14 +1022,14 @@ rule MeasureIntegerInstantiation(variable : java!CompilationUnit) { ), noc: smm!DimensionalMeasure ( name <- 'IntegerInstantiation', - shortDescription <- 'Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Integer() is deprecated since JDK 9 for that reason.' + shortDescription <- 'Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Integer() is deprecated since JDK 9 for that reason.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'In the Class '+ variable.name + ' an instantiation of Integer must be Integer.ValueOf().' ) - + do { - noc; + noc; } } @@ -1044,10 +1046,10 @@ rule MeasureLongVariable(variable : java!VariableDeclarationFragment) { shortDescription <- ': Fields, formal arguments, or local variable names that are too long can make the code difficult ' ), measurement: smm!DirectMeasurement ( - error <- variable.name + ' is too Long ' + error <- variable.name + ' is too Long ' ) do { - noc; + noc; } } @@ -1064,10 +1066,10 @@ rule MeasureAvoidCallingFinalize(methode : java!MethodInvocation) { shortDescription <- ': The method Object.finalize() is called by the garbage collector on an object when garbage collect... ' ), measurement: smm!DirectMeasurement ( - error <- 'finalize() is called in class' + methode.originalCompilationUnit.name + error <- 'finalize() is called in class' + methode.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1084,10 +1086,10 @@ rule MeasureAvoidStringBufferField(declaration : java!VariableDeclaration) { shortDescription <- ': StringBuffers/StringBuilders can grow considerably, and so may become a source of memory leaksif ...' ), measurement: smm!DirectMeasurement ( - error <- 'AvoidStringBufferField is detected in ' + declaration.originalCompilationUnit.name + error <- 'AvoidStringBufferField is detected in ' + declaration.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1107,7 +1109,7 @@ rule MeasureAvoidThrowingNullPointerException(c : java!ClassInstanceCreation) { error <- 'AvoidThrowingNullPointerException is detected in ' + c.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1128,7 +1130,7 @@ rule MeasureEmptyTryBlock(t : java!TryStatement) { error <- 'EmptyTryBlock is detected in ' + t.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1148,7 +1150,7 @@ rule MeasureEmptyWhileStmt(w : java!TryStatement) { error <- 'EmptyWhileStmt is detected in ' + w.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1168,7 +1170,7 @@ rule MeasureDontImportSun(p : java!CompilationUnit) { error <- ' Import Sun. , is detected in '+ p -> collect(i | i.name) ) do { - noc; + noc; } } @@ -1188,7 +1190,7 @@ rule MesureFinalizeShouldBeProtected(m : java!MethodDeclaration) { error <- 'Finalize is not protected in class : ' + m.originalCompilationUnit.name ) do { - noc; + noc; } } -----------------------EmptySwitchStatement--------------------------------------------- @@ -1247,7 +1249,7 @@ rule MeasureEmptyFinallyBlock(finallyBlock : java!TryStatement) { error <- 'EmptyFinallyBlock is detected in ' + finallyBlock.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1267,7 +1269,7 @@ rule MeasureEmptyFinalizer(finalizeMethod : java!MethodDeclaration) { error <- 'EmptyFinalizer is detected in ' + finalizeMethod.originalCompilationUnit.name ) do { - noc; + noc; } } -------------------------------------------UseAssertSameInsteadOfAssertTrue---------------------------------------------- @@ -1305,7 +1307,7 @@ rule MesureAvoidNoPackageDeclaration(class : java!CompilationUnit) { error <- class.name + ' class have no package declaration' ) do { - noc; + noc; } } @@ -1324,7 +1326,7 @@ rule MeasureUnconditionalIfStatement(w: java!IfStatement) { error <- 'UnconditionalIfStatement is detected in ' + w.originalCompilationUnit.name ) do { - noc; + noc; } } @@ -1343,7 +1345,7 @@ rule MeasureEmptyInitializer(w: java!Initializer) { error <- ' class '+w.originalCompilationUnit.name +' hase an empty Initializer! do not declare an EmptyInitializer, EmptyInitializer! this block need to be deleted' ) do { - noc; + noc; } } @@ -1362,7 +1364,7 @@ rule MeasureExcessiveClassLength(w: java!MethodDeclaration) { error <- ' class '+w.originalCompilationUnit.name+ ' has a block with more than 1000 line of code per a method it may need a separation in the code' ) do { - noc; + noc; } } @@ -1381,7 +1383,7 @@ rule MeasureCloneMethodMustBePublic(w: java!MethodDeclaration) { error <- ' class '+w.originalCompilationUnit.name+ ' has a clone methode witch need to be public ' ) do { - noc; + noc; } } @@ -1400,7 +1402,7 @@ rule MeasureAvoidEnumAsIdentifier(w: java!VariableDeclaration) { error <- ' class '+w.originalCompilationUnit.name+ ' has a variable named to enum witch is a reserved name' ) do { - noc; + noc; } } @@ -1421,7 +1423,7 @@ rule MeasureAvoidCatchingNPE(w: java!CatchClause) { original error, causing other, more subtle problems later on.' ) do { - noc; + noc; } } @@ -1441,7 +1443,7 @@ rule MeasureUseProperClassLoader(w: java!MethodInvocation) { use Thread.currentThread().getContextClassLoader() instead ' ) do { - noc; + noc; } } -------------------------------------------GenericsNaming---------------------------------------------- @@ -1588,14 +1590,14 @@ rule MeasureExcessiveImports(i : java!CompilationUnit) { ), noc: smm!DimensionalMeasure ( name <- 'ExcessiveImports', - shortDescription <- 'A high number of imports can indicate a high degree of coupling within an object. This rule counts the number of unique imports and reports a violation if the count is above the user-specified threshold.' + shortDescription <- 'A high number of imports can indicate a high degree of coupling within an object. This rule counts the number of unique imports and reports a violation if the count is above the user-specified threshold.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The class '+ i.name + ' has an excessive imports.', value<- i.imports.size() ) do { - noc; + noc; } } @@ -1609,13 +1611,13 @@ rule MeasureIfStmtsMustUseBraces(i : java!IfStatement) { ), noc: smm!DimensionalMeasure ( name <- 'If then Statement must use braces', - shortDescription <- 'Deprecated Avoid using if statements without using braces to surround the code block. If the code formatting...' + shortDescription <- 'Deprecated Avoid using if statements without using braces to surround the code block. If the code formatting...' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error <- 'The class ' + i.originalCompilationUnit.name + ' has an if statement without braces. ' ) do { - noc; + noc; } } @@ -1629,13 +1631,13 @@ rule MeasureSimplifyBooleanAssertion(i : java!PrefixExpression) { ), noc: smm!DimensionalMeasure ( name <- 'SimplifyBooleanAssertion', - shortDescription <- 'Avoid negation in an assertTrue or assertFalse test.' + shortDescription <- 'Avoid negation in an assertTrue or assertFalse test.' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The method test ' + i.eContainer().eContainer().eContainer().eContainer().name + ' contains a negation in an assertTrue or assertFalse.' ) do { - noc; + noc; } } @@ -1650,13 +1652,13 @@ rule MeasureAbstractClassWithoutAnyMethod(i : java!ClassDeclaration) { ), noc: smm!DimensionalMeasure ( name <- 'AbstractClassWithoutAnyMethod', - shortDescription <- 'If an abstract class does not provides any methods, it may be acting as a simple data containerth...' + shortDescription <- 'If an abstract class does not provides any methods, it may be acting as a simple data containerth...' ), - measurement: smm!DirectMeasurement ( + measurement: smm!DirectMeasurement ( error<-'The class anstract' + i.name + ' has not method.' ) do { - noc; + noc; } } @@ -1678,7 +1680,7 @@ rule MeasureStartWith(w: java!MethodInvocation) { error <- ' class'+ w.originalCompilationUnit.name+ 'has an instruction that use startWith, use chartAt(0) instand ' ) do { - noc; + noc; } } @@ -1699,7 +1701,7 @@ rule MeasureInsufficientStringBufferDeclaration(w: java!CompilationUnit) { error <- ' class'+ w.name+ 'has insufficientStringBufferDeclaration' ) do { - noc; + noc; } } @@ -1720,7 +1722,7 @@ rule MeasureTestClassWithoutTest(w: java!CompilationUnit) { error <- ' class'+ w.name+ 'has testClassWithoutTest' ) do { - noc; + noc; } } @@ -1741,6 +1743,25 @@ rule MesureAddEmptyString(w: java!CompilationUnit) { error <- ' class'+ w.name+ 'has AddEmptyString' ) do { - noc; + noc; } -} \ No newline at end of file +} +------------------------------------------- AvoidFinalLocalVariable ------------------------------------------------------------------------------------ +-- creates a new Measure when a final local variable is used. +rule ruleAvoidFinalLocalVariable() { + to + om: smm!ObservedMeasure ( + measure <- noc, + measurements <- measurement + ), + noc: smm!DimensionalMeasure ( + name <- 'Avoid Final Local Variable', + shortDescription <- 'Avoid using final local variables, turn them into fields.' + ), + measurement: smm!DirectMeasurement ( + error<- 'Avoid Final Local Variable' + ) + do { + noc; + } +} diff --git a/src/main/atl/codestyle.atl b/src/main/atl/codestyle.atl index 5c847f7..19b23bb 100644 --- a/src/main/atl/codestyle.atl +++ b/src/main/atl/codestyle.atl @@ -4,7 +4,7 @@ library codestyle; -- Rule for metrics AvoidDollarSigns : return the set of class Measures that violates the rule. helper def: avoidDollarSigns() : Set(smm!Measure) = - -- Browse through all variable/method/class/interface. + -- Browse through all variable/method/class/interface. java!TypeDeclaration.allInstances()->union(java!MethodDeclaration.allInstances())->union(java!VariableDeclaration.allInstances())->select(i | i.name.indexOf('$') <> -1) ->collect(i | thisModule.MesureAvoidDollarSigns(i)); @@ -28,8 +28,8 @@ helper def: tooManyStaticImports() : Set(smm!Measure) = -- Add a new measurement if there are more than 4 static imports in the file. -> select (c | c.types.first().oclIsTypeOf(java!ClassDeclaration) and c.imports->select(i | i.static)->size() > 4) -> collect(c | thisModule.MesureTooManyStaticImports(c)); - - + + --------------------------------------------- ExtendsObject --------------------------------------------- -- Rule for metrics ExtendsObject @@ -46,7 +46,7 @@ helper def: extendsObject() : Set(smm!Measure) = --------------------------------------------- UnnecessaryReturn --------------------------------------------- -- Rule for metrics UnnecessaryReturn : -helper def: unnecessaryReturn() : Set (smm!Measure) = +helper def: unnecessaryReturn() : Set (smm!Measure) = -- Browse through all method declarations java!ReturnStatement.allInstances() ->select(state | not state.expression.oclIsTypeOf(java!SingleVariableAccess)) @@ -73,7 +73,7 @@ helper def: shortVariableName() : Set(smm!Measure) = ----- Fix Issues #699 ---- helper noPackageDeclaration +--- helper noPackageDeclaration --- get all the compilation units --- check if this units contains a defined package or not --- if there is make a call for MesureAvoidNoPackageDeclaration rule @@ -104,8 +104,24 @@ helper def: misLeadingVariableName() : Set(smm!Measure) = --------------------------------------------- IfStmtsMustUseBraces --------------------------------------------- -- Helper for issue IfStmtsMustUseBraces : return a Measure for each class that contains an if statement without braces. -helper def: IfBraces() : Set(smm!Measure) = +helper def: IfBraces() : Set(smm!Measure) = java!IfStatement.allInstances() -> select(i | i.thenStatement <> OclUndefined) -> select(i | not i.thenStatement.oclIsTypeOf(java!Block)) - -> collect(i | thisModule.MeasureIfStmtsMustUseBraces(i)); \ No newline at end of file + -> collect(i | thisModule.MeasureIfStmtsMustUseBraces(i)); + + --------------------------------------------- AvoidFinalLocalVariable --------------------------------------------- +helper def : AvoidFinalLocalVariable(): Set(smm!Measure)= + --Selectione les classes + java!ClassDeclaration.allInstances() + ->select(i | not i.bodyDeclarations.oclIsUndefined()) + ->select(i | thisModule.contientFinalLocalVariable(i)) + ->collect(i| thisModule.ruleAvoidFinalLocalVariable(i)) + ; + +helper def : contientFinalLocalVariable(class :java!ClassDeclaration) : Boolean = + --renvoie true si la classe contient une variable final + class.bodyDeclarations->select(i|i.oclIsTypeOf(java!FieldDeclaration)) + ->select(i|not i.modifier.oclIsUndefined()) + ->select(i|i.modifier.inheritance=#final)->size()>0 + ; -- GitLab