Update docs/hooks.txt for ShowSearchHitTitle
[mediawiki.git] / tests / phan / bin / postprocess-phan.php
blob3e8059867757b02c08cd783e54b807e93d1b477e
1 <?php
3 abstract class Suppressor {
4 /**
5 * @param string $input
6 * @return bool do errors remain
7 */
8 abstract public function suppress( $input );
10 /**
11 * @param string[] $source
12 * @param string $type
13 * @param int $lineno
14 * @return bool
16 protected function isSuppressed( array $source, $type, $lineno ) {
17 return $lineno > 0 && preg_match(
18 "|/\*\* @suppress {$type} |",
19 $source[$lineno - 1]
24 class TextSuppressor extends Suppressor {
25 /**
26 * @param string $input
27 * @return bool do errors remain
29 public function suppress( $input ) {
30 $hasErrors = false;
31 $errors = [];
32 foreach ( explode( "\n", $input ) as $error ) {
33 if ( empty( $error ) ) {
34 continue;
36 if ( !preg_match( '/^(.*):(\d+) (Phan\w+) (.*)$/', $error, $matches ) ) {
37 echo "Failed to parse line: $error\n";
38 continue;
40 list( $source, $file, $lineno, $type, $message ) = $matches;
41 $errors[$file][] = [
42 'orig' => $error,
43 // convert from 1 indexed to 0 indexed
44 'lineno' => $lineno - 1,
45 'type' => $type,
48 foreach ( $errors as $file => $fileErrors ) {
49 $source = file( $file );
50 foreach ( $fileErrors as $error ) {
51 if ( !$this->isSuppressed( $source, $error['type'], $error['lineno'] ) ) {
52 echo $error['orig'], "\n";
53 $hasErrors = true;
58 return $hasErrors;
62 class CheckStyleSuppressor extends Suppressor {
63 /**
64 * @param string $input
65 * @return bool True do errors remain
67 public function suppress( $input ) {
68 $dom = new DOMDocument();
69 $dom->loadXML( $input );
70 $hasErrors = false;
71 // DOMNodeList's are "live", convert to an array so it works as expected
72 $files = [];
73 foreach ( $dom->getElementsByTagName( 'file' ) as $file ) {
74 $files[] = $file;
76 foreach ( $files as $file ) {
77 $errors = [];
78 foreach ( $file->getElementsByTagName( 'error' ) as $error ) {
79 $errors[] = $error;
81 $source = file( $file->getAttribute( 'name' ) );
82 $fileHasErrors = false;
83 foreach ( $errors as $error ) {
84 $lineno = $error->getAttribute( 'line' ) - 1;
85 $type = $error->getAttribute( 'source' );
86 if ( $this->isSuppressed( $source, $type, $lineno ) ) {
87 $error->parentNode->removeChild( $error );
88 } else {
89 $fileHasErrors = true;
90 $hasErrors = true;
93 if ( !$fileHasErrors ) {
94 $file->parentNode->removeChild( $file );
97 echo $dom->saveXML();
99 return $hasErrors;
103 class NoopSuppressor extends Suppressor {
104 private $mode;
106 public function __construct( $mode ) {
107 $this->mode = $mode;
109 public function suppress( $input ) {
110 echo "Unsupported output mode: {$this->mode}\n$input";
111 return true;
115 $opt = getopt( "m:", [ "output-mode:" ] );
116 // if provided multiple times getopt returns an array
117 if ( isset( $opt['m'] ) ) {
118 $mode = $opt['m'];
119 } elseif ( isset( $mode['output-mode'] ) ) {
120 $mode = $opt['output-mode'];
121 } else {
122 $mode = 'text';
124 if ( is_array( $mode ) ) {
125 // If an option is passed multiple times getopt returns an
126 // array. Just take the last one.
127 $mode = end( $mode );
130 switch ( $mode ) {
131 case 'text':
132 $suppressor = new TextSuppressor();
133 break;
134 case 'checkstyle':
135 $suppressor = new CheckStyleSuppressor();
136 break;
137 default:
138 $suppressor = new NoopSuppressor( $mode );
141 $input = file_get_contents( 'php://stdin' );
142 $hasErrors = $suppressor->suppress( $input );
144 if ( $hasErrors ) {
145 exit( 1 );