private static ValidationResult validateFormatStringVariable(
      ExpressionTree formatStringTree,
      final Symbol formatStringSymbol,
      final List<? extends ExpressionTree> args,
      final VisitorState state) {
    if (formatStringSymbol.getKind() != ElementKind.LOCAL_VARIABLE) {
      return ValidationResult.create(
          null,
          String.format(
              "Variables used as format strings that are not local variables must be compile time"
                  + " constants.\n%s is neither a local variable nor a compile time constant.",
              formatStringTree));
    }

    // Find the Tree for the block in which the variable is defined. If it is not defined in this
    // class (though it may have been in a super class). We require compile time constant values in
    // that case.
    Symbol owner = formatStringSymbol.owner;
    TreePath path = TreePath.getPath(state.getPath(), formatStringTree);
    while (path != null && ASTHelpers.getSymbol(path.getLeaf()) != owner) {
      path = path.getParentPath();
    }

    // A local variable must be declared in a parent tree to be accessed. This case should be
    // impossible.
    if (path == null) {
      throw new IllegalStateException(
          String.format(
              "Could not find the Tree where local variable %s is declared. "
                  + "This should be impossible.",
              formatStringTree));
    }

    // Scan down from the scope where the variable was declared
    ValidationResult result =
        path.getLeaf()
            .accept(
                new TreeScanner<ValidationResult, Void>() {
                  @Override
                  public ValidationResult visitVariable(VariableTree node, Void unused) {
                    if (ASTHelpers.getSymbol(node) == formatStringSymbol) {
                      if (node.getInitializer() == null) {
                        return ValidationResult.create(
                            null,
                            String.format(
                                "Variables used as format strings must be initialized when they are"
                                    + " declared.\nInvalid declaration: %s",
                                node));
                      }
                      return validateStringFromAssignment(node, node.getInitializer(), args, state);
                    }
                    return super.visitVariable(node, unused);
                  }

                  @Override
                  public ValidationResult reduce(ValidationResult r1, ValidationResult r2) {
                    if (r1 == null && r2 == null) {
                      return null;
                    }
                    return MoreObjects.firstNonNull(r1, r2);
                  }
                },
                null);

    return result;
  }
private static ValidationResult validateFormatStringVariable ( ExpressionTree formatStringTree , final Symbol formatStringSymbol , final List < ? extends ExpressionTree > args , final VisitorState state ) { if ( formatStringSymbol . getKind ( ) != ElementKind . LOCAL_VARIABLE ) { return ValidationResult . create ( null , String . format ( "Variables used as format strings that are not local variables must be compile time" + " constants.\n%s is neither a local variable nor a compile time constant." , formatStringTree ) ) ; } Symbol owner = formatStringSymbol . owner ; TreePath path = TreePath . getPath ( state . getPath ( ) , formatStringTree ) ; while ( path != null && ASTHelpers . getSymbol ( path . getLeaf ( ) ) != owner ) { path = path . getParentPath ( ) ; } if ( path == null ) { throw new IllegalStateException ( String . format ( "Could not find the Tree where local variable %s is declared. " + "This should be impossible." , formatStringTree ) ) ; } ValidationResult result = path . getLeaf ( ) . accept ( new TreeScanner < ValidationResult , Void > ( ) { @ Override public ValidationResult visitVariable ( VariableTree node , Void unused ) { if ( ASTHelpers . getSymbol ( node ) == formatStringSymbol ) { if ( node . getInitializer ( ) == null ) { return ValidationResult . create ( null , String . format ( "Variables used as format strings must be initialized when they are" + " declared.\nInvalid declaration: %s" , node ) ) ; } return validateStringFromAssignment ( node , node . getInitializer ( ) , args , state ) ; } return super . visitVariable ( node , unused ) ; } @ Override public ValidationResult reduce ( ValidationResult r1 , ValidationResult r2 ) { if ( r1 == null && r2 == null ) { return null ; } return MoreObjects . firstNonNull ( r1 , r2 ) ; } } , null ) ; return result ; }
Helps {@code validate()} validate a format string that is a variable, but not a parameter. This
method assumes that the format string variable has already been asserted to be final or
effectively final.