diff options
Diffstat (limited to 'www/wiki/tests/phan/bin/postprocess-phan.php')
-rw-r--r-- | www/wiki/tests/phan/bin/postprocess-phan.php | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/www/wiki/tests/phan/bin/postprocess-phan.php b/www/wiki/tests/phan/bin/postprocess-phan.php new file mode 100644 index 00000000..3e805986 --- /dev/null +++ b/www/wiki/tests/phan/bin/postprocess-phan.php @@ -0,0 +1,146 @@ +<?php + +abstract class Suppressor { + /** + * @param string $input + * @return bool do errors remain + */ + abstract public function suppress( $input ); + + /** + * @param string[] $source + * @param string $type + * @param int $lineno + * @return bool + */ + protected function isSuppressed( array $source, $type, $lineno ) { + return $lineno > 0 && preg_match( + "|/\*\* @suppress {$type} |", + $source[$lineno - 1] + ); + } +} + +class TextSuppressor extends Suppressor { + /** + * @param string $input + * @return bool do errors remain + */ + public function suppress( $input ) { + $hasErrors = false; + $errors = []; + foreach ( explode( "\n", $input ) as $error ) { + if ( empty( $error ) ) { + continue; + } + if ( !preg_match( '/^(.*):(\d+) (Phan\w+) (.*)$/', $error, $matches ) ) { + echo "Failed to parse line: $error\n"; + continue; + } + list( $source, $file, $lineno, $type, $message ) = $matches; + $errors[$file][] = [ + 'orig' => $error, + // convert from 1 indexed to 0 indexed + 'lineno' => $lineno - 1, + 'type' => $type, + ]; + } + foreach ( $errors as $file => $fileErrors ) { + $source = file( $file ); + foreach ( $fileErrors as $error ) { + if ( !$this->isSuppressed( $source, $error['type'], $error['lineno'] ) ) { + echo $error['orig'], "\n"; + $hasErrors = true; + } + } + } + + return $hasErrors; + } +} + +class CheckStyleSuppressor extends Suppressor { + /** + * @param string $input + * @return bool True do errors remain + */ + public function suppress( $input ) { + $dom = new DOMDocument(); + $dom->loadXML( $input ); + $hasErrors = false; + // DOMNodeList's are "live", convert to an array so it works as expected + $files = []; + foreach ( $dom->getElementsByTagName( 'file' ) as $file ) { + $files[] = $file; + } + foreach ( $files as $file ) { + $errors = []; + foreach ( $file->getElementsByTagName( 'error' ) as $error ) { + $errors[] = $error; + } + $source = file( $file->getAttribute( 'name' ) ); + $fileHasErrors = false; + foreach ( $errors as $error ) { + $lineno = $error->getAttribute( 'line' ) - 1; + $type = $error->getAttribute( 'source' ); + if ( $this->isSuppressed( $source, $type, $lineno ) ) { + $error->parentNode->removeChild( $error ); + } else { + $fileHasErrors = true; + $hasErrors = true; + } + } + if ( !$fileHasErrors ) { + $file->parentNode->removeChild( $file ); + } + } + echo $dom->saveXML(); + + return $hasErrors; + } +} + +class NoopSuppressor extends Suppressor { + private $mode; + + public function __construct( $mode ) { + $this->mode = $mode; + } + public function suppress( $input ) { + echo "Unsupported output mode: {$this->mode}\n$input"; + return true; + } +} + +$opt = getopt( "m:", [ "output-mode:" ] ); +// if provided multiple times getopt returns an array +if ( isset( $opt['m'] ) ) { + $mode = $opt['m']; +} elseif ( isset( $mode['output-mode'] ) ) { + $mode = $opt['output-mode']; +} else { + $mode = 'text'; +} +if ( is_array( $mode ) ) { + // If an option is passed multiple times getopt returns an + // array. Just take the last one. + $mode = end( $mode ); +} + +switch ( $mode ) { +case 'text': + $suppressor = new TextSuppressor(); + break; +case 'checkstyle': + $suppressor = new CheckStyleSuppressor(); + break; +default: + $suppressor = new NoopSuppressor( $mode ); +} + +$input = file_get_contents( 'php://stdin' ); +$hasErrors = $suppressor->suppress( $input ); + +if ( $hasErrors ) { + exit( 1 ); +} |