Prototype fix
This commit is contained in:
parent
cb57b4a74f
commit
41613babd9
|
@ -1336,7 +1336,10 @@ prop_checkBackticks1 = verify checkBackticks "echo `foo`"
|
||||||
prop_checkBackticks2 = verifyNot checkBackticks "echo $(foo)"
|
prop_checkBackticks2 = verifyNot checkBackticks "echo $(foo)"
|
||||||
prop_checkBackticks3 = verifyNot checkBackticks "echo `#inlined comment` foo"
|
prop_checkBackticks3 = verifyNot checkBackticks "echo `#inlined comment` foo"
|
||||||
checkBackticks _ (T_Backticked id list) | not (null list) =
|
checkBackticks _ (T_Backticked id list) | not (null list) =
|
||||||
style id 2006 "Use $(...) notation instead of legacy backticked `...`."
|
addComment $
|
||||||
|
makeCommentWithFix StyleC id 2006 "Use $(...) notation instead of legacy backticked `...`."
|
||||||
|
((replaceStart 1 "$(") ++ (replaceEnd 1 ")"))
|
||||||
|
-- style id 2006 "Use $(...) notation instead of legacy backticked `...`."
|
||||||
checkBackticks _ _ = return ()
|
checkBackticks _ _ = return ()
|
||||||
|
|
||||||
prop_checkIndirectExpansion1 = verify checkIndirectExpansion "${foo$n}"
|
prop_checkIndirectExpansion1 = verify checkIndirectExpansion "${foo$n}"
|
||||||
|
@ -1640,8 +1643,10 @@ checkSpacefulness params t =
|
||||||
makeComment InfoC (getId token) 2223
|
makeComment InfoC (getId token) 2223
|
||||||
"This default assignment may cause DoS due to globbing. Quote it."
|
"This default assignment may cause DoS due to globbing. Quote it."
|
||||||
else
|
else
|
||||||
makeComment InfoC (getId token) 2086
|
makeCommentWithFix InfoC (getId token) 2086
|
||||||
"Double quote to prevent globbing and word splitting."
|
"Double quote to prevent globbing and word splitting." (surroundWith "\"")
|
||||||
|
-- makeComment InfoC (getId token) 2086
|
||||||
|
-- "Double quote to prevent globbing and word splitting."
|
||||||
|
|
||||||
writeF _ _ name (DataString SourceExternal) = setSpaces name True >> return []
|
writeF _ _ name (DataString SourceExternal) = setSpaces name True >> return []
|
||||||
writeF _ _ name (DataString SourceInteger) = setSpaces name False >> return []
|
writeF _ _ name (DataString SourceInteger) = setSpaces name False >> return []
|
||||||
|
@ -2538,7 +2543,9 @@ checkUncheckedCdPushdPopd params root =
|
||||||
&& not (isSafeDir t)
|
&& not (isSafeDir t)
|
||||||
&& not (name t `elem` ["pushd", "popd"] && ("n" `elem` map snd (getAllFlags t)))
|
&& not (name t `elem` ["pushd", "popd"] && ("n" `elem` map snd (getAllFlags t)))
|
||||||
&& not (isCondition $ getPath (parentMap params) t)) $
|
&& not (isCondition $ getPath (parentMap params) t)) $
|
||||||
warn (getId t) 2164 "Use 'cd ... || exit' or 'cd ... || return' in case cd fails."
|
-- warn (getId t) 2164 "Use 'cd ... || exit' or 'cd ... || return' in case cd fails."
|
||||||
|
warnWithFix (getId t) 2164 "Use 'cd ... || exit' or 'cd ... || return' in case cd fails."
|
||||||
|
(replaceEnd 0 " || exit")
|
||||||
checkElement _ = return ()
|
checkElement _ = return ()
|
||||||
name t = fromMaybe "" $ getCommandName t
|
name t = fromMaybe "" $ getCommandName t
|
||||||
isSafeDir t = case oversimplify t of
|
isSafeDir t = case oversimplify t of
|
||||||
|
@ -2695,7 +2702,7 @@ checkArrayAssignmentIndices params root =
|
||||||
T_Literal id str -> [(id,str)]
|
T_Literal id str -> [(id,str)]
|
||||||
_ -> []
|
_ -> []
|
||||||
guard $ '=' `elem` str
|
guard $ '=' `elem` str
|
||||||
return $ warn id 2191 "The = here is literal. To assign by index, use ( [index]=value ) with no spaces. To keep as literal, quote it."
|
return $ warnWithFix id 2191 "The = here is literal. To assign by index, use ( [index]=value ) with no spaces. To keep as literal, quote it." (surroundWith "\"")
|
||||||
in
|
in
|
||||||
if null literalEquals && isAssociative
|
if null literalEquals && isAssociative
|
||||||
then warn (getId t) 2190 "Elements in associative arrays need index, e.g. array=( [index]=value ) ."
|
then warn (getId t) 2190 "Elements in associative arrays need index, e.g. array=( [index]=value ) ."
|
||||||
|
|
|
@ -150,6 +150,19 @@ err id code str = addComment $ makeComment ErrorC id code str
|
||||||
info id code str = addComment $ makeComment InfoC id code str
|
info id code str = addComment $ makeComment InfoC id code str
|
||||||
style id code str = addComment $ makeComment StyleC id code str
|
style id code str = addComment $ makeComment StyleC id code str
|
||||||
|
|
||||||
|
warnWithFix id code str fix = addComment $
|
||||||
|
let comment = makeComment WarningC id code str in
|
||||||
|
comment {
|
||||||
|
tcFix = Just fix
|
||||||
|
}
|
||||||
|
|
||||||
|
makeCommentWithFix :: Severity -> Id -> Code -> String -> Fix -> TokenComment
|
||||||
|
makeCommentWithFix severity id code str fix =
|
||||||
|
let comment = makeComment severity id code str in
|
||||||
|
comment {
|
||||||
|
tcFix = Just fix
|
||||||
|
}
|
||||||
|
|
||||||
makeParameters spec =
|
makeParameters spec =
|
||||||
let params = Parameters {
|
let params = Parameters {
|
||||||
rootNode = root,
|
rootNode = root,
|
||||||
|
|
|
@ -42,7 +42,8 @@ tokenToPosition startMap t = fromMaybe fail $ do
|
||||||
return $ newPositionedComment {
|
return $ newPositionedComment {
|
||||||
pcStartPos = fst span,
|
pcStartPos = fst span,
|
||||||
pcEndPos = snd span,
|
pcEndPos = snd span,
|
||||||
pcComment = tcComment t
|
pcComment = tcComment t,
|
||||||
|
pcFix = tcFix t
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
fail = error "Internal shellcheck error: id doesn't exist. Please report!"
|
fail = error "Internal shellcheck error: id doesn't exist. Please report!"
|
||||||
|
|
|
@ -129,8 +129,47 @@ outputForFile color sys comments = do
|
||||||
putStrLn (color "source" line)
|
putStrLn (color "source" line)
|
||||||
mapM_ (\c -> putStrLn (color (severityText c) $ cuteIndent c)) x
|
mapM_ (\c -> putStrLn (color (severityText c) $ cuteIndent c)) x
|
||||||
putStrLn ""
|
putStrLn ""
|
||||||
|
mapM_ (\c -> putStrLn "Did you mean:" >> putStrLn (fixedString c line)) x
|
||||||
) groups
|
) groups
|
||||||
|
|
||||||
|
-- need to do something smart about sorting by end index
|
||||||
|
fixedString :: PositionedComment -> String -> String
|
||||||
|
fixedString comment line =
|
||||||
|
case (pcFix comment) of
|
||||||
|
Nothing -> ""
|
||||||
|
Just rs ->
|
||||||
|
apply_replacement rs line 0
|
||||||
|
where
|
||||||
|
apply_replacement [] s _ = s
|
||||||
|
apply_replacement ((Start n r):xs) s offset =
|
||||||
|
let start = (posColumn . pcStartPos) comment
|
||||||
|
end = start + n
|
||||||
|
z = do_replace start end s r
|
||||||
|
len_r = (fromIntegral . length) r in
|
||||||
|
apply_replacement xs z (offset + (end - start) + len_r)
|
||||||
|
apply_replacement ((End n r):xs) s offset =
|
||||||
|
-- tricky math because column is 1 based
|
||||||
|
let end = (posColumn . pcEndPos) comment + 1
|
||||||
|
start = end - n
|
||||||
|
z = do_replace start end s r
|
||||||
|
len_r = (fromIntegral . length) r in
|
||||||
|
apply_replacement xs z (offset + (end - start) + len_r)
|
||||||
|
|
||||||
|
-- start and end comes from pos, which is 1 based
|
||||||
|
-- do_replace 0 0 "1234" "A" -> "A1234" -- technically not valid
|
||||||
|
-- do_replace 1 1 "1234" "A" -> "A1234"
|
||||||
|
-- do_replace 1 2 "1234" "A" -> "A234"
|
||||||
|
-- do_replace 3 3 "1234" "A" -> "12A34"
|
||||||
|
-- do_replace 4 4 "1234" "A" -> "123A4"
|
||||||
|
-- do_replace 5 5 "1234" "A" -> "1234A"
|
||||||
|
do_replace start end o r =
|
||||||
|
let si = fromIntegral (start-1)
|
||||||
|
ei = fromIntegral (end-1)
|
||||||
|
(x, xs) = splitAt si o
|
||||||
|
(y, z) = splitAt (ei - si) xs
|
||||||
|
in
|
||||||
|
x ++ r ++ z
|
||||||
|
|
||||||
cuteIndent :: PositionedComment -> String
|
cuteIndent :: PositionedComment -> String
|
||||||
cuteIndent comment =
|
cuteIndent comment =
|
||||||
replicate (fromIntegral $ colNo comment - 1) ' ' ++
|
replicate (fromIntegral $ colNo comment - 1) ' ' ++
|
||||||
|
|
|
@ -34,9 +34,9 @@ module ShellCheck.Interface
|
||||||
, Severity(ErrorC, WarningC, InfoC, StyleC)
|
, Severity(ErrorC, WarningC, InfoC, StyleC)
|
||||||
, Position(posFile, posLine, posColumn)
|
, Position(posFile, posLine, posColumn)
|
||||||
, Comment(cSeverity, cCode, cMessage)
|
, Comment(cSeverity, cCode, cMessage)
|
||||||
, PositionedComment(pcStartPos , pcEndPos , pcComment)
|
, PositionedComment(pcStartPos , pcEndPos , pcComment, pcFix)
|
||||||
, ColorOption(ColorAuto, ColorAlways, ColorNever)
|
, ColorOption(ColorAuto, ColorAlways, ColorNever)
|
||||||
, TokenComment(tcId, tcComment)
|
, TokenComment(tcId, tcComment, tcFix)
|
||||||
, emptyCheckResult
|
, emptyCheckResult
|
||||||
, newParseResult
|
, newParseResult
|
||||||
, newAnalysisSpec
|
, newAnalysisSpec
|
||||||
|
@ -49,10 +49,16 @@ module ShellCheck.Interface
|
||||||
, emptyCheckSpec
|
, emptyCheckSpec
|
||||||
, newPositionedComment
|
, newPositionedComment
|
||||||
, newComment
|
, newComment
|
||||||
|
, Fix
|
||||||
|
, Replacement(Start, End)
|
||||||
|
, surroundWith
|
||||||
|
, replaceStart
|
||||||
|
, replaceEnd
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import ShellCheck.AST
|
import ShellCheck.AST
|
||||||
import Control.Monad.Identity
|
import Control.Monad.Identity
|
||||||
|
import Data.Monoid
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,27 +196,50 @@ newComment = Comment {
|
||||||
cMessage = ""
|
cMessage = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- only support single line for now
|
||||||
|
data Replacement =
|
||||||
|
Start Integer String
|
||||||
|
| End Integer String
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
type Fix = [Replacement]
|
||||||
|
|
||||||
|
surroundWith s =
|
||||||
|
(replaceStart 0 s) ++ (replaceEnd 0 s)
|
||||||
|
|
||||||
|
-- replace first n chars
|
||||||
|
replaceStart n r =
|
||||||
|
[ Start n r ]
|
||||||
|
|
||||||
|
-- replace last n chars
|
||||||
|
replaceEnd n r =
|
||||||
|
[ End n r ]
|
||||||
|
|
||||||
data PositionedComment = PositionedComment {
|
data PositionedComment = PositionedComment {
|
||||||
pcStartPos :: Position,
|
pcStartPos :: Position,
|
||||||
pcEndPos :: Position,
|
pcEndPos :: Position,
|
||||||
pcComment :: Comment
|
pcComment :: Comment,
|
||||||
|
pcFix :: Maybe Fix
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
newPositionedComment :: PositionedComment
|
newPositionedComment :: PositionedComment
|
||||||
newPositionedComment = PositionedComment {
|
newPositionedComment = PositionedComment {
|
||||||
pcStartPos = newPosition,
|
pcStartPos = newPosition,
|
||||||
pcEndPos = newPosition,
|
pcEndPos = newPosition,
|
||||||
pcComment = newComment
|
pcComment = newComment,
|
||||||
|
pcFix = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
data TokenComment = TokenComment {
|
data TokenComment = TokenComment {
|
||||||
tcId :: Id,
|
tcId :: Id,
|
||||||
tcComment :: Comment
|
tcComment :: Comment,
|
||||||
|
tcFix :: Maybe Fix
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
newTokenComment = TokenComment {
|
newTokenComment = TokenComment {
|
||||||
tcId = Id 0,
|
tcId = Id 0,
|
||||||
tcComment = newComment
|
tcComment = newComment,
|
||||||
|
tcFix = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
data ColorOption =
|
data ColorOption =
|
||||||
|
|
Loading…
Reference in New Issue