javaabstract-syntax-treeast-grep

How to add a specific line at the end of a java constructor using ast-grep?


I'm working with ast-grep and trying to modify Java code by adding a new line at the end of a constructor. Despite several attempts, I haven't been able to figure out the correct approach.

Here's what I'm trying to achieve:

Original constructor:

public RiskHandler() {
    EnvironmentInitializer.initAppConfig();
    final RiskApplicationComponent riskApplicationComponent = DaggerRiskApplicationComponent.create();
    processor = riskApplicationComponent.riskProcessor();
}

Desired output:

public RiskHandler() {
    EnvironmentInitializer.initAppConfig();
    final RiskApplicationComponent riskApplicationComponent = DaggerRiskApplicationComponent.create();
    processor = riskApplicationComponent.riskProcessor();
    testObj = new TestClassProvider().provideTestObj(true);
}

I need to add the line testObj = new TestClassProvider().provideTestObj(true); as the last line inside the constructor.

I've tried using this YAML configuration, but it's not working:

id: add_agent_declaration
language: java
rule:
  kind: constructor_declaration
  pattern: |
    public $CLASS_NAME() {
      $$$BODY
    }
fix: |-
  public $CLASS_NAME() {
    $$$BODY
    testObj = new TestClassProvider().provideTestObj(true);
  }

ast-grep playground link

I've been looking through the ast-grep documentation but haven't found a clear way to achieve this.

Could someone please help me with how to add a specific new line at the end of the constructor body.

Any help or guidance would be greatly appreciated!


Solution

  • It almost works when you match against the constructor_body instead of the constructor_declaration. Strangely, however, you need to provide the opening { but the closing } becomes part of $$$BODY, which means you cannot put any additional lines before the }.

    Pattern:

    language: java
    rule:
      kind: constructor_body
      pattern: |
        {$$$BODY
      
        
    fix: |-
      {
          $$$BODY
          testObj = new TestClassProvider().provideTestObj(true);
      }
    

    Result:

    public RiskHandler() {
            EnvironmentInitializer.initAppConfig();
            final RiskApplicationComponent riskApplicationComponent = DaggerRiskApplicationComponent.create();
            processor = riskApplicationComponent.riskProcessor();
        }
            testObj = new TestClassProvider().provideTestObj(true);
        }
    

    This does not happen when you match the individual lines, which indeed gives the desired result:

    language: java
    rule:
      kind: constructor_body
      pattern: |
        {$BODY_A
        $BODY_B
        $BODY_C
    
    
    fix: |-
      {
          $BODY_A
          $BODY_B
          $BODY_C
          testObj = new TestClassProvider().provideTestObj(true);
      }
    

    However, of course you may not know how many lines there are and in any case it is not a very clean solution.

    To match all lines at once and still add the extra line at the right position you can use a workaround: take the full constructor body as a single node $BODY and strip the final two characters (the } and the character before, which I'm not fully sure what it is but it messes up the layout if you don't remove it).

    id: add_agent_declaration
    language: java
    rule:
      kind: constructor_body
      pattern: $BODY
    transform:
      NEWBODY:
        substring:
          source: $BODY
          startChar: 0
          endChar: -2
        
    fix: 
      $NEWBODY
      testObj = new TestClassProvider().provideTestObj(true);
      
      }
    

    This generates the correct code with the additional line within the braces.