Package com.google.gwt.dev.jjs

Source Code of com.google.gwt.dev.jjs.EnumNameObfuscator$EnumNameReplacer

/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.jjs;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
import com.google.gwt.dev.jjs.ast.JThisRef;

import java.util.List;

/**
* Performs optimizations on Enums.
*/
public class EnumNameObfuscator {

  private static class EnumNameCallChecker extends JModVisitor {

    private final TreeLogger logger;
    private final JMethod enumNameMethod;
    private final JMethod enumToStringMethod;
    private final JMethod enumValueOfMethod;
    private final JDeclaredType classType;
    private final JDeclaredType enumType;
    private final JDeclaredType stringType;

    public EnumNameCallChecker(JProgram jprogram, TreeLogger logger) {
      this.logger = logger;
      this.enumNameMethod = jprogram.getIndexedMethod("Enum.name");
      this.enumToStringMethod = jprogram.getIndexedMethod("Enum.toString");
      this.classType = jprogram.getIndexedType("Class");
      this.enumType = jprogram.getIndexedType("Enum");
      this.stringType = jprogram.getIndexedType("String");
     
      /*
       * Find the correct version of enumValueOfMethod.
       * Note: it doesn't work to check against a ref returned by
       * jprogram.getIndexedMethod("Enum.valueOf"), since there are
       * 2 different versions of Enum.valueOf in our jre emulation library,
       * and the indexed ref won't reliably flag the public instance, which
       * is the one we want here (i.e. Enum.valueOf(Class<T>,String)). 
       * The other version is protected, but is called by the generated
       * constructors for sub-classes of Enum, and we don't want to warn for
       * those cases.
       */
      JMethod foundMethod = null;
      List<JMethod> enumMethods = enumType.getMethods();
      for (JMethod enumMethod : enumMethods) {
        if ("valueOf".equals(enumMethod.getName())) {
          List<JParameter> jParameters = enumMethod.getParams();
          if (jParameters.size() == 2 &&
              jParameters.get(0).getType() == classType &&
              jParameters.get(1).getType() == stringType) {
            foundMethod = enumMethod;
            break;
          }
        }
      }
      this.enumValueOfMethod = foundMethod;
    }
   
    @Override
    public void endVisit(JMethodCall x, Context ctx) {
      JMethod target = x.getTarget();
      JDeclaredType type = target.getEnclosingType();

      if (type instanceof JClassType) {
        JClassType cType = (JClassType) type;
       
        if (target == enumNameMethod ||
              target == enumToStringMethod ||
              target == enumValueOfMethod) {
          warn(x);
        } else if (cType.isEnumOrSubclass() != null) {
          if ("valueOf".equals(target.getName())) {
            /*
             * Check for calls to the auto-generated EnumSubType.valueOf(String).
             * Note, the check of the signature for the single String arg version
             * is to avoid flagging user-defined overloaded versions of the
             * method, which are presumably ok.
             */
            List<JParameter> jParameters = target.getParams();
            if (jParameters.size() == 1 &&
                jParameters.get(0).getType() == stringType) {
              warn(x);
            }
          }
        }
      }
    }
   
    @Override
    public boolean visit(JClassType x, Context ctx) {
      if (x == enumType) {
        // don't traverse into Enum class itself, don't warn on internal method calls
        return false;
      }
      return true;
    }
   
    private void warn(JMethodCall x) {
      /* TODO: add a way to suppress warning with annotation if you know what
       * you're doing.
       */
      logger.log(TreeLogger.WARN, "Call to Enum method "
          + x.getTarget().getName() + " when enum obfuscation is enabled:  "
          + x.getSourceInfo().getFileName() + ":"
          + x.getSourceInfo().getStartLine());
    }
  }

  private static class EnumNameReplacer extends JModVisitor {

    private final TreeLogger logger;
    private final JProgram jprogram;
    private final JMethod enumObfuscatedName;
    private final JClassType enumType;

    public EnumNameReplacer(JProgram jprogram, TreeLogger logger) {
      this.logger = logger;
      this.jprogram = jprogram;
      this.enumType = (JClassType) jprogram.getIndexedType("Enum");
      this.enumObfuscatedName = jprogram.getIndexedMethod("Enum.obfuscatedName");
    }

    @Override
    public void endVisit(JReturnStatement x, Context ctx) {
      info(x);
      JReturnStatement toReturn = new JReturnStatement(x.getSourceInfo(),
          new JMethodCall(x.getSourceInfo(),
          new JThisRef(x.getSourceInfo(),enumType), enumObfuscatedName));
      ctx.replaceMe(toReturn);
    }

    public void exec() {
      accept(jprogram.getIndexedMethod("Enum.name"));
    }
   
    private void info(JReturnStatement x) {
      logger.log(TreeLogger.INFO, "Replacing Enum.name method :  "
          + x.getSourceInfo().getFileName() + ":"
          + x.getSourceInfo().getStartLine());
    }
  }

  public static void exec(JProgram jprogram, TreeLogger logger) {
    new EnumNameCallChecker(jprogram, logger).accept(jprogram);
    new EnumNameReplacer(jprogram, logger).exec();
  }
}
TOP

Related Classes of com.google.gwt.dev.jjs.EnumNameObfuscator$EnumNameReplacer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.