📄 typechecker.java
字号:
/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */package javassist.compiler;import javassist.CtClass;import javassist.CtField;import javassist.ClassPool;import javassist.Modifier;import javassist.NotFoundException;import javassist.compiler.ast.*;import javassist.bytecode.*;public class TypeChecker extends Visitor implements Opcode, TokenId { static final String javaLangObject = "java.lang.Object"; static final String jvmJavaLangObject = "java/lang/Object"; static final String jvmJavaLangString = "java/lang/String"; static final String jvmJavaLangClass = "java/lang/Class"; /* The following fields are used by atXXX() methods * for returning the type of the compiled expression. */ protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ... protected int arrayDim; protected String className; // JVM-internal representation protected MemberResolver resolver; protected CtClass thisClass; protected MethodInfo thisMethod; public TypeChecker(CtClass cc, ClassPool cp) { resolver = new MemberResolver(cp); thisClass = cc; thisMethod = null; } /* * Converts an array of tuples of exprType, arrayDim, and className * into a String object. */ protected static String argTypesToString(int[] types, int[] dims, String[] cnames) { StringBuffer sbuf = new StringBuffer(); sbuf.append('('); int n = types.length; if (n > 0) { int i = 0; while (true) { typeToString(sbuf, types[i], dims[i], cnames[i]); if (++i < n) sbuf.append(','); else break; } } sbuf.append(')'); return sbuf.toString(); } /* * Converts a tuple of exprType, arrayDim, and className * into a String object. */ protected static StringBuffer typeToString(StringBuffer sbuf, int type, int dim, String cname) { String s; if (type == CLASS) s = MemberResolver.jvmToJavaName(cname); else if (type == NULL) s = "Object"; else try { s = MemberResolver.getTypeName(type); } catch (CompileError e) { s = "?"; } sbuf.append(s); while (dim-- > 0) sbuf.append("[]"); return sbuf; } /** * Records the currently compiled method. */ public void setThisMethod(MethodInfo m) { thisMethod = m; } protected static void fatal() throws CompileError { throw new CompileError("fatal"); } /** * Returns the JVM-internal representation of this class name. */ protected String getThisName() { return MemberResolver.javaToJvmName(thisClass.getName()); } /** * Returns the JVM-internal representation of this super class name. */ protected String getSuperName() throws CompileError { return MemberResolver.javaToJvmName( MemberResolver.getSuperclass(thisClass).getName()); } /* Converts a class name into a JVM-internal representation. * * It may also expand a simple class name to java.lang.*. * For example, this converts Object into java/lang/Object. */ protected String resolveClassName(ASTList name) throws CompileError { return resolver.resolveClassName(name); } /* Expands a simple class name to java.lang.*. * For example, this converts Object into java/lang/Object. */ protected String resolveClassName(String jvmName) throws CompileError { return resolver.resolveJvmClassName(jvmName); } public void atNewExpr(NewExpr expr) throws CompileError { if (expr.isArray()) atNewArrayExpr(expr); else { CtClass clazz = resolver.lookupClassByName(expr.getClassName()); String cname = clazz.getName(); ASTList args = expr.getArguments(); atMethodCallCore(clazz, MethodInfo.nameInit, args); exprType = CLASS; arrayDim = 0; className = MemberResolver.javaToJvmName(cname); } } public void atNewArrayExpr(NewExpr expr) throws CompileError { int type = expr.getArrayType(); ASTList size = expr.getArraySize(); ASTList classname = expr.getClassName(); ASTree init = expr.getInitializer(); if (init != null) init.accept(this); if (size.length() > 1) atMultiNewArray(type, classname, size); else { ASTree sizeExpr = size.head(); if (sizeExpr != null) sizeExpr.accept(this); exprType = type; arrayDim = 1; if (type == CLASS) className = resolveClassName(classname); else className = null; } } public void atArrayInit(ArrayInit init) throws CompileError { ASTList list = init; while (list != null) { ASTree h = list.head(); list = list.tail(); if (h != null) h.accept(this); } } protected void atMultiNewArray(int type, ASTList classname, ASTList size) throws CompileError { int count, dim; dim = size.length(); for (count = 0; size != null; size = size.tail()) { ASTree s = size.head(); if (s == null) break; // int[][][] a = new int[3][4][]; ++count; s.accept(this); } exprType = type; arrayDim = dim; if (type == CLASS) className = resolveClassName(classname); else className = null; } public void atAssignExpr(AssignExpr expr) throws CompileError { // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>= int op = expr.getOperator(); ASTree left = expr.oprand1(); ASTree right = expr.oprand2(); if (left instanceof Variable) atVariableAssign(expr, op, (Variable)left, ((Variable)left).getDeclarator(), right); else { if (left instanceof Expr) { Expr e = (Expr)left; if (e.getOperator() == ARRAY) { atArrayAssign(expr, op, (Expr)left, right); return; } } atFieldAssign(expr, op, left, right); } } /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=. * * expr and var can be null. */ private void atVariableAssign(Expr expr, int op, Variable var, Declarator d, ASTree right) throws CompileError { int varType = d.getType(); int varArray = d.getArrayDim(); String varClass = d.getClassName(); if (op != '=') atVariable(var); right.accept(this); exprType = varType; arrayDim = varArray; className = varClass; } private void atArrayAssign(Expr expr, int op, Expr array, ASTree right) throws CompileError { atArrayRead(array.oprand1(), array.oprand2()); int aType = exprType; int aDim = arrayDim; String cname = className; right.accept(this); exprType = aType; arrayDim = aDim; className = cname; } protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right) throws CompileError { CtField f = fieldAccess(left); atFieldRead(f); int fType = exprType; int fDim = arrayDim; String cname = className; right.accept(this); exprType = fType; arrayDim = fDim; className = cname; } public void atCondExpr(CondExpr expr) throws CompileError { booleanExpr(expr.condExpr()); expr.thenExpr().accept(this); int type1 = exprType; int dim1 = arrayDim; String cname1 = className; expr.elseExpr().accept(this); if (dim1 == 0 && dim1 == arrayDim) if (CodeGen.rightIsStrong(type1, exprType)) expr.setThen(new CastExpr(exprType, 0, expr.thenExpr())); else if (CodeGen.rightIsStrong(exprType, type1)) { expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); exprType = type1; } } /* * If atBinExpr() substitutes a new expression for the original * binary-operator expression, it changes the operator name to '+' * (if the original is not '+') and sets the new expression to the * left-hand-side expression and null to the right-hand-side expression. */ public void atBinExpr(BinExpr expr) throws CompileError { int token = expr.getOperator(); int k = CodeGen.lookupBinOp(token); if (k >= 0) { /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>> */ if (token == '+') { Expr e = atPlusExpr(expr); if (e != null) { /* String concatenation has been translated into * an expression using StringBuffer. */ e = CallExpr.makeCall(Expr.make('.', e, new Member("toString")), null); expr.setOprand1(e); expr.setOprand2(null); // <---- look at this! className = jvmJavaLangString; } } else { ASTree left = expr.oprand1(); ASTree right = expr.oprand2(); left.accept(this);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -