{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Strict #-} module Tokstyle.Linter.GlobalFuncs (descr) where import Control.Monad.State.Strict (State) import qualified Control.Monad.State.Strict as State import Data.Fix (Fix (..)) import Data.Text (Text) import qualified Data.Text as Text import Language.Cimple (Lexeme (..), Node, NodeF (..), Scope (..), lexemeText) import Language.Cimple.Diagnostics (CimplePos, Diagnostic) import Prettyprinter (pretty, (<+>)) import System.FilePath (takeExtension) import Tokstyle.Common (backticks, warn, warnDoc) analyse :: (FilePath, [Node (Lexeme Text)]) -> [Diagnostic CimplePos] analyse :: (FilePath, [Node (Lexeme Text)]) -> [Diagnostic CimplePos] analyse (FilePath file, [Node (Lexeme Text)] _) | FilePath -> FilePath takeExtension FilePath file FilePath -> FilePath -> Bool forall a. Eq a => a -> a -> Bool /= FilePath ".c" = [] analyse (FilePath file, [Node (Lexeme Text)] ast) = [Diagnostic CimplePos] -> [Diagnostic CimplePos] forall a. [a] -> [a] reverse ([Diagnostic CimplePos] -> [Diagnostic CimplePos]) -> [Diagnostic CimplePos] -> [Diagnostic CimplePos] forall a b. (a -> b) -> a -> b $ State [Diagnostic CimplePos] [()] -> [Diagnostic CimplePos] -> [Diagnostic CimplePos] forall s a. State s a -> s -> s State.execState ((Node (Lexeme Text) -> StateT [Diagnostic CimplePos] Identity ()) -> [Node (Lexeme Text)] -> State [Diagnostic CimplePos] [()] forall (t :: * -> *) (m :: * -> *) a b. (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b) mapM Node (Lexeme Text) -> StateT [Diagnostic CimplePos] Identity () forall diags a. (HasDiagnosticsRich diags CimplePos, HasDiagnosticInfo (Lexeme a) CimplePos, Pretty a) => Fix (NodeF (Lexeme a)) -> DiagnosticsT diags () go [Node (Lexeme Text)] ast) [] where go :: Fix (NodeF (Lexeme a)) -> DiagnosticsT diags () go (Fix (FunctionDecl Scope Global (Fix (FunctionPrototype Fix (NodeF (Lexeme a)) _ Lexeme a name [Fix (NodeF (Lexeme a))] _)))) = FilePath -> Lexeme a -> Doc AnsiStyle -> DiagnosticsT diags () forall diags at. (HasDiagnosticsRich diags CimplePos, HasDiagnosticInfo at CimplePos) => FilePath -> at -> Doc AnsiStyle -> DiagnosticsT diags () warnDoc FilePath file Lexeme a name (Doc AnsiStyle -> DiagnosticsT diags ()) -> Doc AnsiStyle -> DiagnosticsT diags () forall a b. (a -> b) -> a -> b $ Doc AnsiStyle "global function" Doc AnsiStyle -> Doc AnsiStyle -> Doc AnsiStyle forall ann. Doc ann -> Doc ann -> Doc ann <+> Doc AnsiStyle -> Doc AnsiStyle forall ann. Doc ann -> Doc ann backticks (a -> Doc AnsiStyle forall a ann. Pretty a => a -> Doc ann pretty (Lexeme a -> a forall text. Lexeme text -> text lexemeText Lexeme a name)) Doc AnsiStyle -> Doc AnsiStyle -> Doc AnsiStyle forall ann. Doc ann -> Doc ann -> Doc ann <+> Doc AnsiStyle "declared in .c file" go Fix (NodeF (Lexeme a)) _ = () -> DiagnosticsT diags () forall (m :: * -> *) a. Monad m => a -> m a return () descr :: ((FilePath, [Node (Lexeme Text)]) -> [Diagnostic CimplePos], (Text, Text)) descr :: ((FilePath, [Node (Lexeme Text)]) -> [Diagnostic CimplePos], (Text, Text)) descr = ((FilePath, [Node (Lexeme Text)]) -> [Diagnostic CimplePos] analyse, (Text "global-funcs", [Text] -> Text Text.unlines [ Text "Checks that no extern functions are declared in .c files." , Text "" , Text "Extern functions must only be declared in .h files. In .c files all declarations" , Text "must be static." , Text "" , Text "**Reason:** extern declarations in .c files mean that we depend on a function" , Text "not declared in a .h file we can include. This means we're depending on an" , Text "unexported implementation detail, and there is no compiler that can check" , Text "whether our declaration matches the implementation's definition." ]))