1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-10 14:51:05 +01:00
phorge-arcanist/src/lint/linter/ArcanistHLintLinter.php
Austin Seipp 4c0edd296e [lint] Add HLint-based Haskell linter
Summary:
This adds a lint engine for `hlint`, which is the standard and most general Haskell lint tool around these days.

Signed-off-by: Austin Seipp <aseipp@pobox.com>

Test Plan: Install `hlint`, and run `arc unit`.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: epriestley, Korvin

Projects: #arcanist

Differential Revision: https://secure.phabricator.com/D10250
2014-08-12 19:49:02 -07:00

111 lines
2.5 KiB
PHP

<?php
/**
* Calls `hlint` and parses its results.
*/
final class ArcanistHLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'HLint';
}
public function getInfoURI() {
return 'https://github.com/ndmitchell/hlint';
}
public function getInfoDescription() {
return pht('HLint is a linter for Haskell code.');
}
public function getLinterName() {
return 'HLINT';
}
public function getLinterConfigurationName() {
return 'hlint';
}
public function getDefaultBinary() {
return 'hlint';
}
public function getInstallInstructions() {
return pht('Install hlint with `cabal install hlint`.');
}
public function supportsReadDataFromStdin() {
return true;
}
public function getReadDataFromStdinFilename() {
return '-';
}
public function shouldExpectCommandErrors() {
return true;
}
public function getMandatoryFlags() {
return array('--json');
}
public function getVersion() {
list($stdout, $stderr) = execx(
'%C --version', $this->getExecutableCommand());
$matches = null;
if (preg_match('@HLint v(.*),@', $stdout, $matches)) {
return $matches[1];
}
return null;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$json = phutil_json_decode($stdout);
$messages = array();
foreach ($json as $fix) {
if ($fix === null) {
return;
}
$message = new ArcanistLintMessage();
$message->setCode($this->getLinterName());
$message->setPath($path);
$message->setLine($fix['startLine']);
$message->setChar($fix['startColumn']);
$message->setName($fix['hint']);
$message->setOriginalText($fix['from']);
$message->setReplacementText($fix['to']);
/* Some improvements may slightly change semantics, so attach
all necessary notes too. */
$notes = '';
foreach ($fix['note'] as $note) {
$notes .= ' **NOTE**: '.trim($note, '"').'.';
}
$message->setDescription(
pht(
'In module `%s`, declaration `%s`.%s',
$fix['module'], $fix['decl'], $notes));
switch ($fix['severity']) {
case 'Error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
case 'Warning':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$messages[] = $message;
}
return $messages;
}
}