@@ -38,14 +38,42 @@ namespace ts.codefix {
3838
3939 case SyntaxKind . MethodSignature :
4040 case SyntaxKind . MethodDeclaration :
41+ // The signature for the implementation appears as an entry in `signatures` iff
42+ // there is only one signature.
43+ // If there are overloads and an implementation signature, it appears as an
44+ // extra declaration that isn't a signature for `type`.
45+ // If there is more than one overload but no implementation signature
46+ // (eg: an abstract method or interface declaration), there is a 1-1
47+ // correspondence of declarations and signatures.
4148 const signatures = checker . getSignaturesOfType ( type , SignatureKind . Call ) ;
4249 if ( ! ( signatures && signatures . length > 0 ) ) {
4350 return "" ;
4451 }
45- // TODO: (arozga) Deal with multiple signatures.
46- const sigString = checker . signatureToString ( signatures [ 0 ] , enclosingDeclaration , TypeFormatFlags . SuppressAnyReturnType , SignatureKind . Call ) ;
52+ if ( declarations . length === 1 ) {
53+ Debug . assert ( signatures . length === 1 ) ;
54+ const sigString = checker . signatureToString ( signatures [ 0 ] , enclosingDeclaration , TypeFormatFlags . SuppressAnyReturnType , SignatureKind . Call ) ;
55+ return `${ visibility } ${ name } ${ sigString } ${ getMethodBodyStub ( newlineChar ) } ` ;
56+ }
57+
58+ let result = "" ;
59+ for ( let i = 0 ; i < signatures . length ; i ++ ) {
60+ const sigString = checker . signatureToString ( signatures [ i ] , enclosingDeclaration , TypeFormatFlags . SuppressAnyReturnType , SignatureKind . Call ) ;
61+ result += `${ visibility } ${ name } ${ sigString } ;${ newlineChar } ` ;
62+ }
63+
64+ // If there is a declaration with a body, it is the last declaration,
65+ // and it isn't caught by `getSignaturesOfType`.
66+ let bodySig : Signature | undefined = undefined ;
67+ if ( declarations . length > signatures . length ) {
68+ bodySig = checker . getSignatureFromDeclaration ( declarations [ declarations . length - 1 ] as SignatureDeclaration ) ;
69+ }
70+ else {
71+ bodySig = createBodyDeclarationSignatureWithAnyTypes ( declarations as SignatureDeclaration [ ] , signatures , enclosingDeclaration , checker ) ;
72+ }
73+ const sigString = checker . signatureToString ( bodySig , enclosingDeclaration , TypeFormatFlags . SuppressAnyReturnType , SignatureKind . Call ) ;
74+ result += `${ visibility } ${ name } ${ sigString } ${ getMethodBodyStub ( newlineChar ) } ` ;
4775
48- return ` ${ visibility } ${ name } ${ sigString } ${ getMethodBodyStub ( newlineChar ) } ` ;
76+ return result ;
4977 case SyntaxKind . ComputedPropertyName :
5078 if ( hasDynamicName ( node ) ) {
5179 return "" ;
@@ -59,8 +87,73 @@ namespace ts.codefix {
5987 }
6088 }
6189
90+ function createBodyDeclarationSignatureWithAnyTypes ( signatureDecls : SignatureDeclaration [ ] , signatures : Signature [ ] , enclosingDeclaration : ClassLikeDeclaration , checker : TypeChecker ) : Signature {
91+ Debug . assert ( signatureDecls . length === signatures . length ) ;
92+
93+ const newSignatureDeclaration = createNode ( SyntaxKind . CallSignature ) as SignatureDeclaration ;
94+ newSignatureDeclaration . parent = enclosingDeclaration ;
95+ newSignatureDeclaration . name = signatureDecls [ 0 ] . name ;
96+
97+ let maxArgs = - 1 , maxArgsIndex = 0 ;
98+ let minArgumentCount = signatures [ 0 ] . minArgumentCount ;
99+ let hasRestParameter = false ;
100+ for ( let i = 0 ; i < signatures . length ; i ++ ) {
101+ const sig = signatures [ i ] ;
102+ minArgumentCount = Math . min ( sig . minArgumentCount , minArgumentCount ) ;
103+ if ( sig . parameters . length > maxArgs ) {
104+ maxArgs = sig . parameters . length ;
105+ maxArgsIndex = i ;
106+ }
107+ hasRestParameter = hasRestParameter || sig . hasRestParameter ;
108+ }
109+
110+ const anyTypeNode : TypeNode = createNode ( SyntaxKind . AnyKeyword ) as TypeNode ;
111+ const optionalToken = createToken ( SyntaxKind . QuestionToken ) ;
112+
113+ newSignatureDeclaration . parameters = createNodeArray < ParameterDeclaration > ( ) ;
114+ for ( let i = 0 ; i < maxArgs - 1 ; i ++ ) {
115+ const newParameter = createParameterDeclaration ( i , minArgumentCount , newSignatureDeclaration ) ;
116+ newSignatureDeclaration . parameters . push ( newParameter ) ;
117+ }
118+
119+ const lastParameter = createParameterDeclaration ( maxArgs - 1 , minArgumentCount , newSignatureDeclaration ) ;
120+ if ( hasRestParameter ) {
121+ lastParameter . dotDotDotToken = createToken ( SyntaxKind . DotDotDotToken ) ;
122+
123+ let allMaxArgsAreRest = true ;
124+ for ( const sig of signatures ) {
125+ allMaxArgsAreRest = allMaxArgsAreRest && sig . parameters [ maxArgs - 1 ] && sig . hasRestParameter ;
126+ }
127+ if ( ! allMaxArgsAreRest ) {
128+ const newParameter = createParameterDeclaration ( maxArgs - 1 , minArgumentCount , newSignatureDeclaration ) ;
129+ newSignatureDeclaration . parameters . push ( newParameter ) ;
130+ }
131+ }
132+
133+ newSignatureDeclaration . parameters . push ( lastParameter ) ;
134+
135+ newSignatureDeclaration . type = anyTypeNode ;
136+ newSignatureDeclaration . type . parent = newSignatureDeclaration ;
137+
138+ return checker . getSignatureFromDeclaration ( newSignatureDeclaration ) ;
139+
140+ function createParameterDeclaration ( index : number , minArgCount : number , enclosingSignature : SignatureDeclaration ) : ParameterDeclaration {
141+ const newParameter = createNode ( SyntaxKind . Parameter ) as ParameterDeclaration ;
142+ newParameter . symbol = checker . createSymbol ( SymbolFlags . FunctionScopedVariable , "arg" + index ) ;
143+ newParameter . symbol . valueDeclaration = newParameter ;
144+ newParameter . symbol . declarations = [ newParameter ] ;
145+ newParameter . type = anyTypeNode ;
146+ newParameter . parent = enclosingSignature ;
147+ if ( index >= minArgCount ) {
148+ newParameter . questionToken = optionalToken ;
149+ }
150+
151+ return newParameter ;
152+ }
153+ }
154+
62155 function getMethodBodyStub ( newLineChar : string ) {
63- return `{${ newLineChar } throw new Error('Method not implemented.');${ newLineChar } }${ newLineChar } ` ;
156+ return ` {${ newLineChar } throw new Error('Method not implemented.');${ newLineChar } }${ newLineChar } ` ;
64157 }
65158
66159 function getVisibilityPrefix ( flags : ModifierFlags ) : string {
0 commit comments