2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/test/ext/test_code_error.h"
18 #include "hphp/compiler/parser/parser.h"
19 #include "hphp/compiler/builtin_symbols.h"
20 #include "hphp/compiler/analysis/analysis_result.h"
21 #include "hphp/compiler/code_generator.h"
22 #include "hphp/compiler/option.h"
24 ///////////////////////////////////////////////////////////////////////////////
26 TestCodeError::TestCodeError() {
27 Option::IncludeRoots
["$_SERVER['PHP_ROOT']"] = "";
30 bool TestCodeError::RunTests(const std::string
&which
) {
32 #define CODE_ERROR_ENTRY(x) RUN_TEST(Test ## x);
33 #include "hphp/compiler/analysis/core_code_error.inc"
34 #undef CODE_ERROR_ENTRY
38 bool TestCodeError::Verify(Compiler::ErrorType type
, const char *src
,
39 const char *file
, int line
, bool exists
) {
40 WithOpt
w0(Option::RecordErrors
);
41 WithOpt
w1(Option::WholeProgram
);
42 WithOpt
w2(Option::ParseTimeOpts
);
44 Compiler::ClearErrors();
46 Type::ResetTypeHintTypes();
47 Type::InitTypeHintMap();
48 BuiltinSymbols::LoadSuperGlobals();
50 AnalysisResultPtr
ar(new AnalysisResult());
51 // for TestPHPIncludeFileNotInLib
52 Compiler::Parser::ParseString("<?php ", ar
, "f2");
53 Compiler::Parser::ParseString(src
, ar
, "f1");
54 BuiltinSymbols::Load(ar
);
57 ar
->analyzeProgramFinal();
58 if (Compiler::HasError(type
) != exists
) {
59 std::ostringstream error
;
60 JSON::CodeError::OutputStream
out(error
, ar
);
61 Compiler::SaveErrors(out
);
62 printf("%s:%d: parsing %s\ncode error missing\n%s\n", file
, line
, src
,
69 ///////////////////////////////////////////////////////////////////////////////
71 bool TestCodeError::TestBadPHPIncludeFile() {
72 VE(BadPHPIncludeFile
, "<?php include 'f1';");
76 bool TestCodeError::TestPHPIncludeFileNotFound() {
77 VE(PHPIncludeFileNotFound
, "<?php include $_SERVER['PHP_ROOT'].'a.php';");
78 VEN(PHPIncludeFileNotFound
, "<?php include_once $template_path;");
82 bool TestCodeError::TestUseEvaluation() {
83 VE(UseEvaluation
, "<?php eval('a');");
87 bool TestCodeError::TestUseUndeclaredVariable() {
88 VE(UseUndeclaredVariable
, "<?php $a = 1; function t() { print $a;}");
90 Removing for now. We dont warn about non-static properties.
92 VE(UseUndeclaredVariable,
93 "<?php class T {} function t() { $a = new T(); print $a->a; }");
95 VE(UseUndeclaredVariable
,
96 "<?php class A { public $a = 123; } print A::$a;");
101 bool TestCodeError::TestUseUndeclaredGlobalVariable() {
102 VE(UseUndeclaredGlobalVariable
, "<?php print $a;");
103 VE(UseUndeclaredGlobalVariable
, "<?php print $GLOBALS['a'];");
107 bool TestCodeError::TestUseUndeclaredConstant() {
108 VE(UseUndeclaredConstant
, "<?php print a;");
109 VE(UseUndeclaredConstant
, "<?php class T {} print T::a;");
113 bool TestCodeError::TestUnknownClass() {
114 VE(UnknownClass
, "<?php $a = new T();");
116 VEN(UnknownClass
, "<?php class A { function foo(self $a) {}}");
120 " function foo($f) {"
121 " echo self::FOO+parent::FOO;"
122 " echo self::$f()+parent::$f();"
123 " var_dump(new self, new parent);"
124 " echo self::bar()+parent::bar();"
125 " echo self::$foo+parent::$foo;"
126 " try {} catch (self $p) {}"
127 " try {} catch (parent $p) {}"
133 bool TestCodeError::TestUnknownBaseClass() {
134 VE(UnknownBaseClass
, "<?php class T extends R {}");
138 bool TestCodeError::TestUnknownObjectMethod() {
139 VE(UnknownObjectMethod
,
141 "function test() { $a = new T(); print $a->a(); }");
144 VEN(UnknownObjectMethod
,
145 "<?php class T { function __call($name, $args) {} } "
146 "function t() { $a = new T(); print $a->a(); }");
147 VEN(UnknownObjectMethod
,
148 "<?php class T { function __call($name, $args) {}} class R extends T {} "
149 "function test(R $a) { print $a->a();}");
153 bool TestCodeError::TestInvalidMagicMethod() {
154 VE(InvalidMagicMethod
, "<?php class T { function __tostring($a) {}}");
158 bool TestCodeError::TestUnknownFunction() {
159 VE(UnknownFunction
, "<?php test();");
163 bool TestCodeError::TestBadConstructorCall() {
164 VE(BadConstructorCall
, "<?php class T {} $a = new T(1);");
167 VEN(BadConstructorCall
,
168 "<?php class B { function __construct($a) {}} "
169 "class A extends B {} $a = new A(1);");
174 bool TestCodeError::TestDeclaredVariableTwice() {
175 VE(DeclaredVariableTwice
, "<?php class T { var $a; var $a;}");
176 VE(DeclaredVariableTwice
, "<?php class T { var $a = 1; var $a;}");
177 VE(DeclaredVariableTwice
, "<?php class T { var $a; var $a = 1;}");
178 VE(DeclaredVariableTwice
, "<?php class T { var $a = 1; var $a = 2;}");
179 VE(DeclaredVariableTwice
, "<?php class T { static $a; static $a;}");
180 VE(DeclaredVariableTwice
, "<?php class T { static $a = 1; static $a;}");
181 VE(DeclaredVariableTwice
, "<?php class T { static $a; static $a = 1;}");
182 VE(DeclaredVariableTwice
, "<?php class T { static $a = 1; static $a = 2;}");
183 VE(DeclaredVariableTwice
, "<?php class T { var $a; static $a;}");
184 VE(DeclaredVariableTwice
, "<?php class T { static $a; var $a;}");
185 VE(DeclaredVariableTwice
, "<?php class T { var $a = 1; static $a;}");
186 VE(DeclaredVariableTwice
, "<?php class T { var $a; static $a = 1;}");
187 VE(DeclaredVariableTwice
, "<?php class T { var $a = 1; static $a = 2;}");
191 bool TestCodeError::TestDeclaredConstantTwice() {
192 VE(DeclaredConstantTwice
, "<?php define('t', 1); define('t', 2);");
193 VE(DeclaredConstantTwice
, "<?php class T { const A = 1; const A = 1;}");
197 bool TestCodeError::TestDeclaredMethodTwice() {
198 VE(DeclaredMethodTwice
, "<?php class T { function foo(){} function foo(){}}");
202 bool TestCodeError::TestDeclaredAttributeTwice() {
203 WithOpt
w0(Option::EnableHipHopSyntax
);
205 VE(DeclaredAttributeTwice
, "<?php << Foo, Foo >> class C {}");
206 VE(DeclaredAttributeTwice
, "<?php << Foo, Foo >> function f() {}");
210 bool TestCodeError::TestBadDefine() {
211 VE(BadDefine
, "<?php define($a, 1);");
215 bool TestCodeError::TestRequiredAfterOptionalParam() {
216 VE(RequiredAfterOptionalParam
, "<?php function t($a = 1, $b) {}");
220 bool TestCodeError::TestRedundantParameter() {
221 VE(RedundantParameter
, "<?php function t($a, $a) {}");
225 bool TestCodeError::TestTooFewArgument() {
226 VE(TooFewArgument
, "<?php function test($a) {} test();");
227 VE(TooFewArgument
, "<?php function test($a, $b) {} test(1);");
229 "<?php class T { function t($a) {}} $a = new T(); $a->t();");
231 "<?php class T { function t($a, $b) {}} $a = new T(); $a->t(1);");
233 "<?php class T { function __construct($a) {}} $a = new T();");
235 "<?php class T { function __construct($a, $b) {}} $a = new T(1);");
239 bool TestCodeError::TestTooManyArgument() {
240 VE(TooManyArgument
, "<?php function test() {} test(1);");
242 "<?php class A { function t() {}} "
243 "function test() { $a = new A(); $a->t(1);}");
245 "<?php class T { function __construct($b) {}} $a = new T(1, 2);");
249 "<?php function t() {} function t($a) {} t($a);");
253 bool TestCodeError::TestStatementHasNoEffect() {
254 VE(StatementHasNoEffect
, "<?php $a;");
255 VE(StatementHasNoEffect
, "<?php $a + $b;");
256 VE(StatementHasNoEffect
, "<?php 'test';");
257 VE(StatementHasNoEffect
, "<?php -$a;");
261 bool TestCodeError::TestUseVoidReturn() {
262 VE(UseVoidReturn
, "<?php function test() {} $a = test();");
266 bool TestCodeError::TestMissingObjectContext() {
267 VE(MissingObjectContext
,
268 "<?php class A { public $a = 123; "
269 "public static function test() { print $this->a;}} A::test();");
271 VE(MissingObjectContext
,
272 "<?php class A { public function a() { } "
273 "public static function test() { $this->a();}} A::test();");
276 VEN(MissingObjectContext
,
277 "<?php class A { public function a() {} } "
278 "class B extends A { public function b() { A::a();}}");
280 VEN(MissingObjectContext
,
281 "<?php class A { public function a() {} } print A::a();");
283 VEN(MissingObjectContext
,
284 "<?php class A { public function a() {} } "
285 "class B { public function b() { A::a();}}");
290 bool TestCodeError::TestMoreThanOneDefault() {
291 VE(MoreThanOneDefault
, "<?php switch ($a) { default: default: }");
295 bool TestCodeError::TestInvalidArrayElement() {
296 VE(InvalidArrayElement
, "<?php if (isset($obj[])) var_dump($obj);");
300 bool TestCodeError::TestInvalidDerivation() {
301 VE(InvalidDerivation
,
303 "interface RecurisiveFooFar extends RecurisiveFooFar {}");
304 VE(InvalidDerivation
,
306 "class RecurisiveFooFar extends RecurisiveFooFar {}");
307 VE(InvalidDerivation
,
309 "interface a extends b {}"
310 "interface b extends a {}");
311 VE(InvalidDerivation
,
313 "interface a extends B {}"
314 "interface b extends a {}");
315 VE(InvalidDerivation
,
317 "interface a extends b {}"
318 "interface B extends a {}");
319 VE(InvalidDerivation
,
321 "interface a extends b {}"
322 "interface b extends A {}");
323 VE(InvalidDerivation
,
325 "interface A extends B {}"
326 "interface b extends a {}");
327 VE(InvalidDerivation
,
329 "interface a extends B {}"
330 "interface B extends a {}");
331 VE(InvalidDerivation
,
333 "interface a extends b {}"
334 "interface B extends A {}");
335 VE(InvalidDerivation
,
337 "interface A extends B {}"
338 "interface B extends a {}");
339 VE(InvalidDerivation
,
341 "interface a extends B {}"
342 "interface B extends A {}");
343 VE(InvalidDerivation
,
345 "class a extends b {}"
346 "class B extends A {}");
347 VE(InvalidDerivation
,
349 "interface a extends b {}"
350 "class B extends A {}");
351 VE(InvalidDerivation
, "<?php interface A {} class T implements A, A {}");
352 VE(InvalidDerivation
, "<?php class A {} class B implements A {}");
353 VE(InvalidDerivation
, "<?php class A {} interface B extends A {}");
354 VEN(InvalidDerivation
,
358 "class C extends A implements B {}");
359 VE(InvalidDerivation
, "<?php interface I {} class C extends I {}");
364 bool TestCodeError::TestInvalidOverride() {
366 "<?php class A { protected $x; } class B extends A { private $x; }");
369 "<?php class A { public $x; } class B extends A { private $x; }");
372 "<?php class A { public $x; } class B extends A { protected $x; }");
377 bool TestCodeError::TestMissingAbstractMethodImpl() {
378 VE(MissingAbstractMethodImpl
,
381 " abstract function foo();"
383 "class B extends A {"
385 VE(MissingAbstractMethodImpl
,
390 "class B implements A {"
392 VEN(MissingAbstractMethodImpl
,
395 " abstract class A {"
396 " abstract function foo();"
399 " abstract class A {"
402 "class B extends A {"
404 VEN(MissingAbstractMethodImpl
,
406 " public function foo();"
408 "class B implements A {"
409 " public function foo() {"
413 "interface C extends A { }"
414 "class D extends B implements C {}"
415 "class E extends D { }");
420 bool TestCodeError::TestBadPassByReference() {
421 VE(BadPassByReference
,
423 "function set_to_null(&$i) { $i = null; }"
425 VE(BadPassByReference
,
427 "function set_to_null(&$i) { $i = null; }"
428 "class A { const C = 1; }"
429 "set_to_null(A::C);");
430 VE(BadPassByReference
,
432 "function set_to_null(&$i) { $i = null; }"
433 "set_to_null($a + $b);");
434 VE(BadPassByReference
,
436 "function set_to_null(&$i) { $i = null; }"
437 "set_to_null(foo() + foo());");
438 VE(BadPassByReference
,
440 "function set_to_null(&$i) { $i = null; }"
441 "set_to_null(array(1));");
442 VE(BadPassByReference
,
444 "function set_to_null(&$i) { $i = null; }"
447 VE(BadPassByReference
,
449 "function set_to_null(&$i) { $i = null; }"
450 "set_to_null($a ? $b : $c);");
451 VE(BadPassByReference
,
453 "class A { function foo(&$a) { echo $a;} }"
454 "class B { function bar() { $obj = new A; $obj->foo(1); } }");
456 VEN(BadPassByReference
,
458 "function set_to_null(&$i) { $i = null; }"
459 "function foo() { return 1; }"
460 "class A { var $m; static $n; function f() { return 1;} }"
462 "set_to_null($a = 1);"
463 "set_to_null(($a = 1));"
464 "set_to_null(new A);"
465 "set_to_null(foo());"
471 "set_to_null(++$i); set_to_null($i--);"
472 "set_to_null(--$i); set_to_null($i--);"
474 "set_to_null($obj->f());"
475 "set_to_null($obj->m);"
476 "set_to_null(A::$n);");
477 VEN(BadPassByReference
,
479 " array('10', 11, 100, 100, 'a'),"
480 " array( 1, 2, '2', 3, 1)"
482 "array_multisort($ar[0], SORT_ASC, SORT_STRING,"
483 " $ar[1], SORT_NUMERIC, SORT_DESC);");
487 bool TestCodeError::TestConditionalClassLoading() {
488 VE(ConditionalClassLoading
,
490 "function load_cls($x) { "
491 " if (class_exists($x)) { return; } "
493 " case 'C1': /* require_once somefile */ break; "
494 " case 'C2': /* require_once somefile */ break; "
501 bool TestCodeError::TestBadArgumentType() {
504 "function foo(array $a) { }"
510 bool TestCodeError::TestGotoUndefLabel() {
512 "<?php goto foo_bar;");
515 "<?php function f() { goto baz; } baz:");
520 bool TestCodeError::TestGotoInvalidBlock() {
522 "<?php goto my_block; do { my_block: } while (false);");
528 " for ($i = 0; $i < $x; $i++) {"
529 " foo: var_dump($i);"
536 bool TestCodeError::TestInvalidAttribute() {
538 "<?php abstract class F { abstract $f; }");
541 "<?php class F { abstract $f; }");
544 "<?php final class F { final $f; }");
547 "<?php class F { final $f; }");
550 "<?php interface I { final function foo(); }");
553 "<?php interface I { private function foo(); }");
556 "<?php interface I { protected function foo(); }");
559 "<?php interface I { abstract function foo(); }");
562 "<?php class a { static function a() {} }");
565 "<?php class a { static function __construct() {} }");
567 VEN(InvalidAttribute
,
568 "<?php class a { function __construct() {} static function a() {} }");
573 bool TestCodeError::TestUnknownTrait() {
574 VE(UnknownTrait
, "<?php class C { use T; }");
576 VE(UnknownTrait
, "<?php trait T1 { use T2; }");
581 bool TestCodeError::TestMethodInMultipleTraits() {
582 VE(MethodInMultipleTraits
,
585 " public function Func() { }\n"
588 " public function Func() { }\n"
594 VE(MethodInMultipleTraits
,
597 " public function Func() { }\n"
600 " public function Func() { }\n"
609 VE(MethodInMultipleTraits
,
612 " public function Func() { }\n"
624 VE(MethodInMultipleTraits
,
627 " public function Func1() { }\n"
630 " public function Func2() { }\n"
634 " T2::Func2 as Func1;\n"
644 bool TestCodeError::TestUnknownTraitMethod() {
645 VE(UnknownTraitMethod
,
648 " public function Func1() { }\n"
652 " T1::Func2 as Func3;\n"
659 bool TestCodeError::TestCyclicDependentTraits() {
660 VE(CyclicDependentTraits
,
669 VE(CyclicDependentTraits
,
675 VE(CyclicDependentTraits
,
690 bool TestCodeError::TestInvalidTraitStatement() {
691 VE(InvalidTraitStatement
,
700 bool TestCodeError::TestRedeclaredTrait() {
724 bool TestCodeError::TestInvalidInstantiation() {
725 VE(InvalidInstantiation
, "<?php interface T {}; $a = new T();");
726 VE(InvalidInstantiation
,
727 "<?php abstract class T { abstract function foo(); };"
730 VEN(InvalidInstantiation
, "<?php class T {}; $a = new T();");
734 bool TestCodeError::TestInvalidYield() {
735 WithOpt
w0(Option::EnableHipHopSyntax
);
737 VE(InvalidYield
, "<?php function f() { yield 1; return 2; }");
738 VE(InvalidYield
, "<?php async function f() { await f(); yield 1; }");
739 VE(InvalidYield
, "<?php yield 1; }");
740 VE(InvalidYield
, "<?php class X { function __get() { yield 1; } }");
741 VE(InvalidYield
, "<?php class X { function X() { yield 1; } }");
746 bool TestCodeError::TestInvalidAwait() {
747 WithOpt
w0(Option::EnableHipHopSyntax
);
749 VE(InvalidAwait
, "<?php function f() { yield 1; await f(); }");
750 VE(InvalidAwait
, "<?php await f(); }");
751 VE(InvalidAwait
, "<?php class X { function __get() { await f(); } }");
752 VE(InvalidAwait
, "<?php class X { function X() { await f(); } }");
757 bool TestCodeError::TestBadDefaultValueType() {
758 WithOpt
w0(Option::EnableHipHopSyntax
);
760 VE(BadDefaultValueType
, "<?php class C { function f(int $i1 = array()) {} }");
761 VE(BadDefaultValueType
, "<?php function f(int $i1 = array()) {}");
765 bool TestCodeError::TestInvalidMethodDefinition() {
766 VE(InvalidMethodDefinition
, "<?php interface I {public function f() {}}");