Skip to content

Report linter diagnostics on library declarations at the project usage site - #12560

Draft
Timothee Guerin (timotheeguerin) wants to merge 5 commits into
microsoft:mainfrom
timotheeguerin:linter-library-use-site
Draft

Timothee Guerin (timotheeguerin) wants to merge 5 commits into
microsoft:mainfrom
timotheeguerin:linter-library-use-site

Conversation

@timotheeguerin

@timotheeguerin Timothee Guerin (timotheeguerin) commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Linter diagnostics whose target is declared in a library are silently dropped, even when the user's own code is what pulled that declaration in. Rules then have a permanent blind spot, e.g. the Azure no-query-in-collection rule can never report top coming from Azure.Core.StandardListQueryParameters (typespec-azure#6066).

This applies to every rule, so it's handled by one ownership policy in the linter rather than per-rule opt-in:

  • The library owns its declarations. A #suppress on the library declaration keeps the diagnostic out of every project.
  • Otherwise it's reported on the node in the project responsible for it:
    • the template argument the property's type came from, when the property is declared from the template parameter (value: T, items: T[]). A property that merely shares the argument's type is not attributed to it;
    • else the spread, is, or intersection operand that composed it in (for A & B & C, the operand it came from).
  • Library-internal declarations the project didn't supply or compose (intrinsics like Array<T>, a template's own members) are still dropped.
model Foo { ...SharedQuery; }               // reported on the spread
op list(...SharedQuery): void;              // reported on the spread
model Foo { w: Wrapper<uuid>; }             // reported on `uuid`
op list is ListOp<Intl & SharedQuery>;      // reported on `SharedQuery`

A rule can still pass an explicit useSite when it knows a better node.

Fixes #12558
Related: #1997, #11861

Impact on azure-rest-api-specs

Measured on all 594 projects at 699308ca6aa (warning-free today, so everything is new):

New warnings Projects
First prototype (walk container + instantiations) ~9,200 507
This PR 617 147
This PR, after 8 library edits in typespec-azure 408 93

The 617 come from just 48 (rule, library declaration) pairs, of two kinds.

Library-owned: 209 warnings from 8 declarations. These need fixing or #suppress in typespec-azure before this ships:

  • arm-no-record on ArmTagsProperty.tags, TrackedResource.tags and userAssignedIdentities (154). Tags are Record by ARM design, so suppress.
  • key-visibility-required on ResourceNameParameter.name, OperationStatus.id and ScopeParameter.scope (49). Add @visibility.
  • arm-resource-name-pattern on PrivateEndpointConnectionParameter.name and PrivateLinkResourceParameter.name (6). Add @pattern.

User-caused: 408 warnings. These are real findings on the user's code:

  • documentation-required (283, 66 projects): every one is in a project that blanks the library doc with @@doc(X.name, ""), e.g. AppService CustomDnsSuffixConfiguration.tsp#L75. It's reported on the spread or argument rather than the @@doc; pointing at the augment is the follow-up tracked in typespec-azure#5445.
  • missing-x-ms-identifiers (76): user item types without identifiers, e.g. is Azure.Core.Page<SkuResource>, ArmResponse<NetworkStatusContractByLocation[]>.
  • no-unknown (17), arm-no-record (12, e.g. ProxyResource<Record<unknown>>), request-body-problem (8), arm-resource-path-segment-invalid-chars and arm-resource-key-invalid-chars (8), no-query-explode (3, the AIGateway operands from Avoid duplicate null check and fix null serialization property name #6066), bad-record-type (1).

Rollout

Even after the library cleanup, upgrading surfaces about 400 warnings in 93 spec projects. The library edits should land first. The spec repo then needs fixes or suppressions, or a staged rollout, before taking this compiler version.

Known limitations

  • Only model properties are resolved; operations, interfaces and extends are not.
  • Only the first responsible node is reported; the rest of the chain isn't rendered as a trace.
  • A diagnostic caused by an augment decorator in the project (@@doc(X, "")) is reported on the composition rather than the augment.

@microsoft-github-policy-service microsoft-github-policy-service Bot added compiler:core Issues for @typespec/compiler eng labels Nov 12, 2026
@timotheeguerin Timothee Guerin (timotheeguerin) added the int:azure-specs Run integration tests against azure-rest-api-specs label Nov 12, 2026
@pkg-pr-new

pkg-pr-new Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/compiler@12560

commit: c26f712

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • ✅ @typespec/compiler
Show changes

@typespec/compiler - feature ✏️

Linter diagnostics on a library declaration are no longer always dropped. When the project is responsible for the declaration being there, the diagnostic is reported on that node instead: the template argument the property's type came from, or the spread, is or intersection operand that composed it in. A library can still #suppress a diagnostic on its own declaration to keep it from being reported in projects.

@azure-sdk-automation

azure-sdk-automation Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler:core Issues for @typespec/compiler eng int:azure-specs Run integration tests against azure-rest-api-specs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linter diagnostics on library-defined model properties are dropped

1 participant