microsoft / microsoft/typespec

Linter silently drops diagnostics on library templates instantiated by the user project

Open
#11,861 0 comments 1 reaction 1 assignee Claimed by @timotheeguerin View on GitHub
compiler:core design:needed triaged:core
Dominant language
Java
Stars
5.9k
Forks
394
Avg merge
1d 23h
Merged PRs (30d)
104

Description

### Describe the bug

Linter rules cannot report on library types that only exist because the **user project instantiated a library template**. The diagnostic is created, then silently thrown away.

`createLinterRuleContext.reportDiagnostic` filters on the target's *primary* source location ([`core/linter.ts`](https://github.com/microsoft/typespec/blob/main/packages/compiler/src/core/linter.ts)):

```ts
const context = getLocationContext(program, diagnostic.target);
// Only report diagnostic in the user project.
if (context.type === "project") {
diagnosticCollector.add(diagnostic);
}
```

For a template instantiation, `getLocationContext` → `getSourceLocation` resolves to the template *declaration*, which lives in the library. The template instantiation trace (`getDiagnosticTemplateInstantitationTrace`) that points back at the user's file is never consulted.

The coarse filter is intentional — users shouldn't be blamed for library-internal code. But a template the user instantiated is not library-internal: the type only exists because of the arguments *they* passed, so the diagnostic is actionable.

It's also inconsistent. A plain (non-linter) diagnostic on the exact same target renders fine, with the trace pointing at the user's own line — only linter diagnostics vanish.

### Reproduction

A library declaring `model Wrapper { value: T }` and a rule reporting on properties typed `uuid`:

```tsp
// user project
model Direct { id: uuid; } // ✅ reported
model Instantiated { wrapped: Wrapper; } // ❌ silently dropped
```

Dumping what the linter sees for the two properties the rule fires on:

```
Direct.id: locationContext=project hasTemplateMapper=false -> KEPT
Wrapper.value: locationContext=library hasTemplateMapper=true -> DROPPED
```

Reporting the very same targets as ordinary diagnostics shows the information needed to surface it at the usage site already exists:

```
../lib/lib/main.tsp:14:3 - warning repro-lib/raw-uuid: uuid usage is not recommended.
> 14 | value: T;
main.tsp:21:12 - occurred while instantiating template
> 21 | wrapped: Wrapper;
```

### Real-world impact

Hit while adding an ARM `no-uuid` rule in Azure/typespec-azure#5336: `ResourceNameParameter<..., NameType = Azure.Core.uuid>.name` is generated from a library template, so the rule can never fire on it. In the migration corpus that's 9 UUID resource-name declarations across 6 projects — a permanent blind spot unless rules work around the compiler with bespoke HTTP-projection logic ([discussion](https://github.com/Azure/typespec-azure/pull/5336#discussion_r3931935676)).

### Expected behavior

A linter diagnostic whose target's instantiation trace reaches the user project should be reported, rendered with the instantiation trace — same as plain diagnostics already do.

Narrower follow-up to #1997, which covers the general "show library diagnostics at point of usage" problem.

### Checklist

- [x] Follow our [Code of Conduct](https://github.com/microsoft/typespec/blob/main/CODE_OF_CONDUCT.md)
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.