diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ff5c8d4c..bc1b07d2 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -83,6 +83,8 @@ phutil_register_library_map(array( 'ArcanistGitHookPreReceiveWorkflow' => 'workflow/ArcanistGitHookPreReceiveWorkflow.php', 'ArcanistGoLintLinter' => 'lint/linter/ArcanistGoLintLinter.php', 'ArcanistGoLintLinterTestCase' => 'lint/linter/__tests__/ArcanistGoLintLinterTestCase.php', + 'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php', + 'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php', 'ArcanistHelpWorkflow' => 'workflow/ArcanistHelpWorkflow.php', 'ArcanistHgClientChannel' => 'hgdaemon/ArcanistHgClientChannel.php', 'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php', @@ -273,6 +275,8 @@ phutil_register_library_map(array( 'ArcanistGitHookPreReceiveWorkflow' => 'ArcanistWorkflow', 'ArcanistGoLintLinter' => 'ArcanistExternalLinter', 'ArcanistGoLintLinterTestCase' => 'ArcanistArcanistLinterTestCase', + 'ArcanistHLintLinter' => 'ArcanistExternalLinter', + 'ArcanistHLintLinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistHelpWorkflow' => 'ArcanistWorkflow', 'ArcanistHgClientChannel' => 'PhutilProtocolChannel', 'ArcanistHgServerChannel' => 'PhutilProtocolChannel', diff --git a/src/lint/linter/ArcanistHLintLinter.php b/src/lint/linter/ArcanistHLintLinter.php new file mode 100644 index 00000000..4c2a5efb --- /dev/null +++ b/src/lint/linter/ArcanistHLintLinter.php @@ -0,0 +1,111 @@ +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; + } +} diff --git a/src/lint/linter/__tests__/ArcanistHLintLinterTestCase.php b/src/lint/linter/__tests__/ArcanistHLintLinterTestCase.php new file mode 100644 index 00000000..581220b1 --- /dev/null +++ b/src/lint/linter/__tests__/ArcanistHLintLinterTestCase.php @@ -0,0 +1,9 @@ +executeTestsInDirectory( + dirname(__FILE__).'/hlint/', + new ArcanistHLintLinter()); + } +} diff --git a/src/lint/linter/__tests__/hlint/01_warn_null.lint-test b/src/lint/linter/__tests__/hlint/01_warn_null.lint-test new file mode 100644 index 00000000..9a021d1f --- /dev/null +++ b/src/lint/linter/__tests__/hlint/01_warn_null.lint-test @@ -0,0 +1,3 @@ +f xs = length xs == 0 +~~~~~~~~~~ +warning:1:8 diff --git a/src/lint/linter/__tests__/hlint/02_err_eta.lint-test b/src/lint/linter/__tests__/hlint/02_err_eta.lint-test new file mode 100644 index 00000000..b9ee0892 --- /dev/null +++ b/src/lint/linter/__tests__/hlint/02_err_eta.lint-test @@ -0,0 +1,5 @@ +f x = x + +test x = f x +~~~~~~~~~~ +error:3:1 diff --git a/src/lint/linter/__tests__/hlint/03_no_err.lint-test b/src/lint/linter/__tests__/hlint/03_no_err.lint-test new file mode 100644 index 00000000..2ca93374 --- /dev/null +++ b/src/lint/linter/__tests__/hlint/03_no_err.lint-test @@ -0,0 +1,2 @@ +main = map (f . g) xs +~~~~~~~~~~