Test type-resolver + make type resolving work for "blocked" namespaces

Test type-resolver created from resolvecontext with:
 - File containing single namespace and no block
 - File containing one namespace with a block ('{}')
 - File containing multiple namespaces with blocks

Patch `phpinspect--make-type-resolver-for-resolvecontext' to support namespaces with
blocks.
WIP
Hugo Thunnissen 3 years ago
parent df821c4039
commit faa936a4f0

@ -1513,7 +1513,8 @@ said FQN's by class name"
(concat "\\" namespace "\\" type))
;; Clas|interface|trait name
(t (concat "\\" (or (assoc-default type types #'string=) (concat namespace "\\" type))))))
(t (concat "\\" (or (assoc-default type types #'string=)
(concat namespace "\\" type))))))
(defun phpinspect-var-annotation-p (token)
(phpinspect-type-p token :var-annotation))
@ -1702,6 +1703,12 @@ said FQN's by class name"
(extends . ,extends)
(implements . ,implements))))))
(defsubst phpinspect-namespace-body (namespace)
"Return the nested tokens in NAMESPACE tokens' body.
Accounts for namespaces that are defined with '{}' blocks."
(if (phpinspect-block-p (caddr namespace))
(cdaddr namespace)
(cdr namespace)))
(defun phpinspect--index-classes (types classes &optional namespace indexed)
"Index the class tokens in `classes`, using the types in `types`
@ -2087,15 +2094,19 @@ static variables and static methods."
(let ((namespace-or-root
(seq-find #'phpinspect-namespace-or-root-p
(phpinspect--resolvecontext-enclosing-tokens
resolvecontext))))
resolvecontext)))
(namespace-name))
(when (phpinspect-namespace-p namespace-or-root)
(setq namespace-name (cadadr namespace-or-root))
(setq namespace-or-root (phpinspect-namespace-body namespace-or-root)))
(phpinspect--make-type-resolver
(phpinspect--uses-to-types
(seq-filter #'phpinspect-use-p namespace-or-root))
(seq-find #'phpinspect-class-p
(phpinspect--resolvecontext-enclosing-tokens
resolvecontext))
(when (phpinspect-namespace-p namespace-or-root)
(cadadr namespace-or-root)))))
namespace-name)))
(defun phpinspect--get-last-statement-in-token (token)
(setq token (cond ((phpinspect-function-p token)

@ -0,0 +1 @@
(:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Controller") (:incomplete-block (:use (:word "Symfony\\Component\\HttpFoundation\\Response") (:terminator ";")) (:use (:word "App\\Entity\\Address") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\RedirectResponse") (:terminator ";")) (:use (:word "App\\Repository\\AddressRepository") (:terminator ";")) (:use (:word "App\\Repository\\UserRepository") (:terminator ";")) (:use (:word "Doctrine\\ORM\\EntityManagerInterface") (:terminator ";")) (:use (:word "Twig\\Environment") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\Request") (:terminator ";")) (:use (:word "Symfony\\Component\\Routing\\Annotation\\Route") (:terminator ";")) (:word "class") (:word "AddressController") (:incomplete-block (:const (:word "A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE") (:assignment "=") (:string "a value") (:terminator ";")) (:public (:const (:word "ARRAY_CONSTANT") (:assignment "=") (:array (:string "key") (:fat-arrow "=>") (:string "value") (:comma ",") (:string "key") (:fat-arrow "=>")) (:terminator ";"))) (:private (:variable "repo") (:terminator ";")) (:private (:variable "user_repo") (:terminator ";")) (:private (:variable "twig") (:terminator ";")) (:private (:variable "em") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "AddressRepository") (:variable "repo") (:comma ",") (:word "UserRepository") (:variable "user_repo") (:comma ",") (:word "Environment") (:variable "twig") (:comma ",") (:word "EntityManagerInterface") (:variable "em"))) (:block (:variable "this") (:object-attrib (:word "repo")) (:assignment "=") (:variable "repo") (:terminator ";") (:variable "this") (:object-attrib (:word "user_repo")) (:assignment "=") (:variable "user_repo") (:terminator ";") (:variable "this") (:object-attrib (:word "twig")) (:assignment "=") (:variable "twig") (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:assignment "=") (:variable "em") (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressPage") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:word "return") (:word "new") (:word "Response") (:list (:variable "this") (:object-attrib (:word "twig")) (:object-attrib (:word "render")) (:list (:string "address/create.html.twig") (:comma ",") (:array (:string "user") (:fat-arrow "=>") (:variable "user") (:comma ",")))) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:variable "address_string") (:assignment "=") (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address")) (:terminator ";") (:variable "address") (:assignment "=") (:word "new") (:word "Address") (:list (:variable "user") (:comma ",") (:variable "address_string")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "persist")) (:list (:variable "address")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "flush")) (:list) (:terminator ";") (:word "return") (:word "new") (:word "RedirectResponse") (:list (:string "/user/") (:variable "user") (:object-attrib (:word "getLoginName")) (:list) (:string "/manage")) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "deleteAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:incomplete-block (:variable "address") (:assignment "=") (:variable "this") (:object-attrib (:word "repo")) (:object-attrib (:word "find")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address"))) (:terminator ";") (:comment) (:comment) (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "remove")) (:incomplete-list (:variable "this") (:object-attrib (:word "em")) (:object-attrib nil)))))))))

@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace App\Controller {
use Symfony\Component\HttpFoundation\Response;
use App\Entity\Address;
use Symfony\Component\HttpFoundation\RedirectResponse;
use App\Repository\AddressRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Twig\Environment;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AddressController
{
const A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE = 'a value';
public const ARRAY_CONSTANT = [
'key' => 'value',
'key' => 0
];
private $repo;
private $user_repo;
private $twig;
private $em;
public function __construct(
AddressRepository $repo,
UserRepository $user_repo,
Environment $twig,
EntityManagerInterface $em
) {
$this->repo = $repo;
$this->user_repo = $user_repo;
$this->twig = $twig;
$this->em = $em;
}
/**
* @Route("/address/add", methods={"GET"})
*/
public function addAddressPage(Request $req): Response
{
$user = $this->user_repo->findOne($req->get('user'));
return new Response(
$this->twig->render('address/create.html.twig', [
'user' => $user,
])
);
}
/**
* @Route("/address/add", methods={"POST"})
*/
public function addAddressAction(Request $req): Response
{
$user = $this->user_repo->findOne($req->request->get('user'));
$address_string = $req->request->get('address');
$address = new Address($user, $address_string);
$this->em->persist($address);
$this->em->flush();
return new RedirectResponse('/user/' . $user->getLoginName() . '/manage');
}
/**
* @Route("/address/delete", methods={"POST"})
*/
public function deleteAddressAction(Request $req): Response
{
$address = $this->repo->find($req->request->get('address'));
// This is what a while looks like to phpinspect when it parses up
// until "point" to complete.
$this->em->remove($this->em->

File diff suppressed because one or more lines are too long

@ -0,0 +1,164 @@
<?php
declare(strict_types=1);
namespace Circus\Artist {
use Symfony\Component\HttpFoundation\Response;
use App\Entity\Address;
use Symfony\Component\HttpFoundation\RedirectResponse;
use App\Repository\AddressRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Twig\Environment;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AddressController
{
const A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE = 'a value';
public const ARRAY_CONSTANT = [
'key' => 'value',
'key' => 0
];
private $repo;
private $user_repo;
private $twig;
private $em;
public function __construct(
AddressRepository $repo,
UserRepository $user_repo,
Environment $twig,
EntityManagerInterface $em
) {
$this->repo = $repo;
$this->user_repo = $user_repo;
$this->twig = $twig;
$this->em = $em;
}
/**
* @Route("/address/add", methods={"GET"})
*/
public function addAddressPage(Request $req): Response
{
$user = $this->user_repo->findOne($req->get('user'));
return new Response(
$this->twig->render('address/create.html.twig', [
'user' => $user,
])
);
}
/**
* @Route("/address/add", methods={"POST"})
*/
public function addAddressAction(Request $req): Response
{
$user = $this->user_repo->findOne($req->request->get('user'));
$address_string = $req->request->get('address');
$address = new Address($user, $address_string);
$this->em->persist($address);
$this->em->flush();
return new RedirectResponse('/user/' . $user->getLoginName() . '/manage');
}
/**
* @Route("/address/delete", methods={"POST"})
*/
public function deleteAddressAction(Request $req): Response
{
$address = $this->repo->find($req->request->get('address'));
$this->em->remove($address);
$this->em->flush();
return new RedirectResponse('/user/' . $address->getUser()->getLoginName() . '/manage');
}
}
}
namespace App\Controller {
use Symfony\Component\HttpFoundation\Response;
use App\Entity\Address;
use Symfony\Component\HttpFoundation\RedirectResponse;
use App\Repository\AddressRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Twig\Environment;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AddressController
{
const A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE = 'a value';
public const ARRAY_CONSTANT = [
'key' => 'value',
'key' => 0
];
private $repo;
private $user_repo;
private $twig;
private $em;
public function __construct(
AddressRepository $repo,
UserRepository $user_repo,
Environment $twig,
EntityManagerInterface $em
) {
$this->repo = $repo;
$this->user_repo = $user_repo;
$this->twig = $twig;
$this->em = $em;
}
/**
* @Route("/address/add", methods={"GET"})
*/
public function addAddressPage(Request $req): Response
{
$user = $this->user_repo->findOne($req->get('user'));
return new Response(
$this->twig->render('address/create.html.twig', [
'user' => $user,
])
);
}
/**
* @Route("/address/add", methods={"POST"})
*/
public function addAddressAction(Request $req): Response
{
$user = $this->user_repo->findOne($req->request->get('user'));
$address_string = $req->request->get('address');
$address = new Address($user, $address_string);
$this->em->persist($address);
$this->em->flush();
return new RedirectResponse('/user/' . $user->getLoginName() . '/manage');
}
/**
* @Route("/address/delete", methods={"POST"})
*/
public function deleteAddressAction(Request $req): Response
{
$address = $this->repo->find($req->request->get('address'));
// This is what a while looks like to phpinspect when it parses up
// until "point" to complete.
$this->em->remove($this->em->

@ -127,7 +127,7 @@
(phpinspect-test-read-fixture-data
"class-index-1-2-undestructive-merge"))))
(ert-deftest phpinspect-find-innermost-incomplete-nested-token ()
(ert-deftest phpinspect--get-resolvecontext ()
(let ((resolvecontext (phpinspect--get-resolvecontext
(phpinspect-test-read-fixture-data "IncompleteClass"))))
@ -150,7 +150,58 @@
(should (phpinspect-incomplete-class-p
(cadddr (phpinspect--resolvecontext-enclosing-tokens
resolvecontext))))))
resolvecontext))))))
(ert-deftest phpinspect-type-resolver-for-resolvecontext ()
(let* ((resolvecontext (phpinspect--get-resolvecontext
(phpinspect-test-read-fixture-data "IncompleteClass")))
(type-resolver (phpinspect--make-type-resolver-for-resolvecontext
resolvecontext)))
(should (string= "\\array" (funcall type-resolver "array")))
(should (string= "\\array" (funcall type-resolver "\\array")))
(should (string= "\\Symfony\\Component\\HttpFoundation\\Response"
(funcall type-resolver "Response")))
(should (string= "\\Response" (funcall type-resolver "\\Response")))
(should (string= "\\App\\Controller\\GastonLagaffe"
(funcall type-resolver "GastonLagaffe")))
(should (string= "\\App\\Controller\\Dupuis\\GastonLagaffe"
(funcall type-resolver "Dupuis\\GastonLagaffe")))))
(ert-deftest phpinspect-type-resolver-for-resolvecontext-namespace-block ()
(let* ((resolvecontext (phpinspect--get-resolvecontext
(phpinspect-test-read-fixture-data
"IncompleteClassBlockedNamespace")))
(type-resolver (phpinspect--make-type-resolver-for-resolvecontext
resolvecontext)))
(should (string= "\\array" (funcall type-resolver "array")))
(should (string= "\\array" (funcall type-resolver "\\array")))
(should (string= "\\Symfony\\Component\\HttpFoundation\\Response"
(funcall type-resolver "Response")))
(should (string= "\\Response" (funcall type-resolver "\\Response")))
(should (string= "\\App\\Controller\\GastonLagaffe"
(funcall type-resolver "GastonLagaffe")))
(should (string= "\\App\\Controller\\Dupuis\\GastonLagaffe"
(funcall type-resolver "Dupuis\\GastonLagaffe")))))
(ert-deftest phpinspect-type-resolver-for-resolvecontext-multiple-namespace-blocks ()
(let* ((resolvecontext (phpinspect--get-resolvecontext
(phpinspect-test-read-fixture-data
"IncompleteClassMultipleNamespaces")))
(type-resolver (phpinspect--make-type-resolver-for-resolvecontext
resolvecontext)))
(should (string= "\\array" (funcall type-resolver "array")))
(should (string= "\\array" (funcall type-resolver "\\array")))
(should (string= "\\Symfony\\Component\\HttpFoundation\\Response"
(funcall type-resolver "Response")))
(should (string= "\\Response" (funcall type-resolver "\\Response")))
(should (string= "\\App\\Controller\\GastonLagaffe"
(funcall type-resolver "GastonLagaffe")))
(should (string= "\\App\\Controller\\Dupuis\\GastonLagaffe"
(funcall type-resolver "Dupuis\\GastonLagaffe")))))
(provide 'phpinspect-test)
;;; phpinspect-test.el ends here

@ -3,7 +3,9 @@
(let ((here (file-name-directory
(or load-file-name
buffer-file-name))))
buffer-file-name)))
(print-length 1000)
(print-level 1000))
(dolist (file (directory-files (concat here "/../fixtures" ) t "\\.php$"))
(with-temp-buffer
(insert-file-contents-literally file)

Loading…
Cancel
Save