vrana Fri Jun 24 05:14:10 2005 EDT
Modified files:
/phpdoc/scripts check-references.php
Log:
Check return types
http://cvs.php.net/diff.php/phpdoc/scripts/check-references.php?r1=1.17&r2=1.18&ty=u
Index: phpdoc/scripts/check-references.php
diff -u phpdoc/scripts/check-references.php:1.17
phpdoc/scripts/check-references.php:1.18
--- phpdoc/scripts/check-references.php:1.17 Wed Jun 22 06:38:05 2005
+++ phpdoc/scripts/check-references.php Fri Jun 24 05:14:10 2005
@@ -76,6 +76,8 @@
$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_types = implode('|', array_keys($retval_mapping));
$operators = "!=|<=?|>=?|==";
$max_args = 12; // maximum number of regular function arguments
@@ -118,6 +120,17 @@
"soapclient::__soapcall",
);
+$difficult_retvals = array(
+ "set_error_handler", "set_exception_handler", "highlight_file",
"highlight_string", "pg_cancel_query", "pg_connection_busy", "mysqli_query",
+ // better to fix in sources:
+ "debug_print_backtrace", // array instead of void
+ "dbmopen", // int instead of resource
+ "pg_lo_open", // int instead of resource
+ "ircg_pconnect", // int instead of resource
+ "notes_search", // RETURN_LONG commented out
+ "exif_tagname", // RETURN_BOOL(FALSE) instead of RETURN_FALSE
+);
+
$difficult_params = array(
"ibase_blob_import", "ibase_execute",
"imagefilter",
@@ -132,8 +145,9 @@
"snmp_set_quick_print",
"apd_echo",
"easter_date",
- "mysql_pconnect",
+ "tidy_repair_string",
);
+
$difficult_arg_count = array(
"getdate", "min", "max", "implode", "strtok", "sybase_fetch_object",
"cpdf_text", "pdf_get_parameter", "pg_fetch_assoc", "odbc_exec",
"odbc_result_all", "yaz_wait",
@@ -147,7 +161,9 @@
// read referenced parameters from sources
$source_refs = array(); // array("function_name" => number_ref, ...)
$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) {
$files = array();
$aliases = array(); // php_function => sources_function
@@ -155,7 +171,7 @@
$files[$filename] = file_get_contents($filename);
// named functions
- preg_match_all('~PHP_NAMED_FE\\((\\w*)\\s*,\\s*(\\w*)~',
$files[$filename], $matches, PREG_SET_ORDER);
+
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];
}
@@ -178,17 +194,45 @@
preg_match_all('~^(?:ZEND|PHP)(_NAMED)?_(?:FUNCTION|METHOD)\\(([^)]+)\\)(.*)^\\}~msU',
$file, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); // }}} is not in all
sources so ^} is used instead
foreach ($matches as $val) {
$function_name =
strtolower(trim(preg_replace('~\\s*,\\s*~', '::', ($val[1][0] ?
$aliases[$val[2][0]] : $val[2][0]))));
+ $function_body = $val[3][0];
+ $lineno = substr_count(substr($file, 0, $val[3][1]),
"\n") + 1;
+
+ // return type
+ if (!in_array($function_name, $difficult_retvals)) {
+
preg_match_all("~\\b(?:RETURN|RETVAL|(?:return_value->type|Z_TYPE_P\\(return_value\\))\\s*=\\s*IS)_($retval_types)|(?:ZVAL_|convert_to_)((?i)$retval_types)(?:_ex)?\\(return_value~",
$function_body, $types, PREG_SET_ORDER);
+ if
(preg_match_all('~()(array|object)(?:_and_properties)?_init\\(return_value~',
$function_body, $matches, PREG_SET_ORDER)) {
+ $types = array_merge($types, $matches);
+ }
+ if
(preg_match('~(?:ZEND_REGISTER_RESOURCE\\(|php_stream_to_zval.*)return_value~',
$function_body)) {
+ $types[] = array("", "RESOURCE", "");
+ }
+ if ($types) {
+ $type = $retval_mapping[$types[0][1] .
strtoupper($types[0][2])];
+ for ($i=1; $i < count($types); $i++) {
+ $type1 =
$retval_mapping[$types[$i][1] . strtoupper($types[$i][2])];
+ if ($type1 != $type) {
+ if (($type1 == "int" ||
$type1 == "float") && ($type == "int" || $type == "float" || $type ==
"number")) {
+ $type =
"number";
+ } else {
+ $type = "mixed";
+ break;
+ }
+ }
+ }
+ $return_types[$function_name] =
array($type, $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"
&& 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])
) {
- $val[3] = $matches2[1];
+ $function_body = $matches2[1][0];
+ $lineno = substr_count(substr($file, 0,
$matches2[1][1]), "\n") + 1;
}
- $lineno = substr_count(substr($file, 0, $val[3][1]),
"\n") + 1;
- $function_body = $val[3][0];
-
// types and optional
if (!in_array($function_name, $difficult_params)
&& strpos($function_body, 'zend_parse_parameters_ex')
=== false // indicate difficulty
@@ -254,11 +298,10 @@
foreach ($matches2 as $val2) {
$function_name = strtolower($val2[2]);
$method_name =
strtolower("$val[1]::$val2[1]");
- if
(isset($source_types[$function_name])) {
- $source_types[$method_name] =
$source_types[$function_name];
- }
- if ($source_arg_counts[$function_name])
{
-
$source_arg_counts[$method_name] = $source_arg_counts[$function_name];
+ foreach (array("source_types",
"source_arg_counts", "return_types") as $var) {
+ if
(isset($GLOBALS[$var][$function_name])) {
+
$GLOBALS[$var][$method_name] = $GLOBALS[$var][$function_name];
+ }
}
}
}
@@ -268,7 +311,7 @@
echo "Sources were read.\n";
// compare with documentation
-$counts = array("refs" => 0, "types" => 0, "arg_counts" => 0);
+$counts = array("refs" => 0, "types" => 0, "arg_counts" => 0, "return" => 0);
foreach (glob("$phpdoc_dir/reference/*/functions/*.xml") as $filename) {
if
(preg_match('~^(.*(?:(\\w+)</classname></ooclass>\\s*)?<methodsynopsis>(.*))<methodname>([^<]+)<(.*)</methodsynopsis>~sU',
file_get_contents($filename), $matches)) {
$lineno = substr_count($matches[1], "\n") + 1;
@@ -277,7 +320,14 @@
$methodsynopsis = $matches[5];
// return type
- if (preg_match("~<type>(callback|$invalid_types)</type>~",
$return_type)) {
+ if (isset($return_types[$function_name])) {
+ $counts["return"]++;
+ if (!preg_match("~<type>(" .
$return_types[$function_name][0] . ")</type>~", $return_type) &&
($return_types[$function_name][0] != "object" ||
preg_match("~<type>($valid_types|$invalid_types)</type>~", $return_type))) {
+ 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";
}
@@ -366,4 +416,4 @@
echo "$counts[refs]/". count($source_refs) ." references checked.\n";
echo "$counts[types]/". count($source_types) ." types checked.\n";
echo "$counts[arg_counts]/". count($source_arg_counts) ." arg counts
checked.\n";
-?>
+echo "$counts[return]/". count($return_types) ." return types checked.\n";