44
55use PhpParser \Node ;
66use PhpParser \Node \Stmt \ClassLike ;
7+ use PhpParser \Node \Stmt \Const_ ;
78use PhpParser \Node \Stmt \Enum_ ;
9+ use PhpParser \Node \Stmt \Function_ ;
810use PhpParser \Node \Stmt \GroupUse ;
911use PhpParser \Node \Stmt \Interface_ ;
1012use PhpParser \Node \Stmt \Namespace_ ;
1618use PHPStan \Rules \IdentifierRuleError ;
1719use PHPStan \Rules \Rule ;
1820use PHPStan \Rules \RuleErrorBuilder ;
21+ use PHPStan \ShouldNotHappenException ;
1922use function in_array ;
2023use function sprintf ;
2124use function strtolower ;
@@ -59,25 +62,19 @@ public function processNode(Node $node, Scope $scope): array
5962 }
6063
6164 /**
62- * @param array<string, string[]> $usedNames
65+ * @param array<Use_::TYPE_*, array< string, list< string>>> $usedNames
6366 * @return list<IdentifierRuleError>
6467 */
6568 private function findErrorsForNode (Node $ node , string $ namespace , array &$ usedNames ): array
6669 {
6770 $ lowerNamespace = strtolower ($ namespace );
6871 if ($ node instanceof Use_) {
69- if ($ this ->shouldBeIgnored ($ node )) {
70- return [];
71- }
72- return $ this ->findErrorsInUses ($ node ->uses , '' , $ lowerNamespace , $ usedNames );
72+ return $ this ->findErrorsInUses ($ node ->uses , '' , $ lowerNamespace , $ usedNames , $ node ->type );
7373 }
7474
7575 if ($ node instanceof GroupUse) {
76- if ($ this ->shouldBeIgnored ($ node )) {
77- return [];
78- }
7976 $ useGroupPrefix = $ node ->prefix ->toString ();
80- return $ this ->findErrorsInUses ($ node ->uses , $ useGroupPrefix , $ lowerNamespace , $ usedNames );
77+ return $ this ->findErrorsInUses ($ node ->uses , $ useGroupPrefix , $ lowerNamespace , $ usedNames, $ node -> type );
8178 }
8279
8380 if ($ node instanceof ClassLike) {
@@ -93,7 +90,7 @@ private function findErrorsForNode(Node $node, string $namespace, array &$usedNa
9390 $ type = 'enum ' ;
9491 }
9592 $ name = $ node ->name ->toLowerString ();
96- if (in_array ($ name , $ usedNames [$ lowerNamespace ] ?? [], true )) {
93+ if (in_array ($ name , $ usedNames [Use_:: TYPE_NORMAL ][ $ lowerNamespace ] ?? [], true )) {
9794 return [
9895 RuleErrorBuilder::message (sprintf (
9996 'Cannot declare %s %s because the name is already in use. ' ,
@@ -106,27 +103,64 @@ private function findErrorsForNode(Node $node, string $namespace, array &$usedNa
106103 ->build (),
107104 ];
108105 }
109- $ usedNames [$ lowerNamespace ][] = $ name ;
106+ $ usedNames [Use_:: TYPE_NORMAL ][ $ lowerNamespace ][] = $ name ;
110107 return [];
111108 }
112109
110+ if ($ node instanceof Function_) {
111+ $ name = $ node ->name ->toLowerString ();
112+ if (in_array ($ name , $ usedNames [Use_::TYPE_FUNCTION ][$ lowerNamespace ] ?? [], true )) {
113+ return [
114+ RuleErrorBuilder::message (sprintf (
115+ 'Cannot declare function %s() because the name is already in use. ' ,
116+ $ namespace !== '' ? $ namespace . '\\' . $ node ->name ->toString () : $ node ->name ->toString (),
117+ ))
118+ ->identifier ('function.nameInUse ' )
119+ ->line ($ node ->getStartLine ())
120+ ->build (),
121+ ];
122+ }
123+ $ usedNames [Use_::TYPE_FUNCTION ][$ lowerNamespace ][] = $ name ;
124+ return [];
125+ }
126+
127+ if ($ node instanceof Const_) {
128+ $ errors = [];
129+ foreach ($ node ->consts as $ constNode ) {
130+ $ name = $ constNode ->name ->toLowerString ();
131+ if (in_array ($ name , $ usedNames [Use_::TYPE_CONSTANT ][$ lowerNamespace ] ?? [], true )) {
132+ $ errors [] = RuleErrorBuilder::message (sprintf (
133+ 'Cannot declare constant %s because the name is already in use. ' ,
134+ $ namespace !== '' ? $ namespace . '\\' . $ constNode ->name ->toString () : $ constNode ->name ->toString (),
135+ ))
136+ ->identifier ('const.nameInUse ' )
137+ ->line ($ constNode ->getStartLine ())
138+ ->build ();
139+ }
140+ $ usedNames [Use_::TYPE_CONSTANT ][$ lowerNamespace ][] = $ name ;
141+ }
142+ return $ errors ;
143+ }
144+
113145 return [];
114146 }
115147
116148 /**
117149 * @param Node\UseItem[] $uses
118- * @param array<string, string[]> $usedNames
150+ * @param array<Use_::TYPE_*, array<string, list<string>>> $usedNames
151+ * @param Use_::TYPE_* $useType
119152 * @return list<IdentifierRuleError>
120153 */
121- private function findErrorsInUses (array $ uses , string $ useGroupPrefix , string $ lowerNamespace , array &$ usedNames ): array
154+ private function findErrorsInUses (array $ uses , string $ useGroupPrefix , string $ lowerNamespace , array &$ usedNames, int $ useType ): array
122155 {
123156 $ errors = [];
124157 foreach ($ uses as $ use ) {
125- if ($ this ->shouldBeIgnored ($ use )) {
126- continue ;
158+ $ realUseType = $ this ->getRealUseType ($ use ->type , $ useType );
159+ if ($ realUseType === Use_::TYPE_UNKNOWN ) {
160+ throw new ShouldNotHappenException ();
127161 }
128162 $ useAlias = $ use ->getAlias ()->toLowerString ();
129- if (in_array ($ useAlias , $ usedNames [$ lowerNamespace ] ?? [], true )) {
163+ if (in_array ($ useAlias , $ usedNames [$ realUseType ][ $ lowerNamespace ] ?? [], true )) {
130164 $ errors [] = RuleErrorBuilder::message (sprintf (
131165 'Cannot use %s as %s because the name is already in use. ' ,
132166 $ useGroupPrefix !== '' ? $ useGroupPrefix . '\\' . $ use ->name ->toString () : $ use ->name ->toString (),
@@ -138,14 +172,28 @@ private function findErrorsInUses(array $uses, string $useGroupPrefix, string $l
138172 ->build ();
139173 continue ;
140174 }
141- $ usedNames [$ lowerNamespace ][] = $ useAlias ;
175+ $ usedNames [$ realUseType ][ $ lowerNamespace ][] = $ useAlias ;
142176 }
143177 return $ errors ;
144178 }
145179
146- private function shouldBeIgnored (Use_ |GroupUse |Node \UseItem $ use ): bool
180+ /**
181+ * @param Use_::TYPE_* $useType
182+ * @param Use_::TYPE_* $parentUseType
183+ * @return Use_::TYPE_*
184+ */
185+ private function getRealUseType (int $ useType , int $ parentUseType ): int
147186 {
148- return in_array ($ use ->type , [Use_::TYPE_FUNCTION , Use_::TYPE_CONSTANT ], true );
187+ if ($ parentUseType === Use_::TYPE_UNKNOWN ) {
188+ return $ useType ;
189+ }
190+ if ($ useType === Use_::TYPE_UNKNOWN ) {
191+ return $ parentUseType ;
192+ }
193+ if ($ useType === $ parentUseType ) {
194+ return $ useType ;
195+ }
196+ return Use_::TYPE_UNKNOWN ;
149197 }
150198
151199}
0 commit comments