1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-29 02:02:40 +01:00

Adding php -l linter

Summary: Adds a linter that checks php files for syntax errors using php -l

Test Plan:
Add a section to your .arclint file similar to:
```
"php": {
  "type": "php",
  "include": "(\\.php$)"
}
```

Then run arc lint on a php file with a syntax error.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: epriestley, jacobwalker0814, Korvin

Differential Revision: https://secure.phabricator.com/D10370
This commit is contained in:
Michael Peters 2014-08-27 17:29:31 -07:00 committed by epriestley
parent e4bbcaf8f7
commit 9fc8a2f61b
6 changed files with 120 additions and 0 deletions

View file

@ -132,6 +132,8 @@ phutil_register_library_map(array(
'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php', 'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php',
'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php', 'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php',
'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php', 'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php',
'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php',
'ArcanistPhpLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpLinterTestCase.php',
'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php', 'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php',
'ArcanistPhpcsLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpcsLinterTestCase.php', 'ArcanistPhpcsLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpcsLinterTestCase.php',
'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php', 'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php',
@ -313,6 +315,8 @@ phutil_register_library_map(array(
'ArcanistPEP8LinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistPEP8LinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistPasteWorkflow' => 'ArcanistWorkflow', 'ArcanistPasteWorkflow' => 'ArcanistWorkflow',
'ArcanistPatchWorkflow' => 'ArcanistWorkflow', 'ArcanistPatchWorkflow' => 'ArcanistWorkflow',
'ArcanistPhpLinter' => 'ArcanistExternalLinter',
'ArcanistPhpLinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistPhpcsLinter' => 'ArcanistExternalLinter', 'ArcanistPhpcsLinter' => 'ArcanistExternalLinter',
'ArcanistPhpcsLinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistPhpcsLinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow', 'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow',

View file

@ -0,0 +1,85 @@
<?php
/**
* Uses "php -l" to detect syntax errors in PHP code.
*/
final class ArcanistPhpLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'php -l';
}
public function getInfoURI() {
return 'http://php.net/';
}
public function getInfoDescription() {
return pht(
'Checks for syntax errors in php files.');
}
public function getLinterName() {
return 'PHP';
}
public function getLinterConfigurationName() {
return 'php';
}
public function getMandatoryFlags() {
return array('-l');
}
public function getInstallInstructions() {
return pht('Install PHP.');
}
public function getDefaultBinary() {
return 'php';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^PHP (?P<version>\d+\.\d+\.\d+)\b/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function shouldExpectCommandErrors() {
return true;
}
public function supportsReadDataFromStdin() {
return false;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
// Older versions of php had both on $stdout, newer ones split it
// Combine $stdout and $stderr for consistency
$stdout = $stderr."\n".$stdout;
$matches = array();
$regex = '/PHP (?<type>.+?) error:\s+(?<error>.*?)\s+in\s+(?<file>.*?)'.
'\s+on line\s+(?<line>\d*)/';
if (preg_match($regex, $stdout, $matches)) {
$type = strtolower($matches['type']);
$message = new ArcanistLintMessage();
$message->setPath($matches['file']);
$message->setLine($matches['line']);
$message->setCode('php.'.$type);
$message->setDescription('This file contains a '.$type.' error: '.
$matches['error'].' on line '.$matches['line']);
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
// php -l only returns the first error
return array($message);
}
return array();
}
}

View file

@ -0,0 +1,11 @@
<?php
final class ArcanistPhpLinterTestCase extends ArcanistArcanistLinterTestCase {
public function testPHPLint() {
$this->executeTestsInDirectory(
dirname(__FILE__).'/php/',
new ArcanistPhpLinter());
}
}

View file

@ -0,0 +1,7 @@
<?php
function f() {
$this = "cannot be re-assigned";
}
~~~~~~~~~
error:4:

View file

@ -0,0 +1,6 @@
<?php
function f() {
return "foobar";
}
~~~~~~~~~~

View file

@ -0,0 +1,7 @@
<?php
function f() {
this is bad syntax;
}
~~~~~~~~~
error:4: