Skip to content

Remove annotation support - #86

Merged
janlam7 merged 9 commits into
hostnet:masterfrom
janlam7:bye-annotations
Sep 24, 2026
Merged

janlam7 merged 9 commits into
hostnet:masterfrom
janlam7:bye-annotations

Conversation

@janlam7

@janlam7 janlam7 commented Sep 23, 2026

Copy link
Copy Markdown
Contributor
  • Removes annotations support
  • Drops Symfony 5 compatibiliy
  • Generates :static return type hints

Jan Lam and others added 4 commits September 23, 2026 14:33
Removes docblock-annotation support entirely: PropertyInformation no
longer runs Doctrine's DocParser, only native PHP attributes are read.
Deletes the deprecated Annotation\Generate/Enumerator docblock shims,
the annotation_loader.php test bootstrap, and
PropertyProcessorInterface::getProcessableNamespace() (which only
existed to support docblock-import filtering).

Converts all docblock-style Generator test fixtures to native
attributes via Rector, and fixes a real bug this exposed:
PropertyInformation::getDocumentation() used
strstr($doc, '@', true), which silently discarded all documentation
on a docblock with no leftover @-tag - now the common case once
markers move to attributes.

Generated set/add/remove accessor methods (previously undeclared) now
return : static, with the now-redundant @return $this|... docblock
dropped, and a nullable complex-type parameter now correctly gets
?Type (avoids a PHP 8.4 implicit-nullable-parameter deprecation). The
Enumerator accessor class's set/remove/clear methods keep their
existing explicit return type unchanged.

AttributeInstantiator no longer silently swallows a malformed attribute
from this package's own Attribute\ namespace - it rethrows; unrelated
or unloadable foreign attributes are still skipped silently.

Also: typed properties in PropertyInformation, #[\Override] on
interface implementations, fixes an implicit-nullable-parameter
deprecation in Plugin::__construct, adds the missing direct
symfony/finder requirement, widens symfony/filesystem to allow ^7.0,
and swaps cli-config.php off the deprecated Setup/EntityManager::create()
APIs. CI: bumps actions/checkout to v4, adds composer validate --strict,
adds a --prefer-lowest matrix leg.

Verified against a real downstream package (email-bounce-entities) via
a path-repo scratch install: regenerated Generated/ output diffs only
by the intended return-type/nullability changes, and phpstan stays
clean.

Rollout to the ~111 dependent entity/bundle packages, then to
applications, is tracked separately and gated on review of this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
symfony/filesystem and symfony/finder now require ^6.0||^7.0 instead
of ^5.4||^6.0||^7.0 - nothing in the installed dependency graph needed
the wider floor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Doctrine's @enum({"public","protected","private","none"}) validated
the get/set/add/remove/is arguments at docblock-parse time; nothing
replaced that once DocParser was dropped. Two non-breaking additions
restore the same guarantee without changing the public string-based
API (which ~111 downstream packages already call with string
literals):

- Generate's constructor now validates get/set/add/remove/is against
  the allowed set itself and throws \DomainException on a bad value,
  same as DocParser used to.
- Each parameter's inline docblock gets a literal-string union
  (@var 'public'|'protected'|'private'|'none'|null) in place of the
  removed @enum tag, for IDE/phpstan-level checking - the same
  #[..\Enumerator[]] convention this file already used for the
  $enumerators parameter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PropertyProcessorInterface::apply() and its two implementations
(AccessorGenerationProcessor, DoctrineMappingProcessor) still named
their parameter/local variables $annotation from the docblock-parsing
era; now that only native attributes flow through this path, rename
to $attribute throughout. Also type the parameter as object (it was
previously untyped) - matches what AttributeInstantiator::instantiate()
actually returns and what the interface's own docblock already
claimed. DoctrineMappingProcessor::processBidirectional() gets the
same treatment.

Test methods that exercise apply() via a data provider (testApply,
testAssociation) now type their $attribute parameter as object too,
and drop the @PARAM docblock lines that are now redundant with the
native types.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@janlam7 janlam7 self-assigned this Sep 23, 2026
@janlam7 janlam7 changed the title Bye annotations Remove annotation support Sep 23, 2026
It was pinned to ^7.4 (composer require's auto-picked resolution),
which forced the --prefer-lowest CI matrix leg to still install
Symfony 7 for cache while filesystem/finder correctly dropped to 6.0 -
defeating the point of that leg for this package. ^6.4||^7.0 matches
symfony/filesystem and symfony/finder's own floor; confirmed via
`composer update --prefer-lowest --dry-run` that all three now
resolve to their Symfony 6 floor together.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread src/Resources/templates/enum_class.php.twig Outdated
Jan Lam and others added 4 commits September 23, 2026 15:55
…hints

CodeGeneratorInterface.php and CodeGenerator.php had several @PARAM
tags that only restated an already-native parameter type
(ReflectionClass, PropertyInformation, Enumerator, etc.) - dropped
those. Several private helper methods (addImportForType, isAliased,
getPlainImportIfExists, fqcn) had string/array parameters typed only
in the docblock, not natively; added the native type hints (verified
safe against every call site) so the now-redundant plain @PARAM lines
could go too. Kept every @PARAM that adds real information a native
type can't express (string[] element-type refinement on bare array
params) and all @throws tags.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Where a generated method's parameter already carries a native type
hint identical to what the docblock's @PARAM line said, drop the
@PARAM line - matches the same cleanup already done in the plugin's
own source.

- add.php.twig / remove.php.twig: the parameter is always a complex
  (object) type for collection add/remove methods, already natively
  hinted - @PARAM was always fully redundant here, remove
  unconditionally.
- set.php.twig: the parameter only gets a native type hint when
  property.isComplexType (scalar setters stay untyped, validated at
  runtime instead) - @PARAM now only renders for the scalar case,
  where it's the sole source of type information. The optional
  $round parameter (never natively typed) keeps its @PARAM
  unconditionally, since its line also carries a real description
  ("round the number fit in the precision and scale") beyond the
  type. Made the blank-line separator before the @PARAM block
  conditional on the same test, so dropping @PARAM for a complex
  type doesn't leave a dangling blank comment line before */.
- enum_class.php.twig: the constructor's three parameters and the
  generated setter's $value parameter are always natively typed
  identically to their docblocks (Collection/object/string, and
  EnumItemInformation::getTypeHint() always returns a native PHP
  type name) - drop both @PARAM blocks entirely.

keys.php.twig's KeyRegistry::addPublicKeyPath()/addPrivateKeyPath()
keep their @PARAM lines unchanged - $alias/$path have no native type
hint there, so the docblock is the only source of type information.

Regenerated and re-verified every test/Generator/fixtures/expected/
file; diff is confined to the intended @param/blank-line removals.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same cleanup as the earlier CodeGenerator/templates passes, applied
to the remaining source: drop any @PARAM tag that only restates a
type the native signature already declares, with no description or
element-type refinement beyond it. Where a parameter was untyped but
every real call site is provably safe to type (verified against
callers, not assumed), add the native type hint and then drop the
now-fully-redundant docblock:

- PropertyInformation::limitMaximumRemoveVisibility() gets the same
  `string $visibility` type its three siblings
  (get/set/add) already had - its only caller always passes a string.
- Twig\PerLineNode::__construct() gets `string $prefix, string
  $postfix, int $lineno` - both call sites in PerLineTokenParser
  always pass exactly those types.

Left untouched where a native type is genuinely absent and could
introduce a regression: DoctrineMappingProcessor::transformType()/
transformComplexType() take values from Doctrine's own Column::$type
and OneToMany::$targetEntity, which are both nullable - typing those
params `string` would newly fatal on a value these methods currently
handle permissively. Also left every @PARAM that adds real
information a bare native type can't (string[] element-type
refinement, a genuinely untyped parameter, or a non-obvious
description) - Collection/ConstCollectionInterface's $key/$element
docs, ReflectionClass/TokenStream's $loc-position descriptions,
AttributeInstantiator's, and keys.php.twig's KeyRegistry methods
(no native type there at all) all stay as-is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@janlam7
janlam7 merged commit ba8d14b into hostnet:master Sep 24, 2026
4 checks passed
@janlam7
janlam7 deleted the bye-annotations branch September 24, 2026 05:14
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.

3 participants