@@ -19,7 +19,7 @@ use ide_db::{
19
19
} ;
20
20
use itertools:: { Itertools , izip} ;
21
21
use syntax:: {
22
- AstNode , NodeOrToken , SyntaxKind ,
22
+ AstNode , NodeOrToken , SyntaxKind , SyntaxToken ,
23
23
ast:: {
24
24
self , HasArgList , HasGenericArgs , Pat , PathExpr , edit:: IndentLevel , edit_in_place:: Indent ,
25
25
} ,
@@ -311,6 +311,80 @@ fn get_fn_params(
311
311
Some ( params)
312
312
}
313
313
314
+ fn is_self_in_expression_context ( self_token : & SyntaxToken ) -> bool {
315
+ let mut current = self_token. parent ( ) ;
316
+ while let Some ( node) = current {
317
+ // Check for function call expressions: Self::method() or Self(...)
318
+ if let Some ( call_expr) = ast:: CallExpr :: cast ( node. clone ( ) ) {
319
+ if let Some ( expr) = call_expr. expr ( ) {
320
+ if expr. syntax ( ) . text_range ( ) . contains_range ( self_token. text_range ( ) ) {
321
+ return true ;
322
+ }
323
+ }
324
+ }
325
+
326
+ if let Some ( method_call) = ast:: MethodCallExpr :: cast ( node. clone ( ) ) {
327
+ if let Some ( receiver) = method_call. receiver ( ) {
328
+ if receiver. syntax ( ) . text_range ( ) . contains_range ( self_token. text_range ( ) ) {
329
+ return true ;
330
+ }
331
+ }
332
+ }
333
+
334
+ if let Some ( _path_expr) = ast:: PathExpr :: cast ( node. clone ( ) ) {
335
+ return true ;
336
+ }
337
+
338
+ // Check for record expressions (struct construction)
339
+ if let Some ( record_expr) = ast:: RecordExpr :: cast ( node. clone ( ) ) {
340
+ if let Some ( path) = record_expr. path ( ) {
341
+ if path. syntax ( ) . text_range ( ) . contains_range ( self_token. text_range ( ) ) {
342
+ return true ;
343
+ }
344
+ }
345
+ }
346
+
347
+ // Stop at certain boundaries (type/pattern contexts)
348
+ if ast:: Type :: cast ( node. clone ( ) ) . is_some ( )
349
+ || ast:: Pat :: cast ( node. clone ( ) ) . is_some ( )
350
+ || ast:: RetType :: cast ( node. clone ( ) ) . is_some ( )
351
+ {
352
+ return false ;
353
+ }
354
+
355
+ current = node. parent ( ) ;
356
+ }
357
+ false
358
+ }
359
+
360
+ fn get_qualified_type_for_turbofish ( ty : & ast:: Type ) -> String {
361
+ match ty {
362
+ ast:: Type :: PathType ( path_type) => {
363
+ if let Some ( path) = path_type. path ( ) {
364
+ // For turbofish, we need the full path but potentially without generic args
365
+ // depending on context. For now, use the bare name.
366
+ if let Some ( segment) = path. segments ( ) . last ( ) {
367
+ if let Some ( name) = segment. name_ref ( ) {
368
+ return name. text ( ) . to_string ( ) ;
369
+ }
370
+ }
371
+ }
372
+ }
373
+ _ => { }
374
+ }
375
+ ty. syntax ( ) . text ( ) . to_string ( )
376
+ }
377
+
378
+ fn have_same_self_type ( source_impl : & ast:: Impl , target_impl : & ast:: Impl ) -> bool {
379
+ match ( source_impl. self_ty ( ) , target_impl. self_ty ( ) ) {
380
+ ( Some ( source_ty) , Some ( target_ty) ) => {
381
+ // Compare the textual representation of the types
382
+ source_ty. syntax ( ) . text ( ) == target_ty. syntax ( ) . text ( )
383
+ }
384
+ _ => false ,
385
+ }
386
+ }
387
+
314
388
fn inline (
315
389
sema : & Semantics < ' _ , RootDatabase > ,
316
390
function_def_file_id : EditionedFileId ,
@@ -391,22 +465,46 @@ fn inline(
391
465
// We should place the following code after last usage of `usages_for_locals`
392
466
// because `ted::replace` will change the offset in syntax tree, which makes
393
467
// `FileReference` incorrect
394
- if let Some ( imp ) =
468
+ if let Some ( source_impl ) =
395
469
sema. ancestors_with_macros ( fn_body. syntax ( ) . clone ( ) ) . find_map ( ast:: Impl :: cast)
396
470
{
397
- if !node. syntax ( ) . ancestors ( ) . any ( |anc| & anc == imp. syntax ( ) ) {
398
- if let Some ( t) = imp. self_ty ( ) {
399
- while let Some ( self_tok) = body
471
+ // Check if the target (call site) is also in an impl block
472
+ let target_impl = node. syntax ( ) . ancestors ( ) . find_map ( ast:: Impl :: cast) ;
473
+
474
+ let should_replace_self = match target_impl {
475
+ Some ( target_impl) => {
476
+ // Both source and target are in impl blocks
477
+ // Only replace Self if they have different Self types
478
+ !have_same_self_type ( & source_impl, & target_impl)
479
+ }
480
+ None => {
481
+ // Target is not in an impl block, so we must replace Self
482
+ true
483
+ }
484
+ } ;
485
+
486
+ if should_replace_self {
487
+ if let Some ( self_ty) = source_impl. self_ty ( ) {
488
+ let self_tokens: Vec < _ > = body
400
489
. syntax ( )
401
490
. descendants_with_tokens ( )
402
491
. filter_map ( NodeOrToken :: into_token)
403
- . find ( |tok| tok. kind ( ) == SyntaxKind :: SELF_TYPE_KW )
404
- {
405
- let replace_with = t. clone_subtree ( ) . syntax ( ) . clone_for_update ( ) ;
406
- ted:: replace ( self_tok, replace_with) ;
492
+ . filter ( |tok| tok. kind ( ) == SyntaxKind :: SELF_TYPE_KW )
493
+ . collect ( ) ;
494
+
495
+ // Replace each Self token based on its context
496
+ for self_tok in self_tokens {
497
+ let replacement = if is_self_in_expression_context ( & self_tok) {
498
+ let qualified_name = get_qualified_type_for_turbofish ( & self_ty) ;
499
+ make:: name_ref ( & qualified_name) . syntax ( ) . clone_for_update ( )
500
+ } else {
501
+ self_ty. clone_subtree ( ) . syntax ( ) . clone_for_update ( )
502
+ } ;
503
+ ted:: replace ( self_tok, replacement) ;
407
504
}
408
505
}
409
506
}
507
+ // If same Self type context, leave Self as-is (it remains valid)
410
508
}
411
509
412
510
let mut func_let_vars: BTreeSet < String > = BTreeSet :: new ( ) ;
@@ -1832,4 +1930,72 @@ fn f() {
1832
1930
"# ,
1833
1931
) ;
1834
1932
}
1933
+
1934
+ #[ test]
1935
+ fn inline_call_generic_self_constructor ( ) {
1936
+ check_assist (
1937
+ inline_call,
1938
+ r#"
1939
+ struct Generic<T>(T);
1940
+
1941
+ impl<T> Generic<T> {
1942
+ fn new(value: T) -> Self {
1943
+ Self(value)
1944
+ }
1945
+ }
1946
+
1947
+ fn main() {
1948
+ let x = Generic::<i32>::new$0(42);
1949
+ }
1950
+ "# ,
1951
+ r#"
1952
+ struct Generic<T>(T);
1953
+
1954
+ impl<T> Generic<T> {
1955
+ fn new(value: T) -> Self {
1956
+ Self(value)
1957
+ }
1958
+ }
1959
+
1960
+ fn main() {
1961
+ let x = Generic(42);
1962
+ }
1963
+ "# ,
1964
+ )
1965
+ }
1966
+
1967
+ #[ test]
1968
+ fn inline_call_generic_self_type_position ( ) {
1969
+ check_assist (
1970
+ inline_call,
1971
+ r#"
1972
+ struct Generic<T>(T);
1973
+
1974
+ impl<T> Generic<T> {
1975
+ fn identity(self) -> Self {
1976
+ self
1977
+ }
1978
+ }
1979
+
1980
+ fn main() {
1981
+ let x = Generic(42);
1982
+ let y = x.identity$0();
1983
+ }
1984
+ "# ,
1985
+ r#"
1986
+ struct Generic<T>(T);
1987
+
1988
+ impl<T> Generic<T> {
1989
+ fn identity(self) -> Self {
1990
+ self
1991
+ }
1992
+ }
1993
+
1994
+ fn main() {
1995
+ let x = Generic(42);
1996
+ let y = x;
1997
+ }
1998
+ "# ,
1999
+ )
2000
+ }
1835
2001
}
0 commit comments