/** * Check to see if a class must be abstract. This method replaces * isAbstract(env) */ public final boolean mustBeAbstract(Environment env) { // If it is declared abstract, return true. // (Fix for 4110534.) if (isAbstract()) { return true; } // Check to see if the class should have been declared to be // abstract. // We make sure that the inherited method collection has been // performed. collectInheritedMethods(env); // We check for any abstract methods inherited or declared // by this class. Iterator methods = getMethods(); while (methods.hasNext()) { MemberDefinition method = (MemberDefinition) methods.next(); if (method.isAbstract()) { return true; } } // We check for hidden "permanently abstract" methods in // our superclasses. return getPermanentlyAbstractMethods().hasNext(); } /** * Check if this is a super class of another class */ public boolean superClassOf(Environment env, ClassDeclaration otherClass) throws ClassNotFound { while (otherClass != null) { if (getClassDeclaration().equals(otherClass)) { return true; } otherClass = otherClass.getClassDefinition(env).getSuperClass(); } return false; } /** * Check if this is an enclosing class of another class */ public boolean enclosingClassOf(ClassDefinition otherClass) { while ((otherClass = otherClass.getOuterClass()) != null) { if (this == otherClass) { return true; } } return false; } /** * Check if this is a sub class of another class */ public boolean subClassOf(Environment env, ClassDeclaration otherClass) throws ClassNotFound { ClassDeclaration c = getClassDeclaration(); while (c != null) { if (c.equals(otherClass)) { return true; } c = c.getClassDefinition(env).getSuperClass(); } return false; } /** * Check if this class is implemented by another class */ public boolean implementedBy(Environment env, ClassDeclaration c) throws ClassNotFound { for (; c != null ; c = c.getClassDefinition(env).getSuperClass()) { if (getClassDeclaration().equals(c)) { return true; } ClassDeclaration intf[] = c.getClassDefinition(env).getInterfaces(); for (int i = 0 ; i < intf.length ; i++) { if (implementedBy(env, intf[i])) { return true; } } } return false; } /** * Check to see if a class which implements interface `this' could * possibly implement the interface `intDef'. Note that the only * way that this can fail is if `this' and `intDef' have methods * which are of the same signature and different return types. This * method is used by Environment.explicitCast() to determine if a * cast between two interfaces is legal. * * This method should only be called on a class after it has been * basicCheck()'ed. */ public boolean couldImplement(ClassDefinition intDef) { // Check to see if we could have done the necessary checks. if (!doInheritanceChecks) { throw new CompilerError("couldImplement: no checks"); } // This method should only be called for interfaces. if (!isInterface() || !intDef.isInterface()) { throw new CompilerError("couldImplement: not interface"); } // Make sure we are not called before we have collected our // inheritance information. if (allMethods == null) { throw new CompilerError("couldImplement: called early"); } // Get the other classes' methods. getMethods() in // general can return methods which are not visible to the // current package. We need to make sure that these do not // prevent this class from being implemented. Iterator otherMethods = intDef.getMethods(); while (otherMethods.hasNext()) { // Get one of the methods from intDef... MemberDefinition method = (MemberDefinition) otherMethods.next(); Identifier name = method.getName(); Type type = method.getType(); // See if we implement a method of the same signature... MemberDefinition myMethod = allMethods.lookupSig(name, type); //System.out.println("Comparing\n\t" + myMethod + // "\nand\n\t" + method); if (myMethod != null) { // We do. Make sure the methods have the same return type. if (!myMethod.sameReturnType(method)) { return false; } } } return true; } /** * Check if another class can be accessed from the 'extends' or 'implements' * clause of this class. */ public boolean extendsCanAccess(Environment env, ClassDeclaration c) throws ClassNotFound { // Names in the 'extends' or 'implements' clause of an inner class // are checked as if they appeared in the body of the surrounding class. if (outerClass != null) { return outerClass.canAccess(env, c); } // We are a package member. ClassDefinition cdef = c.getClassDefinition(env); if (cdef.isLocal()) { // No locals should be in scope in the 'extends' or // 'implements' clause of a package member. throw new CompilerError("top local"); } if (cdef.isInnerClass()) { MemberDefinition f = cdef.getInnerClassMember(); // Access to public member is always allowed. if (f.isPublic()) { return true; } // Private access is ok only from the same class nest. This can // happen only if the class represented by 'this' encloses the inner // class represented by 'f'. if (f.isPrivate()) { return getClassDeclaration().equals(f.getTopClass().getClassDeclaration()); } // Protected or default access -- allow access if in same package. return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier()); } // Access to public member is always allowed. if (cdef.isPublic()) { return true; } // Default access -- allow access if in same package. return getName().getQualifier().equals(c.getName().getQualifier()); } /** * Check if another class can be accessed from within the body of this class. */ public boolean canAccess(Environment env, ClassDeclaration c) throws ClassNotFound { ClassDefinition cdef = c.getClassDefinition(env); if (cdef.isLocal()) { // if it's in scope, it's accessible return true; } if (cdef.isInnerClass()) { return canAccess(env, cdef.getInnerClassMember()); } // Public access is always ok if (cdef.isPublic()) { return true; } // It must be in the same package return getName().getQualifier().equals(c.getName().getQualifier()); } /** * Check if a field can be accessed from a class */ public boolean canAccess(Environment env, MemberDefinition f) throws ClassNotFound { // Public access is always ok if (f.isPublic()) { return true; } // Protected access is ok from a subclass if (f.isProtected() && subClassOf(env, f.getClassDeclaration())) { return true; } // Private access is ok only from the same class nest if (f.isPrivate()) { return getTopClass().getClassDeclaration() .equals(f.getTopClass().getClassDeclaration()); } // It must be in the same package return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier()); } /** * Check if a class is entitled to inline access to a class from * another class. */ public boolean permitInlinedAccess(Environment env, ClassDeclaration c) throws ClassNotFound { return (env.opt() && c.equals(declaration)) || (env.opt_interclass() && canAccess(env, c)); } /** * Check if a class is entitled to inline access to a method from * another class. */ public boolean permitInlinedAccess(Environment env, MemberDefinition f) throws ClassNotFound { return (env.opt() && (f.clazz.getClassDeclaration().equals(declaration))) || (env.opt_interclass() && canAccess(env, f)); } /** * We know the the field is marked protected (and not public) and that * the field is visible (as per canAccess). Can we access the field as * <accessor>.<field>, where <accessor> has the type <accessorType>? * * Protected fields can only be accessed when the accessorType is a * subclass of the current class */ public boolean protectedAccess(Environment env, MemberDefinition f, Type accessorType) throws ClassNotFound { return // static protected fields are accessible f.isStatic() || // allow array.clone() (accessorType.isType(TC_ARRAY) && (f.getName() == idClone) && (f.getType().getArgumentTypes().length == 0)) || // <accessorType> is a subtype of the current class (accessorType.isType(TC_CLASS) && env.getClassDefinition(accessorType.getClassName()) .subClassOf(env, getClassDeclaration())) || // we are accessing the field from a friendly class (same package) (getName().getQualifier() .equals(f.getClassDeclaration().getName().getQualifier())); } /** * Find or create an access method for a private member, * or return null if this is not possible. */ public MemberDefinition getAccessMember(Environment env, Context ctx, MemberDefinition field, boolean isSuper) { throw new CompilerError("binary getAccessMember"); } /** * Find or create an update method for a private member, * or return null if this is not possible. */ public MemberDefinition getUpdateMember(Environment env, Context ctx, MemberDefinition field, boolean isSuper) { throw new CompilerError("binary getUpdateMember"); } /** * Get a field from this class. Report ambiguous fields. * If no accessible field is found, this method may return an * inaccessible field to allow a useful error message. * * getVariable now takes the source class `source' as an argument. * This allows getVariable to check whether a field is inaccessible * before it signals that a field is ambiguous. The compiler used to * signal an ambiguity even when one of the fields involved was not * accessible. (bug 4053724) */ public MemberDefinition getVariable(Environment env, Identifier nm, ClassDefinition source) throws AmbiguousMember, ClassNotFound { return getVariable0(env, nm, source, true, true); } /* * private fields are never inherited. package-private fields are * not inherited across package boundaries. To capture this, we * take two booleans as parameters: showPrivate indicates whether * we have passed a class boundary, and showPackage indicates whether * we have crossed a package boundary. */ private MemberDefinition getVariable0(Environment env, Identifier nm, ClassDefinition source, boolean showPrivate, boolean showPackage) throws AmbiguousMember, ClassNotFound { // Check to see if this field is defined in the current class for (MemberDefinition member = getFirstMatch(nm); member != null; member = member.getNextMatch()) { if (member.isVariable()) { if ((showPrivate || !member.isPrivate()) && (showPackage || !member.isPackagePrivate())) { // It is defined in this class. return member; } else { // Even though this definition is not inherited, // it hides all definitions in supertypes. return null; } } } // Find the field in our superclass. ClassDeclaration sup = getSuperClass(); MemberDefinition field = null; if (sup != null) { field = sup.getClassDefinition(env) .getVariable0(env, nm, source, false, showPackage && inSamePackage(sup)); } // Find the field in our superinterfaces. for (int i = 0 ; i < interfaces.length ; i++) { // Try to look up the field in an interface. Since interfaces // only have public fields, the values of the two boolean // arguments are not important. MemberDefinition field2 = interfaces[i].getClassDefinition(env) .getVariable0(env, nm, source, true, true); if (field2 != null) { // If we have two different, accessible fields, then // we've found an ambiguity. if (field != null && source.canAccess(env, field) && field2 != field) { throw new AmbiguousMember(field2, field); } field = field2; } } return field; } /** * Tells whether to report a deprecation error for this class. */ public boolean reportDeprecated(Environment env) { return (isDeprecated() || (outerClass != null && outerClass.reportDeprecated(env))); } /** * Note that this class is being used somehow by <tt>ref</tt>. * Report deprecation errors, etc. */ public void noteUsedBy(ClassDefinition ref, long where, Environment env) { // (Have this deal with canAccess() checks, too?) if (reportDeprecated(env)) { env.error(where, "warn.class.is.deprecated", this); } } /** * Get an inner class. * Look in supers but not outers. * (This is used directly to resolve expressions like "site.K", and * inside a loop to resolve lone names like "K" or the "K" in "K.L".) * * Called from 'Context' and 'FieldExpression' as well as this class. * * @see FieldExpression.checkCommon * @see resolveName */ public MemberDefinition getInnerClass(Environment env, Identifier nm) throws ClassNotFound { // Note: AmbiguousClass will not be thrown unless and until // inner classes can be defined inside interfaces. // Check if it is defined in the current class for (MemberDefinition field = getFirstMatch(nm); field != null ; field = field.getNextMatch()) { if (field.isInnerClass()) { if (field.getInnerClass().isLocal()) { continue; // ignore this name; it is internally generated } return field; } } // Get it from the super class // It is likely that 'getSuperClass()' could be made to work here // but we would have to assure somehow that 'resolveTypeStructure' // has been called on the current class nest. Since we can get // here from 'resolveName', which is called from 'resolveSupers', // it is possible that the first attempt to resolve the superclass // will originate here, instead of in the call to 'getSuperClass' // in 'checkSupers'. See 'resolveTypeStructure', in which a call // to 'resolveSupers' precedes the call to 'checkSupers'. Why is // name resolution done twice, first in 'resolveName'? // NOTE: 'SourceMember.resolveTypeStructure' may initiate type // structure resolution for an inner class. Normally, this // occurs during the resolution of the outer class, but fields // added after the resolution of their containing class will // be resolved late -- see 'addMember(env,field)' below. // This should only happen for synthetic members, which should // never be an inner class. ClassDeclaration sup = getSuperClass(env); if (sup != null) return sup.getClassDefinition(env).getInnerClass(env, nm); return null; } /** * Lookup a method. This code implements the method lookup * mechanism specified in JLS 15.11.2. * * This mechanism cannot be used to lookup synthetic methods. */ private MemberDefinition matchMethod(Environment env, ClassDefinition accessor, Identifier methodName, Type[] argumentTypes, boolean isAnonConstCall, Identifier accessPackage) throws AmbiguousMember, ClassNotFound { if (allMethods == null || !allMethods.isFrozen()) { // This may be too restrictive. throw new CompilerError("matchMethod called early"); // collectInheritedMethods(env); } // A tentative maximally specific method. MemberDefinition tentative = null; // A list of other methods which may be maximally specific too. List candidateList = null; Lines 501–1000 of 2085. Previous lines Load more
/** * Check to see if a class must be abstract. This method replaces * isAbstract(env) */ public final boolean mustBeAbstract(Environment env) { // If it is declared abstract, return true. // (Fix for 4110534.) if (isAbstract()) { return true; } // Check to see if the class should have been declared to be // abstract. // We make sure that the inherited method collection has been // performed. collectInheritedMethods(env); // We check for any abstract methods inherited or declared // by this class. Iterator methods = getMethods(); while (methods.hasNext()) { MemberDefinition method = (MemberDefinition) methods.next(); if (method.isAbstract()) { return true; } } // We check for hidden "permanently abstract" methods in // our superclasses. return getPermanentlyAbstractMethods().hasNext(); } /** * Check if this is a super class of another class */ public boolean superClassOf(Environment env, ClassDeclaration otherClass) throws ClassNotFound { while (otherClass != null) { if (getClassDeclaration().equals(otherClass)) { return true; } otherClass = otherClass.getClassDefinition(env).getSuperClass(); } return false; } /** * Check if this is an enclosing class of another class */ public boolean enclosingClassOf(ClassDefinition otherClass) { while ((otherClass = otherClass.getOuterClass()) != null) { if (this == otherClass) { return true; } } return false; } /** * Check if this is a sub class of another class */ public boolean subClassOf(Environment env, ClassDeclaration otherClass) throws ClassNotFound { ClassDeclaration c = getClassDeclaration(); while (c != null) { if (c.equals(otherClass)) { return true; } c = c.getClassDefinition(env).getSuperClass(); } return false; } /** * Check if this class is implemented by another class */ public boolean implementedBy(Environment env, ClassDeclaration c) throws ClassNotFound { for (; c != null ; c = c.getClassDefinition(env).getSuperClass()) { if (getClassDeclaration().equals(c)) { return true; } ClassDeclaration intf[] = c.getClassDefinition(env).getInterfaces(); for (int i = 0 ; i < intf.length ; i++) { if (implementedBy(env, intf[i])) { return true; } } } return false; } /** * Check to see if a class which implements interface `this' could * possibly implement the interface `intDef'. Note that the only * way that this can fail is if `this' and `intDef' have methods * which are of the same signature and different return types. This * method is used by Environment.explicitCast() to determine if a * cast between two interfaces is legal. * * This method should only be called on a class after it has been * basicCheck()'ed. */ public boolean couldImplement(ClassDefinition intDef) { // Check to see if we could have done the necessary checks. if (!doInheritanceChecks) { throw new CompilerError("couldImplement: no checks"); } // This method should only be called for interfaces. if (!isInterface() || !intDef.isInterface()) { throw new CompilerError("couldImplement: not interface"); } // Make sure we are not called before we have collected our // inheritance information. if (allMethods == null) { throw new CompilerError("couldImplement: called early"); } // Get the other classes' methods. getMethods() in // general can return methods which are not visible to the // current package. We need to make sure that these do not // prevent this class from being implemented. Iterator otherMethods = intDef.getMethods(); while (otherMethods.hasNext()) { // Get one of the methods from intDef... MemberDefinition method = (MemberDefinition) otherMethods.next(); Identifier name = method.getName(); Type type = method.getType(); // See if we implement a method of the same signature... MemberDefinition myMethod = allMethods.lookupSig(name, type); //System.out.println("Comparing\n\t" + myMethod + // "\nand\n\t" + method); if (myMethod != null) { // We do. Make sure the methods have the same return type. if (!myMethod.sameReturnType(method)) { return false; } } } return true; } /** * Check if another class can be accessed from the 'extends' or 'implements' * clause of this class. */ public boolean extendsCanAccess(Environment env, ClassDeclaration c) throws ClassNotFound { // Names in the 'extends' or 'implements' clause of an inner class // are checked as if they appeared in the body of the surrounding class. if (outerClass != null) { return outerClass.canAccess(env, c); } // We are a package member. ClassDefinition cdef = c.getClassDefinition(env); if (cdef.isLocal()) { // No locals should be in scope in the 'extends' or // 'implements' clause of a package member. throw new CompilerError("top local"); } if (cdef.isInnerClass()) { MemberDefinition f = cdef.getInnerClassMember(); // Access to public member is always allowed. if (f.isPublic()) { return true; } // Private access is ok only from the same class nest. This can // happen only if the class represented by 'this' encloses the inner // class represented by 'f'. if (f.isPrivate()) { return getClassDeclaration().equals(f.getTopClass().getClassDeclaration()); } // Protected or default access -- allow access if in same package. return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier()); } // Access to public member is always allowed. if (cdef.isPublic()) { return true; } // Default access -- allow access if in same package. return getName().getQualifier().equals(c.getName().getQualifier()); } /** * Check if another class can be accessed from within the body of this class. */ public boolean canAccess(Environment env, ClassDeclaration c) throws ClassNotFound { ClassDefinition cdef = c.getClassDefinition(env); if (cdef.isLocal()) { // if it's in scope, it's accessible return true; } if (cdef.isInnerClass()) { return canAccess(env, cdef.getInnerClassMember()); } // Public access is always ok if (cdef.isPublic()) { return true; } // It must be in the same package return getName().getQualifier().equals(c.getName().getQualifier()); } /** * Check if a field can be accessed from a class */ public boolean canAccess(Environment env, MemberDefinition f) throws ClassNotFound { // Public access is always ok if (f.isPublic()) { return true; } // Protected access is ok from a subclass if (f.isProtected() && subClassOf(env, f.getClassDeclaration())) { return true; } // Private access is ok only from the same class nest if (f.isPrivate()) { return getTopClass().getClassDeclaration() .equals(f.getTopClass().getClassDeclaration()); } // It must be in the same package return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier()); } /** * Check if a class is entitled to inline access to a class from * another class. */ public boolean permitInlinedAccess(Environment env, ClassDeclaration c) throws ClassNotFound { return (env.opt() && c.equals(declaration)) || (env.opt_interclass() && canAccess(env, c)); } /** * Check if a class is entitled to inline access to a method from * another class. */ public boolean permitInlinedAccess(Environment env, MemberDefinition f) throws ClassNotFound { return (env.opt() && (f.clazz.getClassDeclaration().equals(declaration))) || (env.opt_interclass() && canAccess(env, f)); } /** * We know the the field is marked protected (and not public) and that * the field is visible (as per canAccess). Can we access the field as * <accessor>.<field>, where <accessor> has the type <accessorType>? * * Protected fields can only be accessed when the accessorType is a * subclass of the current class */ public boolean protectedAccess(Environment env, MemberDefinition f, Type accessorType) throws ClassNotFound { return // static protected fields are accessible f.isStatic() || // allow array.clone() (accessorType.isType(TC_ARRAY) && (f.getName() == idClone) && (f.getType().getArgumentTypes().length == 0)) || // <accessorType> is a subtype of the current class (accessorType.isType(TC_CLASS) && env.getClassDefinition(accessorType.getClassName()) .subClassOf(env, getClassDeclaration())) || // we are accessing the field from a friendly class (same package) (getName().getQualifier() .equals(f.getClassDeclaration().getName().getQualifier())); } /** * Find or create an access method for a private member, * or return null if this is not possible. */ public MemberDefinition getAccessMember(Environment env, Context ctx, MemberDefinition field, boolean isSuper) { throw new CompilerError("binary getAccessMember"); } /** * Find or create an update method for a private member, * or return null if this is not possible. */ public MemberDefinition getUpdateMember(Environment env, Context ctx, MemberDefinition field, boolean isSuper) { throw new CompilerError("binary getUpdateMember"); } /** * Get a field from this class. Report ambiguous fields. * If no accessible field is found, this method may return an * inaccessible field to allow a useful error message. * * getVariable now takes the source class `source' as an argument. * This allows getVariable to check whether a field is inaccessible * before it signals that a field is ambiguous. The compiler used to * signal an ambiguity even when one of the fields involved was not * accessible. (bug 4053724) */ public MemberDefinition getVariable(Environment env, Identifier nm, ClassDefinition source) throws AmbiguousMember, ClassNotFound { return getVariable0(env, nm, source, true, true); } /* * private fields are never inherited. package-private fields are * not inherited across package boundaries. To capture this, we * take two booleans as parameters: showPrivate indicates whether * we have passed a class boundary, and showPackage indicates whether * we have crossed a package boundary. */ private MemberDefinition getVariable0(Environment env, Identifier nm, ClassDefinition source, boolean showPrivate, boolean showPackage) throws AmbiguousMember, ClassNotFound { // Check to see if this field is defined in the current class for (MemberDefinition member = getFirstMatch(nm); member != null; member = member.getNextMatch()) { if (member.isVariable()) { if ((showPrivate || !member.isPrivate()) && (showPackage || !member.isPackagePrivate())) { // It is defined in this class. return member; } else { // Even though this definition is not inherited, // it hides all definitions in supertypes. return null; } } } // Find the field in our superclass. ClassDeclaration sup = getSuperClass(); MemberDefinition field = null; if (sup != null) { field = sup.getClassDefinition(env) .getVariable0(env, nm, source, false, showPackage && inSamePackage(sup)); } // Find the field in our superinterfaces. for (int i = 0 ; i < interfaces.length ; i++) { // Try to look up the field in an interface. Since interfaces // only have public fields, the values of the two boolean // arguments are not important. MemberDefinition field2 = interfaces[i].getClassDefinition(env) .getVariable0(env, nm, source, true, true); if (field2 != null) { // If we have two different, accessible fields, then // we've found an ambiguity. if (field != null && source.canAccess(env, field) && field2 != field) { throw new AmbiguousMember(field2, field); } field = field2; } } return field; } /** * Tells whether to report a deprecation error for this class. */ public boolean reportDeprecated(Environment env) { return (isDeprecated() || (outerClass != null && outerClass.reportDeprecated(env))); } /** * Note that this class is being used somehow by <tt>ref</tt>. * Report deprecation errors, etc. */ public void noteUsedBy(ClassDefinition ref, long where, Environment env) { // (Have this deal with canAccess() checks, too?) if (reportDeprecated(env)) { env.error(where, "warn.class.is.deprecated", this); } } /** * Get an inner class. * Look in supers but not outers. * (This is used directly to resolve expressions like "site.K", and * inside a loop to resolve lone names like "K" or the "K" in "K.L".) * * Called from 'Context' and 'FieldExpression' as well as this class. * * @see FieldExpression.checkCommon * @see resolveName */ public MemberDefinition getInnerClass(Environment env, Identifier nm) throws ClassNotFound { // Note: AmbiguousClass will not be thrown unless and until // inner classes can be defined inside interfaces. // Check if it is defined in the current class for (MemberDefinition field = getFirstMatch(nm); field != null ; field = field.getNextMatch()) { if (field.isInnerClass()) { if (field.getInnerClass().isLocal()) { continue; // ignore this name; it is internally generated } return field; } } // Get it from the super class // It is likely that 'getSuperClass()' could be made to work here // but we would have to assure somehow that 'resolveTypeStructure' // has been called on the current class nest. Since we can get // here from 'resolveName', which is called from 'resolveSupers', // it is possible that the first attempt to resolve the superclass // will originate here, instead of in the call to 'getSuperClass' // in 'checkSupers'. See 'resolveTypeStructure', in which a call // to 'resolveSupers' precedes the call to 'checkSupers'. Why is // name resolution done twice, first in 'resolveName'? // NOTE: 'SourceMember.resolveTypeStructure' may initiate type // structure resolution for an inner class. Normally, this // occurs during the resolution of the outer class, but fields // added after the resolution of their containing class will // be resolved late -- see 'addMember(env,field)' below. // This should only happen for synthetic members, which should // never be an inner class. ClassDeclaration sup = getSuperClass(env); if (sup != null) return sup.getClassDefinition(env).getInnerClass(env, nm); return null; } /** * Lookup a method. This code implements the method lookup * mechanism specified in JLS 15.11.2. * * This mechanism cannot be used to lookup synthetic methods. */ private MemberDefinition matchMethod(Environment env, ClassDefinition accessor, Identifier methodName, Type[] argumentTypes, boolean isAnonConstCall, Identifier accessPackage) throws AmbiguousMember, ClassNotFound { if (allMethods == null || !allMethods.isFrozen()) { // This may be too restrictive. throw new CompilerError("matchMethod called early"); // collectInheritedMethods(env); } // A tentative maximally specific method. MemberDefinition tentative = null; // A list of other methods which may be maximally specific too. List candidateList = null;