@@ -2168,8 +2168,9 @@ impl AnonymousInstance {
21682168 values : captures,
21692169 identity : candidate. identity . as_ref ( ) ,
21702170 value_types,
2171+ substitute_this : true ,
21712172 }
2172- . rewrite_anonymous_body ( & mut body) ;
2173+ . rewrite_root_anonymous_body ( & mut body) ;
21732174 if let Some ( identity) = candidate. identity . as_ref ( ) {
21742175 AnonymousIdentitySubstitution { identity } . rewrite_anonymous_body ( & mut body) ;
21752176 }
@@ -2655,9 +2656,19 @@ struct CaptureSubstitution<'a> {
26552656 values : BTreeMap < JavaIdentifier , JavaExpr > ,
26562657 identity : Option < & ' a JavaType > ,
26572658 value_types : & ' a BTreeMap < JavaIdentifier , LexicalValueType > ,
2659+ // A nested anonymous body's `this` owns a separate field namespace. Its
2660+ // explicit QualifiedThis references can still target this capture owner.
2661+ substitute_this : bool ,
26582662}
26592663
26602664impl JavaAstRewriter for CaptureSubstitution < ' _ > {
2665+ fn rewrite_anonymous_body ( & mut self , body : & mut JavaAnonymousClassBody ) {
2666+ let substitute_this = self . substitute_this ;
2667+ self . substitute_this = false ;
2668+ self . rewrite_anonymous_members ( body) ;
2669+ self . substitute_this = substitute_this;
2670+ }
2671+
26612672 fn finish_expression ( & mut self , expression : JavaExpr ) -> JavaExpr {
26622673 match expression {
26632674 JavaExpr :: Cast { ty, value }
@@ -2668,7 +2679,7 @@ impl JavaAstRewriter for CaptureSubstitution<'_> {
26682679 * value
26692680 }
26702681 JavaExpr :: Field { owner, name }
2671- if matches ! ( owner. as_ref( ) , JavaExpr :: This )
2682+ if self . substitute_this && matches ! ( owner. as_ref( ) , JavaExpr :: This )
26722683 || matches ! (
26732684 ( owner. as_ref( ) , self . identity) ,
26742685 ( JavaExpr :: QualifiedThis ( owner) , Some ( identity) ) if owner == identity
@@ -2685,6 +2696,36 @@ impl JavaAstRewriter for CaptureSubstitution<'_> {
26852696}
26862697
26872698impl CaptureSubstitution < ' _ > {
2699+ fn rewrite_root_anonymous_body ( & mut self , body : & mut JavaAnonymousClassBody ) {
2700+ self . rewrite_anonymous_members ( body) ;
2701+ }
2702+
2703+ fn rewrite_anonymous_members ( & mut self , body : & mut JavaAnonymousClassBody ) {
2704+ for field in & mut body. fields {
2705+ self . rewrite_annotations ( & mut field. annotations ) ;
2706+ field. initializer = field
2707+ . initializer
2708+ . take ( )
2709+ . map ( |value| self . rewrite_expression ( value) ) ;
2710+ }
2711+ for method in & mut body. methods {
2712+ self . rewrite_annotations ( & mut method. annotations ) ;
2713+ for parameter in & mut method. parameters {
2714+ self . rewrite_annotations ( & mut parameter. annotations ) ;
2715+ }
2716+ if let Some ( body) = & mut method. body {
2717+ self . rewrite_body ( body) ;
2718+ }
2719+ }
2720+ let substitute_this = self . substitute_this ;
2721+ self . substitute_this = false ;
2722+ for nested in & mut body. nested {
2723+ self . rewrite_type_declaration ( nested) ;
2724+ }
2725+ self . substitute_this = substitute_this;
2726+ self . finish_anonymous_body ( body) ;
2727+ }
2728+
26882729 fn capture_type ( & self , expression : & JavaExpr ) -> Option < & LexicalValueType > {
26892730 match expression {
26902731 JavaExpr :: Name ( name) if self . values . values ( ) . any ( |captured| captured == expression) => {
@@ -2705,3 +2746,80 @@ impl CaptureSubstitution<'_> {
27052746 }
27062747 }
27072748}
2749+
2750+ #[ cfg( test) ]
2751+ mod capture_substitution_tests {
2752+ use super :: * ;
2753+ use crate :: language:: java:: JavaFieldDeclaration ;
2754+
2755+ fn field ( name : & str , initializer : JavaExpr ) -> JavaFieldDeclaration {
2756+ JavaFieldDeclaration {
2757+ annotations : Vec :: new ( ) ,
2758+ modifiers : Vec :: new ( ) ,
2759+ ty : JavaType :: Class ( JavaClassType :: from_source ( "java.lang.Object" ) ) ,
2760+ name : JavaIdentifier :: from_dex ( name) ,
2761+ initializer : Some ( initializer) ,
2762+ }
2763+ }
2764+
2765+ #[ test]
2766+ fn captured_field_substitution_stops_at_nested_anonymous_body ( ) {
2767+ let captured = JavaIdentifier :: from_dex ( "captured" ) ;
2768+ let direct_reference = JavaExpr :: Field {
2769+ owner : Box :: new ( JavaExpr :: This ) ,
2770+ name : captured. clone ( ) ,
2771+ } ;
2772+ let nested_reference = direct_reference. clone ( ) ;
2773+ let identity = JavaType :: Class ( JavaClassType :: from_source ( "example.ParentAnonymous" ) ) ;
2774+ let enclosing_reference = JavaExpr :: Field {
2775+ owner : Box :: new ( JavaExpr :: QualifiedThis ( identity. clone ( ) ) ) ,
2776+ name : captured. clone ( ) ,
2777+ } ;
2778+ let nested_body = JavaAnonymousClassBody {
2779+ fields : vec ! [
2780+ field( "nestedUse" , nested_reference. clone( ) ) ,
2781+ field( "enclosingUse" , enclosing_reference) ,
2782+ ] ,
2783+ methods : Vec :: new ( ) ,
2784+ nested : Vec :: new ( ) ,
2785+ } ;
2786+ let mut body = JavaAnonymousClassBody {
2787+ fields : vec ! [
2788+ field( "directUse" , direct_reference) ,
2789+ field(
2790+ "nested" ,
2791+ JavaExpr :: New {
2792+ enclosing: None ,
2793+ ty: JavaType :: Class ( JavaClassType :: from_source( "example.Listener" ) ) ,
2794+ target_type: None ,
2795+ args: Vec :: new( ) ,
2796+ anonymous_body: Some ( Box :: new( nested_body) ) ,
2797+ } ,
2798+ ) ,
2799+ ] ,
2800+ methods : Vec :: new ( ) ,
2801+ nested : Vec :: new ( ) ,
2802+ } ;
2803+ let replacement = JavaExpr :: Name ( JavaIdentifier :: from_dex ( "value" ) ) ;
2804+ let value_types = BTreeMap :: new ( ) ;
2805+
2806+ CaptureSubstitution {
2807+ values : BTreeMap :: from ( [ ( captured, replacement. clone ( ) ) ] ) ,
2808+ identity : Some ( & identity) ,
2809+ value_types : & value_types,
2810+ substitute_this : true ,
2811+ }
2812+ . rewrite_root_anonymous_body ( & mut body) ;
2813+
2814+ assert_eq ! ( body. fields[ 0 ] . initializer, Some ( replacement. clone( ) ) ) ;
2815+ let Some ( JavaExpr :: New {
2816+ anonymous_body : Some ( nested) ,
2817+ ..
2818+ } ) = body. fields [ 1 ] . initializer . as_ref ( )
2819+ else {
2820+ panic ! ( "expected nested anonymous body" ) ;
2821+ } ;
2822+ assert_eq ! ( nested. fields[ 0 ] . initializer, Some ( nested_reference) ) ;
2823+ assert_eq ! ( nested. fields[ 1 ] . initializer, Some ( replacement) ) ;
2824+ }
2825+ }
0 commit comments