Skip to content

Commit 38c9921

Browse files
crisbetothePunderWoman
authored andcommitted
fix(compiler-cli): signal not invoked diagnostic not raised when input has same name in template (#63754)
The diagnostic that flags signals which haven't been invoked has some logic to skip over inputs, however it was looking at the used directives across the entire template, not the ones on the specific node. Fixes #63739. PR Close #63754
1 parent e0b9ecb commit 38c9921

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

packages/compiler-cli/src/ngtsc/typecheck/extended/checks/interpolated_signal_not_invoked/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@ class InterpolatedSignalCheck extends TemplateCheckWithVisitor<ErrorCode.INTERPO
5454
}
5555
// bound properties like `[prop]="mySignal"`
5656
else if (node instanceof TmplAstBoundAttribute) {
57-
// we skip the check if the node is an input binding
58-
const usedDirectives = ctx.templateTypeChecker.getUsedDirectives(component);
57+
const symbol = ctx.templateTypeChecker.getSymbolOfNode(node, component);
58+
5959
if (
60-
usedDirectives !== null &&
61-
usedDirectives.some((dir) => dir.inputs.getByBindingPropertyName(node.name) !== null)
60+
symbol?.kind === SymbolKind.Input &&
61+
symbol.bindings.length > 0 &&
62+
symbol.bindings.some((binding) => binding.target.kind === SymbolKind.Directive)
6263
) {
6364
return [];
6465
}
66+
6567
// otherwise, we check if the node is
6668
const nodeAst = isPropertyReadNodeAst(node);
6769
if (

packages/compiler-cli/src/ngtsc/typecheck/extended/test/checks/interpolated_signal_not_invoked/interpolated_signal_not_invoked_spec.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,56 @@ runInEachFileSystem(() => {
627627
expect(getSourceCodeForDiagnostic(diags[0])).toBe(`myNestedSignal`);
628628
});
629629

630+
// See https://github.com/angular/angular/issues/63739
631+
it('should produce a warning if the template contains a directive with the same input name, but on a different node', () => {
632+
const fileName = absoluteFrom('/main.ts');
633+
const {program, templateTypeChecker} = setup([
634+
{
635+
fileName,
636+
templates: {
637+
'TestCmp': `<child /> <div [id]="title"></div>`,
638+
},
639+
source: `
640+
import {signal, input} from '@angular/core';
641+
642+
export class Child {
643+
id = input(0);
644+
}
645+
646+
export class TestCmp {
647+
title = signal('');
648+
}`,
649+
declarations: [
650+
{
651+
type: 'directive',
652+
name: 'Child',
653+
selector: 'child',
654+
inputs: {
655+
id: {
656+
isSignal: true,
657+
bindingPropertyName: 'id',
658+
classPropertyName: 'id',
659+
required: false,
660+
transform: null,
661+
},
662+
},
663+
},
664+
],
665+
},
666+
]);
667+
const sf = getSourceFileOrError(program, fileName);
668+
const component = getClass(sf, 'TestCmp');
669+
const extendedTemplateChecker = new ExtendedTemplateCheckerImpl(
670+
templateTypeChecker,
671+
program.getTypeChecker(),
672+
[interpolatedSignalFactory],
673+
{} /* options */,
674+
);
675+
const diags = extendedTemplateChecker.getDiagnosticsForComponent(component);
676+
expect(diags.length).toBe(1);
677+
expect(diags[0].messageText).toBe('title is a function and should be invoked: title()');
678+
});
679+
630680
[
631681
['dom property', 'id'],
632682
['class', 'class.green'],
@@ -640,7 +690,7 @@ runInEachFileSystem(() => {
640690
{
641691
fileName,
642692
templates: {
643-
'TestCmp': `<div [${binding}]="mySignal"></div>
693+
'TestCmp': `<div [${binding}]="mySignal"></div>
644694
<div [${binding}]="!negatedSignal"></div>`,
645695
},
646696
source: `

0 commit comments

Comments
 (0)