diff --git a/.chronus/changes/tcgc-fixPathInOverride-2026-5-16-15-19-10.md b/.chronus/changes/tcgc-fixPathInOverride-2026-5-16-15-19-10.md new file mode 100644 index 0000000000..404cc64296 --- /dev/null +++ b/.chronus/changes/tcgc-fixPathInOverride-2026-5-16-15-19-10.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@azure-tools/typespec-client-generator-core" +--- + +Verify all `@path` parameters are present in override \ No newline at end of file diff --git a/packages/typespec-client-generator-core/src/decorators.ts b/packages/typespec-client-generator-core/src/decorators.ts index 9d09ce095a..9c31032c76 100644 --- a/packages/typespec-client-generator-core/src/decorators.ts +++ b/packages/typespec-client-generator-core/src/decorators.ts @@ -32,6 +32,7 @@ import { getServers, isBody, isBodyRoot, + isPathParam, } from "@typespec/http"; import { getVersion, resolveVersions, type Version } from "@typespec/versioning"; import { @@ -749,6 +750,24 @@ export const $override = ( } } + // Warn if original param has @path but override param doesn't, + // unless any override param has @clientLocation (indicating an intentional customization + // where non-path params are just pass-throughs) + if ( + isPathParam(context.program, originalParam) && + !isPathParam(context.program, overrideParams[index]) && + !overrideParams.some((p) => p.decorators.some((d) => d.decorator.name === "$clientLocation")) + ) { + reportDiagnostic(context.program, { + code: "override-parameters-mismatch", + target: context.decoratorTarget, + format: { + methodName: original.name, + checkParameter: overrideParams[index].name, + }, + }); + } + // Apply the alternate type to the original parameter const overrideParam = overrideParams[index]; overrideParam.decorators diff --git a/packages/typespec-client-generator-core/src/http.ts b/packages/typespec-client-generator-core/src/http.ts index 5177d91457..94f3725455 100644 --- a/packages/typespec-client-generator-core/src/http.ts +++ b/packages/typespec-client-generator-core/src/http.ts @@ -417,6 +417,7 @@ function getSdkHttpParameters( (segment) => segment[segment.length - 1], ); } + return diagnostics.wrap(retval); } diff --git a/packages/typespec-client-generator-core/test/decorators/override.test.ts b/packages/typespec-client-generator-core/test/decorators/override.test.ts index e2e26cdc63..8db4329c23 100644 --- a/packages/typespec-client-generator-core/test/decorators/override.test.ts +++ b/packages/typespec-client-generator-core/test/decorators/override.test.ts @@ -547,6 +547,30 @@ it("remove optional query param and add secret name", async () => { strictEqual(maxResultsParam.name, "maxresults"); }); +it("reports diagnostic when override parameter is missing @path", async () => { + const [_, diagnostics] = await SimpleBaseTester.compileAndDiagnose( + createClientCustomizationInput( + ` + @service + namespace MyService; + + @route("/items/{itemId}") + op getItem(@path itemId: string): void; + `, + ` + namespace MyCustomizations; + + op getItemOverride(itemId: string): void; + + @@override(MyService.getItem, MyCustomizations.getItemOverride); + `, + ), + ); + expectDiagnostics(diagnostics, { + code: "@azure-tools/typespec-client-generator-core/override-parameters-mismatch", + }); +}); + describe("@clientName", () => { it("original method", async () => { const { program } = await SimpleBaseTester.compile(