diff --git a/README.md b/README.md index 1fd2b9519..06fa7efca 100644 --- a/README.md +++ b/README.md @@ -408,6 +408,7 @@ The power of Mulang is grounded on more than 70 different kind of inspections: | `declaresTypeAlias` | any | is a given type synonym declared? | `declaresTypeSignature` | any | is a given computation type signature declared? | `declaresVariable` | any | is a given local o global variable declared? +| `delegates` | delegates | is a method, function or procedure declared AND called? | `discardsExceptions` | any | are exceptions discarded within an empty catch block? | `doesConsolePrint` | any | is there any console-print-statement like `System.out.println`, `puts` or `console.log`? | `doesNullTest` | object oriented | is there a test agains a null value, like `if x == nil then puts 'is nil'` diff --git a/spec/InspectorSpec.hs b/spec/InspectorSpec.hs index 155b79ab7..a06db0a9f 100644 --- a/spec/InspectorSpec.hs +++ b/spec/InspectorSpec.hs @@ -336,6 +336,53 @@ spec = do it "is False if there is no usage" $ do uses (named "m") (EntryPoint "main" (Reference "f")) `shouldBe` False + describe "delegates" $ do + context "when subroutine is declared" $ do + it "is True on function application in entry point" $ do + delegates (named "m") (Sequence [ + EntryPoint "main" (Application (Reference "m") []), + SimpleProcedure "m" [] None]) `shouldBe` True + + it "is True on message send application in entry point" $ do + delegates (named "m") (Sequence [ + EntryPoint "main" (Send Self (Reference "m") []), + SimpleMethod "m" [] None]) `shouldBe` True + + it "is False on direct usage in entry point" $ do + delegates (named "m") (Sequence [ + EntryPoint "main" (Reference "m"), + Class "m" Nothing None]) `shouldBe` False + + it "is False if there is no usage" $ do + delegates (named "m") (Sequence [ + EntryPoint "main" (Reference "f"), + SimpleProcedure "m" [] None]) `shouldBe` False + + it "is True when delegated and a wildcard is used" $ do + delegates anyone (Sequence [ + EntryPoint "main" (Application (Reference "m") []), + SimpleProcedure "m" [] None]) `shouldBe` True + + it "is False when not delegated and a wildcard is used" $ do + delegates anyone (Sequence [ + EntryPoint "main" (Application (Reference "g") []), + SimpleProcedure "m" [] None]) `shouldBe` False + + + context "when subroutine is not declared" $ do + it "is False on function application in entry point" $ do + delegates (named "m") (EntryPoint "main" (Application (Reference "m") [])) `shouldBe` False + + it "is False on message send application in entry point" $ do + delegates (named "m") (EntryPoint "main" (Send Self (Reference "m") [])) `shouldBe` False + + it "is False on direct usage in entry point" $ do + delegates (named "m") (EntryPoint "main" (Reference "m")) `shouldBe` False + + it "is False if there is no usage" $ do + delegates (named "m") (EntryPoint "main" (Reference "f")) `shouldBe` False + + describe "calls" $ do it "is True on function application in entry point" $ do calls (named "m") (EntryPoint "main" (Application (Reference "m") [])) `shouldBe` True diff --git a/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs b/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs index 46a48f582..ecfb6743a 100644 --- a/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs +++ b/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs @@ -80,14 +80,15 @@ compileInspectionPrimitive = f f "DeclaresTypeAlias" = binded declaresTypeAlias f "DeclaresTypeSignature" = binded declaresTypeSignature f "DeclaresVariable" = binded declaresVariable + f "Delegates" = binded delegates f "Implements" = binded implements f "Includes" = binded includes f "Inherits" = binded inherits f "Instantiates" = binded instantiates f "Raises" = binded raises f "Rescues" = binded rescues - f "TypesParameterAs" = binded typesParameterAs f "TypesAs" = binded typesAs + f "TypesParameterAs" = binded typesParameterAs f "TypesReturnAs" = binded typesReturnAs f "Uses" = binded uses f "UsesAnonymousVariable" = simple usesAnonymousVariable diff --git a/src/Language/Mulang/Inspector/Generic.hs b/src/Language/Mulang/Inspector/Generic.hs index 9a61137bd..58d22fd55 100644 --- a/src/Language/Mulang/Inspector/Generic.hs +++ b/src/Language/Mulang/Inspector/Generic.hs @@ -2,6 +2,7 @@ module Language.Mulang.Inspector.Generic ( parses, assigns, calls, + delegates, uses, usesIf, usesYield, @@ -23,12 +24,13 @@ module Language.Mulang.Inspector.Generic ( import Language.Mulang.Ast import Language.Mulang.Identifier import Language.Mulang.Inspector.Primitive -import Language.Mulang.Generator (declaredIdentifiers, referencedIdentifiers) +import Language.Mulang.Generator (declaredIdentifiers, referencedIdentifiers, declarations, expressions) +import Control.Monad (guard) + import Data.Maybe (listToMaybe) import Data.List.Extra (has) - -- | Inspection that tells whether an expression is equal to a given piece of code after being parsed parses :: (String -> Expression) -> String -> Inspection parses parser code = (== (parser code)) @@ -51,6 +53,13 @@ calls p = containsExpression f where f (Call (Reference id) _ ) = p id f _ = False +-- uncontextualizable +delegates :: IdentifierInspection +delegates p expression = inspect $ do + (Subroutine name1 _) <- declarations expression + (Call (Reference name2) _) <- expressions expression + guard (name1 == name2) + guard (p name1) -- | Inspection that tells whether an expression uses ifs -- in its definition diff --git a/src/Language/Mulang/Inspector/ObjectOriented/Polymorphism.hs b/src/Language/Mulang/Inspector/ObjectOriented/Polymorphism.hs index 6066120c4..3699db403 100644 --- a/src/Language/Mulang/Inspector/ObjectOriented/Polymorphism.hs +++ b/src/Language/Mulang/Inspector/ObjectOriented/Polymorphism.hs @@ -10,11 +10,11 @@ module Language.Mulang.Inspector.ObjectOriented.Polymorphism ( import Language.Mulang.Ast import Language.Mulang.Identifier -import Language.Mulang.Inspector.Primitive (Inspection) +import Language.Mulang.Inspector.Primitive (Inspection, InspectionContext, inspect) import Language.Mulang.Inspector.ObjectOriented (implements, declaresMethod) import Language.Mulang.Inspector.Typed (usesType) -import Control.Monad (MonadPlus, guard) +import Control.Monad (guard) import Language.Mulang.Generator (Generator, declarations, expressions) usesDynamicMethodOverload :: Inspection @@ -44,11 +44,13 @@ usesTemplateMethod expression = inspect $ do (SimpleSend Self selector _) <- expressions klass guard (not . declaresMethod (named selector) $ klass) +-- uncontextualizable usesDyamicPolymorphism :: Inspection usesDyamicPolymorphism expression = inspect $ do (SimpleSend _ selector _) <- expressions expression guardCount (>1) (methodDeclarationsOf selector expression) +-- uncontextualizable usesStaticPolymorphism :: Inspection usesStaticPolymorphism expression = inspect $ do interface@(Interface interfaceId _ _) <- declarations expression @@ -58,10 +60,7 @@ usesStaticPolymorphism expression = inspect $ do -- private -inspect :: [a] -> Bool -inspect = not.null - -guardCount :: MonadPlus m => (Int -> Bool) -> [a] -> m () +guardCount :: (Int -> Bool) -> [Expression] -> InspectionContext guardCount condition list = guard (condition . length $ list) methodDeclarationsOf :: Identifier -> Generator Expression diff --git a/src/Language/Mulang/Inspector/Primitive.hs b/src/Language/Mulang/Inspector/Primitive.hs index 9390743cf..5fe61cbf6 100644 --- a/src/Language/Mulang/Inspector/Primitive.hs +++ b/src/Language/Mulang/Inspector/Primitive.hs @@ -1,10 +1,12 @@ module Language.Mulang.Inspector.Primitive ( + inspect, containsExpression, containsDeclaration, containsBoundDeclaration, containsBody, matchesType, Inspection, + InspectionContext, IdentifierInspection) where import Language.Mulang.Ast @@ -13,7 +15,8 @@ import Language.Mulang.Generator (expressions, boundDeclarations, equa import Data.List.Extra (has) -type Inspection = Expression -> Bool +type Inspection = Expression -> Bool +type InspectionContext = [()] type IdentifierInspection = IdentifierPredicate -> Inspection containsExpression :: (Expression -> Bool) -> Inspection @@ -34,3 +37,5 @@ matchesType predicate (AsPattern _ (TypePattern n)) = predicate n matchesType predicate (UnionPattern patterns) = any (matchesType predicate) patterns matchesType _ _ = False +inspect :: InspectionContext -> Bool +inspect = not.null