vrana Fri Jun 24 09:50:21 2005 EDT
Modified files: /phpdoc/scripts check-references.php Log: Expand macros, return type void, skip undocumented PECL extensions http://cvs.php.net/diff.php/phpdoc/scripts/check-references.php?r1=1.18&r2=1.19&ty=u Index: phpdoc/scripts/check-references.php diff -u phpdoc/scripts/check-references.php:1.18 phpdoc/scripts/check-references.php:1.19 --- phpdoc/scripts/check-references.php:1.18 Fri Jun 24 05:14:10 2005 +++ phpdoc/scripts/check-references.php Fri Jun 24 09:50:20 2005 @@ -28,9 +28,10 @@ } if (!isset($_SERVER["argv"][1]) || !is_dir($phpdoc_dir)) { - echo "Purpose: Check parameters (types, optional, reference, count) from PHP sources.\n"; + echo "Purpose: Check parameters (types, optional, reference, count) and return types.\n"; echo "Usage: check-references.php language\n"; echo "Notes:\n"; + echo "- Compares documentation with PHP sources (Zend, extensions, PECL, SAPI).\n"; echo "- Functions not found in sources are checked as without references.\n"; echo "- Types and optional params are checked only in some functions.\n"; exit(); @@ -76,7 +77,7 @@ $valid_types = "int|float|string|bool|resource|array|object|mixed|number"; $invalid_types = "integer|long|double|boolean|class"; // objects are written as appropriate class name so there is no complete list of valid types -$retval_mapping = array("TRUE" => "bool", "BOOL" => "bool", "LONG" => "int", "DOUBLE" => "float", "STRING" => "string", "STRINGL" => "string", "ARRAY" => "array", "OBJECT" => "object", "RESOURCE" => "resource"); // FALSE and NULL omitted because they are used for errors +$retval_mapping = array("TRUE" => "bool", "BOOL" => "bool", "LONG" => "int", "DOUBLE" => "float", "STRING" => "string", "STRINGL" => "string", "ARRAY" => "array", "OBJECT" => "object", "RESOURCE" => "resource", "ZVAL" => "mixed"); // FALSE and NULL omitted because they are used for errors $retval_types = implode('|', array_keys($retval_mapping)); $operators = "!=|<=?|>=?|=="; $max_args = 12; // maximum number of regular function arguments @@ -111,6 +112,17 @@ return $return; } +// expand macros defined in $GLOBALS['macros'] (callback for preg_replace_callback) +function expand_macros($matches) +{ + $macro = $GLOBALS['macros'][$matches[1]]; + if ($matches[2]) { + $params = explode(",", trim($matches[2], '()'), count($macro[1])); + return str_replace($macro[1], $params, $macro[0]); + } + return $macro[0]; +} + // some parameters should be passed only by reference but they are not forced to $wrong_refs = array( "dbplus_curr", "dbplus_first", "dbplus_info", "dbplus_last", "dbplus_next", "dbplus_prev", "dbplus_tremove", @@ -122,6 +134,7 @@ $difficult_retvals = array( "set_error_handler", "set_exception_handler", "highlight_file", "highlight_string", "pg_cancel_query", "pg_connection_busy", "mysqli_query", + "mb_send_mail", // better to fix in sources: "debug_print_backtrace", // array instead of void "dbmopen", // int instead of resource @@ -163,21 +176,40 @@ $source_types = array(); // array("function_name" => array("type_spec", filename, lineno), ...) $return_types = array(); // array("function_name" => array("doc_type", filename, lineno), ...) $source_arg_counts = array(); // array("function_name" => array(disallowed_count => true, ...), ...) -//~ foreach (array("$phpsrc_dir/ext/dbx") as $dirname) { -foreach (array_merge(array($zend_dir), glob("$phpsrc_dir/ext/*"), glob("$phpsrc_dir/sapi/*"), glob("$pecl_dir/*")) as $dirname) { +//~ foreach (array("$pecl_dir/standard") as $dirname) { +foreach (array_merge(array($zend_dir), glob("$phpsrc_dir/ext/*", GLOB_ONLYDIR), glob("$pecl_dir/*", GLOB_ONLYDIR), glob("$phpsrc_dir/sapi/*", GLOB_ONLYDIR)) as $dirname) { + if (dirname($dirname) == $pecl_dir && !file_exists("$phpdoc_dir/reference/" . strtolower(basename($dirname)))) { + continue; // skip undocumented PECL extensions + } $files = array(); $aliases = array(); // php_function => sources_function - foreach ((array) glob("$dirname/*.c*") as $filename) { - $files[$filename] = file_get_contents($filename); + $macros = array(); // MACRO => array(body, array(params)) + $largedir = ($dirname == $zend_dir || $dirname == "$phpsrc_dir/ext/standard"); + foreach (array_merge((array) glob("$dirname/*.c*"), (array) glob("$dirname/*.h")) as $filename) { + $file = file_get_contents($filename); + // macros + if (!$largedir) { + preg_match_all("~^#define[ \t]+(\\w+)(\\([^)]+\\))?([ \t]+.+[^\\\\])\$~msU", $file, $matches, PREG_SET_ORDER); + foreach ($matches as $val) { + $params = preg_split('~,\\s*~', trim($val[2], '()')); + $macros[$val[1]] = array(trim(str_replace(array("\r", "\\\n"), "", $val[3])), $params); + } + } - // named functions - preg_match_all('~(?:PHP|ZEND)_NAMED_FE\\((\\w*)\\s*,\\s*(\\w*)~', $files[$filename], $matches, PREG_SET_ORDER); - foreach ($matches as $val) { - $aliases[$val[2]] = $val[1]; + if (substr($filename, -2) != ".h") { + $files[$filename] = $file; + + // named functions + preg_match_all('~(?:PHP|ZEND)_NAMED_FE\\((\\w*)\\s*,\\s*(\\w*)~', $file, $matches, PREG_SET_ORDER); + foreach ($matches as $val) { + $aliases[$val[2]] = $val[1]; + } } } foreach ($files as $filename => $file) { + $file = preg_replace_callback('~\\b(' . implode('|', array_keys($macros)) . ')\\b(\\(.*\\))?~', 'expand_macros', $file); + // references preg_match_all("~^[ \t]*(?:ZEND|PHP)_FE\\((\\w+)\\s*,\\s*(\\w+)\\s*[,)]~m", $file, $matches, PREG_SET_ORDER); preg_match_all("~^[ \t]*(?:ZEND|PHP)_FALIAS\\((\\w+)\\s*,[^,]+,\\s*(\\w+)\\s*[,)]~m", $file, $matches2, PREG_SET_ORDER); @@ -220,12 +252,14 @@ } } $return_types[$function_name] = array($type, $filename, $lineno); + } elseif (!$largedir && !preg_match('~INTERNAL_FUNCTION_PARAM_PASSTHRU|return_value~', $function_body)) { + $return_types[$function_name] = array("void", $filename, $lineno); } } // other function call - if (preg_match('~(\\w+)\\(INTERNAL_FUNCTION_PARAM_PASSTHRU~', $val[3][0], $matches2) - && !preg_match('~ZEND_NUM_ARGS\\(\\)~', $val[3][0]) && $matches2[1] != "php_exec_ex" + if (preg_match('~(\\w+)\\(INTERNAL_FUNCTION_PARAM_PASSTHRU~', $function_body, $matches2) + && !preg_match('~ZEND_NUM_ARGS\\(\\)~', $function_body) && $matches2[1] != "php_exec_ex" && preg_match('~' . preg_quote($matches2[1], '~') . '\\(INTERNAL_FUNCTION_PARAMETERS(.*)^\\}~msU', $file, $matches2, PREG_OFFSET_CAPTURE) && !preg_match('~^.*\\b(?:expected_args|behavior|st)\\b~', $matches2[1][0]) ) { @@ -326,7 +360,6 @@ echo "Wrong return type in $filename on line $lineno.\n"; echo ": (" . $return_types[$function_name][0] . ") in " . $return_types[$function_name][1] . " on line " . $return_types[$function_name][2] . ".\n"; } - unset($return_types[$function_name]); } elseif (preg_match("~<type>(callback|$invalid_types)</type>~", $return_type)) { echo "Wrong return type in $filename on line $lineno.\n"; }