> */ public $after_method_checks = []; /** @var list> */ public $legacy_after_method_checks = []; /** * Static methods to be called after project function checks have completed * * Called after function calls to functions defined in the project. * * Allows influencing the return type and adding of modifications. * * @var list> */ public $after_function_checks = []; /** @var list> */ public $legacy_after_function_checks = []; /** * Static methods to be called after every function call * * Called after each function call, including php internal functions. * * Cannot change the call or influence its return type * * @var list> */ public $after_every_function_checks = []; /** @var list> */ public $legacy_after_every_function_checks = []; /** * Static methods to be called after expression checks have completed * * @var list> */ public $after_expression_checks = []; /** @var list> */ public $legacy_after_expression_checks = []; /** * Static methods to be called after statement checks have completed * * @var list> */ public $after_statement_checks = []; /** @var list> */ public $legacy_after_statement_checks = []; /** * Static methods to be called after method checks have completed * * @var list> */ public $string_interpreters = []; /** @var list> */ public $legacy_string_interpreters = []; /** * Static methods to be called after classlike exists checks have completed * * @var list> */ public $after_classlike_exists_checks = []; /** @var list> */ public $legacy_after_classlike_exists_checks = []; /** * Static methods to be called after classlike checks have completed * * @var list> */ public $after_classlike_checks = []; /** @var list> */ public $legacy_after_classlike_checks = []; /** * Static methods to be called after classlikes have been scanned * * @var list> */ public $after_visit_classlikes = []; /** @var list> */ public $legacy_after_visit_classlikes = []; /** * Static methods to be called after codebase has been populated * * @var list> */ public $after_codebase_populated = []; /** @var list> */ public $legacy_after_codebase_populated = []; /** * Static methods to be called after codebase has been populated * * @var list> */ public $after_analysis = []; /** @var list> */ public $legacy_after_analysis = []; /** * Static methods to be called after a file has been analyzed * * @var list> */ public $after_file_checks = []; /** @var list> */ public $legacy_after_file_checks = []; /** * Static methods to be called before a file is analyzed * * @var list> */ public $before_file_checks = []; /** @var list> */ public $legacy_before_file_checks = []; /** * Static methods to be called after functionlike checks have completed * * @var list> */ public $after_functionlike_checks = []; /** @var list> */ public $legacy_after_functionlike_checks = []; /** * @param class-string $class */ public function registerClass(string $class): void { if (is_subclass_of($class, Hook\AfterMethodCallAnalysisInterface::class)) { $this->legacy_after_method_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterMethodCallAnalysisInterface::class)) { $this->after_method_checks[] = $class; } if (is_subclass_of($class, Hook\AfterFunctionCallAnalysisInterface::class)) { $this->legacy_after_function_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterFunctionCallAnalysisInterface::class)) { $this->after_function_checks[] = $class; } if (is_subclass_of($class, Hook\AfterEveryFunctionCallAnalysisInterface::class)) { $this->legacy_after_every_function_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterEveryFunctionCallAnalysisInterface::class)) { $this->after_every_function_checks[] = $class; } if (is_subclass_of($class, Hook\AfterExpressionAnalysisInterface::class)) { $this->legacy_after_expression_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterExpressionAnalysisInterface::class)) { $this->after_expression_checks[] = $class; } if (is_subclass_of($class, Hook\AfterStatementAnalysisInterface::class)) { $this->legacy_after_statement_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterStatementAnalysisInterface::class)) { $this->after_statement_checks[] = $class; } if (is_subclass_of($class, Hook\StringInterpreterInterface::class)) { $this->legacy_string_interpreters[] = $class; } elseif (is_subclass_of($class, EventHandler\StringInterpreterInterface::class)) { $this->string_interpreters[] = $class; } if (is_subclass_of($class, Hook\AfterClassLikeExistenceCheckInterface::class)) { $this->legacy_after_classlike_exists_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterClassLikeExistenceCheckInterface::class)) { $this->after_classlike_exists_checks[] = $class; } if (is_subclass_of($class, Hook\AfterClassLikeAnalysisInterface::class)) { $this->legacy_after_classlike_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterClassLikeAnalysisInterface::class)) { $this->after_classlike_checks[] = $class; } if (is_subclass_of($class, Hook\AfterClassLikeVisitInterface::class)) { $this->legacy_after_visit_classlikes[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterClassLikeVisitInterface::class)) { $this->after_visit_classlikes[] = $class; } if (is_subclass_of($class, Hook\AfterCodebasePopulatedInterface::class)) { $this->legacy_after_codebase_populated[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterCodebasePopulatedInterface::class)) { $this->after_codebase_populated[] = $class; } if (is_subclass_of($class, Hook\AfterAnalysisInterface::class)) { $this->legacy_after_analysis[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterAnalysisInterface::class)) { $this->after_analysis[] = $class; } if (is_subclass_of($class, Hook\AfterFileAnalysisInterface::class)) { $this->legacy_after_file_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterFileAnalysisInterface::class)) { $this->after_file_checks[] = $class; } if (is_subclass_of($class, Hook\BeforeFileAnalysisInterface::class)) { $this->legacy_before_file_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\BeforeFileAnalysisInterface::class)) { $this->before_file_checks[] = $class; } if (is_subclass_of($class, Hook\AfterFunctionLikeAnalysisInterface::class)) { $this->legacy_after_functionlike_checks[] = $class; } elseif (is_subclass_of($class, EventHandler\AfterFunctionLikeAnalysisInterface::class)) { $this->after_functionlike_checks[] = $class; } } public function dispatchAfterMethodCallAnalysis(Event\AfterMethodCallAnalysisEvent $event): void { foreach ($this->after_method_checks as $handler) { $handler::afterMethodCallAnalysis($event); } foreach ($this->legacy_after_method_checks as $handler) { $file_replacements = $event->getFileReplacements(); $return_type_candidate = $event->getReturnTypeCandidate(); $handler::afterMethodCallAnalysis( $event->getExpr(), $event->getMethodId(), $event->getAppearingMethodId(), $event->getDeclaringMethodId(), $event->getContext(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements, $return_type_candidate ); $event->setFileReplacements($file_replacements); $event->setReturnTypeCandidate($return_type_candidate); } } public function dispatchAfterFunctionCallAnalysis(Event\AfterFunctionCallAnalysisEvent $event): void { foreach ($this->after_function_checks as $handler) { $handler::afterFunctionCallAnalysis($event); } foreach ($this->legacy_after_function_checks as $handler) { $file_replacements = $event->getFileReplacements(); $handler::afterFunctionCallAnalysis( $event->getExpr(), $event->getFunctionId(), $event->getContext(), $event->getStatementsSource(), $event->getCodebase(), $event->getReturnTypeCandidate(), $file_replacements ); $event->setFileReplacements($file_replacements); } } public function dispatchAfterEveryFunctionCallAnalysis(Event\AfterEveryFunctionCallAnalysisEvent $event): void { foreach ($this->after_every_function_checks as $handler) { $handler::afterEveryFunctionCallAnalysis($event); } foreach ($this->legacy_after_every_function_checks as $handler) { $handler::afterEveryFunctionCallAnalysis( $event->getExpr(), $event->getFunctionId(), $event->getContext(), $event->getStatementsSource(), $event->getCodebase() ); } } public function dispatchAfterExpressionAnalysis(Event\AfterExpressionAnalysisEvent $event): ?bool { foreach ($this->after_expression_checks as $handler) { if ($handler::afterExpressionAnalysis($event) === false) { return false; } } foreach ($this->legacy_after_expression_checks as $handler) { $file_replacements = $event->getFileReplacements(); if ($handler::afterExpressionAnalysis( $event->getExpr(), $event->getContext(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements ) === false) { return false; } $event->setFileReplacements($file_replacements); } return null; } public function dispatchAfterStatementAnalysis(Event\AfterStatementAnalysisEvent $event): ?bool { foreach ($this->after_statement_checks as $handler) { if ($handler::afterStatementAnalysis($event) === false) { return false; } } foreach ($this->legacy_after_statement_checks as $handler) { $file_replacements = $event->getFileReplacements(); if ($handler::afterStatementAnalysis( $event->getStmt(), $event->getContext(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements ) === false) { return false; } $event->setFileReplacements($file_replacements); } return null; } public function dispatchStringInterpreter(Event\StringInterpreterEvent $event): ?TLiteralString { foreach ($this->string_interpreters as $handler) { if ($type = $handler::getTypeFromValue($event)) { return $type; } } foreach ($this->legacy_string_interpreters as $handler) { if ($type = $handler::getTypeFromValue($event->getValue())) { return $type; } } return null; } public function dispatchAfterClassLikeExistenceCheck(Event\AfterClassLikeExistenceCheckEvent $event): void { foreach ($this->after_classlike_exists_checks as $handler) { $handler::afterClassLikeExistenceCheck($event); } foreach ($this->legacy_after_classlike_exists_checks as $handler) { $file_replacements = $event->getFileReplacements(); $handler::afterClassLikeExistenceCheck( $event->getFqClassName(), $event->getCodeLocation(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements ); $event->setFileReplacements($file_replacements); } } public function dispatchAfterClassLikeAnalysis(Event\AfterClassLikeAnalysisEvent $event): ?bool { foreach ($this->after_classlike_checks as $handler) { if ($handler::afterStatementAnalysis($event) === false) { return false; } } foreach ($this->legacy_after_classlike_checks as $handler) { $file_replacements = $event->getFileReplacements(); if ($handler::afterStatementAnalysis( $event->getStmt(), $event->getClasslikeStorage(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements ) === false) { return false; } $event->setFileReplacements($file_replacements); } return null; } public function dispatchAfterClassLikeVisit(Event\AfterClassLikeVisitEvent $event): void { foreach ($this->after_visit_classlikes as $handler) { $handler::afterClassLikeVisit($event); } foreach ($this->legacy_after_visit_classlikes as $handler) { $file_replacements = $event->getFileReplacements(); $handler::afterClassLikeVisit( $event->getStmt(), $event->getStorage(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements ); $event->setFileReplacements($file_replacements); } } public function dispatchAfterCodebasePopulated(Event\AfterCodebasePopulatedEvent $event): void { foreach ($this->after_codebase_populated as $handler) { $handler::afterCodebasePopulated($event); } foreach ($this->legacy_after_codebase_populated as $handler) { $handler::afterCodebasePopulated( $event->getCodebase() ); } } public function dispatchAfterAnalysis(Event\AfterAnalysisEvent $event): void { foreach ($this->after_analysis as $handler) { $handler::afterAnalysis($event); } foreach ($this->legacy_after_analysis as $handler) { /** @psalm-suppress MixedArgumentTypeCoercion due to Psalm bug */ $handler::afterAnalysis( $event->getCodebase(), $event->getIssues(), $event->getBuildInfo(), $event->getSourceControlInfo() ); } } public function dispatchAfterFileAnalysis(Event\AfterFileAnalysisEvent $event): void { foreach ($this->after_file_checks as $handler) { $handler::afterAnalyzeFile($event); } foreach ($this->legacy_after_file_checks as $handler) { $handler::afterAnalyzeFile( $event->getStatementsSource(), $event->getFileContext(), $event->getFileStorage(), $event->getCodebase() ); } } public function dispatchBeforeFileAnalysis(Event\BeforeFileAnalysisEvent $event): void { foreach ($this->before_file_checks as $handler) { $handler::beforeAnalyzeFile($event); } foreach ($this->legacy_before_file_checks as $handler) { $handler::beforeAnalyzeFile( $event->getStatementsSource(), $event->getFileContext(), $event->getFileStorage(), $event->getCodebase() ); } } public function dispatchAfterFunctionLikeAnalysis(Event\AfterFunctionLikeAnalysisEvent $event): ?bool { foreach ($this->after_functionlike_checks as $handler) { if ($handler::afterStatementAnalysis($event) === false) { return false; } } foreach ($this->legacy_after_functionlike_checks as $handler) { $file_replacements = $event->getFileReplacements(); if ($handler::afterStatementAnalysis( $event->getStmt(), $event->getClasslikeStorage(), $event->getStatementsSource(), $event->getCodebase(), $file_replacements ) === false) { return false; } $event->setFileReplacements($file_replacements); } return null; } }