function processFileTokens($file) { global $processed; if (array_key_exists($file, $processed)) { return false; } $processed[$file] = true; if (substr($file, strrpos($file, '.') + 1) != 'php') { return false; } // system("php -l $file > /dev/null", $lint); // if ($lint != 0) { // //try again: // system("php -l $file", $lint); // if ($lint != 0) { // I2CE::raiseError("Skipping $file as it does not lint ($lint)"); // return false; // } // } $tokens = token_get_all(file_get_contents($file)); if (!is_array($tokens)) { I2CE::raiseError("No tokens for {$file}"); } $classes = array(); $class = false; //we start in the global scope reset($tokens); while (($pair = each($tokens)) !== false) { list($index, $token) = $pair; if ($class) { $check = array(T_DOC_COMMENT, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_ABSTRACT); } else { $check = array(T_DOC_COMMENT, T_CLASS, T_ABSTRACT); } if (is_array($token) && in_array($token[0], $check)) { if ($token[0] == T_DOC_COMMENT) { $comment = cleanupComment($token[1]); $declr = false; $following = ''; $in_class = false; $abstract = false; } else { if ($token[0] == T_ABSTRACT) { $comment = ''; $abstract = true; $following .= $token[1]; $declr = false; $in_class = false; } else { if ($token[0] == T_CLASS) { $comment = ''; $in_class = true; $declr = false; $following = $token[1]; $abstract = false; } else { $comment = ''; $declr = strtolower(substr(token_name($token[0]), 2)); $following = $token[1]; $in_class = false; $abstract = false; } } } $line = false; $desc = ''; $in_func = false; $in_var = false; $got_name = false; $var_list = array(); $static = false; $in_default = false; $in_var_list = false; $extends = false; $implements = array(); $in_implements = false; $open_paren = false; $in_extends = false; $in_const = false; $by_ref = false; $returns_by_ref = false; $final = false; while (($pair = each($tokens)) !== false) { list($index, $token2) = $pair; if ($token2 === '{') { if (!$in_class) { I2CE::raiseError("BadnessA {$file}\n[{$following}]\n[{$comment}]\n{$in_default}/{$default}", E_USER_WARNING); return false; } break; } if ($token2 === '}') { //maybe ending the class have an unused comment; break; } if ($token2 === ')') { if (!$in_func) { if (!$in_class && !$declr) { I2CE::raiseError("BadnessB {$file}/{$following}", E_USER_WARNING); return false; } } $following .= ')'; if (!$in_default) { break; } else { //we are in a default value of an arg if ($open_paren) { $open_paren = false; $var_list[$var_list_which]['default'] .= ')'; $following .= ")"; continue; } else { break; } } } if ($token2 === '(') { if ($in_func) { if ($in_var_list) { if (!$in_default) { I2CE::raiseError("BadnessC0 {$file}", E_USER_WARNING); return false; } $open_paren = true; } else { $following .= '('; $in_var_list = true; continue; } } else { if ($declr) { if (!$in_default) { I2CE::raiseError("BadnessC1 {$file}", E_USER_WARNING); return false; } else { $default .= '('; $following .= '('; continue; } } else { //can happen if there is aphpdoc embeeded in a function in a class. just ignore it for now as it will get warned later //I2CE::raiseError("BadnessC2 $file\n$following",E_USER_WARNING); break 2; } } } if ($token2 === ',') { if (!$in_implements) { if (!$in_class && !$in_func && $declr && $in_default) { $default .= ')'; $following .= ')'; continue; } else { $in_default = false; if (!$in_var_list) { I2CE::raiseError("BadnessD {$file}/{$following}", E_USER_WARNING); return false; } } } $following .= ','; continue; } if ($token2 === ';') { if ($in_const) { break; } else { if ($declr && (!$in_class && !$in_func)) { break; } else { if (!$declr || $in_class || $in_func) { I2CE::raiseError("BadnessE {$file}/{$following}", E_USER_WARNING); return false; } } } $following .= ';'; break; } if ($token2 === '=') { $in_default = true; if ($in_class) { I2CE::raiseError("BadnessF {$file}", E_USER_WARNING); return false; } if ($in_var_list) { //in function arguement list $var_list[$var_list_which]['default'] = ''; } else { if ($declr) { //variable decl. $default = ''; } else { if ($in_const) { $default = ''; } else { I2CE::raiseError("BadnessG {$file}", E_USER_WARNING); return false; } } } } if ($token2 == '&') { if ($in_func) { if ($in_var_list) { $by_ref = true; $following .= '&'; continue; } else { $returns_by_ref = true; $following .= '&'; continue; } } else { I2CE::raiseError("unexpected token {$file}:\n" . print_r($token2, true) . "\n{$following}", E_USER_WARNING); } } if (is_string($token2)) { if ($in_default) { if ($in_var_list) { $var_list[$var_list_which]['default'] .= $token2; } else { $default .= $token2; } } } if (!is_array($token2)) { if (!$in_default) { I2CE::raiseError("unexpected token {$file}:\n" . print_r($token2, true) . "\n{$following}", E_USER_WARNING); return false; } continue; } if ($in_default) { if ($in_var_list) { $var_list[$var_list_which]['default'] .= $token2[1]; } else { $default .= $token2[1]; } } switch ($token2[0]) { case T_CONST: $in_const = true; $following .= $token2[1]; break; case T_DOC_COMMENT: if ($t_com = cleanupComment($token2[1])) { $comment .= "\n" . $t_com; } break; case T_CLASS: if ($in_func) { I2CE::raiseError("baddness0 on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } else { if ($in_class) { I2CE::raiseError("baddness1 on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } } $in_class = true; $following .= $token2[1]; break; case T_FUNCTION: if ($in_func) { I2CE::raiseError("baddness0 on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } else { if ($in_class) { I2CE::raiseError("baddness1 on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } } $in_func = true; $following .= $token2[1]; break; case T_IMPLEMENTS: $in_extends = false; $in_implements = true; if ($in_class) { $following .= $token2[1]; break; } else { //shouldn't happen I2CE::raiseError("baddness on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } case T_EXTENDS: $in_extends = true; if ($in_class) { $following .= $token2[1]; break; } else { //shouldn't happen I2CE::raiseError("baddness on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } case T_VARIABLE: if ($in_class) { I2CE::raiseError("baddness0 on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } else { if ($in_func) { $var_list_which = $token2[1]; $var_list[$var_list_which] = array('default' => '', 'by_reference' => $by_ref); $by_ref = false; } else { if ($declr) { $got_name = $token2[1]; $line = $token2[2]; } else { //can happen if there is aphpdoc embeeded in a function in a class. just ignore it for now as it will get warned later //I2CE::raiseError("baddness1 on " . token_name($token2[0]) . " token $file" . "\nline:" .$token2[2] . "\ntoken:" . $token2[1]); break 2; } } } $following .= $token2[1]; break; case T_STRING: if ($in_implements) { $implements[] = $token2[1]; } else { if ($in_extends) { $extends = $token2[1]; } else { if (!$got_name) { $got_name = $token2[1]; $line = $token2[2]; } else { if ($in_var_list) { //assuming it is a variable type hint $hint = $token2[1]; } else { if (!$in_default) { print_r($token2); var_dump($in_var_list); I2CE::raiseError("baddness on " . token_name($token2[0]) . " token {$file}" . "\nline:" . $token2[2] . "\ntoken:" . $token2[1], E_USER_WARNING); return false; } } } } } $following .= $token2[1]; break; case T_PRIVATE: case T_PROTECTED: case T_PUBLIC: $declr = strtolower(substr(token_name($token2[0]), 2)); $following .= $token2[1]; break; case T_ABSTRACT: $abstract = true; $following .= $token2[1]; break; case T_STATIC: $static = true; $following .= $token2[1]; break; case T_FINAL: $final = true; $following .= $token2[1]; break; case T_ENCAPSED_AND_WHITESPACE: case T_STRING: case T_WHITESPACE: case T_COMMENT: $following .= $token2[1]; break; default: if (!$in_default) { break 2; } } continue; } //we have finished readding all that we need. if ($in_class) { $class = $got_name; if (array_key_exists($class, $classes)) { I2CE::raiseError("baddness repeated class {$class} in {$file}"); return false; } $classes[$class]['abstract'] = $abstract; $classes[$class]['comment'] = $comment; $classes[$class]['following'] = $following; $classes[$class]['extends'] = $extends; $classes[$class]['implements'] = $implements; $classes[$class]['functions'] = array(); $classes[$class]['vars'] = array(); $classes[$class]['constants'] = array(); $classes[$class]['line'] = $line; } else { if ($in_const) { $const = $got_name; $classes[$class]['constants'][$got_name] = array('default' => $default, 'comment' => $comment, 'line' => $line, 'following' => $following); } else { if ($in_func) { if (!$class) { continue; } $function = $got_name; if (array_key_exists($function, $classes[$class]['functions'])) { I2CE::raiseError("baddness repeated function {$function} in {$file}", E_USER_WARNING); return false; } $classes[$class]['functions'][$function] = array('declaration' => $declr, 'comment' => $comment, 'abstract' => $abstract, 'final' => $final, 'static' => $static, 'returns_by_ref' => $returns_by_ref, 'following' => $following, 'line' => $line, 'var_list' => $var_list); } else { if ($declr) { //we are in a variable decl if (!$class) { continue; } $var = $got_name; if (!is_string($var)) { I2CE::raiseError("baddness variable naeme ({$var}) in {$file}/{$following}/{$comment}", E_USER_WARNING); } if (array_key_exists($var, $classes[$class]['vars'])) { I2CE::raiseError("baddness repeated var {$var} in {$file}"); return false; } $default = false; if (preg_match('/=(.*);/', $following, $matches)) { $default = $matches[0]; } $classes[$class]['vars'][$var] = array('declaration' => $declr, 'comment' => $comment, 'static' => $static, 'following' => $following, 'default' => $default, 'line' => $line); } else { if ($comment = trim($comment)) { I2CE::raiseError("Unused comment in {$file}:\n{$comment}\n"); } } } } } } } return $classes; }
function prepareComment($comment, array $more, $indent = '') { $comment = cleanupComment($comment); if (empty($comment) && empty($more)) { return ''; } $comment = wordwrap($comment, 70, "\n", false); if (!empty($more)) { if (!empty($comment)) { $comment .= "\n\n"; } foreach ($more as $s) { $comment .= str_replace("\n", "\n ", wordwrap(cleanupComment($s), 68, "\n", false)) . "\n"; } } $comment = rtrim($comment); // add indentation and asterisk $comment = preg_replace("#^#m", $indent . " * ", $comment); return $indent . "/**\n" . $comment . "\n" . $indent . " **/\n"; }