Skip to content

Let users apply [UseWithArgumentNames] and [NonDefaultable] to their own code - #971

Merged
FreeApophis merged 4 commits into
mainfrom
code-analysis-attributes-for-consumers
Oct 20, 2026
Merged

FreeApophis merged 4 commits into
mainfrom
code-analysis-attributes-for-consumers

Conversation

@FreeApophis

Copy link
Copy Markdown
Member

Closes #750

What

Two changes that together make the attribute-driven rules usable on the consumer's own members, without making the attributes public in Funcky (the thread's concern about a runtime dependency on a type we may want to rename).

1. The analyzers match the attribute by name

λ1003 ([UseWithArgumentNames]) and λ1009 ([NonDefaultable]) resolved the attribute with GetTypeByMetadataName and compared symbols. That lookup returns null as soon as two referenced assemblies define the same full name, so a consumer that copied the attribute into a shared library silently lost both rules, even for Funcky's own Match. The analyzers now compare Funcky.CodeAnalysis.<Name>Attribute by name, so a copy in any assembly counts.

The new test AttributeInSeveralAssembliesTest defines the attribute in two referenced projects; it fails on main (0 diagnostics) and passes here. The symbol lookup in the compilation's own source never had the problem, which is why the existing tests did not catch it.

2. Opt-in generator in Funcky.Analyzers

<PropertyGroup>
  <FunckyCodeAnalysisAttributes>UseWithArgumentNames;NonDefaultable</FunckyCodeAnalysisAttributes>
</PropertyGroup>

emits the listed attributes as internal types into the project. Opt-in, as tautropfli suggested, because a project that already pasted the attribute would otherwise get a duplicate. Unknown names produce the build warning λ.BUILD.0002 from the package targets.

Two MSBuild details worth knowing when reviewing Funcky.Analyzers.targets:

  • Properties reach the compiler through a generated .editorconfig, where ; starts a comment. The targets therefore hand the generator a comma-separated copy (_FunckyCodeAnalysisAttributes); the user-facing property keeps the usual semicolon list.
  • Property functions escape the semicolons they produce, so the validation item list goes through [MSBuild]::Unescape.

Verified end to end by packing the package and consuming it from a scratch project: both attributes generate, λ1003 and λ1009 fire on the project's own members, and only the bogus name is warned about.

Docs

λ1003 and λ1009 pages gained a "Using the attribute on your own …" section with both the property and the hand-written attribute; the rules overview and the package readme describe the generator.

🤖 Generated with Claude Code

…own code

The analyzers λ1003 and λ1009 now match their attribute by full name instead
of resolving it through GetTypeByMetadataName. A copy of the attribute in any
assembly therefore counts, and the rules no longer go silent in a project that
references two assemblies which both define the attribute (the lookup returns
null on that ambiguity).

Funcky.Analyzers gains an incremental generator that emits the internal
attributes into the consuming project when it opts in through the MSBuild
property FunckyCodeAnalysisAttributes. The package targets expose the
property to the compiler (comma-separated, since a semicolon starts a
comment in the generated .editorconfig) and warn with λ.BUILD.0002 about
unknown names.

Closes #750

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Both generated attribute templates emit a C# 8-only directive that breaks C# 7.3 consumer builds.

1 open issue
What changed in this PR

Enables consumers to apply Funcky’s attribute-driven rules to their own code without exposing public attributes in Funcky.

Changes:

  • Matches attributes by full name across assemblies.
  • Adds opt-in attribute generation and build-time validation.
  • Adds regression tests and usage documentation.
File Description
Funcky.Analyzers/​Funcky.Analyzers/​UseWithArgumentNamesAnalyzer.cs Matches attributes by name.
Funcky.Analyzers/​Funcky.Analyzers/​NonDefaultable/​NonDefaultableStyleCopSuppressor.cs Uses name-based attribute detection.
Funcky.Analyzers/​Funcky.Analyzers/​NonDefaultable/​NonDefaultableAnalyzer.cs Removes assembly-specific attribute lookup.
Funcky.Analyzers/​Funcky.Analyzers/​CodeAnalysisExtensions/​SymbolExtensions.cs Adds full-name attribute matching.
Funcky.Analyzers/​Funcky.Analyzers/​CodeAnalysisAttributes/​CodeAnalysisAttributesGenerator.cs Generates requested internal attributes.
Funcky.Analyzers/​Funcky.Analyzers.Test/​CodeAnalysisAttributes/​CodeAnalysisAttributesGeneratorTest.cs Tests generation and property parsing.
Funcky.Analyzers/​Funcky.Analyzers.Test/​CodeAnalysisAttributes/​AttributeInSeveralAssembliesTest.cs Tests duplicate attribute names across assemblies.
Funcky.Analyzers/​Funcky.Analyzers.Package/​package.md Documents generator opt-in.
Funcky.Analyzers/​Funcky.Analyzers.Package/​buildTransitive/​Funcky.Analyzers.targets Passes generator settings and validates names.
Documentation/​src/​analyzer-rules/​λ1009.md Documents custom struct annotations.
Documentation/​src/​analyzer-rules/​λ1003.md Documents custom method annotations.
Documentation/​src/​analyzer-rules/​analyzer-rules.md Explains attribute generation.
changelog.md Records consumer support and lookup fixes.

Review effort: Balanced

FreeApophis and others added 3 commits October 20, 2026 10:01
…s compile

The directive is an error (CS8370) before C# 8, which .NET Framework
projects use by default, and the attributes have no members that would
need annotations. A new test generates into a C# 7.3 compilation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
#964 moved λ1009 into Funcky.BuiltinAnalyzers; the name-based attribute
matching from this branch follows it there: the built-in SymbolExtensions
gains the full-name HasAttribute, the analyzer registers its actions
without a metadata lookup, and the two-assembly test targets the moved
analyzer. λ1003 keeps the Funcky.Style category from main. The λ1009 page
says that the rule is built in while the generator ships with
Funcky.Analyzers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@FreeApophis
FreeApophis merged commit dbf3204 into main Oct 20, 2026
10 checks passed
@FreeApophis
FreeApophis deleted the code-analysis-attributes-for-consumers branch October 20, 2026 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make UseWithArgumentNamesAttribute publicly available

3 participants