packages feed

hs-inspector 0.4.0.0 → 0.5.0.0

raw patch · 7 files changed

+167/−99 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Language.Haskell.Detector: detect :: Inspection -> Code -> [Binding]
- Language.Haskell.Explorer: exploreEO :: (EO -> Bool) -> [EO] -> Bool
- Language.Haskell.Explorer: exploreEO' :: (EO -> Bool) -> EO -> Bool
- Language.Haskell.Explorer: exploreExprs :: (EO -> Bool) -> [HsExp] -> Bool
- Language.Haskell.Explorer: topExprs :: HsRhs -> [HsExp]
- Language.Haskell.Inspector: bindingInMatch :: HsMatch -> String
- Language.Haskell.Inspector: concatRhs :: HsRhs -> [HsDecl] -> [HsRhs]
- Language.Haskell.Inspector: findBindingRhs :: String -> Code -> Maybe [HsRhs]
- Language.Haskell.Inspector: isBindingEO :: (EO -> Bool) -> Binding -> Code -> Bool
- Language.Haskell.Inspector: isBindingRhs :: (HsRhs -> Bool) -> Binding -> Code -> Bool
- Language.Haskell.Inspector: isName :: String -> HsName -> Bool
- Language.Haskell.Inspector: nameOf :: HsName -> String
- Language.Haskell.Inspector: negateInspection :: Inspection -> Inspection
- Language.Haskell.Inspector: orFalse :: Maybe Bool -> Bool
- Language.Haskell.Inspector: orNil :: Maybe [t] -> [t]
- Language.Haskell.Inspector: rhsForBinding :: HsDecl -> [HsRhs]
- Language.Haskell.Inspector: testWithBindingRhs :: ([HsRhs] -> Bool) -> Binding -> Code -> Bool
- Language.Haskell.Inspector: testWithCode :: ([HsDecl] -> Bool) -> Code -> Bool
- Language.Haskell.Inspector: type Binding = String
- Language.Haskell.Inspector: type Code = String
- Language.Haskell.Inspector: withBindingRhs :: ([HsRhs] -> a) -> Binding -> Code -> Maybe a
- Language.Haskell.Inspector: withCode :: ([HsDecl] -> a) -> Code -> Maybe a
+ Language.Haskell.Explorer: declsOf :: Binding -> Code -> [HsDecl]
+ Language.Haskell.Explorer: expressionToBinding :: EO -> Maybe Binding
+ Language.Haskell.Explorer: expressionsOf :: Binding -> Code -> [EO]
+ Language.Haskell.Explorer: parseBindings :: Code -> [Binding]
+ Language.Haskell.Explorer: parseDecls :: Code -> [HsDecl]
+ Language.Haskell.Explorer: rhssOf :: Binding -> Code -> [HsRhs]
+ Language.Haskell.Explorer: type Binding = String
+ Language.Haskell.Explorer: type Code = String
+ Language.Haskell.Inspector: hasDecl :: (HsDecl -> Bool) -> GlobalInspection
+ Language.Haskell.Inspector: hasExpression :: (EO -> Bool) -> Inspection
+ Language.Haskell.Inspector: hasRhs :: (HsRhs -> Bool) -> Inspection
+ Language.Haskell.Inspector: type GlobalInspection = Code -> Bool
+ Language.Haskell.Inspector.Combiner: detect :: Inspection -> Code -> [Binding]
+ Language.Haskell.Inspector.Combiner: negative :: Inspection -> Inspection
+ Language.Haskell.Inspector.Combiner: transitive :: Inspection -> Inspection
+ Language.Haskell.Names: declName :: HsDecl -> String
+ Language.Haskell.Names: isName :: String -> HsName -> Bool
+ Language.Haskell.Names: name :: HsName -> String
+ Language.Haskell.Names: qName :: HsQName -> Maybe String
- Language.Haskell.Inspector: isParseable :: Code -> Bool
+ Language.Haskell.Inspector: isParseable :: GlobalInspection

Files

hs-inspector.cabal view
@@ -2,7 +2,7 @@ --  http://haskell.org/cabal/users-guide/  name:                hs-inspector-version:             0.4.0.0+version:             0.5.0.0 license:             MIT license-file:        LICENSE author:              Franco Leonardo Bulgarelli@@ -21,10 +21,11 @@   hs-source-dirs:       src   exposed-modules:+    Language.Haskell.Names     Language.Haskell.Explorer-    Language.Haskell.Detector     Language.Haskell.Inspector     Language.Haskell.Inspector.Smell+    Language.Haskell.Inspector.Combiner   build-depends:     base                      >= 4     && < 5,     haskell-src               >= 1     && < 1.1
− src/Language/Haskell/Detector.hs
@@ -1,16 +0,0 @@-module Language.Haskell.Detector (detect) where--import Language.Haskell.Inspector-import Language.Haskell.Syntax--bindingsOf :: Code -> [String]-bindingsOf = orNil . withCode (concatMap bindings)-  where-  bindings (HsTypeSig _ [b] _) = [nameOf b]-  bindings (HsTypeDecl _ b _ _) = [nameOf b]-  bindings (HsPatBind _ (HsPVar n) _ _) = [nameOf n]-  bindings (HsFunBind cases)  = map bindingInMatch cases-  bindings _                  = []--detect :: Inspection -> Code -> [Binding]-detect inspection code = filter (`inspection` code) $ bindingsOf code
src/Language/Haskell/Explorer.hs view
@@ -1,24 +1,79 @@-module Language.Haskell.Explorer where+module Language.Haskell.Explorer (+  parseDecls,+  parseBindings,+  declsOf,+  rhssOf,+  expressionsOf,+  expressionToBinding,+  EO(..),+  Binding,+  Code) where  import Language.Haskell.Syntax+import Language.Haskell.Names+import Language.Haskell.Parser +type Binding = String+type Code = String+ data EO = E HsExp | O HsQOp -exploreExprs f exprs = exploreEO f $ map (E) exprs+-- xxxOf functions: take a binding and code+-- parseXxx functions: take just code -exploreEO f es = any f es || any (exploreEO' f) es+declsOf :: Binding -> Code -> [HsDecl]+declsOf binding = filter (isBinding binding) . parseDecls -exploreEO' :: (EO -> Bool) -> EO -> Bool-exploreEO' f (E (HsInfixApp a b c)) = exploreEO f [E a, O b, E c]-exploreEO' f (E (HsApp a b))  = exploreEO f [E a, E b]-exploreEO' f (E (HsNegApp a))  = exploreEO f [E a]-exploreEO' f (E (HsLambda _ _ a)) = exploreEO f [E a]-exploreEO' f (E (HsList as)) = exploreExprs f as-exploreEO' f (E (HsListComp a _)) = exploreExprs f [a] --TODO-exploreEO' f (E (HsTuple as))  = exploreExprs f as-exploreEO' f (E (HsParen a)) = exploreExprs f [a]-exploreEO' f (E (HsIf a b c)) = exploreExprs f [a, b, c]-exploreEO' _ _ = False+rhssOf :: Binding -> Code -> [HsRhs]+rhssOf binding = concatMap rhsForBinding . declsOf binding -topExprs (HsUnGuardedRhs e) = [e]-topExprs (HsGuardedRhss rhss) = rhss >>= \(HsGuardedRhs _ es1 es2) -> [es1, es2]+expressionsOf :: Binding -> Code -> [EO]+expressionsOf binding code = do+  rhs <- rhssOf binding code+  top <- topExpressions rhs+  unfoldExpression top++parseDecls :: Code -> [HsDecl]+parseDecls code+  | ParseOk (HsModule _ _ _ _ decls) <- parseModule code = decls+  | otherwise = []++parseBindings :: Code -> [Binding]+parseBindings = map declName . parseDecls++expressionToBinding :: EO -> Maybe Binding+expressionToBinding (O (HsQVarOp q)) = qName q+expressionToBinding (E (HsVar    q)) = qName q+expressionToBinding _                = Nothing++-- private++topExpressions :: HsRhs -> [EO]+topExpressions (HsUnGuardedRhs e) = [E e]+topExpressions (HsGuardedRhss rhss) = rhss >>= \(HsGuardedRhs _ es1 es2) -> [E es1, E es2]++unfoldExpression :: EO -> [EO]+unfoldExpression expr = expr : concatMap unfoldExpression (subExpressions expr)++subExpressions :: EO -> [EO]+subExpressions (E (HsInfixApp a b c)) = [E a, O b, E c]+subExpressions (E (HsApp a b))        = [E a, E b]+subExpressions (E (HsNegApp a))       = [E a]+subExpressions (E (HsLambda _ _ a))   = [E a]+subExpressions (E (HsList as))        = map (E) as+subExpressions (E (HsListComp a _))   = [E a] --TODO+subExpressions (E (HsTuple as))       = map (E) as+subExpressions (E (HsParen a))        = [E a]+subExpressions (E (HsIf a b c))       = [E a, E b, E c]+subExpressions _ = []++isBinding :: Binding -> HsDecl -> Bool+isBinding binding = (==binding).declName++rhsForBinding :: HsDecl -> [HsRhs]+rhsForBinding (HsPatBind _ _ rhs localDecls) = concatRhs rhs localDecls+rhsForBinding (HsFunBind cases) = cases >>= \(HsMatch _ _ _ rhs localDecls) -> concatRhs rhs localDecls+rhsForBinding _ = []++concatRhs rhs l = [rhs] ++ concatMap rhsForBinding l+
src/Language/Haskell/Inspector.hs view
@@ -1,34 +1,48 @@-module Language.Haskell.Inspector where+module Language.Haskell.Inspector (+  hasComposition,+  hasGuards,+  hasIf,+  hasConditional,+  hasLambda,+  hasDirectRecursion,+  hasUsage,+  hasComprehension,+  hasBinding,+  hasTypeDeclaration,+  hasTypeSignature,+  hasExpression,+  hasDecl,+  hasRhs,+  isParseable,+  Inspection,+  GlobalInspection+  ) where -import  Language.Haskell.Parser import  Language.Haskell.Syntax-import  Data.Maybe (fromMaybe, isJust)-import  Control.Monad (join)-import  Data.List (find)+import  Language.Haskell.Names (isName) import  Language.Haskell.Explorer -type Binding = String-type Code = String type Inspection = Binding -> Code  -> Bool+type GlobalInspection = Code  -> Bool  -- | Inspection that tells whether a binding uses the composition operator '.' -- in its definition hasComposition :: Inspection-hasComposition = isBindingEO f+hasComposition = hasExpression f   where f (O (HsQVarOp (UnQual (HsSymbol ".")))) = True         f _ = False  -- | Inspection that tells whether a binding uses guards -- in its definition hasGuards :: Inspection-hasGuards = isBindingRhs f+hasGuards = hasRhs f   where f (HsGuardedRhss _) = True         f _ = False  -- | Inspection that tells whether a binding uses ifs -- in its definition hasIf :: Inspection-hasIf = isBindingEO f+hasIf = hasExpression f   where f (E (HsIf _ _ _)) = True         f _ = False @@ -40,7 +54,7 @@ -- | Inspection that tells whether a binding uses a lambda expression -- in its definition hasLambda :: Inspection-hasLambda = isBindingEO f+hasLambda = hasExpression f   where f (E (HsLambda _ _ _)) = True         f _ = False @@ -52,80 +66,47 @@ -- | Inspection that tells whether a binding uses the the given target binding -- in its definition hasUsage :: String -> Inspection-hasUsage target = isBindingEO f-  where f (O (HsQVarOp name)) = isTarget name-        f (E (HsVar    name)) = isTarget name-        f _ = False--        isTarget (Qual  _ n) = isName target n-        isTarget (UnQual  n) = isName target n-        isTarget _           = False+hasUsage target = hasExpression f+  where f expr | (Just n) <- expressionToBinding expr = n == target+               | otherwise = False  -- | Inspection that tells whether a binding uses lists comprehensions -- in its definition hasComprehension :: Inspection-hasComprehension = isBindingEO f+hasComprehension = hasExpression f   where f (E (HsListComp _ _)) = True         f _ = False  -- | Inspection that tells whether a top level binding exists hasBinding :: Inspection-hasBinding binding = isJust . findBindingRhs binding+hasBinding binding = not.null.rhssOf binding  hasTypeDeclaration :: Inspection-hasTypeDeclaration binding = testWithCode (any f)+hasTypeDeclaration binding = hasDecl f   where f (HsTypeDecl _ hsName _ _) = isName binding hsName         f _                         = False  hasTypeSignature :: Inspection-hasTypeSignature binding = testWithCode (any f)+hasTypeSignature binding = hasDecl f   where f (HsTypeSig _ [hsName] _)  = isName binding hsName         f _                         = False -isParseable :: Code -> Bool-isParseable = testWithCode (const True)+hasExpression :: (EO -> Bool) -> Inspection+hasExpression f binding = has f (expressionsOf binding) -negateInspection :: Inspection -> Inspection-negateInspection f code = not . f code+hasRhs :: (HsRhs -> Bool)-> Inspection+hasRhs f binding = has f (rhssOf binding) --- ===================================================+isParseable :: GlobalInspection+isParseable = not.null.parseDecls -isName name hsName = nameOf hsName == name+hasDecl :: (HsDecl -> Bool) -> GlobalInspection+hasDecl f = has f parseDecls -nameOf (HsSymbol n) = n-nameOf (HsIdent  n) = n -bindingInMatch (HsMatch _ n _ _ _) = nameOf n+-- private -isBindingEO f = isBindingRhs isExpr-  where isExpr rhs = exploreExprs f $ topExprs rhs+has f g = any f . g -isBindingRhs f = testWithBindingRhs (any f) -testWithBindingRhs :: ([HsRhs] -> Bool) -> Binding -> Code -> Bool-testWithBindingRhs f binding  = orFalse . withBindingRhs f binding--withBindingRhs :: ([HsRhs] -> a) -> Binding -> Code -> Maybe a-withBindingRhs f binding = fmap f . findBindingRhs binding--findBindingRhs binding = fmap rhsForBinding . join . withCode (find isBinding)-  where isBinding (HsPatBind _ (HsPVar n)  _ _) = nameOf n == binding-        isBinding (HsFunBind cases)  = any ((== binding).bindingInMatch) cases-        isBinding _ = False--rhsForBinding :: HsDecl -> [HsRhs]-rhsForBinding (HsPatBind _ _ rhs localDecls) = concatRhs rhs localDecls-rhsForBinding (HsFunBind cases) = cases >>= \(HsMatch _ _ _ rhs localDecls) -> concatRhs rhs localDecls-rhsForBinding _ = []--concatRhs rhs l = [rhs] ++ concatMap rhsForBinding l--testWithCode f =  orFalse . withCode f--withCode :: ([HsDecl] -> a) -> Code -> Maybe a-withCode f code | ParseOk (HsModule _ _ _ _ decls) <- parseModule code = Just (f decls)-                | otherwise = Nothing--orFalse = fromMaybe False-orNil = fromMaybe [] 
+ src/Language/Haskell/Inspector/Combiner.hs view
@@ -0,0 +1,20 @@+module Language.Haskell.Inspector.Combiner (+  detect,+  negative,+  transitive) where++import Language.Haskell.Inspector+import Language.Haskell.Explorer+import Data.Maybe (maybeToList)++detect :: Inspection -> Code -> [Binding]+detect inspection code = filter (`inspection` code) $ parseBindings code++negative :: Inspection -> Inspection+negative f code = not . f code++transitive :: Inspection -> Inspection+transitive inspection binding code = inspection binding code || inUsage+  where inUsage = any (flip (transitive inspection) code) $ do+                      expr <- expressionsOf binding code+                      maybeToList . expressionToBinding $ expr
src/Language/Haskell/Inspector/Smell.hs view
@@ -9,27 +9,27 @@ import Language.Haskell.Inspector  hasRedundantBooleanComparison :: Inspection-hasRedundantBooleanComparison = isBindingEO f+hasRedundantBooleanComparison = hasExpression f   where f (E (HsInfixApp x (HsQVarOp (UnQual (HsSymbol c))) y)) = any isBooleanLiteral [x, y] && isComp c         f _ = False          isComp c = c == "==" || c == "/="  hasRedundantIf :: Inspection-hasRedundantIf = isBindingEO f+hasRedundantIf = hasExpression f   where f (E (HsIf _ x y)) = all isBooleanLiteral [x, y]         f _            = False   hasRedundantGuards :: Inspection-hasRedundantGuards = isBindingRhs f -- TODO not true when condition is a pattern+hasRedundantGuards = hasRhs f -- TODO not true when condition is a pattern   where f (HsGuardedRhss [             HsGuardedRhs _ _ x,             HsGuardedRhs _ (HsVar (UnQual (HsIdent "otherwise"))) y]) = all isBooleanLiteral [x, y]         f _ = False  hasRedundantLambda :: Inspection-hasRedundantLambda = isBindingEO f+hasRedundantLambda = hasExpression f   where f (E (HsLambda _ [HsPVar (HsIdent x)] (HsApp _ (HsVar (UnQual (HsIdent y)))))) = x == y         f _ = False -- TODO consider parenthesis and symbols 
+ src/Language/Haskell/Names.hs view
@@ -0,0 +1,27 @@+module Language.Haskell.Names (+  isName,+  name,+  qName,+  declName) where++import  Language.Haskell.Syntax++isName :: String -> HsName -> Bool+isName n hsName = name hsName == n++name :: HsName -> String+name (HsSymbol n) = n+name (HsIdent  n) = n++qName :: HsQName -> Maybe String+qName (Qual  _ hsName) = Just (name hsName)+qName (UnQual  hsName) = Just (name hsName)+qName _                = Nothing++declName :: HsDecl -> String+declName (HsTypeSig _ [b] _) = name b+declName (HsTypeDecl _ b _ _) = name b+declName (HsPatBind _ (HsPVar n) _ _) = name n+declName (HsFunBind cases)  | (HsMatch _ n _ _ _) <- head cases = name n+declName _                  = []+