Check類のduplicate declaration checking/class name generation/type Checking

10972 ワード


1、duplicate declaration checking


 
/** Check that variable does not hide variable with same name in
     *  immediately enclosing local scope.
     *
     *  e.g
     *  public void m1(boolean a){
     *       int a = 3;
     *       boolean a = true; //  checkTransparentVar() , checkUnique() 
     *  }
     *
     *  @param pos           Position for error reporting.
     *  @param v             The symbol.
     *  @param s             The scope.
     */
    void checkTransparentVar(DiagnosticPosition pos, VarSymbol v, Scope s) {
        if (s.next != null) {
            for (Scope.Entry e = s.next.lookup(v.name);
                 e.scope != null && e.sym.owner == v.owner;
                 e = e.next()) {
                if (e.sym.kind == VAR &&
                    (e.sym.owner.kind & (VAR | MTH)) != 0 &&
                    v.name != names.error) {
                    duplicateError(pos, e.sym);
                    return;
                }
            }
        }
    }

e.g
	public void m1(boolean a){
		int a = 3;
		
		for(int x = 0;x<2;x++){
			int x = 3;
		}
	}

ここで、int a=3およびint x=3は、checkTransparentVar()メソッドを呼び出して重複宣言を検出する.
 
 
/** Check that a class or interface does not hide a class or
     *  interface with same name in immediately enclosing local scope.
     *  @param pos           Position for error reporting.
     *  @param c             The symbol.
     *  @param s             The scope.
     */
    void checkTransparentClass(DiagnosticPosition pos, ClassSymbol c, Scope s) {
        if (s.next != null) {
            for (Scope.Entry e = s.next.lookup(c.name);
                 e.scope != null && e.sym.owner == c.owner;
                 e = e.next()) {
                if (e.sym.kind == TYP && e.sym.type.tag != TYPEVAR &&
                    (e.sym.owner.kind & (VAR | MTH)) != 0 &&
                    c.name != names.error) {
                    duplicateError(pos, e.sym);
                    return;
                }
            }
        }
    }

 
e.g
	public void m1() {
		class A{}
		{
			class A{} // err Duplicate nested type A
		}
	

e.symの場合owner.kindがVARの場合はまだ例を挙げていません.  
 
 /** Check that class does not have the same name as one of
     *  its enclosing classes, or as a class defined in its enclosing scope.
     *  return true if class is unique in its enclosing scope.
     *  @param pos           Position for error reporting.
     *  @param name          The class name.
     *  @param s             The enclosing scope.
     */
    boolean checkUniqueClassName(DiagnosticPosition pos, Name name, Scope s) {
        for (Scope.Entry e = s.lookup(name); e.scope == s; e = e.next()) {
            if (e.sym.kind == TYP && e.sym.name != names.error) {
                duplicateError(pos, e.sym);
                return false;
            }
        }
        for (Symbol sym = s.owner; sym != null; sym = sym.owner) {
            if (sym.kind == TYP && sym.name == name && sym.name != names.error) {
                duplicateError(pos, sym);
                return true;
            }
        }
        return true;
    }

e.g
	{
		class A {}
		interface A{} // A checkUniqueClassName()  
	}
	{
		class B {
			class B {
			}
		}
	}

  

2、Class name generation


 


 
 /** Return name of local class.
     *  This is of the form     $ n 
     *  where
     *    enclClass is the flat name of the enclosing class,
     *    classname is the simple name of the local class
     */
    Name localClassName(ClassSymbol c) {
        for (int i=1; ; i++) {
            Name flatname = names.
                fromString("" + c.owner.enclClass().flatname +
                           syntheticNameChar + i +
                           c.name);
            if (compiled.get(flatname) == null)
                return flatname;
        }
    }

 
 
e.g
package com.test07;
public class Test3{
	
	interface I {
	}

	// com.test07.Test3$1
	final I i1 = new I() {

	};
	
	// com.test07.Test3$2
	final I i2 = new I() {

	};

	{
		// com.test07.Test3$1B
		class B {
		}
	}


	public void m1() {
		// com.test07.Test3$2B
		class B {
		}
		// com.test07.Test3$1C
		class C {
		}
		// com.test07.Test3$3
		final I i3 = new I() {

		};
	}
	
	public void m2() {
		// com.test07.Test3$3B
		class B {
		}
		// com.test07.Test3$1D
		class D {
		}
	}

}

  
  

3、Type Checking


 
   /** Check that a given type is assignable to a given proto-type.
     *  If it is, return the type, otherwise return errType.
     *  @param pos        Position to be used for error reporting.
     *  @param found      The type that was found.
     *  @param req        The type that was required.
     */
    Type checkType(DiagnosticPosition pos, Type found, Type req) {
        //  
        return checkType(pos, found, req, "incompatible.types");
    }

    Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) {
        if (req.tag == ERROR)
            return req;
        if (found.tag == FORALL)
            return instantiatePoly(pos, (ForAll)found, req, convertWarner(pos, found, req));
        if (req.tag == NONE)
            return found;
        if (types.isAssignable(found, req, convertWarner(pos, found, req)))
            return found;
        if (found.tag <= DOUBLE && req.tag <= DOUBLE)
            //  
            return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req);
        if (found.isSuperBound()) {
            //   super-bound  {0} 
            log.error(pos, "assignment.from.super-bound", found);
            return types.createErrorType(found);
        }
        if (req.isExtendsBound()) {
            log.error(pos, "assignment.to.extends-bound", req);
            return types.createErrorType(found);
        }
        return typeError(pos, diags.fragment(errKey), found, req);
    }

 
checkTypeメソッドは主にAttrクラスのcheck()メソッドで呼び出されます.このメソッドのコードは次のとおりです.
 /** Check kind and type of given tree against protokind and prototype.
     *  If check succeeds, store type in tree and return it.
     *  If check fails, store errType in tree and return it.
     *  No checks are performed if the prototype is a method type.
     *  It is not necessary in this case since we know that kind and type
     *  are correct.
     *
     *  @param tree     The tree whose kind and type is checked
     *  @param owntype  The computed type of the tree
     *  @param ownkind  The computed kind of the tree
     *  @param protokind    The expected kind (or: protokind) of the tree
     *  @param prototype       The expected type (or: prototype) of the tree
     */
    Type check(JCTree tree, Type owntype, int ownkind, int protokind, Type prototype) {
    	// prototype method type
        if (owntype.tag != ERROR && prototype.tag != METHOD && prototype.tag != FORALL) {
            if ((ownkind & ~protokind) == 0) {
                owntype = chk.checkType(tree.pos(), owntype, prototype, errKey);
            } else {
                log.error(tree.pos(), "unexpected.type",kindNames(protokind),kindName(ownkind));
                owntype = types.createErrorType(owntype);
            }
        }
        tree.type = owntype;
        return owntype;
    }

  
owntypeとprototypeはいずれもTypeタイプであり、そのtagの値はTypeクラスの予め定義された値である.
ownkindもprotokindもintタイプであり、その値はKindsが予め定義した値である.
上記の2種類の値を比較することにより,文法ノードのTypeタイプとSymbolタイプを比較した.
 
 
 
 
 /** Check that a type is within some bounds.
     *
     *  Used in TypeApply to verify that, e.g., X in V is a valid type argument.
     *  @param pos           Position to be used for error reporting.
     *  @param a             The type that should be bounded by bs.
     *  @param bs            The bound.
     */
    private boolean checkExtends(Type a, Type bound) {
         if (a.isUnbound()) {
             return true;
         } else if (a.tag != WILDCARD) {
             a = types.upperBound(a);
             return types.isSubtype(a, bound);
         } else if (a.isExtendsBound()) {
             Type ut = types.upperBound(a);
             boolean result = types.isCastable(bound, ut , Warner.noWarnings);
             return result;
         } else if (a.isSuperBound()) {
             Type lt = types.lowerBound(a);
             boolean result = !types.notSoftSubtype(lt, bound);
             return result;
         }
         return true;
     }

e.g
class BC {
	public void test() {
		BC a = null;
		BC extends InputStream> b = null;
		BC super InputStream> c = null;		
	}
}

a.isExtendsBound()の場合、isCastable()メソッドが使用されます.
a.isSuperBound()の場合、notSoftSubtype()メソッドが使用されます.