{-# LANGUAGE RecordWildCards #-}moduleHLint(hlint,Suggestion,suggestionLocation,suggestionSeverity,Severity(..))whereimportControl.ApplicativeimportControl.MonadimportSystem.Console.CmdArgs.VerbosityimportData.ListimportSystem.ExitimportCmdLineimportSettingsimportReportimportIdeaimportApplyimportTest.StandardimportGrepimportTest.ProofimportUtilimportParallelimportHSE.All-- | A suggestion - the @Show@ instance is of particular use.newtypeSuggestion=Suggestion{fromSuggestion::Idea}deriving(Eq,Ord)instanceShowSuggestionwhereshow=show.fromSuggestion-- | From a suggestion, extract the file location it refers to.suggestionLocation::Suggestion->SrcLocsuggestionLocation=getPointLoc.ideaSpan.fromSuggestion-- | From a suggestion, determine how severe it is.suggestionSeverity::Suggestion->SeveritysuggestionSeverity=ideaSeverity.fromSuggestion-- | This function takes a list of command line arguments, and returns the given suggestions.-- To see a list of arguments type @hlint --help@ at the console.-- This function writes to the stdout/stderr streams, unless @--quiet@ is specified.---- As an example:---- > do hints <- hlint ["src", "--ignore=Use map","--quiet"]-- > when (length hints > 3) $ error "Too many hints!"hlint::[String]->IO[Suggestion]hlintargs=docmd<-getCmdargscasecmdofCmdMain{}->hlintMaincmdCmdGrep{}->hlintGrepcmd>>return[]CmdHSE{}->hlintHSEcmd>>return[]CmdTest{}->hlintTestcmd>>return[]hlintHSE::Cmd->IO()hlintHSECmdHSE{..}=dov<-getVerbosityforM_cmdFiles$\x->doputStrLn$"Parse result of "++x++":"res<-parseFilexcaseresofx@ParseFailed{}->printxParseOkm->casevofLoud->printmQuiet->print$prettyPrintm_->print$fmap(const())mputStrLn""hlintTest::Cmd->IO()hlintTestcmd@CmdTest{..}=doifnotNullcmdProofthendofiles<-cmdHintFilescmds<-readSettings2cmdDataDirfiles[]letreps=ifcmdReports==["report.html"]then["report.txt"]elsecmdReportsmapM_(proofrepss)cmdProofelsedofailed<-test(\args->doerrs<-hlintargs;when(lengtherrs>0)$exitWith$ExitFailure1)cmdDataDircmdGivenHintswhen(failed>0)exitFailurehlintGrep::Cmd->IO()hlintGrepcmd@CmdGrep{..}=doencoding<-readEncodingcmdEncodingletflags=parseFlagsSetExtensions(cmdExtensionscmd)$defaultParseFlags{cppFlags=cmdCppcmd,encoding=encoding}ifnullcmdFilesthenexitWithHelpelsedofiles<-concatMapM(resolveFilecmd)cmdFilesifnullfilesthenerror"No files found"elserunGrepcmdPatternflagsfileshlintMain::Cmd->IO[Suggestion]hlintMaincmd@CmdMain{..}=doencoding<-readEncodingcmdEncodingletflags=parseFlagsSetExtensions(cmdExtensionscmd)$defaultParseFlags{cppFlags=cmdCppcmd,encoding=encoding}ifnullcmdFiles&&notNullcmdFindHintsthendohints<-concatMapM(resolveFilecmd)cmdFindHintsmapM_(\x->putStrLn.fst=<<findSettings2flagsx)hints>>return[]elseifnullcmdFilesthenexitWithHelpelsedofiles<-concatMapM(resolveFilecmd)cmdFilesifnullfilesthenerror"No files found"elserunHintscmd{cmdFiles=files}flagsreadAllSettings::Cmd->ParseFlags->IO[Setting]readAllSettingscmd@CmdMain{..}flags=dofiles<-cmdHintFilescmdsettings1<-readSettings2cmdDataDirfilescmdWithHintssettings2<-concatMapM(fmapsnd.findSettings2flags)cmdFindHintssettings3<-return[SettingClassify$ClassifyIgnorex""""|x<-cmdIgnore]return$settings1++settings2++settings3runHints::Cmd->ParseFlags->IO[Suggestion]runHintscmd@CmdMain{..}flags=doletoutStrLn=whenNormal.putStrLnsettings<-readAllSettingscmdflagsideas<-ifcmdCrossthenapplyHintFilesflagssettingscmdFileselseconcat<$>parallel[listM'=<<applyHintFileflagssettingsxNothing|x<-cmdFiles]let(showideas,hideideas)=partition(\i->cmdShowAll||ideaSeverityi/=Ignore)ideasshowItem<-ifcmdColorthenshowANSIelsereturnshowmapM_(outStrLn.showItem)showideasifnullshowideasthenwhen(cmdReports/=[])$outStrLn"Skipping writing reports"elseforM_cmdReports$\x->dooutStrLn$"Writing report to "++x++" ..."writeReportcmdDataDirxshowideasoutStrLn$(leti=lengthshowideasinifi==0then"No suggestions"elseshowi++" suggestion"++['s'|i/=1])++(leti=lengthhideideasinifi==0then""else" ("++showi++" ignored)")return$mapSuggestionshowideas