r72386 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r72385‎ | r72386 | r72387 >
Date:18:30, 4 September 2010
Author:platonides
Status:deferred
Tags:
Comment:
Recurse into the requires and improve detection of missing classes.
Also added require checking, but also when there are no variable arguments.
Modified paths:
  • /trunk/tools/code-utils/check-vars.php (modified) (history)

Diff [purge]

Index: trunk/tools/code-utils/check-vars.php
@@ -4,7 +4,7 @@
55 * Checks a number of syntax conventions on variables from a valid PHP file.
66 *
77 * Run as:
8 - * find phase3/ \( -name \*.php -or -name \*.inc \) -not \( -name importUseModWiki.php -o -name diffLanguage.php \) -exec php tools/code-utils/check-vars.php \{\} +
 8+ * find phase3/ \( -name \*.php -or -name \*.inc \) -not \( -name importUseModWiki.php -o -name diffLanguage.php -o -name LocalSettings.php \) -exec php tools/code-utils/check-vars.php \{\} +
99 */
1010
1111 require_once( dirname( __FILE__ ) . "/../../phase3/includes/Defines.php" ); # Faster than parsing
@@ -43,6 +43,8 @@
4444 class CheckVars {
4545 var $mDebug = false;
4646 static $mDefaultSettingsGlobals = null;
 47+ static $mRequireKnownClasses = array();
 48+ static $mRequireKnownConstants = array();
4749
4850 static $constantIgnorePrefixes = array( "PGSQL_", "OCI_", "SQLT_BLOB", "DB2_", "XMLREADER_", "SQLSRV_" ); # Ignore constants with these prefixes
4951 protected $generateDeprecatedList = false;
@@ -53,6 +55,8 @@
5456 const IN_FUNCTION = 2;
5557 const IN_GLOBAL = 3;
5658 const IN_INTERFACE = 4;
 59+ const IN_REQUIRE_WAITING = 6;
 60+ const IN_FUNCTION_REQUIRE = 8;
5761
5862 /* Token specializations */
5963 const CLASS_NAME = -4;
@@ -150,6 +154,12 @@
151155 function load( $file, $shortcircuit = true ) {
152156 $this->mProblemCount = 0;
153157 $this->mFilename = $file;
 158+
 159+ /* These are used even if it's shortcircuited */
 160+ $this->mKnownFileClasses = array();
 161+ $this->mUnknownClasses = array();
 162+ $this->mConstants = array();
 163+
154164 $source = file_get_contents( $file );
155165 if ( substr( $source, 0, 3 ) == "\xEF\xBB\xBF" ) {
156166 $this->warning( "$file has an UTF-8 BOM" );
@@ -165,8 +175,6 @@
166176 $this->mTokens = token_get_all( $source );
167177 $this->mStatus = self::WAITING_FUNCTION;
168178 $this->mFunctionQualifiers = array();
169 - $this->mKnownFileClasses = array();
170 - $this->mUnknownClasses = array();
171179
172180
173181 $this->mConstants = array( 'PARSEKIT_SIMPLE', 'UNORM_NFC', # Extensions
@@ -237,6 +245,12 @@
238246 $this->mParent = $token[1];
239247 }
240248
 249+ if ( in_array( $token[0], array( T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE ) ) ) {
 250+ $this->mStatus = self::IN_REQUIRE_WAITING;
 251+ $requirePath = "";
 252+ continue;
 253+ }
 254+
241255 if ( $token[0] != T_FUNCTION )
242256 continue;
243257 $this->mStatus = self::IN_FUNCTION_NAME;
@@ -341,6 +355,10 @@
342356
343357 $this->checkClassName( $token );
344358 $currentToken[0] = self::CLASS_NAME;
 359+ } else if ( in_array( $token[0], array( T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE ) ) ) {
 360+ $this->mStatus = self::IN_FUNCTION_REQUIRE;
 361+ $requirePath = '';
 362+ continue;
345363 }
346364 }
347365
@@ -391,11 +409,11 @@
392410 if ( is_array( $token ) ) {
393411 if ( $token[0] == T_VARIABLE ) {
394412 if ( !$this->shouldBeGlobal( $token[1] ) && !$this->canBeGlobal( $token[1] ) ) {
395 - $this->warning( "Global variable {$token[1]} in line $token[2], function {$this->mFunction} does not follow coding conventions" );
 413+ $this->warning( "Global variable {$token[1]} in line {$token[2]}, function {$this->mFunction} does not follow coding conventions" );
396414 }
397415 if ( isset( $this->mFunctionGlobals[ $token[1] ] ) ) {
398416 if ( !$this->mInSwitch ) {
399 - $this->warning( $token[1] . " marked as global again in line $token[2], function {$this->mFunction}" );
 417+ $this->warning( $token[1] . " marked as global again in line {$token[2]}, function {$this->mFunction}" );
400418 }
401419 } else {
402420 $this->checkGlobalName( $token[1] );
@@ -418,6 +436,100 @@
419437 $this->mStatus = self::WAITING_FUNCTION;
420438 }
421439 continue;
 440+
 441+ case self::IN_REQUIRE_WAITING:
 442+ case self::IN_FUNCTION_REQUIRE:
 443+ if ( $token == ';' ) {
 444+ $requirePath = trim( $requirePath, ')("' );
 445+
 446+ if ( substr( $requirePath, 0, 8 ) == "PHPUnit/" ) {
 447+ $this->mStatus = $this->mStatus - self::IN_REQUIRE_WAITING;
 448+ continue;
 449+ }
 450+ if ( $requirePath == "Testing/Selenium.php" ) {
 451+ $this->mStatus = $this->mStatus - self::IN_REQUIRE_WAITING;
 452+ continue;
 453+ }
 454+ if ( substr( $requirePath, 0, 12 ) == "Net/Gearman/" ) {
 455+ $this->mStatus = $this->mStatus - self::IN_REQUIRE_WAITING;
 456+ continue;
 457+ }
 458+
 459+ if ( ( $requirePath == '' ) || ( !file_exists( $requirePath ) && $requirePath[0] != '/' ) ) {
 460+ /* Try prepending the script folder, for maintenance scripts (but see Maintenance.php:758) */
 461+ $requirePath = dirname( $this->mFilename ) . "/" . $requirePath;
 462+ }
 463+ if ( !file_exists( $requirePath ) ) {
 464+ if ( strpos( $requirePath, '$' ) === false ) {
 465+ $this->warning( "Did not found the expected require of $requirePath" );
 466+ }
 467+ } else if ( isset( self::$mRequireKnownClasses[$requirePath] ) ) {
 468+ $this->mKnownFileClasses = array_merge( $this->mKnownFileClasses, self::$mRequireKnownClasses[$requirePath] );
 469+ $this->mConstants = array_merge( $this->mConstants, self::$mRequireKnownConstants[$requirePath] );
 470+ } else {
 471+ $newCheck = new CheckVars;
 472+ $newCheck->load( $requirePath );
 473+ $newCheck->execute();
 474+ /* Get the classes defined there */
 475+ $this->mKnownFileClasses = array_merge( $this->mKnownFileClasses, $newCheck->mKnownFileClasses );
 476+ $this->mConstants = array_merge( $this->mConstants, $newCheck->mConstants );
 477+ self::$mRequireKnownClasses[$requirePath] = $newCheck->mKnownFileClasses;
 478+ self::$mRequireKnownConstants[$requirePath] = $newCheck->mConstants;
 479+ }
 480+ $this->mStatus = $this->mStatus - self::IN_REQUIRE_WAITING;
 481+ continue;
 482+ }
 483+
 484+ if ( $token[0] == T_WHITESPACE )
 485+ continue;
 486+
 487+ if ( $token[0] == T_STRING_VARNAME ) {
 488+ $token[0] = T_VARIABLE;
 489+ $token[1] = '$' . $token[1];
 490+ }
 491+ if ( $token[0] == T_VARIABLE && $this->mStatus == self::IN_FUNCTION_REQUIRE ) {
 492+ if ( isset( $this->mFunctionGlobals[ $token[1] ] ) ) {
 493+ $this->mFunctionGlobals[ $token[1] ][0] ++;
 494+ } elseif ( $this->shouldBeGlobal( $token[1] ) ) {
 495+ $this->warning( "{$token[1]} is used as local variable in line $token[2], function {$this->mFunction}" );
 496+ }
 497+ }
 498+ if ( $token == '.' ) {
 499+ if ( $requirePath == 'dirname(__FILE__)' ) {
 500+ $requirePath = dirname( $this->mFilename );
 501+ } elseif ( $requirePath == 'dirname(dirname(__FILE__))' ) {
 502+ $requirePath = dirname( dirname( $this->mFilename ) );
 503+ }
 504+ } else if ( $token[0] == T_CURLY_OPEN || $token == '}' ) {
 505+ continue;
 506+ } else if ( !is_array( $token ) ) {
 507+ if ( ( $token != '(' ) || $requirePath != '' ) {
 508+ $requirePath .= $token[0];
 509+ }
 510+ } else if ( in_array( $token[0], array( T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE ) ) ) {
 511+ $requirePath .= trim( $token[1], '\'"' );
 512+ } else if ( $token[0] == T_VARIABLE ) {
 513+ if ( $token[1] == '$IP' || $token[1] == '$mwPath' ) {
 514+ $requirePath .= dirname( __FILE__ ) . '/../../phase3';
 515+ } elseif ( $token[1] == '$dir' ) {
 516+ // Scripts at phase3/maintenance/language/
 517+ $requirePath .= dirname( $this->mFilename );
 518+ } elseif ( $token[1] == '$wgStyleDirectory' ) {
 519+ $requirePath .= dirname( __FILE__ ) . '/../../phase3/skins';
 520+ } elseif ( in_array( $token[1], array( '$classFile', '$file', '$_fileName', '$fileName', '$filename' ) ) ) {
 521+ /* Maintenance.php lines 374 and 894 */
 522+ /* LocalisationCache.php, MessageCache.php, AutoLoader.php */
 523+ } else {
 524+ //$this->warning( "require uses unknown variable {$token[1]} in line {$token[2]}" );
 525+ $requirePath .= $token[1];
 526+ }
 527+ } elseif ( $token[0] == T_STRING && $token[1] == 'DO_MAINTENANCE' ) {
 528+ $requirePath .= dirname( __FILE__ ) . '/../../phase3/maintenance/doMaintenance.php';
 529+ } else {
 530+ $requirePath .= $token[1];
 531+ }
 532+ continue;
 533+
422534 }
423535 }
424536
@@ -527,6 +639,10 @@
528640 if ( isset( self::$mGlobalsPerFile[$name] ) && in_array( basename( $this->mFilename ) , self::$mGlobalsPerFile[$name] ) ) {
529641 return true;
530642 }
 643+ if ( $this->mFunction == 'loadWikimediaSettings' ) {
 644+ /* Skip the error about $site and $lang in Maintenance.php */
 645+ return true;
 646+ }
531647
532648 return false;
533649 }
@@ -588,7 +704,9 @@
589705
590706 if ( class_exists( $token[1], false ) ) return $token[1]; # Provided by an extension
591707 if ( substr( $token[1], 0, 8 ) == "PHPUnit_" ) return $token[1];
 708+ if ( $token[1] == "Testing_Selenium" || $token[1] == "Testing_Selenium_Exception" ) return $token[1];
592709 if ( substr( $token[1], 0, 12 ) == "Net_Gearman_" ) return $token[1]; # phase3/maintenance/gearman/gearman.inc
 710+ if ( $token[1] == "PEAR_Error" ) return $token[1]; # Services_JSON.php
593711
594712 if ( !isset( $wgAutoloadLocalClasses[$token[1]] ) && !in_array( $token[1], $this->mKnownFileClasses ) ) {
595713 if ( $warn == 'now' ) {

Status & tagging log