diff --git a/spec/SmellSpec.hs b/spec/SmellSpec.hs index cb7223d9c..cae047c82 100644 --- a/spec/SmellSpec.hs +++ b/spec/SmellSpec.hs @@ -503,5 +503,17 @@ spec = do describe "usesVarInsteadOfLet" $ do it "is True when there is a var" $ do usesVarInsteadOfLet (js "var x = 1; x++") `shouldBe` True + + it "is False when there is no var" $ do usesVarInsteadOfLet (js "let x = 1; x++") `shouldBe` False usesVarInsteadOfLet (js "const x = 1; x++") `shouldBe` False + + describe "usesForInInsteadOfForOf" $ do + it "is True when there is a for..in" $ do + usesForInInsteadOfForOf (js "for (let x in []) {}") `shouldBe` True + usesForInInsteadOfForOf (js "for (var x in []) {}") `shouldBe` True + + it "is False when there is no for..in" $ do + usesForInInsteadOfForOf (js "for (var x of []) {}") `shouldBe` False + usesForInInsteadOfForOf (js "for (let x of []) {}") `shouldBe` False + usesForInInsteadOfForOf (js "for (const x of []) {}") `shouldBe` False diff --git a/src/Language/Mulang/Analyzer/SmellsAnalyzer.hs b/src/Language/Mulang/Analyzer/SmellsAnalyzer.hs index d610535af..660c3d2b9 100644 --- a/src/Language/Mulang/Analyzer/SmellsAnalyzer.hs +++ b/src/Language/Mulang/Analyzer/SmellsAnalyzer.hs @@ -87,7 +87,8 @@ allSmells = [ "UsesFail", "UsesNamedSelfReference", "UsesUnificationOperator", - "JavaScript#UsesVarInsteadOfLet" ] + "JavaScript#UsesVarInsteadOfLet", + "JavaScript#UsesForInInsteadOfForOf" ] --- --- Instantiation @@ -131,49 +132,50 @@ evalSmellInstance :: SmellsContext -> Expression -> SmellInstance -> [Expectatio evalSmellInstance context expression smellInstance = map (expectationFor smellInstance) . detectionFor smellInstance context $ expression detectionFor :: SmellInstance -> Detection -detectionFor ("DiscardsExceptions", Nothing) = simple discardsExceptions -detectionFor ("DoesConsolePrint", Nothing) = simple doesConsolePrint -detectionFor ("DoesNilTest", Nothing) = simple doesNilTest -detectionFor ("DoesNullTest", Nothing) = simple doesNilTest -detectionFor ("DoesTypeTest", Nothing) = simple doesTypeTest -detectionFor ("HasAssignmentCondition", Nothing) = simple hasAssignmentCondition -detectionFor ("HasAssignmentReturn", Nothing) = simple hasAssignmentReturn -detectionFor ("HasCodeDuplication", Nothing) = unsupported -detectionFor ("HasDeclarationTypos", Just target) = raw (detectDeclarationTypos target) -detectionFor ("HasEmptyIfBranches", Nothing) = simple hasEmptyIfBranches -detectionFor ("HasEmptyRepeat", Nothing) = simple hasEmptyRepeat -detectionFor ("HasEqualIfBranches", Nothing) = simple hasEqualIfBranches -detectionFor ("HasLongParameterList", Nothing) = simple hasLongParameterList -detectionFor ("HasMisspelledBindings", Nothing) = withLanguage hasMisspelledIdentifiers -detectionFor ("HasMisspelledIdentifiers", Nothing) = withLanguage hasMisspelledIdentifiers -detectionFor ("HasRedundantBooleanComparison", Nothing) = simple hasRedundantBooleanComparison -detectionFor ("HasRedundantGuards", Nothing) = simple hasRedundantGuards -detectionFor ("HasRedundantIf", Nothing) = simple hasRedundantIf -detectionFor ("HasRedundantLambda", Nothing) = simple hasRedundantLambda -detectionFor ("HasRedundantLocalVariableReturn", Nothing) = simple hasRedundantLocalVariableReturn -detectionFor ("HasRedundantParameter", Nothing) = simple hasRedundantParameter -detectionFor ("HasRedundantReduction", Nothing) = simple hasRedundantReduction -detectionFor ("HasRedundantRepeat", Nothing) = simple hasRedundantRepeat -detectionFor ("HasTooManyMethods", Nothing) = simple hasTooManyMethods -detectionFor ("HasTooShortBindings", Nothing) = withLanguage hasTooShortIdentifiers -detectionFor ("HasTooShortIdentifiers", Nothing) = withLanguage hasTooShortIdentifiers -detectionFor ("HasUnreachableCode", Nothing) = simple hasUnreachableCode -detectionFor ("HasUsageTypos", Just target) = raw (detectUsageTypos target) -detectionFor ("HasWrongCaseBinding", Nothing) = withLanguage hasWrongCaseIdentifiers -detectionFor ("HasWrongCaseIdentifiers", Nothing) = withLanguage hasWrongCaseIdentifiers -detectionFor ("IsLongCode", Nothing) = unsupported -detectionFor ("OverridesEqualOrHashButNotBoth", Nothing) = simple overridesEqualOrHashButNotBoth -detectionFor ("ReturnsNil", Nothing) = simple returnsNil -detectionFor ("ReturnsNull", Nothing) = simple returnsNil -detectionFor ("ShouldInvertIfCondition", Nothing) = simple shouldInvertIfCondition -detectionFor ("ShouldUseOtherwise", Nothing) = simple shouldUseOtherwise -detectionFor ("ShouldUseStrictComparators", Nothing) = simple shouldUseStrictComparators -detectionFor ("UsesCut", Nothing) = simple usesCut -detectionFor ("UsesFail", Nothing) = simple usesFail -detectionFor ("UsesNamedSelfReference", Nothing) = simple usesNamedSelfReference -detectionFor ("UsesUnificationOperator", Nothing) = simple usesUnificationOperator -detectionFor ("JavaScript#UsesVarInsteadOfLet", Nothing) = simple usesVarInsteadOfLet -detectionFor _ = unsupported +detectionFor ("DiscardsExceptions", Nothing) = simple discardsExceptions +detectionFor ("DoesConsolePrint", Nothing) = simple doesConsolePrint +detectionFor ("DoesNilTest", Nothing) = simple doesNilTest +detectionFor ("DoesNullTest", Nothing) = simple doesNilTest +detectionFor ("DoesTypeTest", Nothing) = simple doesTypeTest +detectionFor ("HasAssignmentCondition", Nothing) = simple hasAssignmentCondition +detectionFor ("HasAssignmentReturn", Nothing) = simple hasAssignmentReturn +detectionFor ("HasCodeDuplication", Nothing) = unsupported +detectionFor ("HasDeclarationTypos", Just target) = raw (detectDeclarationTypos target) +detectionFor ("HasEmptyIfBranches", Nothing) = simple hasEmptyIfBranches +detectionFor ("HasEmptyRepeat", Nothing) = simple hasEmptyRepeat +detectionFor ("HasEqualIfBranches", Nothing) = simple hasEqualIfBranches +detectionFor ("HasLongParameterList", Nothing) = simple hasLongParameterList +detectionFor ("HasMisspelledBindings", Nothing) = withLanguage hasMisspelledIdentifiers +detectionFor ("HasMisspelledIdentifiers", Nothing) = withLanguage hasMisspelledIdentifiers +detectionFor ("HasRedundantBooleanComparison", Nothing) = simple hasRedundantBooleanComparison +detectionFor ("HasRedundantGuards", Nothing) = simple hasRedundantGuards +detectionFor ("HasRedundantIf", Nothing) = simple hasRedundantIf +detectionFor ("HasRedundantLambda", Nothing) = simple hasRedundantLambda +detectionFor ("HasRedundantLocalVariableReturn", Nothing) = simple hasRedundantLocalVariableReturn +detectionFor ("HasRedundantParameter", Nothing) = simple hasRedundantParameter +detectionFor ("HasRedundantReduction", Nothing) = simple hasRedundantReduction +detectionFor ("HasRedundantRepeat", Nothing) = simple hasRedundantRepeat +detectionFor ("HasTooManyMethods", Nothing) = simple hasTooManyMethods +detectionFor ("HasTooShortBindings", Nothing) = withLanguage hasTooShortIdentifiers +detectionFor ("HasTooShortIdentifiers", Nothing) = withLanguage hasTooShortIdentifiers +detectionFor ("HasUnreachableCode", Nothing) = simple hasUnreachableCode +detectionFor ("HasUsageTypos", Just target) = raw (detectUsageTypos target) +detectionFor ("HasWrongCaseBinding", Nothing) = withLanguage hasWrongCaseIdentifiers +detectionFor ("HasWrongCaseIdentifiers", Nothing) = withLanguage hasWrongCaseIdentifiers +detectionFor ("IsLongCode", Nothing) = unsupported +detectionFor ("OverridesEqualOrHashButNotBoth", Nothing) = simple overridesEqualOrHashButNotBoth +detectionFor ("ReturnsNil", Nothing) = simple returnsNil +detectionFor ("ReturnsNull", Nothing) = simple returnsNil +detectionFor ("ShouldInvertIfCondition", Nothing) = simple shouldInvertIfCondition +detectionFor ("ShouldUseOtherwise", Nothing) = simple shouldUseOtherwise +detectionFor ("ShouldUseStrictComparators", Nothing) = simple shouldUseStrictComparators +detectionFor ("UsesCut", Nothing) = simple usesCut +detectionFor ("UsesFail", Nothing) = simple usesFail +detectionFor ("UsesNamedSelfReference", Nothing) = simple usesNamedSelfReference +detectionFor ("UsesUnificationOperator", Nothing) = simple usesUnificationOperator +detectionFor ("JavaScript#UsesVarInsteadOfLet", Nothing) = simple usesVarInsteadOfLet +detectionFor ("JavaScript#UsesForInInsteadOfForOf", Nothing) = simple usesForInInsteadOfForOf +detectionFor _ = unsupported unsupported :: Detection unsupported _ _ = [] diff --git a/src/Language/Mulang/Inspector/Smell/JavaScript.hs b/src/Language/Mulang/Inspector/Smell/JavaScript.hs index 6b88f2599..93de4178d 100644 --- a/src/Language/Mulang/Inspector/Smell/JavaScript.hs +++ b/src/Language/Mulang/Inspector/Smell/JavaScript.hs @@ -1,5 +1,6 @@ module Language.Mulang.Inspector.Smell.JavaScript ( - usesVarInsteadOfLet) where + usesVarInsteadOfLet, + usesForInInsteadOfForOf) where import Language.Mulang.Ast import Language.Mulang.Inspector.Primitive (Inspection, containsExpression) @@ -10,3 +11,8 @@ usesVarInsteadOfLet = containsExpression f where f (Other (Just "JSVar") _) = True f (For [Generator (OtherPattern (Just "JSVar") _) _] _) = True f _ = False + +usesForInInsteadOfForOf :: Inspection +usesForInInsteadOfForOf = containsExpression f + where f (Other (Just "JSForIn") _) = True + f _ = False diff --git a/src/Language/Mulang/Parsers/JavaScript.hs b/src/Language/Mulang/Parsers/JavaScript.hs index efbd07760..e8c6677a3 100644 --- a/src/Language/Mulang/Parsers/JavaScript.hs +++ b/src/Language/Mulang/Parsers/JavaScript.hs @@ -35,18 +35,20 @@ muJSAST (JSAstStatement statement _) = muJSStatement statement muJSAST (JSAstExpression expression _) = muJSExpression expression muJSAST (JSAstLiteral expression _) = muJSExpression expression - muJSStatement:: JSStatement -> Expression muJSStatement (JSStatementBlock _ statements _ _) = compactMap muJSStatement statements --muJSStatement (JSConstant _ (JSCommaList JSExpression) _) -- ^const, decl, autosemi muJSStatement (JSDoWhile _ statement _ _ expression _ _) = While (muJSExpression expression) (muJSStatement statement) +muJSStatement (JSForLetIn _ _ _ (JSVarInitExpression id _) _ gen _ body) = muForIn VariablePattern id gen body +muJSStatement (JSForIn _ _ id _ gen _ body) = muForIn muJsVarPattern id gen body +muJSStatement (JSForVarIn _ _ _ (JSVarInitExpression id _) _ gen _ body) = muForIn muJsVarPattern id gen body muJSStatement (JSFor _ _ inits _ conds _ progs _ body) = muFor inits conds progs body muJSStatement (JSForVar _ _ _ inits _ conds _ progs _ body) = muFor inits conds progs body muJSStatement (JSForLet _ _ _ inits _ conds _ progs _ body) = muFor inits conds progs body muJSStatement (JSForConstOf _ _ _ (JSVarInitExpression id _) _ gen _ body) = muForOf ConstantPattern id gen body muJSStatement (JSForLetOf _ _ _ (JSVarInitExpression id _) _ gen _ body) = muForOf VariablePattern id gen body -muJSStatement (JSForOf _ _ id _ gen _ body) = muForOf (otherPattern "JSVar" . VariablePattern) id gen body -muJSStatement (JSForVarOf _ _ _ (JSVarInitExpression id _) _ gen _ body) = muForOf (otherPattern "JSVar" . VariablePattern) id gen body +muJSStatement (JSForOf _ _ id _ gen _ body) = muForOf muJsVarPattern id gen body +muJSStatement (JSForVarOf _ _ _ (JSVarInitExpression id _) _ gen _ body) = muForOf muJsVarPattern id gen body muJSStatement (JSFunction _ ident _ params _ body _) = muComputation ident params body muJSStatement (JSIf _ _ expression _ statement) = If (muJSExpression expression) (muJSStatement statement) None muJSStatement (JSIfElse _ _ expression _ ifStatement _ elseStatement) = If (muJSExpression expression) (muJSStatement ifStatement) (muJSStatement elseStatement) @@ -97,6 +99,8 @@ muJSPatternList = mapJSList muExpressionPattern muJSExpressionFromList = compact . muJSExpressionList +muJsVarPattern = otherPattern "JSVar" . VariablePattern + muFor inits conds progs body = (ForLoop (muJSExpressionFromList inits) (muJSExpressionFromList conds) @@ -106,6 +110,7 @@ muFor inits conds progs body = (ForLoop muForOf kind (JSIdentifier _ id) generator body = (For [Generator (kind id) (muJSExpression generator)] (muJSStatement body)) +muForIn kind id generator body = other "JSForIn" $ muForOf kind id generator body muSwitch expression (def, cases) = Switch (muJSExpression expression) (map muCase cases) (headOrElse None . map muDefault $ def)