changed git call from https to git readonly
[atutor.git] / mods / phpdoc / PHPDoc / analyser / PhpdocClassAnalyser.php
1 <?php\r
2 /**\r
3 * Analyses a class.\r
4\r
5 * @version      $Id: PhpdocClassAnalyser.php,v 1.4 2000/12/03 22:37:36 uw Exp $\r
6 */\r
7 class PhpdocClassAnalyser extends PhpdocAnalyser {\r
8 \r
9         /**\r
10         * Class data.\r
11         *\r
12         * @var  array\r
13         */\r
14         var $classes = array();\r
15         \r
16         /**\r
17         * Name of the baseclass of the given classes.\r
18         *\r
19         * @var  string  \r
20         */\r
21         var $baseclass = "";\r
22         \r
23         /**\r
24         * Ordered list of all classes.\r
25         *\r
26         * @var  array\r
27         */ \r
28         var $classlist = array();\r
29         \r
30         /**\r
31         * List of not inherited elements.\r
32         *\r
33         * @var  array\r
34         */\r
35         var $notinherited = array(\r
36                                                                                                                         "class" => array(\r
37                                                                                                                                                                                                 "name"                  => true,\r
38                                                                                                                                                                                                 "extends"               => true,\r
39                                                                                                                                                                                                 "undoc"                 => true,\r
40                                                                                                                                                                                                 "variables"     => true,\r
41                                                                                                                                                                                                 "functions"     => true,\r
42                                                                                                                                                                                                 "consts"                => true,\r
43                                                                                                                                                                                                 "uses"                  => true,\r
44                                                                                                                                                                                                 "filename"      => true,\r
45                                                                                                                                                                                                 "subclasses"=> true,\r
46                                                                                                                                                                                                 "path"                  => true,\r
47                                                                                                                                                                                                 "baseclass"     => true,\r
48                                                                                                                                                                                                 "abstract"      => true\r
49                                                                                                                                                                                         ),\r
50                                                                                                                                                                                         \r
51                                                                                                                         "functions"     => array(\r
52                                                                                                                                                                                                                 "name"                  => true,\r
53                                                                                                                                                                                                                 "undoc"                 => true,\r
54                                                                                                                                                                                                                 "inherited"     => true,\r
55                                                                                                                                                                                                                 "overrides"     => true,\r
56                                                                                                                                                                                                                 "abstract"      => true\r
57                                                                                                                                                                                                         ),\r
58                                                                                                                                                                                                         \r
59                                                                                                                         "variables"     => array(\r
60                                                                                                                                                                                                                 "name"                  => true,\r
61                                                                                                                                                                                                                 "undoc"                 => true,\r
62                                                                                                                                                                                                                 "inherited"     => true,\r
63                                                                                                                                                                                                                 "overrides"     => true,\r
64                                                                                                                                                                                                                 "abstract"      => true\r
65                                                                                                                                                                                                         ),      \r
66                                                                                                                                                                                                         \r
67                                                                                                                         "uses"                  => array(\r
68                                                                                                                                                                                                                 "name"                  => true,\r
69                                                                                                                                                                                                                 "undoc"                 => true,\r
70                                                                                                                                                                                                                 "inherited"     => true,\r
71                                                                                                                                                                                                                 "overrides"     => true\r
72                                                                                                                                                                                                         ),                                                                                                                                                                                                                                                                                                                                                                                                                                                              \r
73                                                                                                                         \r
74                                                                                                                         "consts"        => array(\r
75                                                                                                                                                                                                                 "name"                  => true,\r
76                                                                                                                                                                                                                 "undoc"                 => true,\r
77                                                                                                                                                                                                                 "inherited"     => true,\r
78                                                                                                                                                                                                                 "overrides"     => true\r
79                                                                                                                                                                                                         )                                                                                                                                                                                                                                               \r
80                                                                                                         );\r
81                                                                                                         \r
82 \r
83         /**\r
84         * Puuuh - findUndocumented() needs this.\r
85         *\r
86         * @var  array\r
87         * @see  findUndocumented()\r
88         */                                                                                                              \r
89         var $undocumentedFields = array(\r
90                                                                                                                         "functions"     => "function",\r
91                                                                                                                         "variables"     => "variable",\r
92                                                                                                                         "uses"                  => "included file",\r
93                                                                                                                         "consts"                => "constant"\r
94                                                                                                         );\r
95 \r
96         /**\r
97         * Sets the class data and the name of the baseclass.\r
98         *\r
99         * @param        array           Raw class data from the parser\r
100         * @param        string  Name of the baseclass of the given classes\r
101         * @access public\r
102         */                                                                                                              \r
103         function setClasses($classes, $baseclass) {\r
104                 \r
105                 $this->classes = $classes;\r
106                 $this->baseclass = $baseclass;\r
107                 \r
108         } // end func setClasses\r
109                                                                                                         \r
110         function analyse() {\r
111                 \r
112                 $this->flag_get = false;\r
113 \r
114                 $this->updateAccessReturn();\r
115                 $this->updateBrothersSisters();\r
116                 $this->checkSee();\r
117                 \r
118                 $this->classlist = array();\r
119                 \r
120                 $this->buildBottomUpClasslist($this->baseclass);\r
121                 \r
122         } // end func analyse\r
123 \r
124         /**\r
125         * Returns an analysed class or false if there're no classes any more.\r
126         *\r
127         * @return       mixed   False if there no classes anymore, otherwise an array with \r
128         *                                                               the data of the class.\r
129         *       @access public\r
130         */      \r
131         function getClass() {\r
132         \r
133                 if (!$this->flag_get) {\r
134                         reset($this->classlist);\r
135                         $this->flag_get = true;\r
136                 }\r
137                 if (list($k, $classname)=each($this->classlist)) {\r
138 \r
139                         if (isset($this->classes[$classname]["path"]))\r
140                                 $this->inheritClassElements($classname);        \r
141                         \r
142                         $this->checkFunctionArgs($classname);\r
143                         $this->findUndocumented($classname);\r
144                         \r
145                         $class = $this->classes[$classname];\r
146                         unset($this->classes[$classname]);\r
147                         return $class;\r
148                         \r
149                 } else {\r
150                 \r
151                         return false;\r
152                         \r
153                 }\r
154         } // end func getClass\r
155 \r
156         /**\r
157         * Looks for undocumented elements in a certain class\r
158         * \r
159         * @param        string  Classname\r
160         */\r
161         function findUndocumented($classname) {\r
162                 \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
166                         \r
167                 reset($this->undocumentedFields);\r
168                 while (list($index, $eltype)=each($this->undocumentedFields)) {\r
169                         if (!isset($this->classes[$index]))\r
170                                 continue;\r
171                                 \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
176                                         \r
177                 }\r
178                 \r
179         } // end func findUndocumented\r
180         \r
181         /**\r
182         * Checks the function documentation of a certain class.\r
183         *\r
184         * @param        string  Classname\r
185         */\r
186         function checkFunctionArgs($classname) {\r
187 \r
188                 if (!isset($this->classes[$classname]["functions"]))\r
189                         return;\r
190                                 \r
191                 $file = $this->classes[$classname]["filename"];\r
192                         \r
193                 reset($this->classes[$classname]["functions"]);\r
194                 while (list($fname, $function)=each($this->classes[$classname]["functions"])) {\r
195 \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
199 \r
200                         if ($inherited)\r
201                                 unset($this->classes[$classname]["functions"][$fname]["paraminherited"]);\r
202                                 \r
203                 }\r
204         } // end func checkFunctionArgs\r
205         \r
206         /**\r
207         * Builds an internal list of all classes.\r
208         * \r
209         * The analyser needs an ordered list of all classes\r
210         * to inherit information effective.\r
211         * \r
212         * @param        string  Name of the class that starts the recursive build process. \r
213         * @see  $classlist\r
214         */\r
215         function buildBottomUpClasslist($classname) {\r
216                 \r
217                 if (isset($this->classes[$classname]["subclasses"])) {\r
218                         \r
219                         reset($this->classes[$classname]["subclasses"]);\r
220                         while (list($subclass, $v)=each($this->classes[$classname]["subclasses"]))\r
221                                 $this->buildBottomUpClasslist($subclass);\r
222                         \r
223                         $this->classlist[] = $classname;\r
224                         \r
225                 } else {\r
226                  \r
227                         $this->classlist[] = $classname;\r
228                 \r
229                 }\r
230         } // end func buildBottomUpClasslist\r
231 \r
232         /**\r
233         * Adds inherited elements to a class.\r
234         * \r
235         * @param        string  Classname\r
236         * @return       boolean $ok\r
237         * @see  $classes, $notinherited, addInheritedElements()\r
238         */      \r
239         function inheritClassElements($classname) {\r
240                 \r
241                 if (!isset($this->classes[$classname]["path"]))\r
242                         return false;\r
243 \r
244                 $undoc = $this->classes[$classname]["undoc"];\r
245                                 \r
246                 $path = $this->classes[$classname]["path"];\r
247                 reset($path);\r
248                 while (list($k, $parentclass)=each($path)) {\r
249 \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
254                         \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
259                         \r
260                         if ($undoc && !$this->classes[$parentclass]["undoc"]) {\r
261                                 $this->classes[$classname]["docinherited"] = true;\r
262                                 $this->classes[$classname]["undoc"] = false;\r
263                                 $undoc = false;\r
264                         }\r
265                         \r
266                 }       \r
267                 \r
268                 return true;\r
269         } // end func inheritClassElements\r
270         \r
271         /**\r
272         * Adds inherited functions, variables, constants or included files to a class.\r
273         *  \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
279         */\r
280         function addInheritedElements($classname, $parentclass, $type) {\r
281         \r
282                 if (!isset($this->classes[$parentclass][$type]))\r
283                         return false;\r
284                         \r
285                 reset($this->classes[$parentclass][$type]);\r
286                 while (list($elementname, $data)=each($this->classes[$parentclass][$type])) {\r
287                         \r
288                         if (!isset($this->classes[$classname][$type][$elementname])) {\r
289 \r
290                                 $this->classes[$classname]["inherited"][$type][$parentclass][$elementname] = true;                      \r
291 \r
292                         } else {\r
293                 \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
297                                 \r
298                                 reset($data);\r
299                                 while (list($field, $value)=each($data)) {\r
300                                 \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
304                                         }\r
305                                                 \r
306                                 }\r
307                         }\r
308                         \r
309                 }\r
310                 \r
311                 return true;\r
312         } // end func addInheritedElements\r
313 \r
314         /**\r
315         * Returns true if the requested element is undocumented and false if it's documented.\r
316         *\r
317         * The function checks if the element might inherit documentation\r
318         * from any parentclass. \r
319         *\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
324         */      \r
325         function isUndocumented($classname, $type, $elementname) {\r
326 \r
327                 if ( !isset($this->classes[$classname][$type][$elementname]) || $this->classes[$classname][$type][$elementname]["undoc"] ||     !isset($this->classes[$classname]["path"]) ) \r
328                         return true;\r
329                 \r
330                 $path = $this->classes[$classname]["path"];\r
331                 while (list($k, $parentclass)=each($path))\r
332                         if ($this->isUndocumented($parentclass, $type, $elementname))\r
333                                 return true;\r
334                 \r
335                 return false;\r
336         } // end func isUndocumented\r
337         \r
338         function updateBrothersSisters() {\r
339                 \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
344                 }       \r
345                 \r
346         } // end func updateBrothersSisters\r
347         \r
348         /**\r
349         * @param        string  Name of the class to update\r
350         * @param        string  Elementtype: functions, variables, ...\r
351         * @return       boolean\r
352         */\r
353         function updateBrotherSisterElements($classname, $type) {\r
354                 \r
355                 if (!isset($this->classes[$classname][$type])) \r
356                         return false;\r
357                         \r
358                 reset($this->classes[$classname][$type]);\r
359                 while (list($elementname, $data) = each($this->classes[$classname][$type])) {\r
360                         \r
361                         if (isset($data["brother"])) {\r
362 \r
363                                 $name = ( "functions" == $type ) ? substr($data["brother"], 0, -2) : substr($data["brother"], 1);\r
364                                 $name = strtolower($name);\r
365 \r
366                                 if (!isset($this->classes[$classname][$type][$name])) {\r
367                                 \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
370                                         \r
371                                 } else {\r
372                                 \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
375 \r
376                                 }\r
377 \r
378                         }\r
379                         \r
380                 }\r
381                 \r
382         } // end func updateBrotherSisterElements\r
383         \r
384         function updateAccessReturn() {\r
385                 \r
386                 reset($this->classes);\r
387                 while (list($classname, $data)=each($this->classes)) {\r
388                         \r
389                         if (!isset($data["access"]))\r
390                                 $this->classes[$classname]["access"] = "private";\r
391                                 \r
392                         $this->updateAccessReturnElements($classname, "functions");\r
393                         $this->updateAccessElements($classname, "variables");\r
394                         $this->updateAccessElements($classname, "consts");\r
395                         \r
396                 }\r
397                                 \r
398         } // end func updateAccessReturn\r
399         \r
400         /**\r
401         * Updates access and return for certain elements.\r
402         * \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
407         * return void.\r
408         * \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
413         */\r
414         function updateAccessReturnElements($classname, $type) {\r
415                 \r
416                 if (!isset($this->classes[$classname][$type]))\r
417                         return false;\r
418 \r
419                 reset($this->classes[$classname][$type]);\r
420                 while (list($elementname, $data)=each($this->classes[$classname][$type])) {\r
421                 \r
422                         if (!isset($data["access"])) \r
423                                 $this->classes[$classname][$type][$elementname]["access"] = ("functions" == $type && strtolower($elementname) == strtolower($classname)) ? "public" : "private";\r
424                                 \r
425                         if (!isset($data["return"]))\r
426                                 $this->classes[$classname][$type][$elementname]["return"] = "void";\r
427                         else \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
431                                 }\r
432                                 \r
433                 }\r
434                                 \r
435         } // end func updateAccessReturnElements\r
436         \r
437         /**\r
438         * Updates access tags.\r
439         *\r
440         * @param        string  Classname\r
441         * @param        string  Element type: functions, variables, consts (, uses)\r
442         * @see  updateAccessReturnElements()\r
443         */\r
444         function updateAccessElements($classname, $type) {\r
445                 \r
446                 if (!isset($this->classes[$classname][$type]))\r
447                         return false;\r
448                         \r
449                 reset($this->classes[$classname][$type]);\r
450                 while (list($elementname, $data)=each($this->classes[$classname][$type])) {\r
451                         \r
452                         if (!isset($data["access"])) \r
453                                 $this->classes[$classname][$type][$elementname]["access"] = ("functions" == $type && $elementname == $classname) ? "public" : "private";\r
454                 \r
455                 }\r
456                 \r
457         } // end func updateAccessElements\r
458         \r
459         function checkSee() {\r
460                 \r
461                 reset($this->classes);\r
462                 while (list($classname, $class) = each($this->classes)) {\r
463                 \r
464                         $this->buildElementlist($classname);\r
465                         \r
466                         if (isset($class["functions"])) \r
467                                 $this->checkSeeElements($class["functions"], $classname, "functions");\r
468                                 \r
469                         if (isset($class["variables"]))\r
470                                 $this->checkSeeElements($class["variables"], $classname, "variables");\r
471                         \r
472                         if (isset($class["consts"])) \r
473                                 $this->checkSeeElements($class["consts"], $classname, "consts");\r
474                                 \r
475                         if (isset($class["uses"]))\r
476                                 $this->checkSeeElements($class["uses"], $classname, "uses");\r
477                         \r
478                 }\r
479                 \r
480         } // end func checkSee\r
481 \r
482         /**\r
483         * Checks see references in the given element array (functions, variables...)\r
484         *\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
488         * \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
492         */      \r
493         function checkSeeElements($elements, $classname, $eltype) {\r
494                 \r
495                 reset($elements);\r
496                 while (list($elname, $element) = each($elements)) {\r
497                 \r
498                         if (isset($element["see"])) {\r
499                                 \r
500                                 if (isset($element["see"]["var"])) {\r
501                                         \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
507                                                 }\r
508 \r
509                                 }\r
510                                 \r
511                                 if (isset($element["see"]["function"])) {\r
512                                         \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
518                                                 }\r
519 \r
520                                 }\r
521                                 \r
522                         }\r
523                         \r
524                 }       \r
525                 \r
526         } // end func checkSeeElement\r
527         \r
528         /**\r
529         * Builds an array with all elements of a class and saves it to $this->elementlist.\r
530         * \r
531         * @param        string  Name of the class to scan.\r
532         */\r
533         function buildElementlist($classname) {\r
534                 \r
535                 $elements = array();\r
536                 $fields = array("functions", "variables", "consts", "uses");\r
537                 \r
538                 reset($fields);\r
539                 while (list($k, $field) = each($fields)) \r
540                         if (isset($this->classes[$classname][$field])) {\r
541                                 \r
542                                 reset($this->classes[$classname][$field]);\r
543                                 while (list($element, ) = each($this->classes[$classname][$field])) \r
544                                         $elements[$field][$element] = true;\r
545                                         \r
546                         }\r
547                 \r
548                 $this->elementlist = $elements;\r
549                 \r
550         } // end func buildElementlist\r
551 \r
552 } // end class PhpdocClassAnalyser\r
553 ?>