Support emitting a correct end column on SC2086

This does the necessary work to emit end columns on AST analyses. SC2086
is made to emit a correct end column as an illustrative example.

For example:
```
$ shellcheck -s bash -f json /dev/stdin <<< 'echo $1'
[{"file":"/dev/stdin","line":1,"endLine":1,"column":6,"endColumn":8,"level":"info","code":2086,"message":"Double quote to prevent globbing and word splitting."}]
```

This change deprecates the parser's getNextId and getNextIdAt, replacing
it with a new withNextId function. This function has the type signature:

withNextId :: Monad m => ParsecT s UserState (SCBase m) (Id -> b) -> ParsecT s UserState (SCBase m) b

Specifically, it should be used to wrap read* functions and will pass in
a newly generated Id which should be used to represent that node.
Sub-parsers will need their own call to withNextId in order to get a
unique Id.

In doing this, withNextId can now track both the entry and exit position
of every read* parser which uses it, enabling the tracking of end
columns throughout the application.
This commit is contained in:
Russell Harmon 2016-06-18 22:15:01 -07:00 committed by Ng Zhi An
parent b5e5d249c4
commit 4470fe715c
3 changed files with 59 additions and 17 deletions

View file

@ -29,6 +29,7 @@ import Data.Functor
import Data.List
import Data.Maybe
import Data.Ord
import Control.Applicative
import Control.Monad.Identity
import qualified Data.Map as Map
import qualified System.IO
@ -37,11 +38,14 @@ import Control.Monad
import Test.QuickCheck.All
tokenToPosition map (TokenComment id c) = fromMaybe fail $ do
position <- Map.lookup id map
return $ PositionedComment position position c
tokenToPosition startMap endMap (TokenComment id c) = fromMaybe fail $ do
position <- maybePosition
endPosition <- maybeEndPosition <|> maybePosition
return $ PositionedComment position endPosition c
where
fail = error "Internal shellcheck error: id doesn't exist. Please report!"
maybeEndPosition = Map.lookup id endMap
maybePosition = Map.lookup id startMap
checkScript :: Monad m => SystemInterface m -> CheckSpec -> m CheckResult
checkScript sys spec = do
@ -62,7 +66,7 @@ checkScript sys spec = do
fromMaybe [] $
(arComments . analyzeScript . analysisSpec)
<$> prRoot result
let translator = tokenToPosition (prTokenPositions result)
let translator = tokenToPosition (prTokenPositions result) (prTokenEndPositions result)
return . nub . sortMessages . filter shouldInclude $
(parseMessages ++ map translator analysisMessages)