@@ -97,7 +97,7 @@ function parseFileContent(filename: string, content: string): GoTest | undefined
97
97
}
98
98
99
99
function getTestInput ( content : string ) : string {
100
- const lines = content . split ( "\n" ) ;
100
+ const lines = content . split ( "\n" ) . map ( line => line . endsWith ( "\r" ) ? line . slice ( 0 , - 1 ) : line ) ;
101
101
let testInput : string [ ] = [ ] ;
102
102
for ( const line of lines ) {
103
103
let newLine = "" ;
@@ -118,7 +118,14 @@ function getTestInput(content: string): string {
118
118
}
119
119
120
120
// chomp leading spaces
121
- if ( ! testInput . some ( line => line . length != 0 && ! line . startsWith ( " " ) && ! line . startsWith ( "// " ) ) ) {
121
+ if (
122
+ ! testInput . some ( line =>
123
+ line . length != 0 &&
124
+ ! line . startsWith ( " " ) &&
125
+ ! line . startsWith ( "// " ) &&
126
+ ! line . startsWith ( "//@" )
127
+ )
128
+ ) {
122
129
testInput = testInput . map ( line => {
123
130
if ( line . startsWith ( " " ) ) return line . substring ( 1 ) ;
124
131
return line ;
@@ -182,6 +189,13 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined {
182
189
// - `verify.baselineGetDefinitionAtPosition(...)` called getDefinitionAtPosition
183
190
// LSP doesn't have two separate commands though. It's unclear how we would model bound spans though.
184
191
return parseBaselineGoToDefinitionArgs ( callExpression . arguments ) ;
192
+ case "baselineRename" :
193
+ case "baselineRenameAtRangesWithText" :
194
+ // `verify.baselineRename...(...)`
195
+ return parseBaselineRenameArgs ( func . text , callExpression . arguments ) ;
196
+ case "renameInfoSucceeded" :
197
+ case "renameInfoFailed" :
198
+ return parseRenameInfo ( func . text , callExpression . arguments ) ;
185
199
}
186
200
}
187
201
// `goTo....`
@@ -793,6 +807,151 @@ function parseBaselineGoToDefinitionArgs(args: readonly ts.Expression[]): [Verif
793
807
} ] ;
794
808
}
795
809
810
+ function parseRenameInfo ( funcName : "renameInfoSucceeded" | "renameInfoFailed" , args : readonly ts . Expression [ ] ) : [ VerifyRenameInfoCmd ] | undefined {
811
+ let preferences = "nil /*preferences*/" ;
812
+ let prefArg ;
813
+ switch ( funcName ) {
814
+ case "renameInfoSucceeded" :
815
+ if ( args [ 6 ] ) {
816
+ prefArg = args [ 6 ] ;
817
+ }
818
+ break ;
819
+ case "renameInfoFailed" :
820
+ if ( args [ 1 ] ) {
821
+ prefArg = args [ 1 ] ;
822
+ }
823
+ break ;
824
+ }
825
+ if ( prefArg ) {
826
+ if ( ! ts . isObjectLiteralExpression ( prefArg ) ) {
827
+ console . error ( `Expected object literal expression for preferences, got ${ prefArg . getText ( ) } ` ) ;
828
+ return undefined ;
829
+ }
830
+ const parsedPreferences = parseUserPreferences ( prefArg ) ;
831
+ if ( ! parsedPreferences ) {
832
+ console . error ( `Unrecognized user preferences in ${ funcName } : ${ prefArg . getText ( ) } ` ) ;
833
+ return undefined ;
834
+ }
835
+ }
836
+ return [ { kind : funcName , preferences } ] ;
837
+ }
838
+
839
+ function parseBaselineRenameArgs ( funcName : string , args : readonly ts . Expression [ ] ) : [ VerifyBaselineRenameCmd ] | undefined {
840
+ let newArgs : string [ ] = [ ] ;
841
+ let preferences : string | undefined ;
842
+ for ( const arg of args ) {
843
+ let typedArg ;
844
+ if ( ( typedArg = getArrayLiteralExpression ( arg ) ) ) {
845
+ for ( const elem of typedArg . elements ) {
846
+ const newArg = parseBaselineRenameArg ( elem ) ;
847
+ if ( ! newArg ) {
848
+ return undefined ;
849
+ }
850
+ newArgs . push ( newArg ) ;
851
+ }
852
+ }
853
+ else if ( ts . isObjectLiteralExpression ( arg ) ) {
854
+ preferences = parseUserPreferences ( arg ) ;
855
+ if ( ! preferences ) {
856
+ console . error ( `Unrecognized user preferences in verify.baselineRename: ${ arg . getText ( ) } ` ) ;
857
+ return undefined ;
858
+ }
859
+ continue ;
860
+ }
861
+ else if ( typedArg = parseBaselineRenameArg ( arg ) ) {
862
+ newArgs . push ( typedArg ) ;
863
+ }
864
+ else {
865
+ return undefined ;
866
+ }
867
+ }
868
+ return [ {
869
+ kind : funcName === "baselineRenameAtRangesWithText" ? "verifyBaselineRenameAtRangesWithText" : "verifyBaselineRename" ,
870
+ args : newArgs ,
871
+ preferences : preferences ? preferences : "nil /*preferences*/" ,
872
+ } ] ;
873
+ }
874
+
875
+ function parseUserPreferences ( arg : ts . ObjectLiteralExpression ) : string | undefined {
876
+ const preferences : string [ ] = [ ] ;
877
+ for ( const prop of arg . properties ) {
878
+ if ( ts . isPropertyAssignment ( prop ) ) {
879
+ switch ( prop . name . getText ( ) ) {
880
+ // !!! other preferences
881
+ case "providePrefixAndSuffixTextForRename" :
882
+ preferences . push ( `UseAliasesForRename: PtrTo(${ prop . initializer . getText ( ) } )` ) ;
883
+ break ;
884
+ case "quotePreference" :
885
+ preferences . push ( `QuotePreference: PtrTo(ls.QuotePreference(${ prop . initializer . getText ( ) } ))` ) ;
886
+ break ;
887
+ }
888
+ }
889
+ else {
890
+ return undefined ;
891
+ }
892
+ }
893
+ if ( preferences . length === 0 ) {
894
+ return "nil /*preferences*/" ;
895
+ }
896
+ return `&ls.UserPreferences{${ preferences . join ( "," ) } }` ;
897
+ }
898
+
899
+ function parseBaselineRenameArg ( arg : ts . Expression ) : string | undefined {
900
+ if ( ts . isStringLiteral ( arg ) ) {
901
+ return getGoStringLiteral ( arg . text ) ;
902
+ }
903
+ else if ( ts . isIdentifier ( arg ) || ( ts . isElementAccessExpression ( arg ) && ts . isIdentifier ( arg . expression ) ) ) {
904
+ const argName = ts . isIdentifier ( arg ) ? arg . text : ( arg . expression as ts . Identifier ) . text ;
905
+ const file = arg . getSourceFile ( ) ;
906
+ const varStmts = file . statements . filter ( ts . isVariableStatement ) ;
907
+ for ( const varStmt of varStmts ) {
908
+ for ( const decl of varStmt . declarationList . declarations ) {
909
+ if ( ts . isArrayBindingPattern ( decl . name ) && decl . initializer ?. getText ( ) . includes ( "ranges" ) ) {
910
+ for ( let i = 0 ; i < decl . name . elements . length ; i ++ ) {
911
+ const elem = decl . name . elements [ i ] ;
912
+ if ( ts . isBindingElement ( elem ) && ts . isIdentifier ( elem . name ) && elem . name . text === argName ) {
913
+ // `const [range_0, ..., range_n, ...] = test.ranges();` and arg is `range_n`
914
+ if ( elem . dotDotDotToken === undefined ) {
915
+ return `f.Ranges()[${ i } ]` ;
916
+ }
917
+ // `const [range_0, ..., ...rest] = test.ranges();` and arg is `rest[n]`
918
+ if ( ts . isElementAccessExpression ( arg ) ) {
919
+ return `f.Ranges()[${ i + parseInt ( arg . argumentExpression ! . getText ( ) ) } ]` ;
920
+ }
921
+ // `const [range_0, ..., ...rest] = test.ranges();` and arg is `rest`
922
+ return `ToAny(f.Ranges()[${ i } :])...` ;
923
+ }
924
+ }
925
+ }
926
+ }
927
+ }
928
+ const init = getNodeOfKind ( arg , ts . isCallExpression ) ;
929
+ if ( init ) {
930
+ const result = getRangesByTextArg ( init ) ;
931
+ if ( result ) {
932
+ return result ;
933
+ }
934
+ }
935
+ }
936
+ else if ( ts . isCallExpression ( arg ) ) {
937
+ const result = getRangesByTextArg ( arg ) ;
938
+ if ( result ) {
939
+ return result ;
940
+ }
941
+ }
942
+ console . error ( `Unrecognized argument in verify.baselineRename: ${ arg . getText ( ) } ` ) ;
943
+ return undefined ;
944
+ }
945
+
946
+ function getRangesByTextArg ( arg : ts . CallExpression ) : string | undefined {
947
+ if ( arg . getText ( ) . startsWith ( "test.rangesByText()" ) ) {
948
+ if ( ts . isStringLiteralLike ( arg . arguments [ 0 ] ) ) {
949
+ return `ToAny(f.GetRangesByText().Get(${ getGoStringLiteral ( arg . arguments [ 0 ] . text ) } ))...` ;
950
+ }
951
+ }
952
+ return undefined ;
953
+ }
954
+
796
955
function parseBaselineQuickInfo ( args : ts . NodeArray < ts . Expression > ) : VerifyBaselineQuickInfoCmd {
797
956
if ( args . length !== 0 ) {
798
957
// All calls are currently empty!
@@ -1097,6 +1256,12 @@ interface VerifyBaselineSignatureHelpCmd {
1097
1256
kind : "verifyBaselineSignatureHelp" ;
1098
1257
}
1099
1258
1259
+ interface VerifyBaselineRenameCmd {
1260
+ kind : "verifyBaselineRename" | "verifyBaselineRenameAtRangesWithText" ;
1261
+ args : string [ ] ;
1262
+ preferences : string ;
1263
+ }
1264
+
1100
1265
interface GoToCmd {
1101
1266
kind : "goTo" ;
1102
1267
// !!! `selectRange` and `rangeStart` require parsing variables and `test.ranges()[n]`
@@ -1116,6 +1281,11 @@ interface VerifyQuickInfoCmd {
1116
1281
docs ?: string ;
1117
1282
}
1118
1283
1284
+ interface VerifyRenameInfoCmd {
1285
+ kind : "renameInfoSucceeded" | "renameInfoFailed" ;
1286
+ preferences : string ;
1287
+ }
1288
+
1119
1289
type Cmd =
1120
1290
| VerifyCompletionsCmd
1121
1291
| VerifyBaselineFindAllReferencesCmd
@@ -1124,7 +1294,9 @@ type Cmd =
1124
1294
| VerifyBaselineSignatureHelpCmd
1125
1295
| GoToCmd
1126
1296
| EditCmd
1127
- | VerifyQuickInfoCmd ;
1297
+ | VerifyQuickInfoCmd
1298
+ | VerifyBaselineRenameCmd
1299
+ | VerifyRenameInfoCmd ;
1128
1300
1129
1301
function generateVerifyCompletions ( { marker, args, isNewIdentifierLocation } : VerifyCompletionsCmd ) : string {
1130
1302
let expectedList : string ;
@@ -1185,6 +1357,15 @@ function generateQuickInfoCommand({ kind, marker, text, docs }: VerifyQuickInfoC
1185
1357
}
1186
1358
}
1187
1359
1360
+ function generateBaselineRename ( { kind, args, preferences } : VerifyBaselineRenameCmd ) : string {
1361
+ switch ( kind ) {
1362
+ case "verifyBaselineRename" :
1363
+ return `f.VerifyBaselineRename(t, ${ preferences } , ${ args . join ( ", " ) } )` ;
1364
+ case "verifyBaselineRenameAtRangesWithText" :
1365
+ return `f.VerifyBaselineRenameAtRangesWithText(t, ${ preferences } , ${ args . join ( ", " ) } )` ;
1366
+ }
1367
+ }
1368
+
1188
1369
function generateCmd ( cmd : Cmd ) : string {
1189
1370
switch ( cmd . kind ) {
1190
1371
case "verifyCompletions" :
@@ -1207,6 +1388,13 @@ function generateCmd(cmd: Cmd): string {
1207
1388
case "quickInfoExists" :
1208
1389
case "notQuickInfoExists" :
1209
1390
return generateQuickInfoCommand ( cmd ) ;
1391
+ case "verifyBaselineRename" :
1392
+ case "verifyBaselineRenameAtRangesWithText" :
1393
+ return generateBaselineRename ( cmd ) ;
1394
+ case "renameInfoSucceeded" :
1395
+ return `f.VerifyRenameSucceeded(t, ${ cmd . preferences } )` ;
1396
+ case "renameInfoFailed" :
1397
+ return `f.VerifyRenameFailed(t, ${ cmd . preferences } )` ;
1210
1398
default :
1211
1399
let neverCommand : never = cmd ;
1212
1400
throw new Error ( `Unknown command kind: ${ neverCommand as Cmd [ "kind" ] } ` ) ;
@@ -1267,7 +1455,8 @@ function usesHelper(goTxt: string): boolean {
1267
1455
}
1268
1456
return goTxt . includes ( "Ignored" )
1269
1457
|| goTxt . includes ( "DefaultCommitCharacters" )
1270
- || goTxt . includes ( "PtrTo" ) ;
1458
+ || goTxt . includes ( "PtrTo" )
1459
+ || goTxt . includes ( "ToAny" ) ;
1271
1460
}
1272
1461
1273
1462
function getNodeOfKind < T extends ts . Node > ( node : ts . Node , hasKind : ( n : ts . Node ) => n is T ) : T | undefined {
0 commit comments