private static Optional < Fix > stringBufferFix ( VisitorState state ) { Tree tree = state . getPath ( ) . getLeaf ( ) ; // expect `new StringBuffer()` if ( ! ( tree instanceof NewClassTree ) ) { return Optional . empty ( ) ; } // expect e.g. `StringBuffer sb = new StringBuffer();` NewClassTree newClassTree = ( NewClassTree ) tree ; Tree parent = state . getPath ( ) . getParentPath ( ) . getLeaf ( ) ; if ( ! ( parent instanceof VariableTree ) ) { return Optional . empty ( ) ; } VariableTree varTree = ( VariableTree ) parent ; VarSymbol varSym = ASTHelpers . getSymbol ( varTree ) ; TreePath methodPath = findEnclosingMethod ( state ) ; if ( methodPath == null ) { return Optional . empty ( ) ; } // Expect all uses to be of the form `sb.<method>` (append, toString, etc.) // We don't want to refactor StringBuffers that escape the current method. // Use an array to get a boxed boolean that we can update in the anonymous class. boolean [ ] escape = { false } ; new TreePathScanner < Void , Void > ( ) { @ Override public Void visitIdentifier ( IdentifierTree tree , Void unused ) { if ( varSym . equals ( ASTHelpers . getSymbol ( tree ) ) ) { Tree parent = getCurrentPath ( ) . getParentPath ( ) . getLeaf ( ) ; if ( parent == varTree ) { // the use of the variable in its declaration gets a pass return null ; } // the LHS of a select (e.g. in `sb.append(...)`) does not escape if ( ! ( parent instanceof MemberSelectTree ) || ( ( MemberSelectTree ) parent ) . getExpression ( ) != tree ) { escape [ 0 ] = true ; } } return null ; } } . scan ( methodPath , null ) ; if ( escape [ 0 ] ) { return Optional . empty ( ) ; } return Optional . of ( SuggestedFix . builder ( ) . replace ( newClassTree . getIdentifier ( ) , "StringBuilder" ) . replace ( varTree . getType ( ) , "StringBuilder" ) . build ( ) ) ; }
current method .