Summary
Filter attribute-name completion by the attribute's declared targets, so a #[
position only offers attributes valid there — e.g. don't offer a
TARGET_METHOD-only attribute on a class, or a TARGET_CLASS-only attribute in a
function-parameter position. This also covers suppressing completion entirely where
#[ is not a syntactically valid attribute position at all (see below).
Background
The initial attribute completion work added attribute-name completion (#[Ro →
attribute classes only) via ClassCandidateFilter::Attribute +
CodeResolver::isAttribute. That filter is target-agnostic: every confirmed
attribute is offered at any #[ on the line, regardless of position. This is the
"less sophisticated version first" explicitly called out in the parent issue.
Because detection is text-only, it also offers attributes after a #[ that appears in
a syntactically invalid spot (e.g. an expression position like $x = #[Fo). Deciding
"is this even a valid attribute position, and if so what target?" is the same
position analysis — so both concerns are resolved here rather than by bolting a second
validity check onto the text classifier.
Work
- Capture the attribute's target flags (the
#[Attribute(Attribute::TARGET_*)]
bitmask; #[Attribute] with no argument defaults to TARGET_ALL) on
ClassInfo, populated from both the AST factory (attrGroups → the Attribute
attribute's argument) and reflection.
- Detect the current attribute target at the cursor (class / method / property /
parameter / constant / function / enum-case), and detect the absence of a valid
attribute target. This needs position context beyond the text classifier — an
AST-first path with a text fallback, consistent with the member/call detection seam.
The text classifier deliberately stays resilient (see docs/features/completion.md),
so target detection should layer on rather than convert the classifier to AST.
- Narrow the attribute filter (or a new
CodeResolver predicate) by the detected
target, and offer nothing when no attribute target applies.
Acceptance
- A
TARGET_METHOD attribute is offered on a method but not on a class.
TARGET_ALL / unflagged attributes are offered everywhere an attribute is valid.
- No attributes are offered where
#[ is not a valid attribute position (e.g. an
expression/statement position inside a body).
- When the position is valid but the target cannot be determined, fall back to offering
all attributes (optimistic) rather than hiding valid completions.
Part of #252 (parent #311).
Issue body written by AI, from a design discussion with the maintainer.
Summary
Filter attribute-name completion by the attribute's declared targets, so a
#[position only offers attributes valid there — e.g. don't offer a
TARGET_METHOD-only attribute on a class, or aTARGET_CLASS-only attribute in afunction-parameter position. This also covers suppressing completion entirely where
#[is not a syntactically valid attribute position at all (see below).Background
The initial attribute completion work added attribute-name completion (
#[Ro→attribute classes only) via
ClassCandidateFilter::Attribute+CodeResolver::isAttribute. That filter is target-agnostic: every confirmedattribute is offered at any
#[on the line, regardless of position. This is the"less sophisticated version first" explicitly called out in the parent issue.
Because detection is text-only, it also offers attributes after a
#[that appears ina syntactically invalid spot (e.g. an expression position like
$x = #[Fo). Deciding"is this even a valid attribute position, and if so what target?" is the same
position analysis — so both concerns are resolved here rather than by bolting a second
validity check onto the text classifier.
Work
#[Attribute(Attribute::TARGET_*)]bitmask;
#[Attribute]with no argument defaults toTARGET_ALL) onClassInfo, populated from both the AST factory (attrGroups→ theAttributeattribute's argument) and reflection.
parameter / constant / function / enum-case), and detect the absence of a valid
attribute target. This needs position context beyond the text classifier — an
AST-first path with a text fallback, consistent with the member/call detection seam.
The text classifier deliberately stays resilient (see
docs/features/completion.md),so target detection should layer on rather than convert the classifier to AST.
CodeResolverpredicate) by the detectedtarget, and offer nothing when no attribute target applies.
Acceptance
TARGET_METHODattribute is offered on a method but not on a class.TARGET_ALL/ unflagged attributes are offered everywhere an attribute is valid.#[is not a valid attribute position (e.g. anexpression/statement position inside a body).
all attributes (optimistic) rather than hiding valid completions.
Part of #252 (parent #311).
Issue body written by AI, from a design discussion with the maintainer.