Allow to customize the TODO marker string

This commit is contained in:
Alexander Kobjolke 2022-03-07 12:48:33 +01:00
parent 461f34a100
commit 4514d0f120
5 changed files with 61 additions and 28 deletions

View file

@ -44,13 +44,15 @@ Usage: annotator [OPTIONS] files...
A tool to semi-automatically add Coverity source-code annotations based on found defects.
-v --verbose be more verbose, pass multiple times to increase verbosity
-i --inplace replace source-file after inserting annotations
-V --version show version
--short-version show version
-h --help show usage information
-a --all handle all defects not just Newest
-C[NUM] --context[=NUM] specify how much context should be shown around a violation
-v --verbose be more verbose, pass multiple times to increase verbosity
-i --inplace replace source-file after inserting annotations
-V --version show full version information
--short-version show just the version number
-h --help show usage information
-a --all handle all defects not just Newest
-C[NUM] --context[=NUM] specify how much context should be shown around a violation
-t[STRING] --todo-marker[=STRING] override the default TODO marker with a custom string
-A FILE --annotations=FILE load automatic annotation rules
```
### In-place annotations
@ -65,3 +67,18 @@ By default the annotator will only handle *Newest* violations and not those that
are already contained within the Coverity database for some reason. However,
it's still possible to process all found violations by passing `-a` or `--all`
on the command-line.
### Insert annotations automatically
In case you have violations that always result in the same annotation over and
over again, you can supply one or more files that contain automatic decisions.
Each line may be one of the following:
```
Intentional (Rule "autosar_cpp14_a18_9_1") "reason why it's intentional"
FalsePositive (Rule "autosar_cpp14_a18_9_1") "reason why it's a false-positive"
ToDo (Rule "autosar_cpp14_a18_9_1")
```
Lines may be disabled by prefixing them with `#` or `--`.

View file

@ -1 +1,4 @@
Intentional (Rule "autosar_cpp14_a18_9_1") "Test auto"
Intentional (Rule "autosar_cpp14_a18_9_1") "Test intentional auto"
--FalsePositive (Rule "autosar_cpp14_a18_9_2") "Test false auto"
ToDo (Rule "autosar_cpp14_a18_9_3")
#ToDo (Rule "autosar_cpp14_a18_9_4")

View file

@ -30,7 +30,7 @@ import Annotator.Rule
import Annotator.Annotation
version :: Vsn.Version
version = Vsn.makeVersion [0,0,3,0]
version = Vsn.makeVersion [0,0,4,0]
type App a = ReaderT Options IO a
@ -54,6 +54,7 @@ data Options = Options
, onlyNewest :: Bool
, annotationFiles :: [FilePath]
, autoAnnotations :: [Annotation]
, todoMarker :: String
}
deriving (Show, Eq)
@ -67,6 +68,7 @@ defaultOptions = Options
, onlyNewest = True
, annotationFiles = []
, autoAnnotations = []
, todoMarker = "TODO"
}
options :: [OptDescr (Options -> Options)]
@ -90,11 +92,22 @@ options =
(NoArg (\opts -> opts { onlyNewest = False}))
"handle all defects not just Newest"
, Option ['C'] ["context"]
(OptArg ((\f opts -> opts { contextLines = fromMaybe 0 $ readMaybe f }) . fromMaybe "0") "NUM")
(OptArg (\f opts -> opts { contextLines = fromMaybe 0 (f >>= readMaybe) }) "NUM")
"specify how much context should be shown around a violation"
, Option ['t'] ["todo-marker"]
(OptArg (\f opts -> opts { todoMarker = fromMaybe "TODO" f }) "STRING")
"override the default TODO marker with a custom string"
, Option ['A'] ["annotations"]
(ReqArg (\f opts -> opts { annotationFiles = (nub $ annotationFiles opts ++ [f]) }) "FILE")
"load automatic annotation rules"
(unlines [ "load automatic annotation rules"
, " some examples:"
, " " <> show (Intentional (Rule "rule_1") "some reason")
, " " <> show (FalsePositive (Rule "rule_1") "some reason")
, " " <> show (ToDo (Rule "rule_1"))
, " # a comment"
, " -- another comment"
]
)
]
readMaybe :: (Read a) => String -> Maybe a
@ -230,6 +243,7 @@ handleViolations violations = do
opts <- ask
let fname = filename $ NE.head violations
fname' = fname <> ".fix"
todo = todoMarker opts
header' = "Processing " <> (show $ NE.length violations) <> " violation(s) in file " <> fname
header = unlines
[ header'
@ -252,7 +266,7 @@ handleViolations violations = do
annotations <- (catMaybes . NE.toList) <$> mapM (handleViolation content) violations
let annotatedLines = sortBy (comparing fst) $ fmap annotationToLine annotations
let annotatedLines = sortBy (comparing fst) $ fmap (annotationToLine todo) annotations
newContent = unlines . map snd $ mergeLines annotatedLines numberedContent
liftIO $ writeFile fname' newContent
@ -261,10 +275,14 @@ handleViolations violations = do
else do
verbose Low $ "skipping non-existent file " <> fname
where
annotationToLine :: AnnotatedViolation -> (Int, String)
annotationToLine (AnnotatedViolation Violation{..} a indent) =
(line, indent ++ showAnnotation a description)
annotationToLine :: String -> AnnotatedViolation -> (Int, String)
annotationToLine todo (AnnotatedViolation Violation{..} a indent) =
(line, indent ++ showAnnotation todo a description)
showAnnotation :: String -> Annotation -> String -> String
showAnnotation _ (Intentional (Rule rule) reason) _ = mconcat ["// ", "coverity[", rule, "_violation", "] ", reason]
showAnnotation _ (FalsePositive (Rule rule) reason) _ = mconcat ["// ", "coverity[", rule, "_violation", " : FALSE", "] ", reason]
showAnnotation todo (ToDo (Rule rule)) description = "// " <> todo <> " " <> rule <> ": " <> description
data UserChoice = Abort
| Annotate Annotation

View file

@ -1,24 +1,23 @@
{-# LANGUAGE LambdaCase #-}
module Annotator.Annotation (Annotation(..), showAnnotation, fromFile) where
module Annotator.Annotation (Annotation(..), fromFile) where
import Data.Char (isSpace)
import Annotator.Rule
import Data.Monoid
data Annotation = Intentional !Rule !String
| FalsePositive !Rule !String
| ToDo !Rule
deriving (Show, Read, Eq)
showAnnotation :: Annotation -> String -> String
showAnnotation (Intentional (Rule rule) reason) _ = mconcat ["// ", "coverity[", rule, "_violation", "] ", reason]
showAnnotation (FalsePositive (Rule rule) reason) _ = mconcat ["// ", "coverity[", rule, "_violation", " : FALSE", "] ", reason]
showAnnotation (ToDo (Rule rule)) description = "// FIXME violation " <> rule <> ": " <> description
fromFile :: FilePath -> IO [Either String Annotation]
fromFile fn = fmap safeRead . removeBoring . lines <$> readFile fn
where
removeBoring :: [String] -> [String]
removeBoring = filter (const True)
removeBoring = filter (not . isBoring)
isBoring x = isComment x || isEmpty x
isComment x = take 1 x == "#" || take 2 x == "--"
isEmpty = null . dropWhile isSpace
safeRead :: String -> Either String Annotation
safeRead s = case reads s of

View file

@ -3,8 +3,4 @@
module Annotator.Rule where
newtype Rule = Rule String
deriving (Eq, Read)
instance Show Rule where
show :: Rule -> String
show (Rule r) = r
deriving (Eq, Read, Show)