@@ -26,7 +26,7 @@ const signatureErrorDiagnostics = [
26
26
] ;
27
27
28
28
/** List of classes of which the constructor signature has changed. */
29
- const signatureChangedClasses = getAllChanges ( constructorChecks ) ;
29
+ const signatureChangeData = getAllChanges ( constructorChecks ) ;
30
30
31
31
/**
32
32
* Rule that visits every TypeScript new expression or super call and checks if the parameter
@@ -64,9 +64,19 @@ function visitSourceFile(context: WalkContext<null>, program: ts.Program) {
64
64
const className = classType . symbol && classType . symbol . name ;
65
65
const isNewExpression = ts . isNewExpression ( node ) ;
66
66
67
- // TODO(devversion): Consider handling pass-through classes better.
68
- // TODO(devversion): e.g. `export class CustomCalendar extends MatCalendar {}`
69
- if ( ! signatureChangedClasses . includes ( className ) ) {
67
+ // Determine the class names of the actual construct signatures because we cannot assume
68
+ // that the diagnostic refers to a constructor of the actual expression. In case the constructor
69
+ // is inherited, we need to detect that the owner-class of the constructor is added to the
70
+ // constructor checks upgrade data. e.g. `class CustomCalendar extends MatCalendar {}`.
71
+ const signatureClassNames = classType . getConstructSignatures ( )
72
+ . map ( signature => getClassDeclarationOfSignature ( signature ) )
73
+ . map ( declaration => declaration && declaration . name ? declaration . name . text : null )
74
+ . filter ( Boolean ) ;
75
+
76
+ // Besides checking the signature class names, we need to check the actual class name because
77
+ // there can be classes without an explicit constructor.
78
+ if ( ! signatureChangeData . includes ( className ) &&
79
+ ! signatureClassNames . some ( name => signatureChangeData . includes ( name ! ) ) ) {
70
80
continue ;
71
81
}
72
82
@@ -120,3 +130,22 @@ function findConstructorNode(diagnostic: ts.Diagnostic, sourceFile: ts.SourceFil
120
130
121
131
return resolvedNode ;
122
132
}
133
+
134
+ /** Determines the class declaration of the specified construct signature. */
135
+ function getClassDeclarationOfSignature ( signature : ts . Signature ) : ts . ClassDeclaration | null {
136
+ let node : ts . Node = signature . getDeclaration ( ) ;
137
+
138
+ // Handle signatures which don't have an actual declaration. This happens if a class
139
+ // does not have an explicitly written constructor.
140
+ if ( ! node ) {
141
+ return null ;
142
+ }
143
+
144
+ while ( ! ts . isSourceFile ( node = node . parent ) ) {
145
+ if ( ts . isClassDeclaration ( node ) ) {
146
+ return node ;
147
+ }
148
+ }
149
+
150
+ return null ;
151
+ }
0 commit comments