/*
* 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.devtools.j2objc.translate;
import com.google.devtools.j2objc.ast.CommaExpression;
import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.devtools.j2objc.ast.Expression;
import com.google.devtools.j2objc.ast.FieldAccess;
import com.google.devtools.j2objc.ast.NativeExpression;
import com.google.devtools.j2objc.ast.PrefixExpression;
import com.google.devtools.j2objc.ast.QualifiedName;
import com.google.devtools.j2objc.ast.SimpleName;
import com.google.devtools.j2objc.ast.SwitchCase;
import com.google.devtools.j2objc.ast.TreeNode;
import com.google.devtools.j2objc.ast.TreeUtil;
import com.google.devtools.j2objc.ast.UnitTreeVisitor;
import com.google.devtools.j2objc.types.PointerType;
import com.google.devtools.j2objc.util.ElementUtil;
import com.google.devtools.j2objc.util.TranslationUtil;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
/**
* Converts static variable access to static method calls where necessary.
*
* @author Keith Stanger
*/
public class StaticVarRewriter extends UnitTreeVisitor {
public StaticVarRewriter(CompilationUnit unit) {
super(unit);
}
private boolean needsStaticLoad(TreeNode currentNode, VariableElement var) {
if (!ElementUtil.isStatic(var) || ElementUtil.isConstant(var)) {
return false;
}
TypeElement enclosingType = TreeUtil.getEnclosingTypeElement(currentNode);
return enclosingType == null || !enclosingType.equals(ElementUtil.getDeclaringClass(var));
}
private void rewriteStaticAccess(Expression node) {
VariableElement var = TreeUtil.getVariableElement(node);
if (var == null || !needsStaticLoad(node, var)) {
return;
}
TypeElement declaringClass = ElementUtil.getDeclaringClass(var);
boolean assignable = TranslationUtil.isAssigned(node);
StringBuilder code = new StringBuilder(
ElementUtil.isEnumConstant(var) ? "JreLoadEnum" : "JreLoadStatic");
TypeMirror exprType = var.asType();
if (assignable) {
code.append("Ref");
exprType = new PointerType(exprType);
}
code.append("(");
code.append(nameTable.getFullName(declaringClass));
code.append(", ");
code.append(nameTable.getVariableShortName(var));
code.append(")");
NativeExpression nativeExpr = new NativeExpression(code.toString(), exprType);
nativeExpr.addImportType(declaringClass.asType());
Expression newNode = nativeExpr;
if (assignable) {
newNode = new PrefixExpression(var.asType(), PrefixExpression.Operator.DEREFERENCE, newNode);
}
node.replaceWith(newNode);
}
@Override
public boolean visit(FieldAccess node) {
VariableElement var = node.getVariableElement();
if (ElementUtil.isInstanceVar(var)) {
node.getExpression().accept(this);
return false;
}
Expression expr = TreeUtil.remove(node.getExpression());
Expression varNode = TreeUtil.remove(node.getName());
if (!TranslationUtil.hasSideEffect(expr)) {
node.replaceWith(varNode);
varNode.accept(this);
return false;
}
CommaExpression commaExpr = new CommaExpression(expr);
if (TranslationUtil.isAssigned(node)) {
commaExpr.addExpression(new PrefixExpression(
new PointerType(var.asType()), PrefixExpression.Operator.ADDRESS_OF, varNode));
node.replaceWith(new PrefixExpression(
var.asType(), PrefixExpression.Operator.DEREFERENCE, commaExpr));
} else {
commaExpr.addExpression(varNode);
node.replaceWith(commaExpr);
}
commaExpr.accept(this);
return false;
}
@Override
public boolean visit(SimpleName node) {
rewriteStaticAccess(node);
return false;
}
@Override
public boolean visit(QualifiedName node) {
rewriteStaticAccess(node);
return false;
}
@Override
public boolean visit(SwitchCase node) {
// Avoid using an accessor method for enums in a switch case.
return false;
}
}