diff --git a/.arclint b/.arclint --- a/.arclint +++ b/.arclint @@ -45,15 +45,7 @@ "xhpast": { "type": "xhpast", "include": "(\\.php$)", - "severity": { - "16": "advice", - "34": "error" - }, - "xhpast.blacklisted.function": { - "eval": "The eval() function should be avoided. It is potentially unsafe and makes debugging more difficult." - }, - "xhpast.php-version": "5.2.3", - "xhpast.php-version.windows": "5.3.0" + "standard": "phutil.xhpast" } } } diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -161,6 +161,8 @@ 'ArcanistLintSeverity' => 'lint/ArcanistLintSeverity.php', 'ArcanistLintWorkflow' => 'workflow/ArcanistLintWorkflow.php', 'ArcanistLinter' => 'lint/linter/ArcanistLinter.php', + 'ArcanistLinterStandard' => 'lint/linter/standards/ArcanistLinterStandard.php', + 'ArcanistLinterStandardTestCase' => 'lint/linter/standards/__tests__/ArcanistLinterStandardTestCase.php', 'ArcanistLinterTestCase' => 'lint/linter/__tests__/ArcanistLinterTestCase.php', 'ArcanistLintersWorkflow' => 'workflow/ArcanistLintersWorkflow.php', 'ArcanistListAssignmentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistListAssignmentXHPASTLinterRule.php', @@ -202,6 +204,7 @@ 'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php', 'ArcanistPhutilLibraryLinter' => 'lint/linter/ArcanistPhutilLibraryLinter.php', 'ArcanistPhutilXHPASTLinter' => 'lint/linter/ArcanistPhutilXHPASTLinter.php', + 'ArcanistPhutilXHPASTLinterStandard' => 'lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php', 'ArcanistPhutilXHPASTLinterTestCase' => 'lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php', 'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPlusOperatorOnStringsXHPASTLinterRule.php', 'ArcanistPregQuoteMisuseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPregQuoteMisuseXHPASTLinterRule.php', @@ -450,6 +453,8 @@ 'ArcanistLintSeverity' => 'Phobject', 'ArcanistLintWorkflow' => 'ArcanistWorkflow', 'ArcanistLinter' => 'Phobject', + 'ArcanistLinterStandard' => 'Phobject', + 'ArcanistLinterStandardTestCase' => 'PhutilTestCase', 'ArcanistLinterTestCase' => 'PhutilTestCase', 'ArcanistLintersWorkflow' => 'ArcanistWorkflow', 'ArcanistListAssignmentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', @@ -491,6 +496,7 @@ 'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow', 'ArcanistPhutilLibraryLinter' => 'ArcanistLinter', 'ArcanistPhutilXHPASTLinter' => 'ArcanistBaseXHPASTLinter', + 'ArcanistPhutilXHPASTLinterStandard' => 'ArcanistLinterStandard', 'ArcanistPhutilXHPASTLinterTestCase' => 'ArcanistLinterTestCase', 'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistPregQuoteMisuseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', diff --git a/src/lint/linter/ArcanistLinter.php b/src/lint/linter/ArcanistLinter.php --- a/src/lint/linter/ArcanistLinter.php +++ b/src/lint/linter/ArcanistLinter.php @@ -196,7 +196,6 @@ return; } - public function getLinterPriority() { return 1.0; } @@ -209,6 +208,11 @@ return $this; } + public function addCustomSeverityMap(array $map) { + $this->customSeverityMap = $this->customSeverityMap + $map; + return $this; + } + final public function setCustomSeverityRules(array $rules) { $this->customSeverityRules = $rules; return $this; @@ -490,6 +494,10 @@ 'Provide a map of regular expressions to severity levels. All '. 'matching codes have their severity adjusted.'), ), + 'standard' => array( + 'type' => 'optional string | list', + 'help' => pht('The coding standard(s) to apply.'), + ), ); } @@ -548,6 +556,22 @@ } $this->setCustomSeverityRules($value); return; + + case 'standard': + $standards = (array)$value; + + foreach ($standards as $standard) { + $standard = ArcanistLinterStandard::getStandard($value, $this); + + foreach ($standard->getLinterConfiguration() as $k => $v) { + $this->setLinterConfigurationValue($k, $v); + } + $this->addCustomSeverityMap($standard->getLinterSeverityMap()); + } + + return; + + } throw new Exception(pht('Incomplete implementation: %s!', $key)); diff --git a/src/lint/linter/standards/ArcanistLinterStandard.php b/src/lint/linter/standards/ArcanistLinterStandard.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/standards/ArcanistLinterStandard.php @@ -0,0 +1,121 @@ + + */ + public function getLinterConfiguration() { + return array(); + } + + /** + * Get linter severities. + * + * Returns linter severities which are passed to + * @{method:ArcanistLinter::addCustomSeverityMap}. + * + * @return map + */ + public function getLinterSeverityMap() { + return array(); + } + + /** + * Load a linter standard by key. + * + * @param string + * @param ArcanistLinter + * @return ArcanistLinterStandard + */ + final public static function getStandard($key, ArcanistLinter $linter) { + $standards = self::loadAllStandardsForLinter($linter); + + if (empty($standards[$key])) { + throw new ArcanistUsageException( + pht( + 'No such linter standard. Available standards are: %s.', + implode(', ', array_keys($standards)))); + } + + return $standards[$key]; + } + + /** + * Load all linter standards. + * + * @return list + */ + final public static function loadAllStandards() { + return id(new PhutilClassMapQuery()) + ->setAncestorClass(__CLASS__) + ->setUniqueMethod('getKey') + ->execute(); + } + + /** + * Load all linter standards which support a specified linter. + * + * @param ArcanistLinter + * @return list + */ + final public static function loadAllStandardsForLinter( + ArcanistLinter $linter) { + + $all_standards = self::loadAllStandards(); + $standards = array(); + + foreach ($all_standards as $standard) { + if ($standard->supportsLinter($linter)) { + $standards[$standard->getKey()] = $standard; + } + } + + return $standards; + } + +} diff --git a/src/lint/linter/standards/__tests__/ArcanistLinterStandardTestCase.php b/src/lint/linter/standards/__tests__/ArcanistLinterStandardTestCase.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/standards/__tests__/ArcanistLinterStandardTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php b/src/lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php @@ -0,0 +1,45 @@ + array( + 'eval' => pht( + 'The `%s` function should be avoided. It is potentially unsafe '. + 'and makes debugging more difficult.', + 'eval'), + 'xhpast.php-version' => '5.2.3', + 'xhpast.php-version.windows' => '5.3.0', + ), + ); + } + + public function getLinterSeverityMap() { + $advice = ArcanistLintSeverity::SEVERITY_ADVICE; + $error = ArcanistLintSeverity::SEVERITY_ERROR; + + return array( + ArcanistTodoCommentXHPASTLinterRule::ID => $advice, + ArcanistCommentSpacingXHPASTLinterRule::ID => $error, + ); + } + +}