Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
DirUsageSniff
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 2
342
0.00% covered (danger)
0.00%
0 / 1
 register
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 process
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
306
1<?php
2/**
3 * Report error when dirname(__FILE__) is used instead of __DIR__
4 *
5 * Fail: dirname( __FILE__ )
6 * Pass: dirname( __FILE__ . "/.." )
7 * Pass: dirname( __FILE__, 2 )
8 * Pass: dirname( joinpaths( __FILE__, ".." ) )
9 * Pass: $abc->dirname( __FILE__ )
10 * Pass: parent::dirname( __FILE__ )
11 */
12
13namespace MediaWiki\Sniffs\Usage;
14
15use PHP_CodeSniffer\Files\File;
16use PHP_CodeSniffer\Sniffs\Sniff;
17
18class DirUsageSniff implements Sniff {
19
20    /**
21     * @inheritDoc
22     */
23    public function register(): array {
24        // As per https://www.mediawiki.org/wiki/Manual:Coding_conventions/PHP#Other
25        return [ T_STRING ];
26    }
27
28    /**
29     * @param File $phpcsFile
30     * @param int $stackPtr The current token index.
31     * @return void
32     */
33    public function process( File $phpcsFile, $stackPtr ) {
34        $tokens = $phpcsFile->getTokens();
35
36        // Check if the function is dirname()
37        if ( $tokens[$stackPtr]['content'] !== 'dirname' ) {
38            return;
39        }
40
41        // Find the parenthesis for the function
42        $nextToken = $phpcsFile->findNext( T_WHITESPACE, $stackPtr + 1, null, true );
43        if ( $nextToken === false
44            || $tokens[$nextToken]['code'] !== T_OPEN_PARENTHESIS
45        ) {
46            return;
47        }
48
49        // Check if __FILE__ is inside it
50        $nextToken = $phpcsFile->findNext( T_WHITESPACE, $nextToken + 1, null, true );
51        if ( $nextToken == false
52            || $tokens[$nextToken]['code'] !== T_FILE
53        ) {
54            return;
55        }
56
57        // Check if it's a PHP function
58        $prevToken = $phpcsFile->findPrevious( T_WHITESPACE, $stackPtr - 1, null, true );
59        if ( $prevToken === false
60            || $tokens[$prevToken]['code'] === T_OBJECT_OPERATOR
61            || $tokens[$prevToken]['code'] === T_NULLSAFE_OBJECT_OPERATOR
62            || $tokens[$prevToken]['code'] === T_DOUBLE_COLON
63            || $tokens[$prevToken]['code'] === T_FUNCTION
64            || $tokens[$prevToken]['code'] === T_CONST
65        ) {
66            return;
67        }
68
69        // Find close parenthesis
70        $nextToken = $phpcsFile->findNext( T_WHITESPACE, $nextToken + 1, null, true );
71        if ( $nextToken === false
72            || $tokens[$nextToken]['code'] !== T_CLOSE_PARENTHESIS
73        ) {
74            return;
75        }
76
77        $fix = $phpcsFile->addFixableError(
78            'Use __DIR__ constant instead of calling dirname(__FILE__)',
79            $stackPtr,
80            'FunctionFound'
81        );
82        if ( $fix ) {
83            $curToken = $stackPtr;
84            while ( $curToken <= $nextToken ) {
85                if ( $tokens[$curToken]['code'] === T_FILE ) {
86                    $phpcsFile->fixer->replaceToken( $curToken, '__DIR__' );
87                } else {
88                    $phpcsFile->fixer->replaceToken( $curToken, '' );
89                }
90                $curToken++;
91            }
92        }
93    }
94}