Changeset View
Changeset View
Standalone View
Standalone View
src/lint/linter/ArcanistLinter.php
<?php | <?php | ||||
/** | /** | ||||
* Implements lint rules, like syntax checks for a specific language. | * Implements lint rules, like syntax checks for a specific language. | ||||
* | * | ||||
* @task info Human Readable Information | * @task info Human Readable Information | ||||
* @task state Runtime State | |||||
* @task exec Executing Linters | |||||
* @stable | * @stable | ||||
*/ | */ | ||||
abstract class ArcanistLinter { | abstract class ArcanistLinter { | ||||
const GRANULARITY_FILE = 1; | const GRANULARITY_FILE = 1; | ||||
const GRANULARITY_DIRECTORY = 2; | const GRANULARITY_DIRECTORY = 2; | ||||
const GRANULARITY_REPOSITORY = 3; | const GRANULARITY_REPOSITORY = 3; | ||||
const GRANULARITY_GLOBAL = 4; | const GRANULARITY_GLOBAL = 4; | ||||
private $id; | |||||
protected $paths = array(); | protected $paths = array(); | ||||
protected $data = array(); | protected $data = array(); | ||||
protected $engine; | protected $engine; | ||||
protected $activePath; | protected $activePath; | ||||
protected $messages = array(); | protected $messages = array(); | ||||
protected $stopAllLinters = false; | protected $stopAllLinters = false; | ||||
private $customSeverityMap = array(); | private $customSeverityMap = array(); | ||||
private $customSeverityRules = array(); | private $customSeverityRules = array(); | ||||
/* -( Human Readable Information )---------------------------------------- */ | /* -( Human Readable Information )---------------------------------------- */ | ||||
/** | /** | ||||
* Return an optional informative URI where humans can learn more about this | * Return an optional informative URI where humans can learn more about this | ||||
* linter. | * linter. | ||||
* | * | ||||
* For most linters, this should return a link to the project home page. This | * For most linters, this should return a link to the project home page. This | ||||
* is shown on `arc linters`. | * is shown on `arc linters`. | ||||
* | * | ||||
* @return string|null Optionally, return an informative URI. | * @return string|null Optionally, return an informative URI. | ||||
Show All 26 Lines | /* -( Human Readable Information )---------------------------------------- */ | ||||
*/ | */ | ||||
public function getInfoName() { | public function getInfoName() { | ||||
return nonempty( | return nonempty( | ||||
$this->getLinterName(), | $this->getLinterName(), | ||||
$this->getLinterConfigurationName(), | $this->getLinterConfigurationName(), | ||||
get_class($this)); | get_class($this)); | ||||
} | } | ||||
/* -( Runtime State )------------------------------------------------------ */ | |||||
/** | |||||
* @task state | |||||
*/ | |||||
final public function getActivePath() { | |||||
return $this->activePath; | |||||
} | |||||
/** | |||||
* @task state | |||||
*/ | |||||
final public function setActivePath($path) { | |||||
$this->stopAllLinters = false; | |||||
$this->activePath = $path; | |||||
return $this; | |||||
} | |||||
/** | |||||
* @task state | |||||
*/ | |||||
final public function setEngine(ArcanistLintEngine $engine) { | |||||
$this->engine = $engine; | |||||
return $this; | |||||
} | |||||
/** | |||||
* @task state | |||||
*/ | |||||
final protected function getEngine() { | |||||
return $this->engine; | |||||
} | |||||
/** | |||||
* Set the internal ID for this linter. | |||||
* | |||||
* This ID is assigned automatically by the @{class:ArcanistLintEngine}. | |||||
joshuaspence: Should be `@{class:ArcanistLintEngine}` | |||||
* | |||||
* @param string Unique linter ID. | |||||
* @return this | |||||
* @task state | |||||
*/ | |||||
final public function setLinterID($id) { | |||||
$this->id = $id; | |||||
return $this; | |||||
} | |||||
/** | |||||
* Get the internal ID for this linter. | |||||
* | |||||
* Retrieves an internal linter ID managed by the @{class:ArcanistLintEngine}. | |||||
Done Inline ActionsAs above. joshuaspence: As above. | |||||
* This ID is a unique scalar which distinguishes linters in a list. | |||||
* | |||||
* @return string Unique linter ID. | |||||
* @task state | |||||
*/ | |||||
final public function getLinterID() { | |||||
return $this->id; | |||||
} | |||||
/* -( Executing Linters )-------------------------------------------------- */ | |||||
/** | |||||
* Hook called before a list of paths are linted. | |||||
* | |||||
* Parallelizable linters can start multiple requests in parallel here, | |||||
* to improve performance. They can implement @{method:didLintPaths} to | |||||
* collect results. | |||||
* | |||||
* Linters which are not parallelizable should normally ignore this callback | |||||
* and implement @{method:lintPath} instead. | |||||
* | |||||
* @param list<string> A list of paths to be linted | |||||
* @return void | |||||
* @task exec | |||||
*/ | |||||
public function willLintPaths(array $paths) { | |||||
return; | |||||
} | |||||
/** | |||||
* Hook called for each path to be linted. | |||||
* | |||||
* Linters which are not parallelizable can do work here. | |||||
* | |||||
* Linters which are parallelizable may want to ignore this callback and | |||||
* implement @{method:willLintPaths} and @{method:didLintPaths} instead. | |||||
* | |||||
* @param string Path to lint. | |||||
* @return void | |||||
* @task exec | |||||
*/ | |||||
public function lintPath($path) { | |||||
return; | |||||
} | |||||
/** | |||||
* Hook called after a list of paths are linted. | |||||
* | |||||
* Parallelizable linters can collect results here. | |||||
* | |||||
* Linters which are not paralleizable should normally ignore this callback | |||||
* and implement @{method:lintPath} instead. | |||||
* | |||||
* @param list<string> A list of paths which were linted. | |||||
* @return void | |||||
* @task exec | |||||
*/ | |||||
public function didLintPaths(array $paths) { | |||||
return; | |||||
} | |||||
/** | |||||
* Obsolete hook which was invoked before a path was linted. | |||||
* | |||||
* WARNING: This is an obsolete hook which is not called. If you maintain | |||||
* a linter which relies on it, update to use @{method:lintPath} instead. | |||||
* | |||||
* @task exec | |||||
*/ | |||||
final public function willLintPath($path) { | |||||
Done Inline ActionsMissing final joshuaspence: Missing `final` | |||||
// TODO: Remove this method after some time. In the meantime, the "final" | |||||
// will fatal subclasses which implement this hook and point at the API | |||||
// change so maintainers get fewer surprises. | |||||
throw new PhutilMethodNotImplementedException(); | |||||
} | |||||
/** | |||||
* Obsolete hook which was invoked after linters ran. | |||||
* | |||||
* WARNING: This is an obsolete hook which is not called. If you maintain | |||||
* a linter which relies on it, update to use @{method:didLintPaths} instead. | |||||
* | |||||
* @return void | |||||
* @task exec | |||||
*/ | |||||
final public function didRunLinters() { | |||||
// TODO: Remove this method after some time. In the meantime, the "final" | |||||
// will fatal subclasses which implement this hook and point at the API | |||||
// change so maintainers get fewer surprises. | |||||
throw new PhutilMethodNotImplementedException(); | |||||
} | |||||
public function getLinterPriority() { | public function getLinterPriority() { | ||||
return 1.0; | return 1.0; | ||||
} | } | ||||
/** | /** | ||||
* TODO: This should be `final`. | * TODO: This should be `final`. | ||||
*/ | */ | ||||
public function setCustomSeverityMap(array $map) { | public function setCustomSeverityMap(array $map) { | ||||
$this->customSeverityMap = $map; | $this->customSeverityMap = $map; | ||||
return $this; | return $this; | ||||
} | } | ||||
final public function setCustomSeverityRules(array $rules) { | final public function setCustomSeverityRules(array $rules) { | ||||
$this->customSeverityRules = $rules; | $this->customSeverityRules = $rules; | ||||
return $this; | return $this; | ||||
} | } | ||||
final public function getActivePath() { | |||||
return $this->activePath; | |||||
} | |||||
final public function getOtherLocation($offset, $path = null) { | final public function getOtherLocation($offset, $path = null) { | ||||
if ($path === null) { | if ($path === null) { | ||||
$path = $this->getActivePath(); | $path = $this->getActivePath(); | ||||
} | } | ||||
list($line, $char) = $this->getEngine()->getLineAndCharFromOffset( | list($line, $char) = $this->getEngine()->getLineAndCharFromOffset( | ||||
$path, | $path, | ||||
$offset); | $offset); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | /* -( Executing Linters )-------------------------------------------------- */ | ||||
final protected function getData($path) { | final protected function getData($path) { | ||||
if (!array_key_exists($path, $this->data)) { | if (!array_key_exists($path, $this->data)) { | ||||
$this->data[$path] = $this->getEngine()->loadData($path); | $this->data[$path] = $this->getEngine()->loadData($path); | ||||
} | } | ||||
return $this->data[$path]; | return $this->data[$path]; | ||||
} | } | ||||
final public function setEngine(ArcanistLintEngine $engine) { | |||||
$this->engine = $engine; | |||||
return $this; | |||||
} | |||||
final protected function getEngine() { | |||||
return $this->engine; | |||||
} | |||||
public function getCacheVersion() { | public function getCacheVersion() { | ||||
return 0; | return 0; | ||||
} | } | ||||
final public function getLintMessageFullCode($short_code) { | final public function getLintMessageFullCode($short_code) { | ||||
return $this->getLinterName().$short_code; | return $this->getLinterName().$short_code; | ||||
} | } | ||||
final public function getLintMessageSeverity($code) { | final public function getLintMessageSeverity($code) { | ||||
$map = $this->customSeverityMap; | $map = $this->customSeverityMap; | ||||
if (isset($map[$code])) { | if (isset($map[$code])) { | ||||
return $map[$code]; | return $map[$code]; | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | return $this->raiseLintAtLine( | ||||
$line + 1, | $line + 1, | ||||
$char + 1, | $char + 1, | ||||
$code, | $code, | ||||
$desc, | $desc, | ||||
$original, | $original, | ||||
$replacement); | $replacement); | ||||
} | } | ||||
public function willLintPath($path) { | |||||
$this->stopAllLinters = false; | |||||
$this->activePath = $path; | |||||
} | |||||
public function canRun() { | public function canRun() { | ||||
return true; | return true; | ||||
} | } | ||||
public function willLintPaths(array $paths) { | |||||
return; | |||||
} | |||||
abstract public function lintPath($path); | |||||
abstract public function getLinterName(); | abstract public function getLinterName(); | ||||
public function getVersion() { | public function getVersion() { | ||||
return null; | return null; | ||||
} | } | ||||
public function didRunLinters() { | |||||
// This is a hook. | |||||
} | |||||
final protected function isCodeEnabled($code) { | final protected function isCodeEnabled($code) { | ||||
$severity = $this->getLintMessageSeverity($code); | $severity = $this->getLintMessageSeverity($code); | ||||
return $this->getEngine()->isSeverityEnabled($severity); | return $this->getEngine()->isSeverityEnabled($severity); | ||||
} | } | ||||
public function getLintSeverityMap() { | public function getLintSeverityMap() { | ||||
return array(); | return array(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 180 Lines • Show Last 20 Lines |
Should be @{class:ArcanistLintEngine}