diff --git a/src/lint/engine/ArcanistLintEngine.php b/src/lint/engine/ArcanistLintEngine.php --- a/src/lint/engine/ArcanistLintEngine.php +++ b/src/lint/engine/ArcanistLintEngine.php @@ -65,6 +65,8 @@ private $postponedLinters = array(); private $configurationManager; + private $linterResources = array(); + public function __construct() { } @@ -548,4 +550,38 @@ } + /** + * Get a named linter resource shared by another linter. + * + * This mechanism allows linters to share arbitrary resources, like the + * results of computation. If several linters need to perform the same + * expensive computation step, they can use a named resource to synchronize + * construction of the result so it doesn't need to be built multiple + * times. + * + * @param string Resource identifier. + * @param wild Optionally, default value to return if resource does not + * exist. + * @return wild Resource, or default value if not present. + */ + public function getLinterResource($key, $default = null) { + return idx($this->linterResources, $key, $default); + } + + + /** + * Set a linter resource that other linters can accesss. + * + * See @{method:getLinterResource} for a description of this mechanism. + * + * @param string Resource identifier. + * @param wild Resource. + * @return this + */ + public function setLinterResource($key, $value) { + $this->linterResources[$key] = $value; + return $this; + } + + } diff --git a/src/lint/engine/PhutilLintEngine.php b/src/lint/engine/PhutilLintEngine.php --- a/src/lint/engine/PhutilLintEngine.php +++ b/src/lint/engine/PhutilLintEngine.php @@ -58,7 +58,6 @@ $linters[] = $xhpast_linter; $linters[] = id(new ArcanistPhutilXHPASTLinter()) - ->setXHPASTLinter($xhpast_linter) ->setPaths($php_paths); $merge_conflict_linter = id(new ArcanistMergeConflictLinter()); diff --git a/src/lint/linter/ArcanistBaseXHPASTLinter.php b/src/lint/linter/ArcanistBaseXHPASTLinter.php --- a/src/lint/linter/ArcanistBaseXHPASTLinter.php +++ b/src/lint/linter/ArcanistBaseXHPASTLinter.php @@ -1,8 +1,5 @@ xhpastLinter = $linter; - return $this; - } - public function setDeprecatedFunctions($map) { $this->deprecatedFunctions = $map; return $this; @@ -34,15 +25,6 @@ return $this; } - public function setEngine(ArcanistLintEngine $engine) { - if (!$this->xhpastLinter) { - throw new Exception( - 'Call setXHPASTLinter() before using ArcanistPhutilXHPASTLinter.'); - } - $this->xhpastLinter->setEngine($engine); - return parent::setEngine($engine); - } - public function getLintNameMap() { return array( self::LINT_ARRAY_COMBINE => 'array_combine() Unreliable', @@ -73,17 +55,30 @@ return $version; } + private function getXHPASTLinter() { + // If possible, reuse the parse tree generated by an existing vanilla + // XHPASTLinter. Otherwise, provide one as a shared resource. + $engine = $this->getEngine(); + $linter = $engine->getLinterResource('xhpast.linter'); + if (!$linter) { + $linter = new ArcanistXHPASTLinter(); + $linter->setEngine($engine); + $engine->setLinterResource('xhpast.linter', $linter); + } + return $linter; + } + protected function buildFutures(array $paths) { - return $this->xhpastLinter->buildFutures($paths); + return $this->getXHPASTLinter()->buildFutures($paths); } public function willLintPath($path) { - $this->xhpastLinter->willLintPath($path); + $this->getXHPASTLinter()->willLintPath($path); return parent::willLintPath($path); } protected function resolveFuture($path, Future $future) { - $tree = $this->xhpastLinter->getXHPASTTreeForPath($path); + $tree = $this->getXHPASTLinter()->getXHPASTTreeForPath($path); if (!$tree) { return; } diff --git a/src/lint/linter/ArcanistXHPASTLinter.php b/src/lint/linter/ArcanistXHPASTLinter.php --- a/src/lint/linter/ArcanistXHPASTLinter.php +++ b/src/lint/linter/ArcanistXHPASTLinter.php @@ -92,6 +92,18 @@ ); } + public function willLintPaths(array $paths) { + // If nothing has shared an XHPASTLinter yet, provide this linter as a + // shared resource. Other linters which rely on the parse tree will be + // able to reuse the one this linter generates. + $engine = $this->getEngine(); + if (!$engine->getLinterResource('xhpast.linter')) { + $engine->setLinterResource('xhpast.linter', $this); + } + + return parent::willLintPaths($paths); + } + public function getLinterName() { return 'XHP'; } diff --git a/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php b/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php --- a/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php +++ b/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php @@ -8,7 +8,6 @@ public function testPhutilXHPASTLint() { $linter = new ArcanistPhutilXHPASTLinter(); - $linter->setXHPASTLinter(new ArcanistXHPASTLinter()); $linter->setDeprecatedFunctions(array( 'deprecated_function' => 'This function is most likely deprecated.', ));