All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.dev.jjs.impl.JsniRestrictionChecker Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2014 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.impl;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;

/**
 * Checks and throws errors for invalid JSNI constructs.
 */
public class JsniRestrictionChecker extends JVisitor {

  public static void exec(TreeLogger logger, JProgram jprogram) throws UnableToCompleteException {
    JsniRestrictionChecker jsniRestrictionChecker = new JsniRestrictionChecker(logger, jprogram);
    jsniRestrictionChecker.accept(jprogram);
    if (jsniRestrictionChecker.hasErrors) {
      throw new UnableToCompleteException();
    }
  }

  private JMethod currentJsniMethod;
  private final JProgram jprogram;
  private final TreeLogger logger;
  private boolean hasErrors;

  public JsniRestrictionChecker(TreeLogger logger, JProgram jprogram) {
    this.logger = logger;
    this.jprogram = jprogram;
  }

  @Override
  public boolean visit(JsniMethodBody x, Context ctx) {
    currentJsniMethod = x.getMethod();
    return super.visit(x, ctx);
  }

  @Override
  public boolean visit(JsniMethodRef x, Context ctx) {
    JMethod calledMethod = x.getTarget();
    JDeclaredType enclosingTypeOfCalledMethod = calledMethod.getEnclosingType();

    if (isNonStaticJsoClassDispatch(calledMethod, enclosingTypeOfCalledMethod)) {
      logError("JSNI method %s  attempts to call non-static method %s on an instance which is a "
          + "subclass of JavaScriptObject. Only static method calls on JavaScriptObject subclasses "
          + "are allowed in JSNI.", currentJsniMethod.getQualifiedName(),
          calledMethod.getQualifiedName());
    } else if (isJsoInterface(enclosingTypeOfCalledMethod)) {
      logError("JSNI method %s attempts to call method %s on an instance which might be a "
          + "JavaScriptObject. Such a method call is only allowed in pure Java (non-JSNI) "
          + "functions.", currentJsniMethod.getQualifiedName(), calledMethod.getQualifiedName());
    } else if (jprogram.isJavaLangString(enclosingTypeOfCalledMethod) && !calledMethod.isStatic()) {
      logError("JSNI method %s attempts to call method %s. Only static methods from " +
              "java.lang.String can be called from JSNI.",
          currentJsniMethod.getQualifiedName(),
          calledMethod.getQualifiedName());
    } else if (jprogram.isJavaLangObject(enclosingTypeOfCalledMethod) && !calledMethod.isStatic()) {
      log(Type.WARN, "JSNI method %s calls method %s. Instance java.lang.Object methods should " +
              "not be called on String, Array or JSO instances.",
          currentJsniMethod.getQualifiedName(),
          calledMethod.getQualifiedName());
    }
    return super.visit(x, ctx);
  }

  private void log(Type type, String format, Object... args) {
    logger.log(type, String.format(format, args));
    hasErrors |= type == Type.ERROR;
  }

  private void logError(String format, Object... args) {
    log(Type.ERROR, format, args);
  }

  private boolean isJsoInterface(JDeclaredType type) {
    return jprogram.typeOracle.isSingleJsoImpl(type)
        || jprogram.typeOracle.isDualJsoInterface(type);
  }

  private boolean isNonStaticJsoClassDispatch(JMethod method, JDeclaredType enclosingType) {
    return !method.isStatic() && enclosingType.isJsoType();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy