Skip to content

Rewrite Api rules as restricted usage extensions, add tip to RestrictedUsage - #7010

Merged
ondrejmirtes merged 4 commits into
2.3.xfrom
api-rules-restricted-usage
Nov 9, 2026
Merged

ondrejmirtes merged 4 commits into
2.3.xfrom
api-rules-restricted-usage

Conversation

@ondrejmirtes

Copy link
Copy Markdown
Member

Rewrites part of src/Rules/Api on top of the restricted usage extension framework, and adds tip support to RestrictedUsage, which the BC-promise rules need.

Commits

  1. Allow restricted usage extensions to return a tip. RestrictedUsage::create() takes an optional ?string $tip. This is backward compatible for the @api class. All 12 places that turn a RestrictedUsage into a rule error now attach the tip: the 10 Restricted*UsageRule classes, ClassNameCheck, and the constructor check in InstantiationRule.
  2. Rewrite the runtime reflection Api rules as restricted usage extensions.
    • RuntimeReflectionFunctionRule → RuntimeReflectionFunctionUsageExtension (function usage)
    • RuntimeReflectionInstantiationRule → RuntimeReflectionInstantiationUsageExtension (class name usage at the new location)
  3. Rewrite the Api extends / implements / trait-use rules as one restricted class name usage extension. ApiClassExtendsRule, ApiClassImplementsRule, ApiInterfaceExtendsRule and ApiTraitUseRule → ApiClassNameUsageExtension, which switches on ClassNameUsageLocation.

Messages, identifiers, tips and lines are unchanged. The tests now run through the host rules (ExistingClassInClassExtendsRule, InstantiationRule, …), so they also expect the host rules' own errors on the existing data, e.g. "extends final class FileTypeMapper".

Small behaviour differences

  • is_a(...) and similar first-class callables are now reported too, through RestrictedFunctionCallableUsageRule.
  • new parent() that resolves to a Reflection* class is not reported any more. Host rules don't pass self, static or parent to class-name extensions.
  • Errors for multi-line class declarations are reported on the line of the referenced name, not on the line where the class starts.

Still rules, and why

Rule Missing in the framework
ApiMethodCallRule, ApiStaticCallRule, ApiInstantiationRule RestrictedMethodUsageExtension has no usage location. One extension is called for ->m(), ::m(), first-class callables and the constructor on new X, but these rules treat __construct differently. ApiInstantiationRule also can't use class-name usage: InstantiationRule skips self/static/parent and drops class-name errors when it returns early for abstract classes, interfaces, traits or enums.
ApiClassConstFetchRule The CLASS_CONSTANT_ACCESS location carries no constant name when the constant doesn't exist or is ::class.
ApiInstanceofRule, ApiInstanceofTypeRule Extensions get no AST node: the instanceof expression type, the TypeTraverserInstanceofVisitor attribute, and the class name as written in the source are all unavailable.
GetTemplateTypeRule, NodeConnectingVisitorAttributesRule Method usage extensions get no call arguments.
PhpStanNamespaceIn3rdPartyPackageRule, OldPhpParser4ClassRule There is no extension point for namespace declarations or for class names that don't exist.

@ondrejmirtes
ondrejmirtes merged commit 67fe930 into 2.3.x Nov 9, 2026
885 of 892 checks passed
@ondrejmirtes
ondrejmirtes deleted the api-rules-restricted-usage branch November 9, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant