Completed
Push — master ( da65dc...5751ed )
by Tomáš
20:43 queued 16:49
created

Code::generateFileReport()   F

Complexity

Conditions 49
Paths > 20000

Size

Total Lines 279
Code Lines 166

Duplication

Lines 86
Ratio 30.82 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 86
loc 279
rs 2
cc 49
eloc 166
nc 3699302401
nop 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Full report for Symplify\PHP7_CodeSniffer.
4
 *
5
 * @author    Greg Sherwood <[email protected]>
6
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
7
 * @license   https://github.com/squizlabs/Symplify\PHP7_CodeSniffer/blob/master/licence.txt BSD Licence
8
 */
9
10
namespace Symplify\PHP7_CodeSniffer\Reports;
11
12
use Symplify\PHP7_CodeSniffer\Files\File;
13
use Symplify\PHP7_CodeSniffer\Util;
14
15
class Code implements Report
16
{
17
18
19
    /**
20
     * Generate a partial report for a single processed file.
21
     *
22
     * Function should return TRUE if it printed or stored data about the file
23
     * and FALSE if it ignored the file. Returning TRUE indicates that the file and
24
     * its data should be counted in the grand totals.
25
     *
26
     * @param array                 $report      Prepared report data.
27
     * @param \Symplify\PHP7_CodeSniffer\File $phpcsFile   The file being reported on.
28
     * @param bool                  $showSources Show sources?
29
     * @param int                   $width       Maximum allowed line width.
30
     *
31
     * @return bool
32
     */
33
    public function generateFileReport($report, File $phpcsFile, $showSources=false, $width=80)
34
    {
35
        if ($report['errors'] === 0 && $report['warnings'] === 0) {
36
            // Nothing to print.
37
            return false;
38
        }
39
40
        // How many lines to show about and below the error line.
41
        $surroundingLines = 2;
42
43
        $file   = $report['filename'];
44
        $tokens = $phpcsFile->getTokens();
45
        if (empty($tokens) === true) {
46 View Code Duplication
            if (PHP_CodeSniffer_VERBOSITY === 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
47
                $startTime = microtime(true);
48
                echo 'CODE report is parsing '.basename($file).' ';
49
            } else if (PHP_CodeSniffer_VERBOSITY > 1) {
50
                echo "CODE report is forcing parse of $file".PHP_EOL;
51
            }
52
53
            $phpcsFile->parse();
54
55 View Code Duplication
            if (PHP_CodeSniffer_VERBOSITY === 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
56
                $timeTaken = ((microtime(true) - $startTime) * 1000);
0 ignored issues
show
Bug introduced by
The variable $startTime does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
57
                if ($timeTaken < 1000) {
58
                    $timeTaken = round($timeTaken);
59
                    echo "DONE in {$timeTaken}ms";
60
                } else {
61
                    $timeTaken = round(($timeTaken / 1000), 2);
62
                    echo "DONE in $timeTaken secs";
63
                }
64
65
                echo PHP_EOL;
66
            }
67
68
            $tokens = $phpcsFile->getTokens();
69
        }//end if
70
71
        // Create an array that maps lines to the first token on the line.
72
        $lineTokens = array();
73
        $lastLine   = 0;
74
        foreach ($tokens as $stackPtr => $token) {
75
            if ($token['line'] !== $lastLine) {
76
                if ($lastLine > 0) {
77
                    $lineTokens[$lastLine]['end'] = ($stackPtr - 1);
78
                }
79
80
                $lastLine++;
81
                $lineTokens[$lastLine] = array(
82
                                          'start' => $stackPtr,
83
                                          'end'   => null,
84
                                         );
85
            }
86
        }
87
88
        // Make sure the last token in the file sits on an imaginary
89
        // last line so it is easier to generate code snippets at the
90
        // end of the file.
91
        $lineTokens[$lastLine]['end'] = $stackPtr;
0 ignored issues
show
Bug introduced by
The variable $stackPtr seems to be defined by a foreach iteration on line 74. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
92
93
        // Determine the longest code line we will be showing.
94
        $maxSnippetLength = 0;
95
        $eolLen           = strlen($phpcsFile->eolChar);
96
        foreach ($report['messages'] as $line => $lineErrors) {
97
            $startLine = max(($line - $surroundingLines), 1);
98
            $endLine   = min(($line + $surroundingLines), $lastLine);
99
100
            $maxLineNumLength = strlen($endLine);
101
102
            for ($i = $startLine; $i <= $endLine; $i++) {
103
                if ($i === 1) {
104
                    continue;
105
                }
106
107
                $lineLength       = ($tokens[($lineTokens[$i]['start'] - 1)]['column'] + $tokens[($lineTokens[$i]['start'] - 1)]['length'] - $eolLen);
108
                $maxSnippetLength = max($lineLength, $maxSnippetLength);
109
            }
110
        }
111
112
        $maxSnippetLength += ($maxLineNumLength + 8);
0 ignored issues
show
Bug introduced by
The variable $maxLineNumLength does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
113
114
        // Determine the longest error message we will be showing.
115
        $maxErrorLength = 0;
116 View Code Duplication
        foreach ($report['messages'] as $line => $lineErrors) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117
            foreach ($lineErrors as $column => $colErrors) {
118
                foreach ($colErrors as $error) {
119
                    $length = strlen($error['message']);
120
                    if ($showSources === true) {
121
                        $length += (strlen($error['source']) + 3);
122
                    }
123
124
                    $maxErrorLength = max($maxErrorLength, ($length + 1));
125
                }
126
            }
127
        }
128
129
        // The padding that all lines will require that are printing an error message overflow.
130
        if ($report['warnings'] > 0) {
131
            $typeLength = 7;
132
        } else {
133
            $typeLength = 5;
134
        }
135
136
        $errorPadding  = str_repeat(' ', ($maxLineNumLength + 7));
137
        $errorPadding .= str_repeat(' ', $typeLength);
138
        $errorPadding .= ' ';
139
        if ($report['fixable'] > 0) {
140
            $errorPadding .= '    ';
141
        }
142
143
        $errorPaddingLength = strlen($errorPadding);
144
145
        // The maximum amount of space an error message can use.
146
        $maxErrorSpace = ($width - $errorPaddingLength);
147
        if ($showSources === true) {
148
            // Account for the chars used to print colors.
149
            $maxErrorSpace += 8;
150
        }
151
152
        // Figure out the max report width we need and can use.
153
        $fileLength = strlen($file);
154
        $maxWidth   = max(($fileLength + 6), ($maxErrorLength + $errorPaddingLength));
155
        $width      = max(min($width, $maxWidth), $maxSnippetLength);
156
        if ($width < 70) {
157
            $width = 70;
158
        }
159
160
        // Print the file header.
161
        echo PHP_EOL."\033[1mFILE: ";
162 View Code Duplication
        if ($fileLength <= ($width - 6)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163
            echo $file;
164
        } else {
165
            echo '...'.substr($file, ($fileLength - ($width - 6)));
166
        }
167
168
        echo "\033[0m".PHP_EOL;
169
        echo str_repeat('-', $width).PHP_EOL;
170
171
        echo "\033[1m".'FOUND '.$report['errors'].' ERROR';
172
        if ($report['errors'] !== 1) {
173
            echo 'S';
174
        }
175
176 View Code Duplication
        if ($report['warnings'] > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
            echo ' AND '.$report['warnings'].' WARNING';
178
            if ($report['warnings'] !== 1) {
179
                echo 'S';
180
            }
181
        }
182
183
        echo ' AFFECTING '.count($report['messages']).' LINE';
184
        if (count($report['messages']) !== 1) {
185
            echo 'S';
186
        }
187
188
        echo "\033[0m".PHP_EOL;
189
190
        foreach ($report['messages'] as $line => $lineErrors) {
191
            $startLine = max(($line - $surroundingLines), 1);
192
            $endLine   = min(($line + $surroundingLines), $lastLine);
193
194
            $snippet = '';
195
            for ($i = $lineTokens[$startLine]['start']; $i <= $lineTokens[$endLine]['end']; $i++) {
196
                $snippetLine = $tokens[$i]['line'];
197
                if ($lineTokens[$snippetLine]['start'] === $i) {
198
                    // Starting a new line.
199
                    if ($snippetLine === $line) {
200
                        $snippet .= "\033[1m".'>> ';
201
                    } else {
202
                        $snippet .= '   ';
203
                    }
204
205
                    $snippet .= str_repeat(' ', ($maxLineNumLength - strlen($snippetLine)));
206
                    $snippet .= $snippetLine.':  ';
207
                    if ($snippetLine === $line) {
208
                        $snippet .= "\033[0m";
209
                    }
210
                }
211
212
                if (isset($tokens[$i]['orig_content']) === true) {
213
                    $tokenContent = $tokens[$i]['orig_content'];
214
                } else {
215
                    $tokenContent = $tokens[$i]['content'];
216
                }
217
218
                if (strpos($tokenContent, "\t") !== false) {
219
                    $token            = $tokens[$i];
220
                    $token['content'] = $tokenContent;
221
                    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
222
                        $tab = "\000";
223
                    } else {
224
                        $tab = "\033[30;1m»\033[0m";
225
                    }
226
227
                    $phpcsFile->tokenizer->replaceTabsInToken($token, $tab, "\000");
228
                    $tokenContent = $token['content'];
229
                }
230
231
                $tokenContent = Util\Common::prepareForOutput($tokenContent, array("\r", "\n", "\t"));
232
                $tokenContent = str_replace("\000", ' ', $tokenContent);
233
234
                $underline = false;
235
                if ($snippetLine === $line && isset($lineErrors[$tokens[$i]['column']]) === true) {
236
                    $underline = true;
237
                }
238
239
                // Underline invisible characters as well.
240
                if ($underline === true && trim($tokenContent) === '') {
241
                    $snippet .= "\033[4m".' '."\033[0m".$tokenContent;
242
                } else {
243
                    if ($underline === true) {
244
                        $snippet .= "\033[4m";
245
                    }
246
247
                    $snippet .= $tokenContent;
248
249
                    if ($underline === true) {
250
                        $snippet .= "\033[0m";
251
                    }
252
                }
253
            }//end for
254
255
            echo str_repeat('-', $width).PHP_EOL;
256
257 View Code Duplication
            foreach ($lineErrors as $column => $colErrors) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
                foreach ($colErrors as $error) {
259
                    $padding = ($maxLineNumLength - strlen($line));
260
                    echo 'LINE '.str_repeat(' ', $padding).$line.': ';
261
262
                    if ($error['type'] === 'ERROR') {
263
                        echo "\033[31mERROR\033[0m";
264
                        if ($report['warnings'] > 0) {
265
                            echo '  ';
266
                        }
267
                    } else {
268
                        echo "\033[33mWARNING\033[0m";
269
                    }
270
271
                    echo ' ';
272
                    if ($report['fixable'] > 0) {
273
                        echo '[';
274
                        if ($error['fixable'] === true) {
275
                            echo 'x';
276
                        } else {
277
                            echo ' ';
278
                        }
279
280
                        echo '] ';
281
                    }
282
283
                    $message = $error['message'];
284
                    $message = str_replace("\n", "\n".$errorPadding, $message);
285
                    if ($showSources === true) {
286
                        $message = "\033[1m".$message."\033[0m".' ('.$error['source'].')';
287
                    }
288
289
                    $errorMsg = wordwrap(
290
                        $message,
291
                        $maxErrorSpace,
292
                        PHP_EOL.$errorPadding
293
                    );
294
295
                    echo $errorMsg.PHP_EOL;
296
                }//end foreach
297
            }//end foreach
298
299
            echo str_repeat('-', $width).PHP_EOL;
300
            echo rtrim($snippet).PHP_EOL;
301
        }//end foreach
302
303
        echo str_repeat('-', $width).PHP_EOL;
304 View Code Duplication
        if ($report['fixable'] > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
            echo "\033[1m".'PHPCBF CAN FIX THE '.$report['fixable'].' MARKED SNIFF VIOLATIONS AUTOMATICALLY'."\033[0m".PHP_EOL;
306
            echo str_repeat('-', $width).PHP_EOL;
307
        }
308
309
        return true;
310
311
    }//end generateFileReport()
312
313
314
    /**
315
     * Prints all errors and warnings for each file processed.
316
     *
317
     * @param string $cachedData    Any partial report data that was returned from
318
     *                              generateFileReport during the run.
319
     * @param int    $totalFiles    Total number of files processed during the run.
320
     * @param int    $totalErrors   Total number of errors found during the run.
321
     * @param int    $totalWarnings Total number of warnings found during the run.
322
     * @param int    $totalFixable  Total number of problems that can be fixed.
323
     * @param bool   $showSources   Show sources?
324
     * @param int    $width         Maximum allowed line width.
325
     * @param bool   $interactive   Are we running in interactive mode?
326
     * @param bool   $toScreen      Is the report being printed to screen?
327
     *
328
     * @return void
329
     */
330 View Code Duplication
    public function generate(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
331
        $cachedData,
332
        $totalFiles,
333
        $totalErrors,
334
        $totalWarnings,
335
        $totalFixable,
336
        $showSources=false,
337
        $width=80,
338
        $interactive=false,
339
        $toScreen=true
340
    ) {
341
        if ($cachedData === '') {
342
            return;
343
        }
344
345
        echo $cachedData;
346
347
        if ($toScreen === true && $interactive === false) {
348
            Util\Timing::printRunTime();
349
        }
350
351
    }//end generate()
352
353
354
}//end class
355