diff options
Diffstat (limited to 'www/wiki/tests/phan')
-rwxr-xr-x | www/wiki/tests/phan/bin/phan | 90 | ||||
-rw-r--r-- | www/wiki/tests/phan/bin/postprocess-phan.php | 146 | ||||
-rw-r--r-- | www/wiki/tests/phan/config.php | 497 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/README | 3 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/hhvm.php | 26 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/mail.php | 89 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/memcached.php | 16 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/phpunit4.php | 11 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/tideways.php | 12 | ||||
-rw-r--r-- | www/wiki/tests/phan/stubs/wikidiff.php | 39 |
10 files changed, 929 insertions, 0 deletions
diff --git a/www/wiki/tests/phan/bin/phan b/www/wiki/tests/phan/bin/phan new file mode 100755 index 00000000..ad06823a --- /dev/null +++ b/www/wiki/tests/phan/bin/phan @@ -0,0 +1,90 @@ +#!/bin/bash + +# mediawiki-vagrant installs dont have realpath by default +if ! which realpath > /dev/null; then + realpath() { + php -r "echo realpath('$*');" + } +fi + +if hash php7.0 2>/dev/null; then + export PHP="php7.0" +else + export PHP="php" +fi + +# Note that this isn't loaded in via composer because then composer can +# only be run with php7.0 +if [ ! -f "$PHAN" ]; then + # If no PHAN is specified then try to get location from PATH + export PHAN="$(which phan)" + if [ ! -f "$PHAN" ]; then + echo "The environment variable PHAN must point to the 'phan' file" + echo "in a checkout of https://github.com/etsy/phan.git" + echo "Or phan must be included in your PATH" + exit 1 + fi +else + export PHAN="$PHP $PHAN" +fi + +if [ -z "$MW_INSTALL_PATH" ]; then + # Figure out where mediawiki is based on the location of this script + pushd "$(dirname "$0")" > /dev/null + export MW_INSTALL_PATH="$(git rev-parse --show-toplevel)" + popd >/dev/null +fi + +# If the first argument doesn't start with a -, then it's a path +# to another project (extension, skin, etc.) to analyze +if [[ -n "$1" && "$1" != "-"* ]]; then + cd $1 + shift +else + cd "$(dirname "$0")" +fi + +# Root directory of project +export ROOT="$(git rev-parse --show-toplevel)" + +# Go to the root of this git repo +cd "$ROOT" + +export CONFIG_FILE="$ROOT/tests/phan/config.php" +if [ ! -f "$CONFIG_FILE" ]; then + echo "Could not find a phan config file to apply in" + echo "$CONFIG_FILE" + exit 1 +fi + +# Phan's issues directory +export ISSUES="${ROOT}/tests/phan/issues" +mkdir -p "$ISSUES" + +# Get the current hash of HEAD +export REV="$(git rev-parse HEAD)" + +# Destination for issues found +export RUN="${ISSUES}/issues-${REV}" + + +# Run the analysis, emitting output to the +# issues file. +$PHAN \ + --project-root-directory "$ROOT" \ + --config-file "$CONFIG_FILE" \ + --output "php://stdout" \ + "${@}" \ + | php "$MW_INSTALL_PATH/tests/phan/bin/postprocess-phan.php" "${@}" \ + > $RUN + +EXIT_CODE="$?" + +# Re-link the latest file +rm -f "${ISSUES}/latest" +ln -s "${RUN}" "${ISSUES}/latest" + +# Output any issues that were found +cat "${RUN}" + +exit $EXIT_CODE 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 ); +} diff --git a/www/wiki/tests/phan/config.php b/www/wiki/tests/phan/config.php new file mode 100644 index 00000000..71ebd6f4 --- /dev/null +++ b/www/wiki/tests/phan/config.php @@ -0,0 +1,497 @@ +<?php + +// If xdebug is enabled, we need to increase the nesting level for phan +ini_set( 'xdebug.max_nesting_level', 1000 ); + +/** + * This configuration will be read and overlayed on top of the + * default configuration. Command line arguments will be applied + * after this file is read. + * + * @see src/Phan/Config.php + * See Config for all configurable options. + * + * A Note About Paths + * ================== + * + * Files referenced from this file should be defined as + * + * ``` + * Config::projectPath('relative_path/to/file') + * ``` + * + * where the relative path is relative to the root of the + * project which is defined as either the working directory + * of the phan executable or a path passed in via the CLI + * '-d' flag. + */ +return [ + /** + * A list of individual files to include in analysis + * with a path relative to the root directory of the + * project. directory_list won't find .inc files so + * we augment it here. + */ + 'file_list' => array_merge( + function_exists( 'register_postsend_function' ) ? [] : [ 'tests/phan/stubs/hhvm.php' ], + function_exists( 'wikidiff2_do_diff' ) ? [] : [ 'tests/phan/stubs/wikidiff.php' ], + function_exists( 'tideways_enable' ) ? [] : [ 'tests/phan/stubs/tideways.php' ], + class_exists( PEAR::class ) ? [] : [ 'tests/phan/stubs/mail.php' ], + class_exists( Memcached::class ) ? [] : [ 'tests/phan/stubs/memcached.php' ], + // Per composer.json, PHPUnit 6 is used for PHP 7.0+, PHPUnit 4 otherwise. + // Load the interface for the version of PHPUnit that isn't installed. + // Phan only supports PHP 7.0+ (and not HHVM), so we only need to stub PHPUnit 4. + class_exists( PHPUnit_TextUI_Command::class ) ? [] : [ 'tests/phan/stubs/phpunit4.php' ], + [ + 'maintenance/7zip.inc', + 'maintenance/backup.inc', + 'maintenance/cleanupTable.inc', + 'maintenance/CodeCleanerGlobalsPass.inc', + 'maintenance/commandLine.inc', + 'maintenance/importImages.inc', + 'maintenance/sqlite.inc', + 'maintenance/userDupes.inc', + 'maintenance/userOptions.inc', + 'maintenance/language/checkLanguage.inc', + 'maintenance/language/languages.inc', + ] + ), + + /** + * A list of directories that should be parsed for class and + * method information. After excluding the directories + * defined in exclude_analysis_directory_list, the remaining + * files will be statically analyzed for errors. + * + * Thus, both first-party and third-party code being used by + * your application should be included in this list. + */ + 'directory_list' => [ + 'includes/', + 'languages/', + 'maintenance/', + 'mw-config/', + 'resources/', + 'skins/', + 'vendor/', + ], + + /** + * A file list that defines files that will be excluded + * from parsing and analysis and will not be read at all. + * + * This is useful for excluding hopelessly unanalyzable + * files that can't be removed for whatever reason. + */ + 'exclude_file_list' => [], + + /** + * A list of directories holding code that we want + * to parse, but not analyze. Also works for individual + * files. + */ + "exclude_analysis_directory_list" => [ + 'vendor/', + 'tests/phan/stubs/', + // The referenced classes are not available in vendor, only when + // included from composer. + 'includes/composer/', + // Directly references classes that only exist in Translate extension + 'maintenance/language/', + // External class + 'includes/libs/jsminplus.php', + // separate repositories + 'skins/', + ], + + /** + * Backwards Compatibility Checking. This is slow + * and expensive, but you should consider running + * it before upgrading your version of PHP to a + * new version that has backward compatibility + * breaks. + */ + 'backward_compatibility_checks' => false, + + /** + * A set of fully qualified class-names for which + * a call to parent::__construct() is required + */ + 'parent_constructor_required' => [ + ], + + /** + * Run a quick version of checks that takes less + * time at the cost of not running as thorough + * an analysis. You should consider setting this + * to true only when you wish you had more issues + * to fix in your code base. + * + * In quick-mode the scanner doesn't rescan a function + * or a method's code block every time a call is seen. + * This means that the problem here won't be detected: + * + * ```php + * <?php + * function test($arg):int { + * return $arg; + * } + * test("abc"); + * ``` + * + * This would normally generate: + * + * ```sh + * test.php:3 TypeError return string but `test()` is declared to return int + * ``` + * + * The initial scan of the function's code block has no + * type information for `$arg`. It isn't until we see + * the call and rescan test()'s code block that we can + * detect that it is actually returning the passed in + * `string` instead of an `int` as declared. + */ + 'quick_mode' => false, + + /** + * By default, Phan will not analyze all node types + * in order to save time. If this config is set to true, + * Phan will dig deeper into the AST tree and do an + * analysis on all nodes, possibly finding more issues. + * + * See \Phan\Analysis::shouldVisit for the set of skipped + * nodes. + */ + 'should_visit_all_nodes' => true, + + /** + * If enabled, check all methods that override a + * parent method to make sure its signature is + * compatible with the parent's. This check + * can add quite a bit of time to the analysis. + */ + 'analyze_signature_compatibility' => true, + + // Emit all issues. They are then suppressed via + // suppress_issue_types, rather than a minimum + // severity. + "minimum_severity" => 0, + + /** + * If true, missing properties will be created when + * they are first seen. If false, we'll report an + * error message if there is an attempt to write + * to a class property that wasn't explicitly + * defined. + */ + 'allow_missing_properties' => false, + + /** + * Allow null to be cast as any type and for any + * type to be cast to null. Setting this to false + * will cut down on false positives. + */ + 'null_casts_as_any_type' => true, + + /** + * If enabled, scalars (int, float, bool, string, null) + * are treated as if they can cast to each other. + * + * MediaWiki is pretty lax and uses many scalar + * types interchangably. + */ + 'scalar_implicit_cast' => true, + + /** + * If true, seemingly undeclared variables in the global + * scope will be ignored. This is useful for projects + * with complicated cross-file globals that you have no + * hope of fixing. + */ + 'ignore_undeclared_variables_in_global_scope' => true, + + /** + * Set to true in order to attempt to detect dead + * (unreferenced) code. Keep in mind that the + * results will only be a guess given that classes, + * properties, constants and methods can be referenced + * as variables (like `$class->$property` or + * `$class->$method()`) in ways that we're unable + * to make sense of. + */ + 'dead_code_detection' => false, + + /** + * If true, the dead code detection rig will + * prefer false negatives (not report dead code) to + * false positives (report dead code that is not + * actually dead) which is to say that the graph of + * references will create too many edges rather than + * too few edges when guesses have to be made about + * what references what. + */ + 'dead_code_detection_prefer_false_negative' => true, + + /** + * If disabled, Phan will not read docblock type + * annotation comments (such as for @return, @param, + * @var, @suppress, @deprecated) and only rely on + * types expressed in code. + */ + 'read_type_annotations' => true, + + /** + * If a file path is given, the code base will be + * read from and written to the given location in + * order to attempt to save some work from being + * done. Only changed files will get analyzed if + * the file is read + */ + 'stored_state_file_path' => null, + + /** + * Set to true in order to ignore issue suppression. + * This is useful for testing the state of your code, but + * unlikely to be useful outside of that. + */ + 'disable_suppression' => false, + + /** + * If set to true, we'll dump the AST instead of + * analyzing files + */ + 'dump_ast' => false, + + /** + * If set to a string, we'll dump the fully qualified lowercase + * function and method signatures instead of analyzing files. + */ + 'dump_signatures_file' => null, + + /** + * If true (and if stored_state_file_path is set) we'll + * look at the list of files passed in and expand the list + * to include files that depend on the given files + */ + 'expand_file_list' => false, + + // Include a progress bar in the output + 'progress_bar' => false, + + /** + * The probability of actually emitting any progress + * bar update. Setting this to something very low + * is good for reducing network IO and filling up + * your terminal's buffer when running phan on a + * remote host. + */ + 'progress_bar_sample_rate' => 0.005, + + /** + * The number of processes to fork off during the analysis + * phase. + */ + 'processes' => 1, + + /** + * Add any issue types (such as 'PhanUndeclaredMethod') + * to this black-list to inhibit them from being reported. + */ + 'suppress_issue_types' => [ + // approximate error count: 29 + "PhanCommentParamOnEmptyParamList", + // approximate error count: 33 + "PhanCommentParamWithoutRealParam", + // approximate error count: 8 + "PhanDeprecatedClass", + // approximate error count: 415 + "PhanDeprecatedFunction", + // approximate error count: 25 + "PhanDeprecatedProperty", + // approximate error count: 17 + "PhanNonClassMethodCall", + // approximate error count: 11 + "PhanParamReqAfterOpt", + // approximate error count: 888 + "PhanParamSignatureMismatch", + // approximate error count: 7 + "PhanParamSignatureMismatchInternal", + // approximate error count: 1 + "PhanParamSignatureRealMismatchTooFewParameters", + // approximate error count: 125 + "PhanParamTooMany", + // approximate error count: 1 + "PhanParamTooManyCallable", + // approximate error count: 3 + "PhanParamTooManyInternal", + // approximate error count: 1 + "PhanRedefineFunctionInternal", + // approximate error count: 2 + "PhanTraitParentReference", + // approximate error count: 3 + "PhanTypeComparisonFromArray", + // approximate error count: 2 + "PhanTypeComparisonToArray", + // approximate error count: 3 + "PhanTypeInvalidRightOperand", + // approximate error count: 1 + "PhanTypeMagicVoidWithReturn", + // approximate error count: 218 + "PhanTypeMismatchArgument", + // approximate error count: 13 + "PhanTypeMismatchArgumentInternal", + // approximate error count: 6 + "PhanTypeMismatchDeclaredParam", + // approximate error count: 111 + "PhanTypeMismatchDeclaredParamNullable", + // approximate error count: 1 + "PhanTypeMismatchDefault", + // approximate error count: 5 + "PhanTypeMismatchDimAssignment", + // approximate error count: 2 + "PhanTypeMismatchDimEmpty", + // approximate error count: 1 + "PhanTypeMismatchDimFetch", + // approximate error count: 14 + "PhanTypeMismatchForeach", + // approximate error count: 56 + "PhanTypeMismatchProperty", + // approximate error count: 74 + "PhanTypeMismatchReturn", + // approximate error count: 11 + "PhanTypeMissingReturn", + // approximate error count: 5 + "PhanTypeNonVarPassByRef", + // approximate error count: 1 + "PhanUndeclaredClassInCallable", + // approximate error count: 32 + "PhanUndeclaredConstant", + // approximate error count: 233 + "PhanUndeclaredMethod", + // approximate error count: 1224 + "PhanUndeclaredProperty", + // approximate error count: 3 + "PhanUndeclaredStaticMethod", + // approximate error count: 11 + "PhanUndeclaredTypeReturnType", + // approximate error count: 27 + "PhanUndeclaredVariable", + // approximate error count: 58 + "PhanUndeclaredVariableDim", + ], + + /** + * If empty, no filter against issues types will be applied. + * If this white-list is non-empty, only issues within the list + * will be emitted by Phan. + */ + 'whitelist_issue_types' => [ + // 'PhanAccessMethodPrivate', + // 'PhanAccessMethodProtected', + // 'PhanAccessNonStaticToStatic', + // 'PhanAccessPropertyPrivate', + // 'PhanAccessPropertyProtected', + // 'PhanAccessSignatureMismatch', + // 'PhanAccessSignatureMismatchInternal', + // 'PhanAccessStaticToNonStatic', + // 'PhanCompatibleExpressionPHP7', + // 'PhanCompatiblePHP7', + // 'PhanContextNotObject', + // 'PhanDeprecatedClass', + // 'PhanDeprecatedFunction', + // 'PhanDeprecatedProperty', + // 'PhanEmptyFile', + // 'PhanNonClassMethodCall', + // 'PhanNoopArray', + // 'PhanNoopClosure', + // 'PhanNoopConstant', + // 'PhanNoopProperty', + // 'PhanNoopVariable', + // 'PhanParamRedefined', + // 'PhanParamReqAfterOpt', + // 'PhanParamSignatureMismatch', + // 'PhanParamSignatureMismatchInternal', + // 'PhanParamSpecial1', + // 'PhanParamSpecial2', + // 'PhanParamSpecial3', + // 'PhanParamSpecial4', + // 'PhanParamTooFew', + // 'PhanParamTooFewInternal', + // 'PhanParamTooMany', + // 'PhanParamTooManyInternal', + // 'PhanParamTypeMismatch', + // 'PhanParentlessClass', + // 'PhanRedefineClass', + // 'PhanRedefineClassInternal', + // 'PhanRedefineFunction', + // 'PhanRedefineFunctionInternal', + // 'PhanStaticCallToNonStatic', + // 'PhanSyntaxError', + // 'PhanTraitParentReference', + // 'PhanTypeArrayOperator', + // 'PhanTypeArraySuspicious', + // 'PhanTypeComparisonFromArray', + // 'PhanTypeComparisonToArray', + // 'PhanTypeConversionFromArray', + // 'PhanTypeInstantiateAbstract', + // 'PhanTypeInstantiateInterface', + // 'PhanTypeInvalidLeftOperand', + // 'PhanTypeInvalidRightOperand', + // 'PhanTypeMismatchArgument', + // 'PhanTypeMismatchArgumentInternal', + // 'PhanTypeMismatchDefault', + // 'PhanTypeMismatchForeach', + // 'PhanTypeMismatchProperty', + // 'PhanTypeMismatchReturn', + // 'PhanTypeMissingReturn', + // 'PhanTypeNonVarPassByRef', + // 'PhanTypeParentConstructorCalled', + // 'PhanTypeVoidAssignment', + // 'PhanUnanalyzable', + // 'PhanUndeclaredClass', + // 'PhanUndeclaredClassCatch', + // 'PhanUndeclaredClassConstant', + // 'PhanUndeclaredClassInstanceof', + // 'PhanUndeclaredClassMethod', + // 'PhanUndeclaredClassReference', + // 'PhanUndeclaredConstant', + // 'PhanUndeclaredExtendedClass', + // 'PhanUndeclaredFunction', + // 'PhanUndeclaredInterface', + // 'PhanUndeclaredMethod', + // 'PhanUndeclaredProperty', + // 'PhanUndeclaredStaticMethod', + // 'PhanUndeclaredStaticProperty', + // 'PhanUndeclaredTrait', + // 'PhanUndeclaredTypeParameter', + // 'PhanUndeclaredTypeProperty', + // 'PhanUndeclaredVariable', + // 'PhanUnreferencedClass', + // 'PhanUnreferencedConstant', + // 'PhanUnreferencedMethod', + // 'PhanUnreferencedProperty', + // 'PhanVariableUseClause', + ], + + /** + * Override to hardcode existence and types of (non-builtin) globals in the global scope. + * Class names must be prefixed with '\\'. + * (E.g. ['_FOO' => '\\FooClass', 'page' => '\\PageClass', 'userId' => 'int']) + */ + 'globals_type_map' => [ + 'IP' => 'string', + ], + + // Emit issue messages with markdown formatting + 'markdown_issue_messages' => false, + + /** + * Enable or disable support for generic templated + * class types. + */ + 'generic_types_enabled' => true, + + // A list of plugin files to execute + 'plugins' => [ + ], +]; diff --git a/www/wiki/tests/phan/stubs/README b/www/wiki/tests/phan/stubs/README new file mode 100644 index 00000000..c458ab58 --- /dev/null +++ b/www/wiki/tests/phan/stubs/README @@ -0,0 +1,3 @@ +These stubs describe how code that is not available at analysis time should be +used. No implementations are necessary, just define the classes and their +methods and use phpdoc to describe what arguments are allowed. diff --git a/www/wiki/tests/phan/stubs/hhvm.php b/www/wiki/tests/phan/stubs/hhvm.php new file mode 100644 index 00000000..364ebdaa --- /dev/null +++ b/www/wiki/tests/phan/stubs/hhvm.php @@ -0,0 +1,26 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ + +// phpcs:ignoreFile + +/** + * @param callable $callback + * @param mixed ...$parameters + */ +function register_postsend_function( $callback ) { +} diff --git a/www/wiki/tests/phan/stubs/mail.php b/www/wiki/tests/phan/stubs/mail.php new file mode 100644 index 00000000..ba1efb96 --- /dev/null +++ b/www/wiki/tests/phan/stubs/mail.php @@ -0,0 +1,89 @@ +<?php + +/** + * Minimal set of classes necessary for UserMailer to be happy. Types + * taken from documentation at pear.php.net. + * phpcs:ignoreFile + */ + +class PEAR { + /** + * @param mixed $data + * @return bool + */ + public static function isError( $data ) { + } +} + +class PEAR_Error { + /** + * @return string + */ + public function getMessage() { + } +} + +class Mail { + /** + * @param string $driver + * @param array $params + * @return self + */ + static public function factory( $driver, array $params = [] ) { + } + + /** + * @param mixed $recipients + * @param array $headers + * @param string $body + * @return bool|PEAR_Error + */ + public function send( $recipients, array $headers, $body ) { + } +} + +class Mail_smtp extends Mail { +} + +class Mail_mime { + /** + * @param mixed $params + */ + public function __construct( $params = [] ) { + } + + /** + * @param string $data + * @param bool $isfile + * @param bool $append + * @return bool|PEAR_Error + */ + public function setTXTBody( $data, $isfile = false, $append = false ) { + } + + /** + * @param string $data + * @param bool $isfile + * @return bool|PEAR_Error + */ + public function setHTMLBody( $data, $isfile = false ) { + } + + /** + * @param array|null $parms + * @param mixed $filename + * @param bool $skip_head + * @return string|bool|PEAR_Error + */ + public function get( $params = null, $filename = null, $skip_head = false ) { + } + + /** + * @param array|null $xtra_headers + * @param bool $overwrite + * @param bool $skip_content + * @return array + */ + public function headers( array $xtra_headers = null, $overwrite = false, $skip_content = false ) { + } +} diff --git a/www/wiki/tests/phan/stubs/memcached.php b/www/wiki/tests/phan/stubs/memcached.php new file mode 100644 index 00000000..0f8859d2 --- /dev/null +++ b/www/wiki/tests/phan/stubs/memcached.php @@ -0,0 +1,16 @@ +<?php + +/** + * The phpstorm stubs package includes the Memcached class with two parameters and docs saying + * that they are optional. Phan can not detect this and thus throws an error for a usage with + * no params. So we have this small stub just for the constructor to allow no params. + * @see https://secure.php.net/manual/en/memcached.construct.php + * phpcs:ignoreFile + */ + +class Memcached { + + public function __construct() { + } + +} diff --git a/www/wiki/tests/phan/stubs/phpunit4.php b/www/wiki/tests/phan/stubs/phpunit4.php new file mode 100644 index 00000000..e5e88e6b --- /dev/null +++ b/www/wiki/tests/phan/stubs/phpunit4.php @@ -0,0 +1,11 @@ +<?php + +/** + * Some old classes from PHPUnit 4 that MediaWiki (conditionally) references. + * + * phpcs:ignoreFile + */ + +class PHPUnit_TextUI_Command { + +} diff --git a/www/wiki/tests/phan/stubs/tideways.php b/www/wiki/tests/phan/stubs/tideways.php new file mode 100644 index 00000000..34ac735c --- /dev/null +++ b/www/wiki/tests/phan/stubs/tideways.php @@ -0,0 +1,12 @@ +<?php + +/** + * Minimal set of classes necessary for Xhprof using tideways + * phpcs:ignoreFile + */ + +function tideways_enable(){ +} + +function tideways_disable(){ +} diff --git a/www/wiki/tests/phan/stubs/wikidiff.php b/www/wiki/tests/phan/stubs/wikidiff.php new file mode 100644 index 00000000..02bcd1fb --- /dev/null +++ b/www/wiki/tests/phan/stubs/wikidiff.php @@ -0,0 +1,39 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ + +// phpcs:ignoreFile + +/** + * @param string $text1 + * @param string $text2 + * @param int $numContextLines + * @param int $movedParagraphDetectionCutoff + * @return string + */ +function wikidiff2_do_diff( $text1, $text2, $numContextLines, $movedParagraphDetectionCutoff = 0 ) { +} + +/** + * @param string $text1 + * @param string $text2 + * @param int $numContextLines + * @param int $maxMovedLines + * @return string + */ +function wikidiff2_inline_diff( $text1, $text2, $numContextLines, $maxMovedLines = 25 ) { +} |