BaseAnalyzer,AbstractAssignAnalyzer,AssignAnalyzer解析

11 篇文章 0 订阅

前言

本文我们来介绍一下javac在flow阶段使用的BaseAnalyzer,AbstractAssignAnalyzer,AssignAnalyzer.类的继承结构如下:

1

解析

BaseAnalyzer

BaseAnalyzer–> 数据流分析的基类.该类定义了处理break/continue的逻辑.其中定义了一个枚举,JumpKind.定义如下:

enum JumpKind {
    BREAK(JCTree.Tag.BREAK) {
        @Override
        JCTree getTarget(JCTree tree) {
            return ((JCBreak)tree).target;
        }
    },
    CONTINUE(JCTree.Tag.CONTINUE) {
        @Override
        JCTree getTarget(JCTree tree) {
            return ((JCContinue)tree).target;
        }
    };

    final JCTree.Tag treeTag;

    private JumpKind(Tag treeTag) {
        this.treeTag = treeTag;
    }

    abstract JCTree getTarget(JCTree tree);
}

另外, BaseAnalyzer是一个泛型类,其泛型边界为 P extends BaseAnalyzer.PendingExit,代表悬而未决的出口。这些语句是return,break,continue.定义如下:

static class PendingExit {
    JCTree tree;

    PendingExit(JCTree tree) {
        this.tree = tree;
    }

    void resolveJump(JCTree tree) {
        //do nothing
    }
}

BaseAnalyzer的代码如下(去除JumpKind,PendingExit后定义如下):

static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {

       
        /** The currently pending exits that go from current inner blocks
         *  to an enclosing block, in source order.
         *  当前挂起的退出,从当前内部块到封闭块,按源顺序进行
         */
        ListBuffer<P> pendingExits;
        

        abstract void markDead(JCTree tree);

        /** Record an outward transfer of control. */
        void recordExit(JCTree tree, P pe) {
            pendingExits.append(pe);
            markDead(tree);
        }

        /** Resolve all jumps of this statement. */
        private boolean resolveJump(JCTree tree,
                        ListBuffer<P> oldPendingExits,
                        JumpKind jk) {
            boolean resolved = false;
            List<P> exits = pendingExits.toList();
            pendingExits = oldPendingExits;
            for (; exits.nonEmpty(); exits = exits.tail) {
                P exit = exits.head;
                if (exit.tree.hasTag(jk.treeTag) &&
                        jk.getTarget(exit.tree) == tree) {
                    exit.resolveJump(tree);
                    resolved = true;
                } else {
                    pendingExits.append(exit);
                }
            }
            return resolved;
        }

        /** Resolve all continues of this statement. */
        boolean resolveContinues(JCTree tree) {
            return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
        }

        /** Resolve all breaks of this statement. */
        boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
            return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
        }

        @Override
        public void scan(JCTree tree) {
            if (tree != null && (
                    tree.type == null ||
                    tree.type != Type.stuckType)) {
                super.scan(tree);
            }
        }
    }

代码很简单,这里没什么好解释的.

AbstractAssignAnalyzer

AbstractAssignAnalyzer --> 赋值分析的基类.该抽象类同样是一个泛型类,泛型边界为 P extends AbstractAssignAnalyzer.AbstractAssignPendingExit. 定义如下:

public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {

    final Bits inits; // 初始化变量所对应的变量位图
    final Bits uninits; // 变量未初始化的变量位图
    final Bits exit_inits = new Bits(true); // 退出时变量初始化的位图
    final Bits exit_uninits = new Bits(true); // 变量未初始化时变量位图

    public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
        super(tree);
        this.inits = inits;
        this.uninits = uninits;
        this.exit_inits.assign(inits);
        this.exit_uninits.assign(uninits);
    }

    @Override
    public void resolveJump(JCTree tree) {
        inits.andSet(exit_inits); // 将初始化变量所对应的变量位图和退出时变量初始化的位图进行与运算,从而得到最终的结果
        uninits.andSet(exit_uninits); // 同上
    }
}

AbstractAssignAnalyzer 的代码又臭又长,我们这里首先介绍其字段,如下:

// 已赋值的变量位图
protected final Bits inits;

// 未赋值的变量位图
final Bits uninits;

// 当前try块中定义了但是没有分配的变量集。这个变量维护的方式是lazy的;只有在从uninits
// 中删除了某些内容时才对其进行更新,通常是通过在可到达的代码中分配。要获得在当前try块中
// 任何位置都定义了但是没有分配的的正确变量集,那么就uninitsTry和uninits进行交集运算
final Bits uninitsTry;

// 当分析一个条件语句时,inits和uninits都是null,但是有如下字段:
final Bits initsWhenTrue; // 当条件为true时初始化的变量位图
final Bits initsWhenFalse;// 当条件为false时初始化的变量位图
final Bits uninitsWhenTrue;// 当条件为true时未初始化的变量位图
final Bits uninitsWhenFalse; // 当条件为false时未初始化的变量位图

// 变量数组
protected JCVariableDecl[] vardecls;

// 当前正在分析的类
JCClassDecl classDef;

// 在当前的class中第一个变量的地址
int firstadr;

// 下一个变量的地址
protected int nextadr;

// 在block中第一个可以返回的变量地址
protected int returnadr;

// 未引用的资源
Scope unrefdResources;


FlowKind flowKind = FlowKind.NORMAL;

// 当前树的起始位置
int startPos;

final Symtab syms;

protected Names names;

AbstractAssignAnalyzer的构造器如下:

public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
    this.inits = inits;
    uninits = new Bits();
    uninitsTry = new Bits();
    initsWhenTrue = new Bits(true);
    initsWhenFalse = new Bits(true);
    uninitsWhenTrue = new Bits(true);
    uninitsWhenFalse = new Bits(true);
    this.syms = syms;
    this.names = names;
}

同时重写了BaseAnalyzer中的markDead方法,定义如下:

protected void markDead(JCTree tree) {
    inits.inclRange(returnadr, nextadr);
    uninits.inclRange(returnadr, nextadr);
}

在该类中定义了如下处理变量的方法,如下:

// 否需要追踪这个符号的init/uninit状态
// 可追踪: 给定符号的位置>= startPos && (sym 属于方法 || (当前的符号是 final && 当前符号是classDef的成员))
protected boolean trackable(VarSymbol sym) {
    return
        sym.pos >= startPos &&
        ((sym.owner.kind == MTH ||
         ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
      classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
}

// 初始化一个可追踪的变量,其地址设置为nextadr,同时输入到vardecls
void newVar(JCVariableDecl varDecl) {
    VarSymbol sym = varDecl.sym;
    vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);// 对vardecls 进行扩容
    if ((sym.flags() & FINAL) == 0) {// 如果当前符号不是final的
        sym.flags_field |= EFFECTIVELY_FINAL; // 那么就修改该变量的标识符为有效final 
    }
    sym.adr = nextadr;
    vardecls[nextadr] = varDecl;
    exclVarFromInits(varDecl, nextadr); // 从初始化对应的bitmap中去除
    uninits.incl(nextadr);// 加入到未初始化的bitmap中
    nextadr++;
}

// 将位图中指定的位置(adr)置0,意味着该adr所对应的变量是未初始化的
protected void exclVarFromInits(JCTree tree, int adr) {
    inits.excl(adr);
}

// 修改inits的内容为指定的bits
protected void assignToInits(JCTree tree, Bits bits) {
    inits.assign(bits);
}

// inits与指定bits进行与运算
protected void andSetInits(JCTree tree, Bits bits) {
    inits.andSet(bits);
}

// inits与指定bits进行或运算
protected void orSetInits(JCTree tree, Bits bits) {
    inits.orSet(bits);
}


// 记录一个可跟踪变量的初始化
void letInit(DiagnosticPosition pos, VarSymbol sym) {
    if (sym.adr >= firstadr && trackable(sym)) {
        if (uninits.isMember(sym.adr)) {// 如果指定符号是未初始化的,那么就从未初始化的bitmap中去除
            uninit(sym);
        }
        inits.incl(sym.adr); // 加入到初始化的bitmap
    }
}

void uninit(VarSymbol sym) {
    if (!inits.isMember(sym.adr)) {
        // 如果不是inits中的成员,就从uninits,uninitsTry中删除
        uninits.excl(sym.adr);
        uninitsTry.excl(sym.adr);
    } else {
        // 如果是,则从uninits中删除 
        uninits.excl(sym.adr);
    }
}

// 如果tree是简单名称或形如this.name或C.this.name,并且tree表示可跟踪变量,则记录变量的初始化
void letInit(JCTree tree) {
    tree = TreeInfo.skipParens(tree);
    if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
        Symbol sym = TreeInfo.symbol(tree); // 获得树所对应的符号
        if (sym.kind == VAR) {// 符号是变量的话
            letInit(tree.pos(), (VarSymbol)sym);
        }
    }
}

// 检查指定的变量是否已经初始化
void checkInit(DiagnosticPosition pos, VarSymbol sym) {
    checkInit(pos, sym, "var.might.not.have.been.initialized");
}

void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}

// 重置Bits的工具方法
private void resetBits(Bits... bits) {
    for (Bits b : bits) {
        b.reset();
    }
}


// 复制inits/uninits 到   WhenTrue/WhenFalse 中.如果setToNull为true,则重置inits, uninits
void split(boolean setToNull) {
    initsWhenFalse.assign(inits);
    uninitsWhenFalse.assign(uninits);
    initsWhenTrue.assign(inits);
    uninitsWhenTrue.assign(uninits);
    if (setToNull) {
        resetBits(inits, uninits);
    }
}

// 将inits/uninits和 WhenTrue/WhenFals 进行合并
protected void merge(JCTree tree) {
    inits.assign(initsWhenFalse.andSet(initsWhenTrue));
    uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
}

这部分的代码还是很简单的.

接下来是访问语句和定义相关的方法.(javac中大量使用了访问者模式)

void scanExpr(JCTree tree) {
    if (tree != null) {
        scan(tree);
        if (inits.isReset()) { // 如果在扫描指定树时, inits 发生了变化,则进行合并
            merge(tree);
        }
    }
}

// 分析表达式
void scanExprs(List<? extends JCExpression> trees) {
if (trees != null)
for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
    scanExpr(l.head);
}

// 分析condition
void scanCond(JCTree tree) {
	if (tree.type.isFalse()) {
	  /*
		 * 如果给条件分支是 假,那么就设置initsWhenTrue/uninitsWhenTrue 为inits/uninits.同时
		 * initsWhenTrue/uninitsWhenTrue包含的变量范围是firstadr-nextadr.
		 * initsWhenFalse/uninitsWhenFalse 就设置为inits/uninits.
		 * 
		 * 举例: if(false){int a } ,这里分析的就是那个false.那么因为是个常量,就没必要继续扫描了.
		 * initsWhenFalse/uninitsWhenFalse 中的变量和inits/uninits是一样的,不会发生变化
		 */
        if (inits.isReset()) merge(tree);
        initsWhenTrue.assign(inits);
        initsWhenTrue.inclRange(firstadr, nextadr);
        uninitsWhenTrue.assign(uninits);
        uninitsWhenTrue.inclRange(firstadr, nextadr);
        initsWhenFalse.assign(inits);
        uninitsWhenFalse.assign(uninits);
	} else if (tree.type.isTrue()) {
	   /*
		 * 如果给条件分支是 假,那么就设置initsWhenFalse/initsWhenFalse 为inits/uninits.同时
		 * initsWhenFalse/initsWhenFalse包含的变量范围是firstadr-nextadr.
		 * initsWhenFalse/uninitsWhenFalse 就设置为inits/uninits.
		 * 
		 * 举例: if(true){} ,这里分析的就是那个true.那么因为是个常量,就没必要继续扫描了.
		 * initsWhenTrue/uninitsWhenTrue 中的变量和inits/uninits是一样的,不会发生变化
		 */
        if (inits.isReset()) merge(tree);
        initsWhenFalse.assign(inits);
        initsWhenFalse.inclRange(firstadr, nextadr);
        uninitsWhenFalse.assign(uninits);
        uninitsWhenFalse.inclRange(firstadr, nextadr);
        initsWhenTrue.assign(inits);
        uninitsWhenTrue.assign(uninits);
    } else {
       /*
    	 * 这里分析的是if(a > 1){ int a }
    	 */
        scan(tree);
        if (!inits.isReset())
            split(tree.type != syms.unknownType);
    }
    if (tree.type != syms.unknownType) {
    	 // 重置inits, uninits
        resetBits(inits, uninits);
    }
}

scanCond方法还是比较绕的,在本文的后面会有一个案例的.接下来,我们来看一下访问树各个节点的方法.

  1. 首先是访问类定义的方法,定义如下:

    @Override
    public void visitClassDef(JCClassDecl tree) {
    	  // 如果tree 没有对应的符号,则直接return
        if (tree.sym == null) {
            return;
        }
    
    	  // 保留当前Analyzer的状态,会在之后进行复原的
        JCClassDecl classDefPrev = classDef;
        int firstadrPrev = firstadr;
        int nextadrPrev = nextadr;
        ListBuffer<P> pendingExitsPrev = pendingExits;
    
        pendingExits = new ListBuffer<P>();
        if (tree.name != names.empty) {
            firstadr = nextadr;
        }
        classDef = tree;
        try {
            // 处理static fields
            for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                if (l.head.hasTag(VARDEF)) {
                    JCVariableDecl def = (JCVariableDecl)l.head;
                    if ((def.mods.flags & STATIC) != 0) {
                        VarSymbol sym = def.sym;
                        if (trackable(sym)) {// 如果该变量是可追踪的(在当前,意味着该变量是final且未赋值的),就保存到vardecls中
                            newVar(def);
                        }
                    }
                }
            }
    
            // 处理静态初始化器(处理所有的staitc修饰的非方法的定义--字段,块,但是这里不会与上一个循环重复处理的)
            for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                if (!l.head.hasTag(METHODDEF) &&
                    (TreeInfo.flags(l.head) & STATIC) != 0) {
                    scan(l.head);
                }
            }
    
            // 处理实例字段
            for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                if (l.head.hasTag(VARDEF)) {
                    JCVariableDecl def = (JCVariableDecl)l.head;
                    if ((def.mods.flags & STATIC) == 0) {
                        VarSymbol sym = def.sym;
                        if (trackable(sym)) {// 如果该变量是可追踪的(在当前,意味着该变量是final且未赋值的),就保存到vardecls中
                            newVar(def);
                        }
                    }
                }
            }
    
            // 处理实例初始化器
            for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                if (!l.head.hasTag(METHODDEF) &&
                    (TreeInfo.flags(l.head) & STATIC) == 0) {
                    scan(l.head);
                }
            }
    
            // 处理所有的方法
            for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
                if (l.head.hasTag(METHODDEF)) {
                    scan(l.head);
                }
            }
        } finally {
        	  // 回复现场
            pendingExits = pendingExitsPrev;
            nextadr = nextadrPrev;
            firstadr = firstadrPrev;
            classDef = classDefPrev;
        }
    }
    
  2. 访问方法.

    @Override
    public void visitMethodDef(JCMethodDecl tree) {
    	  // 如果该方法的语句体为null,则意味着该方法是一个抽象方法,不处理.
        if (tree.body == null) {
            return;
        }
      	  
      	  // 忽略处理合成方法,但是合成的lambda方法还是处理的
        if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
            return;
        }
    
    	  // 保存现场
        final Bits initsPrev = new Bits(inits);
        final Bits uninitsPrev = new Bits(uninits);
        int nextadrPrev = nextadr;
        int firstadrPrev = firstadr;
        int returnadrPrev = returnadr;
    
        Assert.check(pendingExits.isEmpty());
    
        try {
            boolean isInitialConstructor =
                TreeInfo.isInitialConstructor(tree); // 这是一个构造函数,它的第一个(非合成)语句不是 this(...)的形式吗
    
            if (!isInitialConstructor) {
                firstadr = nextadr;
            }
            
            // 访问方法的参数
            for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
                JCVariableDecl def = l.head;
                scan(def);
                Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
                /*  If we are executing the code from Gen, then there can be
                 *  synthetic or mandated variables, ignore them.
                 */
                initParam(def);
            }
            
            // 处理方法体
            scan(tree.body);
    
            if (isInitialConstructor) {
                boolean isSynthesized = (tree.sym.flags() &
                                         GENERATEDCONSTR) != 0; // 判断该构造器是否是合成的		
                                         					// 这里判断的是构造器是否将类中的变量(final变量但是没有初始赋值的)都初始化了.
                for (int i = firstadr; i < nextadr; i++) {
                    JCVariableDecl vardecl = vardecls[i];
                    VarSymbol var = vardecl.sym;
                    if (var.owner == classDef.sym) {
                        // choose the diagnostic position based on whether
                        // the ctor is default(synthesized) or not
                        if (isSynthesized) {
                            checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
                                var, "var.not.initialized.in.default.constructor");
                        } else {
                            checkInit(TreeInfo.diagEndPos(tree.body), var);
                        }
                    }
                }
            }
            
            // pendingExits 处理,方法结束后,pendingExits如果不为空,那么就只能剩余RETURN
            List<P> exits = pendingExits.toList();
            pendingExits = new ListBuffer<>();
            while (exits.nonEmpty()) {
                P exit = exits.head;
                exits = exits.tail;
                Assert.check(exit.tree.hasTag(RETURN), exit.tree);
                if (isInitialConstructor) {
                    assignToInits(exit.tree, exit.exit_inits);
                    for (int i = firstadr; i < nextadr; i++) {
                        checkInit(exit.tree.pos(), vardecls[i].sym);
                    }
                }
            }
        } finally {
        	  // 恢复现场
            assignToInits(tree, initsPrev);
            uninits.assign(uninitsPrev);
            nextadr = nextadrPrev;
            firstadr = firstadrPrev;
            returnadr = returnadrPrev;
        }
    }
    
    
    protected void initParam(JCVariableDecl def) {
        inits.incl(def.sym.adr);
        uninits.excl(def.sym.adr);
    }
    
  3. 访问变量.

    public void visitVarDef(JCVariableDecl tree) {
    boolean track = trackable(tree.sym);
    if (track && tree.sym.owner.kind == MTH) {// 如果当前变量是方法中的
        newVar(tree);
    }
    if (tree.init != null) {
        scanExpr(tree.init);
        if (track) {
            letInit(tree.pos(), tree.sym);
        }
    }
    }
    
  4. 访问语句块.

    public void visitBlock(JCBlock tree) {
        int nextadrPrev = nextadr;
        scan(tree.stats);
        nextadr = nextadrPrev;
    }
    
  5. 访问if.

    	public void visitIf(JCIf tree) {public void visitIf(JCIf tree) {
    	// 扫描if 语句中的条件
        scanCond(tree.cond);
        // 扫描完condition之后,会设置initsWhenFalse,uninitsWhenFalse,initsWhenTrue,uninitsWhenTrue
        // 那么根据这些,初始化initsBeforeElse,uninitsBeforeElse. 并且将inits设置为 initsWhenTrue,uninits 设置为uninitsWhenTrue.
        /*
         * int c ;
         * int a = 0;
         * if((c = 1) != c){
         * 			
         * }
         * 
         * 则在调用完scanCond之后,initsWhenFalse = {a,c},uninitsWhenFalse={},initsWhenTrue={c,a},uninitsWhenTrue = {}
         * inits = uninits = {}.
         * 执行完下列4行之后.
         * initsBeforeElse = initsWhenFalse = {a,c},uninitsBeforeElse = uninitsWhenFalse={},
         * inits = initsWhenTrue={c,a},uninits = uninitsWhenTrue = {}
         */
        final Bits initsBeforeElse = new Bits(initsWhenFalse);
        final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
        assignToInits(tree.cond, initsWhenTrue);
        uninits.assign(uninitsWhenTrue);
        // 扫描then 部分的代码
        scan(tree.thenpart);
        if (tree.elsepart != null) {
            final Bits initsAfterThen = new Bits(inits);
            final Bits uninitsAfterThen = new Bits(uninits);
            assignToInits(tree.thenpart, initsBeforeElse);
            uninits.assign(uninitsBeforeElse);
            scan(tree.elsepart);
            andSetInits(tree.elsepart, initsAfterThen);
            uninits.andSet(uninitsAfterThen);
        } else {
        	// 最终inits 的集合是 在if 之前初始化和在condition部分初始化和在then部分初始化的交集
            andSetInits(tree.thenpart, initsBeforeElse);
            uninits.andSet(uninitsBeforeElse);
        }
    }
    
  6. 访问 break,continue,return

    @Override
    public void visitBreak(JCBreak tree) {
        recordExit(tree, createNewPendingExit(tree, inits, uninits));
    }
    
    @Override
    public void visitContinue(JCContinue tree) {
        recordExit(tree, createNewPendingExit(tree, inits, uninits));
    }
    
    @Override
    public void visitReturn(JCReturn tree) {
        scanExpr(tree.expr);
        recordExit(tree, createNewPendingExit(tree, inits, uninits));
    }
    
    protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
            return null;
    }
    
  7. 还有访问其他部分的方法,这里就不在赘述了.可自行参看.

接下来,是AbstractAssignAnalyzer的入口,这部分的代码如下:

public void analyzeTree(Env<?> env) {
    analyzeTree(env, env.tree);
 }

public void analyzeTree(Env<?> env, JCTree tree) {
    try {
        startPos = tree.pos().getStartPosition();

        if (vardecls == null)
            vardecls = new JCVariableDecl[32];
        else
            for (int i=0; i<vardecls.length; i++)
                vardecls[i] = null;
        firstadr = 0;
        nextadr = 0;
        pendingExits = new ListBuffer<>();
        this.classDef = null;
        unrefdResources = new Scope(env.enclClass.sym);
        scan(tree);
    } finally {
        // note that recursive invocations of this method fail hard
        startPos = -1;
        resetBits(inits, uninits, uninitsTry, initsWhenTrue,
                initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
        if (vardecls != null) {
            for (int i=0; i<vardecls.length; i++)
                vardecls[i] = null;
        }
        firstadr = 0;
        nextadr = 0;
        pendingExits = null;
        this.classDef = null;
        unrefdResources = null;
    }
}

AssignAnalyzer

AssignAnalyzer --> 继承自AbstractAssignAnalyzer,泛型边界为AssignAnalyzer.AssignPendingExit.定义如下:

public static class AssignPendingExit
            extends AbstractAssignAnalyzer.AbstractAssignPendingExit {

            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
                super(tree, inits, uninits);
            }
}

AssignAnalyzer中的字段有两个,

Log log; // 错误日志输出
Lint lint; // 处理-Xlint子选项和@SuppresssWarnings的类

重写了AbstractAssignAnalyzer的方法如下:

  1. createNewPendingExit方法:

    @Override
    protected AssignPendingExit createNewPendingExit(JCTree tree,
        Bits inits, Bits uninits) {
        return new AssignPendingExit(tree, inits, uninits);
    }
    
  2. letInit

     void letInit(DiagnosticPosition pos, VarSymbol sym) {
            if (sym.adr >= firstadr && trackable(sym)) {// 如果该变量是可以追踪的
                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {// 如果该变量是有效final的
                    if (!uninits.isMember(sym.adr)) {// 如果不是uninits的成员,则修改变量不是有效final的
                        //assignment targeting an effectively final variable
                        //makes the variable lose its status of effectively final
                        //if the variable is _not_ definitively unassigned
                        sym.flags_field &= ~EFFECTIVELY_FINAL;
                    } else {
                    	// 从uninits中去除
                        uninit(sym);
                    }
                }
                else if ((sym.flags() & FINAL) != 0) {// 如果该变量是final的
                    if ((sym.flags() & PARAMETER) != 0) {// 是参数
                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
                        }
                        else {
                            log.error(pos, "final.parameter.may.not.be.assigned",
                                  sym);
                        }
                    } else if (!uninits.isMember(sym.adr)) {
                        log.error(pos, flowKind.errKey, sym);
                    } else {
                        uninit(sym);
                    }
                }
                inits.incl(sym.adr);
            } else if ((sym.flags() & FINAL) != 0) {
                log.error(pos, "var.might.already.be.assigned", sym);
            }
        }
    

    该方法的逻辑如下:

    1. 如果该变量的地址大于firstadr并且该变量是可追踪的
      1. 如果该变量是有效final的
        1. 如果该变量不是 uninits 的成员,则修改变量的修饰符为不是有效final的
        2. 否则从uninits中去除该变量
      2. 如果该变量是final的,
        1. 如果该变量是参数
          1. 如果该变量是try-multi-catch 的参数,那么就是一个错误–> multicatch.parameter.may.not.be.assigned.

          2. 否则,就是一个final.parameter.may.not.be.assigned的错误(final类型的参数是不能再被赋值的)

        2. 如果该变量不是 uninits 的成员,则该变量可能已经付过值了
        3. 否则从uninits中去除该变量
          不管是1还是2,处理完之后,都将该变量加入到inits中
    2. 否则,如果该变量是final的,则该变量可能已经赋值过了
    3. 其他情况不处理
  3. checkInit 方法,代码如下:

    void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
        if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
            trackable(sym) &&
            !inits.isMember(sym.adr)) {
            log.error(pos, errkey, sym);
            inits.incl(sym.adr);
        }
    }
    
  4. reportWarning 方法:

    void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
        String key, Object ... args) {
        log.warning(lc, pos, key, args);
    }
    
  5. getLogNumberOfErrors:

    int getLogNumberOfErrors() {
            return log.nerrors;
    }
    
  6. isEnabled:

    boolean isEnabled(Lint.LintCategory lc) {
    	return lint.isEnabled(lc);
    }
    
  7. visitClassDef:

    public void visitClassDef(JCClassDecl tree) {
            if (tree.sym == null) {
                return;
            }
    
            Lint lintPrev = lint;
            lint = lint.augment(tree.sym);
            try {
                super.visitClassDef(tree);
            } finally {
                lint = lintPrev;
            }
    }
    
  8. visitMethodDef:

     public void visitMethodDef(JCMethodDecl tree) {
            if (tree.body == null) {
                return;
            }
    
            // 合成方法不处理
            if ((tree.sym.flags() & SYNTHETIC) != 0) {
                return;
            }
    
            Lint lintPrev = lint;
            lint = lint.augment(tree.sym);
            try {
                super.visitMethodDef(tree);
            } finally {
                lint = lintPrev;
            }
    }
    
  9. visitVarDef:

    public void visitVarDef(JCVariableDecl tree) {
        if (tree.init == null) {
            super.visitVarDef(tree);
        } else {
            Lint lintPrev = lint;
            lint = lint.augment(tree.sym);
            try{
                super.visitVarDef(tree);
            } finally {
                lint = lintPrev;
            }
        }
    }
    

这部分还是比较简单的,后续的文章会举例子来进行讲解的.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值