Skip to content
4 changes: 2 additions & 2 deletions .github/workflows/php-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
if: ${{ matrix.coverage }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f
with:
file: build/logs/*.xml
files: build/logs/*.xml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

flags: unit
token: ${{ secrets.CODECOV_TOKEN }}

Expand Down Expand Up @@ -158,6 +158,6 @@ jobs:
if: ${{ matrix.coverage }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f
with:
file: build/logs/*.xml
files: build/logs/*.xml
flags: phpcs-sniffs
token: ${{ secrets.CODECOV_TOKEN }}
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,9 @@ private function is_ast_valid_for_direct_access( array $ast ) {
Stmt\Enum_::class,
);

$has_assignments = false;
$has_returns = false;
$has_assignments = false;
$has_returns = false;
$has_structural_declaration = $this->has_structural_declaration( $ast );

foreach ( $ast as $node ) {
$node_class = get_class( $node );
Expand All @@ -428,6 +429,10 @@ private function is_ast_valid_for_direct_access( array $ast ) {
}

if ( $node instanceof Stmt\Expression ) {
if ( $node->expr instanceof Expr\Include_ && $has_structural_declaration ) {
continue;
}

if ( $this->is_safe_expression( $node->expr ) ) {
continue;
}
Expand Down Expand Up @@ -455,6 +460,33 @@ private function is_ast_valid_for_direct_access( array $ast ) {
return true;
}

/**
* Checks whether the AST contains structural declarations.
*
* @since n.e.x.t
*
* @param array $ast The parsed AST nodes.
* @return bool True if the AST contains class/interface/trait/enum declarations, false otherwise.
*/
private function has_structural_declaration( array $ast ) {
foreach ( $ast as $node ) {
if (
$node instanceof Stmt\Class_ ||
$node instanceof Stmt\Interface_ ||
$node instanceof Stmt\Trait_ ||
$node instanceof Stmt\Enum_
) {
return true;
}

if ( $node instanceof Stmt\Namespace_ && ! empty( $node->stmts ) ) {
return $this->has_structural_declaration( $node->stmts );
}
}

return false;
}

/**
* Checks if an expression is an asset file assignment (variable = array/string).
*
Expand Down Expand Up @@ -895,7 +927,7 @@ private function has_procedural_code( $contents ) {
private function has_only_safe_function_calls( $contents ) {
$safe_if_count = preg_match_all( '/if\s*\([^)]*(?:class_exists|function_exists|interface_exists|trait_exists|defined)\s*\(/i', $contents );
$return_count = preg_match_all( '/return\s*;/', $contents );
$all_function_calls = preg_match_all( '/\b(?!class_exists|function_exists|interface_exists|trait_exists|defined|return|if|else|elseif|isset|empty|unset|array|list|echo|print)\w+\s*\(/i', $contents );
$all_function_calls = preg_match_all( '/\b(?!class_exists|function_exists|interface_exists|trait_exists|defined|return|if|else|elseif|isset|empty|unset|array|list|echo|print|require|require_once|include|include_once)\w+\s*\(/i', $contents );

return $safe_if_count > 0 && $return_count >= $safe_if_count && 0 === $all_function_calls;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/**
* File with require_once and class - safe for direct access.
*/

require_once __DIR__ . '/class-parent.php';

/**
* Test class.
*/
class My_Class extends Parent_Class {
/**
* Property.
*
* @var string
*/
private $property = 'test';
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public function test_run_allows_class_only_files() {
// Files with only class definitions should not produce errors.
$this->assertArrayNotHasKey( 'includes/class-only-file.php', $errors );
$this->assertArrayNotHasKey( 'includes/namespace-class-only.php', $errors );
$this->assertArrayNotHasKey( 'includes/require-once-class-only.php', $errors );
}

/**
Expand Down
Loading