5 * @version $Id: PhpdocClassAnalyser.php,v 1.4 2000/12/03 22:37:36 uw Exp $
\r
7 class PhpdocClassAnalyser extends PhpdocAnalyser {
\r
14 var $classes = array();
\r
17 * Name of the baseclass of the given classes.
\r
21 var $baseclass = "";
\r
24 * Ordered list of all classes.
\r
28 var $classlist = array();
\r
31 * List of not inherited elements.
\r
35 var $notinherited = array(
\r
40 "variables" => true,
\r
41 "functions" => true,
\r
45 "subclasses"=> true,
\r
47 "baseclass" => true,
\r
51 "functions" => array(
\r
54 "inherited" => true,
\r
55 "overrides" => true,
\r
59 "variables" => array(
\r
62 "inherited" => true,
\r
63 "overrides" => true,
\r
70 "inherited" => true,
\r
77 "inherited" => true,
\r
84 * Puuuh - findUndocumented() needs this.
\r
87 * @see findUndocumented()
\r
89 var $undocumentedFields = array(
\r
90 "functions" => "function",
\r
91 "variables" => "variable",
\r
92 "uses" => "included file",
\r
93 "consts" => "constant"
\r
97 * Sets the class data and the name of the baseclass.
\r
99 * @param array Raw class data from the parser
\r
100 * @param string Name of the baseclass of the given classes
\r
103 function setClasses($classes, $baseclass) {
\r
105 $this->classes = $classes;
\r
106 $this->baseclass = $baseclass;
\r
108 } // end func setClasses
\r
110 function analyse() {
\r
112 $this->flag_get = false;
\r
114 $this->updateAccessReturn();
\r
115 $this->updateBrothersSisters();
\r
118 $this->classlist = array();
\r
120 $this->buildBottomUpClasslist($this->baseclass);
\r
122 } // end func analyse
\r
125 * Returns an analysed class or false if there're no classes any more.
\r
127 * @return mixed False if there no classes anymore, otherwise an array with
\r
128 * the data of the class.
\r
131 function getClass() {
\r
133 if (!$this->flag_get) {
\r
134 reset($this->classlist);
\r
135 $this->flag_get = true;
\r
137 if (list($k, $classname)=each($this->classlist)) {
\r
139 if (isset($this->classes[$classname]["path"]))
\r
140 $this->inheritClassElements($classname);
\r
142 $this->checkFunctionArgs($classname);
\r
143 $this->findUndocumented($classname);
\r
145 $class = $this->classes[$classname];
\r
146 unset($this->classes[$classname]);
\r
154 } // end func getClass
\r
157 * Looks for undocumented elements in a certain class
\r
159 * @param string Classname
\r
161 function findUndocumented($classname) {
\r
163 $file = $this->classes["filename"];
\r
164 if ($this->classes["undoc"])
\r
165 $this->warn->addDocWarning($file, "class", $name, "The class is not documented.", "missing");
\r
167 reset($this->undocumentedFields);
\r
168 while (list($index, $eltype)=each($this->undocumentedFields)) {
\r
169 if (!isset($this->classes[$index]))
\r
172 reset($this->classes[$index]);
\r
173 while (list($elname, $data)=each($this->classes[$index]))
\r
174 if (isset($data["undoc"]) && $data["undoc"])
\r
175 $this->warn->addDocWarning($file, $eltype, $elname, "Undocumented element.", "missing");
\r
179 } // end func findUndocumented
\r
182 * Checks the function documentation of a certain class.
\r
184 * @param string Classname
\r
186 function checkFunctionArgs($classname) {
\r
188 if (!isset($this->classes[$classname]["functions"]))
\r
191 $file = $this->classes[$classname]["filename"];
\r
193 reset($this->classes[$classname]["functions"]);
\r
194 while (list($fname, $function)=each($this->classes[$classname]["functions"])) {
\r
196 $inherited = isset($function["paraminherited"]);
\r
197 $this->classes[$classname]["functions"][$fname]["params"] = $this->checkArgDocs($function["args"], $function["params"], $fname, $file, $inherited);
\r
198 unset($this->classes[$classname]["functions"][$fname]["args"]);
\r
201 unset($this->classes[$classname]["functions"][$fname]["paraminherited"]);
\r
204 } // end func checkFunctionArgs
\r
207 * Builds an internal list of all classes.
\r
209 * The analyser needs an ordered list of all classes
\r
210 * to inherit information effective.
\r
212 * @param string Name of the class that starts the recursive build process.
\r
215 function buildBottomUpClasslist($classname) {
\r
217 if (isset($this->classes[$classname]["subclasses"])) {
\r
219 reset($this->classes[$classname]["subclasses"]);
\r
220 while (list($subclass, $v)=each($this->classes[$classname]["subclasses"]))
\r
221 $this->buildBottomUpClasslist($subclass);
\r
223 $this->classlist[] = $classname;
\r
227 $this->classlist[] = $classname;
\r
230 } // end func buildBottomUpClasslist
\r
233 * Adds inherited elements to a class.
\r
235 * @param string Classname
\r
236 * @return boolean $ok
\r
237 * @see $classes, $notinherited, addInheritedElements()
\r
239 function inheritClassElements($classname) {
\r
241 if (!isset($this->classes[$classname]["path"]))
\r
244 $undoc = $this->classes[$classname]["undoc"];
\r
246 $path = $this->classes[$classname]["path"];
\r
248 while (list($k, $parentclass)=each($path)) {
\r
250 $this->addInheritedElements($classname, $parentclass, "functions");
\r
251 $this->addInheritedElements($classname, $parentclass, "variables");
\r
252 $this->addInheritedElements($classname, $parentclass, "consts");
\r
253 $this->addInheritedElements($classname, $parentclass, "uses");
\r
255 reset($this->classes[$parentclass]);
\r
256 while (list($field, $value)=each($this->classes[$parentclass]))
\r
257 if (!isset($this->notinherited["class"][$field]) && !isset($this->classes[$classname][$field]))
\r
258 $this->classes[$classname][$field] = $value;
\r
260 if ($undoc && !$this->classes[$parentclass]["undoc"]) {
\r
261 $this->classes[$classname]["docinherited"] = true;
\r
262 $this->classes[$classname]["undoc"] = false;
\r
269 } // end func inheritClassElements
\r
272 * Adds inherited functions, variables, constants or included files to a class.
\r
274 * @param string Name of the class that inherits the informations.
\r
275 * @param string Name of the parentclass
\r
276 * @param string Type of elements inherited: "functions", "variables", "uses", "consts"
\r
277 * @return boolean $ok
\r
278 * @see $classes, $notinherited, isUndocumented()
\r
280 function addInheritedElements($classname, $parentclass, $type) {
\r
282 if (!isset($this->classes[$parentclass][$type]))
\r
285 reset($this->classes[$parentclass][$type]);
\r
286 while (list($elementname, $data)=each($this->classes[$parentclass][$type])) {
\r
288 if (!isset($this->classes[$classname][$type][$elementname])) {
\r
290 $this->classes[$classname]["inherited"][$type][$parentclass][$elementname] = true;
\r
294 $this->classes[$classname][$type][$elementname]["overrides"] = $parentclass;
\r
295 $this->classes[$classname][$type][$elementname]["undoc"] = $this->isUndocumented($parentclass, $type, $elementname);
\r
296 $this->classes[$classname]["overrides"][$type][$parentclass][$elementname] = true;
\r
299 while (list($field, $value)=each($data)) {
\r
301 if (!isset($this->classes[$classname][$type][$elementname][$field]) && !isset($this->notinherited[$type][$field])) {
\r
302 $this->classes[$classname][$type][$elementname][$field] = $value;
\r
303 if ("params"==$field && "functions"==$type) $this->classes[$classname][$type][$elementname]["paraminherited"] = true;
\r
312 } // end func addInheritedElements
\r
315 * Returns true if the requested element is undocumented and false if it's documented.
\r
317 * The function checks if the element might inherit documentation
\r
318 * from any parentclass.
\r
320 * @param string Name of the class of the element
\r
321 * @param string Element type: functions, variables, uses, consts.
\r
322 * @param string Element name
\r
323 * @return boolean $ok
\r
325 function isUndocumented($classname, $type, $elementname) {
\r
327 if ( !isset($this->classes[$classname][$type][$elementname]) || $this->classes[$classname][$type][$elementname]["undoc"] || !isset($this->classes[$classname]["path"]) )
\r
330 $path = $this->classes[$classname]["path"];
\r
331 while (list($k, $parentclass)=each($path))
\r
332 if ($this->isUndocumented($parentclass, $type, $elementname))
\r
336 } // end func isUndocumented
\r
338 function updateBrothersSisters() {
\r
340 reset($this->classes);
\r
341 while (list($classname, $data)=each($this->classes)) {
\r
342 $this->updateBrotherSisterElements($classname, "functions");
\r
343 $this->updateBrotherSisterElements($classname, "variables");
\r
346 } // end func updateBrothersSisters
\r
349 * @param string Name of the class to update
\r
350 * @param string Elementtype: functions, variables, ...
\r
353 function updateBrotherSisterElements($classname, $type) {
\r
355 if (!isset($this->classes[$classname][$type]))
\r
358 reset($this->classes[$classname][$type]);
\r
359 while (list($elementname, $data) = each($this->classes[$classname][$type])) {
\r
361 if (isset($data["brother"])) {
\r
363 $name = ( "functions" == $type ) ? substr($data["brother"], 0, -2) : substr($data["brother"], 1);
\r
364 $name = strtolower($name);
\r
366 if (!isset($this->classes[$classname][$type][$name])) {
\r
368 $this->warn->addDocWarning($this->classes[$classname]["filename"], $type, $elementname, "Brother '$name' is unknown. Tags gets ignored.", "mismatch");
\r
369 unset($this->classes[$classname][$type][$elementname]["brother"]);
\r
373 $this->classes[$classname][$type][$elementname]["brother"] = $name;
\r
374 $this->classes[$classname][$type][$elementname] = $this->copyBrotherSisterFields($this->classes[$classname][$type][$elementname], $this->classes[$classname][$type][$name]);
\r
382 } // end func updateBrotherSisterElements
\r
384 function updateAccessReturn() {
\r
386 reset($this->classes);
\r
387 while (list($classname, $data)=each($this->classes)) {
\r
389 if (!isset($data["access"]))
\r
390 $this->classes[$classname]["access"] = "private";
\r
392 $this->updateAccessReturnElements($classname, "functions");
\r
393 $this->updateAccessElements($classname, "variables");
\r
394 $this->updateAccessElements($classname, "consts");
\r
398 } // end func updateAccessReturn
\r
401 * Updates access and return for certain elements.
\r
403 * This function should only be used to update functions.
\r
404 * Functions that have the same name as the class (constructors)
\r
405 * get return void and access public. Functions without
\r
406 * access get access public and functions without return get
\r
409 * @param string Classname
\r
410 * @param string Element type: functions (, variables, consts, uses)
\r
411 * @return boolean $ok
\r
412 * @see updateAccessReturn()
\r
414 function updateAccessReturnElements($classname, $type) {
\r
416 if (!isset($this->classes[$classname][$type]))
\r
419 reset($this->classes[$classname][$type]);
\r
420 while (list($elementname, $data)=each($this->classes[$classname][$type])) {
\r
422 if (!isset($data["access"]))
\r
423 $this->classes[$classname][$type][$elementname]["access"] = ("functions" == $type && strtolower($elementname) == strtolower($classname)) ? "public" : "private";
\r
425 if (!isset($data["return"]))
\r
426 $this->classes[$classname][$type][$elementname]["return"] = "void";
\r
428 if ("functions" == $type && $elementname == $classname) {
\r
429 $this->warn->addDocWarning($this->classes[$classname]["filename"], "functions", $elementname, "The constructor can't have a return value. @return gets ignored.", "mismatch");
\r
430 $this->classes[$classname]["functions"][$elementname]["return"] = "void";
\r
435 } // end func updateAccessReturnElements
\r
438 * Updates access tags.
\r
440 * @param string Classname
\r
441 * @param string Element type: functions, variables, consts (, uses)
\r
442 * @see updateAccessReturnElements()
\r
444 function updateAccessElements($classname, $type) {
\r
446 if (!isset($this->classes[$classname][$type]))
\r
449 reset($this->classes[$classname][$type]);
\r
450 while (list($elementname, $data)=each($this->classes[$classname][$type])) {
\r
452 if (!isset($data["access"]))
\r
453 $this->classes[$classname][$type][$elementname]["access"] = ("functions" == $type && $elementname == $classname) ? "public" : "private";
\r
457 } // end func updateAccessElements
\r
459 function checkSee() {
\r
461 reset($this->classes);
\r
462 while (list($classname, $class) = each($this->classes)) {
\r
464 $this->buildElementlist($classname);
\r
466 if (isset($class["functions"]))
\r
467 $this->checkSeeElements($class["functions"], $classname, "functions");
\r
469 if (isset($class["variables"]))
\r
470 $this->checkSeeElements($class["variables"], $classname, "variables");
\r
472 if (isset($class["consts"]))
\r
473 $this->checkSeeElements($class["consts"], $classname, "consts");
\r
475 if (isset($class["uses"]))
\r
476 $this->checkSeeElements($class["uses"], $classname, "uses");
\r
480 } // end func checkSee
\r
483 * Checks see references in the given element array (functions, variables...)
\r
485 * References to variables and functions within the same class get checked.
\r
486 * It the references element does not exist, the reference gets deleted and
\r
487 * a doc warning gets generated.
\r
489 * @param array List of functions, variables,...
\r
490 * @param string Name of the class that contains the given elements.
\r
491 * @param string Elementtype: functions, variables, consts, uses.
\r
493 function checkSeeElements($elements, $classname, $eltype) {
\r
496 while (list($elname, $element) = each($elements)) {
\r
498 if (isset($element["see"])) {
\r
500 if (isset($element["see"]["var"])) {
\r
502 reset($element["see"]["var"]);
\r
503 while (list($k, $variable) = each($element["see"]["var"]))
\r
504 if (!isset($this->elementlist["variables"][strtolower($variable["name"])])) {
\r
505 $this->warn->addDocWarning($this->classes[$classname]["filename"], "variables", $elname, "@see referrs to the variable '" . $variable["name"] . "' which is not defined in the class. Entry gets ignored.", "mismatch");
\r
506 unset($this->classes[$classname][$eltype][$elname]["see"]["var"][$k]);
\r
511 if (isset($element["see"]["function"])) {
\r
513 reset($element["see"]["function"]);
\r
514 while (list($k, $function) = each($element["see"]["function"]))
\r
515 if (!isset($this->elementlist["functions"][strtolower(substr($function["name"], 0, -2))])) {
\r
516 $this->warn->addDocWarning($this->classes[$classname]["filename"], "functions", $elname, "@see referrs to the function '" . $function["name"] . "' which is not defined in the class. Entry gets ignored.", "mismatch");
\r
517 unset($this->classes[$classname][$eltype][$elname]["see"]["function"][$k]);
\r
526 } // end func checkSeeElement
\r
529 * Builds an array with all elements of a class and saves it to $this->elementlist.
\r
531 * @param string Name of the class to scan.
\r
533 function buildElementlist($classname) {
\r
535 $elements = array();
\r
536 $fields = array("functions", "variables", "consts", "uses");
\r
539 while (list($k, $field) = each($fields))
\r
540 if (isset($this->classes[$classname][$field])) {
\r
542 reset($this->classes[$classname][$field]);
\r
543 while (list($element, ) = each($this->classes[$classname][$field]))
\r
544 $elements[$field][$element] = true;
\r
548 $this->elementlist = $elements;
\r
550 } // end func buildElementlist
\r
552 } // end class PhpdocClassAnalyser
\r