Changeset View
Changeset View
Standalone View
Standalone View
arcanist/linter/LocalDependenceLinter.php
<?php | <?php | ||||
/** | /** | ||||
* Uses the lint-locale-dependence.sh script to output a linting error when | * Uses the lint-locale-dependence.sh script to output a linting error when | ||||
* functions relying on the system locale are used. | * functions relying on the system locale are used. | ||||
*/ | */ | ||||
final class LocaleDependenceLinter extends ArcanistExternalLinter { | final class LocaleDependenceLinter extends ArcanistExternalLinter { | ||||
const ADVICE_MESSAGE = <<<ADVICE | const ADVICE_MESSAGE = <<<ADVICE | ||||
Unnecessary locale dependence can cause bugs and should be avoided. | Unnecessary locale dependence can cause bugs and should be avoided. | ||||
Otherwise an exception can be added to the lint-locale-dependence script. | Otherwise an exception can be added to the lint-locale-dependence script. | ||||
ADVICE; | ADVICE; | ||||
public function getInfoName() { | public function getInfoName() { | ||||
return 'lint-locale-dependence'; | return 'lint-locale-dependence'; | ||||
} | } | ||||
public function getInfoURI() { | public function getInfoURI() { | ||||
return ''; | return ''; | ||||
} | } | ||||
public function getInfoDescription() { | public function getInfoDescription() { | ||||
return pht('Throw an error when functions relying on the system locale '. | return pht('Throw an error when functions relying on the system locale '. | ||||
'are used.'); | 'are used.'); | ||||
} | } | ||||
public function getLinterName() { | public function getLinterName() { | ||||
return 'lint-locale-dependence'; | return 'lint-locale-dependence'; | ||||
} | } | ||||
public function getLinterConfigurationName() { | public function getLinterConfigurationName() { | ||||
return 'lint-locale-dependence'; | return 'lint-locale-dependence'; | ||||
} | } | ||||
public function getLinterConfigurationOptions() { | public function getLinterConfigurationOptions() { | ||||
$options = array( | $options = array(); | ||||
); | |||||
return $options + parent::getLinterConfigurationOptions(); | return $options + parent::getLinterConfigurationOptions(); | ||||
} | } | ||||
public function getDefaultBinary() { | public function getDefaultBinary() { | ||||
return Filesystem::resolvePath( | return Filesystem::resolvePath('test/lint/lint-locale-dependence.sh', | ||||
'test/lint/lint-locale-dependence.sh', | |||||
$this->getProjectRoot()); | $this->getProjectRoot()); | ||||
} | } | ||||
public function shouldUseInterpreter() { | public function shouldUseInterpreter() { | ||||
return true; | return true; | ||||
} | } | ||||
public function getDefaultInterpreter() { | public function getDefaultInterpreter() { | ||||
return "bash"; | return "bash"; | ||||
} | } | ||||
public function getInstallInstructions() { | public function getInstallInstructions() { | ||||
return pht('The test/lint/lint-locale-dependence.sh script is part of the | return pht('The test/lint/lint-locale-dependence.sh script is part of the '. | ||||
bitcoin-abc project. Requires git >= 2.6.5.'); | 'bitcoin-abc project. Requires git >= 2.6.5.'); | ||||
} | } | ||||
public function shouldExpectCommandErrors() { | public function shouldExpectCommandErrors() { | ||||
return false; | return false; | ||||
} | } | ||||
protected function getMandatoryFlags() { | protected function getMandatoryFlags() { | ||||
return array( | return array(); | ||||
); | |||||
} | } | ||||
protected function parseLinterOutput($path, $err, $stdout, $stderr) { | protected function parseLinterOutput($path, $err, $stdout, $stderr) { | ||||
/* | /* | ||||
* Stdout contains 2 sections: | * Stdout contains 2 sections: | ||||
* 1/ The locale dependent function in a sentence: | * 1/ The locale dependent function in a sentence: | ||||
* The locale dependent function <function>(...) appears to be used | * The locale dependent function <function>(...) appears to be used | ||||
* Followed by the file and the corresponding code lines | * Followed by the file and the corresponding code lines | ||||
* <file path>: <code line using the function> | * <file path>: <code line using the function> | ||||
* 2/ Section with a general warning, will not be used by Arcanist. Instead | * 2/ Section with a general warning, will not be used by Arcanist. Instead | ||||
* we define our own advice message. | * we define our own advice message. | ||||
* | * | ||||
* First a list of the locale dependent functions will be determined, then | * First a list of the locale dependent functions will be determined, then | ||||
* the code lines containing these functions. | * the code lines containing these functions. | ||||
* An linting error message is generated for each line of code. | * A linting error message is generated for each line of code. | ||||
*/ | */ | ||||
/* | /* | ||||
* Extract infos from the path | * Extract infos from the path | ||||
*/ | */ | ||||
$pathinfo = pathinfo($path); | $pathinfo = pathinfo($path); | ||||
$fileName = $pathinfo['basename']; | $fileName = $pathinfo['basename']; | ||||
$messages = []; | $messages = []; | ||||
/* Find the functions */ | /* Find the functions */ | ||||
$pattern = '/The locale dependent function (\w+)\(...\)/'; | $pattern = '/The locale dependent function (\w+)\(...\)/'; | ||||
if (!preg_match_all($pattern, $stdout, $matches, $flags = PREG_SET_ORDER)) { | if (!preg_match_all( | ||||
$pattern, | |||||
$stdout, | |||||
$matches, | |||||
$flags = PREG_SET_ORDER | |||||
)) { | |||||
return $messages; | return $messages; | ||||
} | } | ||||
$functions = []; | $functions = []; | ||||
foreach($matches as $match) { | foreach ($matches as $match) { | ||||
$functions[] = $match[1]; | $functions[] = $match[1]; | ||||
} | } | ||||
/* Find the code lines */ | /* Find the code lines */ | ||||
$pattern = '/'.$fileName.':(\d+): (.+)/'; | $pattern = '/'.$fileName.':(\d+): (.+)/'; | ||||
if (preg_match_all($pattern, $stdout, $matches, $flags = PREG_SET_ORDER)) { | if (preg_match_all( | ||||
$pattern, | |||||
$stdout, | |||||
$matches, | |||||
$flags = PREG_SET_ORDER | |||||
)) { | |||||
foreach ($matches as $match) { | foreach ($matches as $match) { | ||||
list(, $lineNumber, $codeSnippet) = $match; | list(, $lineNumber, $codeSnippet) = $match; | ||||
/* Determine which function is used */ | /* Determine which function is used */ | ||||
$functionUsed = ''; | $functionUsed = ''; | ||||
foreach($functions as $function) { | foreach ($functions as $function) { | ||||
if (strpos($codeSnippet, $function) !== FALSE) { | if (strpos($codeSnippet, $function) !== false) { | ||||
$functionUsed = $function; | $functionUsed = $function; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
$messages[] = id(new ArcanistLintMessage()) | $messages[] = id(new ArcanistLintMessage()) | ||||
->setGranularity(ArcanistLinter::GRANULARITY_FILE) | ->setGranularity(ArcanistLinter::GRANULARITY_FILE) | ||||
->setCode('LOCALE_DEPENDENCE') | ->setCode('LOCALE_DEPENDENCE') | ||||
Show All 11 Lines |