Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add delegates inspection #195

Merged
merged 3 commits into from
Jan 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'`
Expand Down
47 changes: 47 additions & 0 deletions spec/InspectorSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/Language/Mulang/Analyzer/ExpectationsCompiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 11 additions & 2 deletions src/Language/Mulang/Inspector/Generic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Language.Mulang.Inspector.Generic (
parses,
assigns,
calls,
delegates,
uses,
usesIf,
usesYield,
Expand All @@ -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))
Expand All @@ -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
Expand Down
11 changes: 5 additions & 6 deletions src/Language/Mulang/Inspector/ObjectOriented/Polymorphism.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
7 changes: 6 additions & 1 deletion src/Language/Mulang/Inspector/Primitive.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
module Language.Mulang.Inspector.Primitive (
inspect,
containsExpression,
containsDeclaration,
containsBoundDeclaration,
containsBody,
matchesType,
Inspection,
InspectionContext,
IdentifierInspection) where

import Language.Mulang.Ast
Expand All @@ -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
Expand All @@ -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