PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/php/scheck/variables_fp.php

https://github.com/facebook/pfff
PHP | 236 lines | 137 code | 40 blank | 59 comment | 8 complexity | f36924b03be7bfbea9bedf11f98e9c9c MD5 | raw file
  1. <?php
  2. //*************************************************************************
  3. // Misc false positives
  4. //*************************************************************************
  5. // My analysis used to have a few false positives because my code was buggy.
  6. function test_unused_var_ok_when_keyword_arguments() {
  7. // no error for now even if $key appeared as unused. PHP has no
  8. // keyword arguments so people use such assignation as a kind of
  9. // comment
  10. misc1($key = 1);
  11. }
  12. // keyword arguments should be considered even when deeply nested ... hmmm
  13. function test_unused_var_ok_when_keyword_arguments_bis() {
  14. misc1(misc1($key = 1));
  15. }
  16. function test_undefined_ok_if_isset() {
  17. if (isset($a)) {
  18. return 1;
  19. }
  20. return 2;
  21. }
  22. function test_isset_implicit_declaration() {
  23. if(isset($a)) {
  24. // TODO: should allow that, we should analyze guards
  25. //return $a;
  26. }
  27. if(!isset($isset_var)) {
  28. $isset_var = 1;
  29. echo $isset_var;
  30. }
  31. }
  32. function test_isset_considered_as_a_use() {
  33. //ERROR: unused local variable
  34. $a = "foo";
  35. //todo? consider this as a use? https://github.com/facebook/pfff/issues/42
  36. echo isset($a);
  37. }
  38. function test_undefined_ok_if_empty() {
  39. if (empty($undefined_variable_but_arg_to_empty_so_ok)) {
  40. return 1;
  41. }
  42. }
  43. class TestClassVariable {
  44. public static $dbGetters;
  45. }
  46. function test_class_variables() {
  47. $db_scb_key = 1;
  48. if (!isset(TestClassVariable::$dbGetters[$db_scb_key])) {
  49. return 2;
  50. }
  51. // checks for use of undefined variable are restricted to local vars
  52. // not class variables of object members. See check_classes_php.ml for that.
  53. echo TestClassVariable::$dbGetters;
  54. $dyn = 'TestClassVariable';
  55. echo $dyn::$dbGetters;
  56. TestClassVariable::$dbGetters = array();
  57. }
  58. //TODO: test_unused_var_ok_when_assign_ref() { }
  59. function test_unused_var_ok_in_catch() {
  60. try {
  61. // this is ok if the variable name has a known name like $unused, $exn, etc
  62. } catch (Exception $exn) {
  63. }
  64. }
  65. // this used to raise false positives when I was using the old visitor-based
  66. // variable checker. Switching to Ast_php_simple and an env-based recursive
  67. // approach solved the problem for free.
  68. function test_declared_in_middle_of_expr() {
  69. // it's ok to use the variable in the right of &&.
  70. if (($v = misc1('')) && misc1($v)) {
  71. // it's also ok to use it here
  72. echo $v;
  73. }
  74. //ERROR: use == or add another set of parens around the assignment
  75. if ($v = misc1('')) {
  76. echo $v;
  77. }
  78. }
  79. // this used to raise a 'use of undefined variable $a' error
  80. // because the list() construct was pattern matched only when at
  81. // the toplevel of an expression. The env-based approach instead
  82. // of visitor-based approach to check_variables_php.ml solved this for free
  83. function test_list_in_middle_of_expr() {
  84. list($a, $b) = misc1(1) or misc1(2);
  85. echo $a;
  86. }
  87. function test_list_and_at() {
  88. @(list($ok1, $ok2) = misc1(1));
  89. echo $ok1;
  90. }
  91. function test_ok_undeclared_sscanf() {
  92. sscanf(PHP_VERSION, '%d', $_PHP_MAJOR_VERSION);
  93. echo $_PHP_MAJOR_VERSION;
  94. }
  95. function take_variable_number_of_args() {
  96. misc1(func_get_args());
  97. }
  98. // this used to raise a "unused variable" because we were not
  99. // visiting all the arguments when the definition of the corresponding
  100. // function didn't have any parameter
  101. function test_unused_and_varargs_function() {
  102. $avar = 1;
  103. take_variable_number_of_args($avar);
  104. }
  105. //*************************************************************************
  106. // Undefined variables and reference parameters
  107. //*************************************************************************
  108. // Sometimes a variable appears as undeclared but it's because it's
  109. // passed by reference. That means the UseOfUndeclaredVar can't be a
  110. // simple local analysis; it needs to know about the prototype of all the
  111. // functions/methods used :( So to be precise we need to pass an
  112. // entity_finder in scheck variable annotater and checker.
  113. function foo_ref($x, &$y) {
  114. $y = $x;
  115. echo $y;
  116. }
  117. function test_ok_undeclared_when_ref_parameter() {
  118. $x = 1;
  119. // this is ok to use $y ... I would rather have people declare $y but
  120. // it's a lost battle so let's accept that and focus on real bugs
  121. foo_ref($x, $passed_by_ref_to_funcall);
  122. echo $passed_by_ref_to_funcall;
  123. }
  124. class RefInStaticMethod {
  125. public static function static_method($x, &$y) {
  126. $y = $x;
  127. }
  128. }
  129. function test_ok_undeclared_when_ref_parameter_static_method() {
  130. $x = 1;
  131. RefInStaticMethod::static_method($x, $passed_by_ref_to_static_method_call);
  132. echo $passed_by_ref_to_static_method_call;
  133. }
  134. class RefInMethod {
  135. public function method($x, &$y) {
  136. $y = $x;
  137. }
  138. public function test_ok_undeclared_when_ref_parameter_method() {
  139. $x = 1;
  140. $this->method($x, $passed_by_ref_to_this_method_call);
  141. echo $passed_by_ref_to_this_method_call;
  142. }
  143. }
  144. class TestRefInConstructor {
  145. public function __construct($x, &$y) {
  146. }
  147. }
  148. function test_ok_undeclared_when_ref_parameter_new() {
  149. $o = new TestRefInConstructor(1, $passed_by_ref_to_new);
  150. echo $passed_by_ref_to_new;
  151. echo $o;
  152. }
  153. function test_ok_undeclared_when_ref_parameter_method() {
  154. //$o = new Foo2();
  155. //$x = 1;
  156. //SKIP: this requires some dataflow analysis ...
  157. //$o->method($x, $y);
  158. //SKIP: same
  159. //echo $y;
  160. }
  161. //*************************************************************************
  162. // Bailout constructs
  163. //*************************************************************************
  164. function test_eval_bailout() {
  165. //this should not generate an "unused variable" error
  166. $used_var_in_eval = 42;
  167. //ERROR: please avoid dynamic code
  168. eval('echo $used_var_in_eval;');
  169. }
  170. function test_eval_var_bailout() {
  171. $used_var_in_eval_field = 42;
  172. $x = 'used_var_in_eval_field';
  173. //ERROR: please avoid dynamic code
  174. echo $$x;
  175. }
  176. function ugly() {
  177. return array('extracted_field' => 2);
  178. }
  179. function test_bailout_extract() {
  180. //ERROR: please avoid dynamic code
  181. extract(ugly());
  182. // this is ok ...
  183. echo $extracted_field;
  184. //SKIP: this is not ok but hard to detect statically in the general case
  185. echo $wrong_extracted_field_but_skipped;
  186. }
  187. function test_bailout_compact() {
  188. // this should not generate a warning for now. At some point
  189. // we want to remove all those ugly compact() but before that, no error.
  190. //should not generate error
  191. $compacted = 1;
  192. // this function is horrible. it's the opposite of extract()
  193. //ERROR: please avoid dynamic code
  194. $arr = compact('compacted');
  195. return $arr;
  196. }