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()メソッドが使用されます.