Clover coverage report - DynamicJava Test Coverage (dynamicjava-20120303-r5436)
Coverage timestamp: Sat Mar 3 2012 03:02:19 CST
file stats: LOC: 426   Methods: 24
NCLOC: 229   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
TypeNameChecker.java 66.1% 66.2% 100% 69.8%
coverage coverage
 1    /*
 2    * DynamicJava - Copyright (C) 1999-2001
 3    *
 4    * Permission is hereby granted, free of charge, to any person obtaining a
 5    * copy of this software and associated documentation files
 6    * (the "Software"), to deal in the Software without restriction, including
 7    * without limitation the rights to use, copy, modify, merge, publish,
 8    * distribute, sublicense, and/or sell copies of the Software, and to permit
 9    * persons to whom the Software is furnished to do so, subject to the
 10    * following conditions:
 11    * The above copyright notice and this permission notice shall be included
 12    * in all copies or substantial portions of the Software.
 13    *
 14    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 15    * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 16    * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 17    * IN NO EVENT SHALL DYADE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 19    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 20    * DEALINGS IN THE SOFTWARE.
 21    *
 22    * Except as contained in this notice, the name of Dyade shall not be
 23    * used in advertising or otherwise to promote the sale, use or other
 24    * dealings in this Software without prior written authorization from
 25    * Dyade.
 26    *
 27    */
 28   
 29    /*BEGIN_COPYRIGHT_BLOCK
 30    *
 31    * This file is part of DrJava. Download the current version of this project:
 32    * http://sourceforge.net/projects/drjava/ or http://www.drjava.org/
 33    *
 34    * DrJava Open Source License
 35    *
 36    * Copyright (C) 2001-2010 JavaPLT group at Rice University (drjava@rice.edu)
 37    * All rights reserved.
 38    *
 39    * Developed by: Java Programming Languages Team
 40    * Rice University
 41    * http://www.cs.rice.edu/~javaplt/
 42    *
 43    * Permission is hereby granted, free of charge, to any person obtaining a
 44    * copy of this software and associated documentation files (the "Software"),
 45    * to deal with the Software without restriction, including without
 46    * limitation the rights to use, copy, modify, merge, publish, distribute,
 47    * sublicense, and/or sell copies of the Software, and to permit persons to
 48    * whom the Software is furnished to do so, subject to the following
 49    * conditions:
 50    *
 51    * - Redistributions of source code must retain the above copyright
 52    * notice, this list of conditions and the following disclaimers.
 53    * - Redistributions in binary form must reproduce the above copyright
 54    * notice, this list of conditions and the following disclaimers in the
 55    * documentation and/or other materials provided with the distribution.
 56    * - Neither the names of DrJava, the JavaPLT, Rice University, nor the
 57    * names of its contributors may be used to endorse or promote products
 58    * derived from this Software without specific prior written permission.
 59    * - Products derived from this software may not be called "DrJava" nor
 60    * use the term "DrJava" as part of their names without prior written
 61    * permission from the JavaPLT group. For permission, write to
 62    * drjava@rice.edu.
 63    *
 64    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 65    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 66    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 67    * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 68    * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 69    * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 70    * OTHER DEALINGS WITH THE SOFTWARE.
 71    *
 72    END_COPYRIGHT_BLOCK*/
 73   
 74    package edu.rice.cs.dynamicjava.interpreter;
 75   
 76    import java.util.*;
 77    import edu.rice.cs.plt.iter.IterUtil;
 78    import edu.rice.cs.plt.lambda.Lambda;
 79   
 80    import edu.rice.cs.dynamicjava.Options;
 81    import edu.rice.cs.dynamicjava.symbol.*;
 82    import edu.rice.cs.dynamicjava.symbol.TypeSystem.*;
 83    import edu.rice.cs.dynamicjava.symbol.type.*;
 84   
 85    import koala.dynamicjava.tree.*;
 86    import koala.dynamicjava.tree.tiger.*;
 87    import koala.dynamicjava.tree.visitor.*;
 88    import koala.dynamicjava.interpreter.error.ExecutionError;
 89   
 90    import static koala.dynamicjava.interpreter.NodeProperties.*;
 91   
 92    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 93   
 94    /**
 95    * This tree visitor checks the typing rules for TypeNames and converts the name to a Type.
 96    * The following properties (from {@code NodeProperties}) are set:<ul>
 97    * <li>TYPE on all {@code TypeName}s</li>
 98    * </ul>
 99    */
 100    public class TypeNameChecker {
 101   
 102    private final TypeContext context;
 103    private final TypeSystem ts;
 104    @SuppressWarnings("unused") private final Options opt;
 105    private final TypeNameVisitor visitor; // singleton per outer instance
 106   
 107  2605 public TypeNameChecker(TypeContext ctx, Options options) {
 108  2605 context = ctx;
 109  2605 ts = options.typeSystem();
 110  2605 opt = options;
 111  2605 visitor = new TypeNameVisitor();
 112    }
 113   
 114    /** Get the type corresponding to {@code t}; verify that it is well-formed. */
 115  2040 public Type check(TypeName t) {
 116  2040 Type result = t.acceptVisitor(visitor);
 117  2040 ensureWellFormed(t);
 118  2036 return result;
 119    }
 120   
 121    /**
 122    * Get the type corresponding to {@code t}; verify that it is structurally well-formed, but
 123    * delay full well-formedness checking until a later {@link #ensureWellFormed} call.
 124    */
 125  329 public Type checkStructure(TypeName t) {
 126  329 return t.acceptVisitor(visitor);
 127    }
 128   
 129    /**
 130    * Verify that a TypeName that has already been checked is well-formed (according to
 131    * {@link TypeSystem#isWellFormed}).
 132    */
 133  2130 public void ensureWellFormed(TypeName t) {
 134  2130 if (!ts.isWellFormed(getType(t))) {
 135  4 throw new ExecutionError("malformed.type", t);
 136    }
 137    }
 138   
 139    /** Invoke {@link #check} on each element of a list. */
 140  737 public Iterable<Type> checkList(Iterable<? extends TypeName> l) {
 141  737 Iterable<Type> result = IterUtil.mapSnapshot(l, visitor);
 142  737 ensureWellFormedList(l);
 143  737 return result;
 144    }
 145   
 146    /** Invoke {@link #checkStructure} on each element of a list. */
 147  521 public Iterable<Type> checkStructureForList(Iterable<? extends TypeName> l) {
 148  521 Iterable<Type> result = IterUtil.mapSnapshot(l, visitor);
 149  521 return result;
 150    }
 151   
 152    /** Invoke {@link #ensureWellFormed} on each element of a list. */
 153  737 public void ensureWellFormedList(Iterable<? extends TypeName> l) {
 154  0 for (TypeName t : l) { ensureWellFormed(t); }
 155    }
 156   
 157   
 158    /**
 159    * Tag the given type parameters with a new VariableType, and set the bounds appropriately;
 160    * verify that the results are well-formed.
 161    */
 162  410 public void checkTypeParameters(Iterable<? extends TypeParameter> tparams) {
 163  410 checkStructureForTypeParameters(tparams);
 164  410 ensureWellFormedTypeParameters(tparams);
 165    }
 166   
 167    /** Tag the given type parameters with a new VariableType, and set the bounds appropriately. */
 168  499 public void checkStructureForTypeParameters(Iterable<? extends TypeParameter> tparams) {
 169  499 for (TypeParameter tparam : tparams) {
 170  69 setTypeVariable(tparam, new VariableType(new BoundedSymbol(tparam, tparam.getRepresentation())));
 171    }
 172  499 for (TypeParameter param : tparams) {
 173  69 Type upperBound = checkStructure(param.getBound());
 174  69 if (!param.getInterfaceBounds().isEmpty()) {
 175    // can't use meet because it may involving subtyping on uninitialized variables
 176  0 upperBound = new IntersectionType(IterUtil.compose(upperBound, checkList(param.getInterfaceBounds())));
 177    }
 178  69 BoundedSymbol b = getTypeVariable(param).symbol();
 179  69 b.initializeUpperBound(upperBound);
 180  69 b.initializeLowerBound(TypeSystem.NULL);
 181    }
 182    }
 183   
 184    /**
 185    * Verify that the given type parameters (for which {@link #checkStructureForTypeParameters} has
 186    * already been invoked) are well-formed.
 187    */
 188  499 public void ensureWellFormedTypeParameters(Iterable<? extends TypeParameter> tparams) {
 189  499 for (TypeParameter tparam : tparams) {
 190  69 if (!ts.isWellFormed(getTypeVariable(tparam))) {
 191  0 throw new ExecutionError("malformed.type", tparam);
 192    }
 193    }
 194    }
 195   
 196    private class TypeNameVisitor extends AbstractVisitor<Type> implements Lambda<TypeName, Type> {
 197   
 198  507 public Type value(TypeName t) { return t.acceptVisitor(this); }
 199   
 200    /**
 201    * Visits a BooleanTypeName
 202    * @return The type of the TypeName
 203    */
 204  233 @Override public Type visit(BooleanTypeName node) { return setType(node, TypeSystem.BOOLEAN); }
 205   
 206    /**
 207    * Visits a ByteTypeName
 208    * @return The type of the TypeName
 209    */
 210  14 @Override public Type visit(ByteTypeName node) { return setType(node, TypeSystem.BYTE); }
 211   
 212    /**
 213    * Visits a ShortTypeName
 214    * @return The type of the TypeName
 215    */
 216  14 @Override public Type visit(ShortTypeName node) { return setType(node, TypeSystem.SHORT); }
 217   
 218    /**
 219    * Visits a CharTypeName
 220    * @return The type of the TypeName
 221    */
 222  9 @Override public Type visit(CharTypeName node) { return setType(node, TypeSystem.CHAR); }
 223   
 224    /**
 225    * Visits a IntTypeName
 226    * @return The type of the TypeName
 227    */
 228  358 @Override public Type visit(IntTypeName node) { return setType(node, TypeSystem.INT); }
 229   
 230    /**
 231    * Visits a LongTypeName
 232    * @return The type of the TypeName
 233    */
 234  4 @Override public Type visit(LongTypeName node) { return setType(node, TypeSystem.LONG); }
 235   
 236    /**
 237    * Visits a FloatTypeName
 238    * @return The type of the TypeName
 239    */
 240  15 @Override public Type visit(FloatTypeName node) { return setType(node, TypeSystem.FLOAT); }
 241   
 242    /**
 243    * Visits a DoubleTypeName
 244    * @return The type of the TypeName
 245    */
 246  8 @Override public Type visit(DoubleTypeName node) { return setType(node, TypeSystem.DOUBLE); }
 247   
 248    /**
 249    * Visits a VoidTypeName
 250    * @return The type of the TypeName
 251    */
 252  207 @Override public Type visit(VoidTypeName node) { return setType(node, TypeSystem.VOID); }
 253   
 254    /**
 255    * Visits a ReferenceTypeName
 256    * @return The type of the TypeName
 257    */
 258  1340 @Override public Type visit(ReferenceTypeName node) {
 259  1340 Iterator<? extends IdentifierToken> ids = node.getIdentifiers().iterator();
 260  1340 String name = "";
 261  1340 Type t = null;
 262   
 263  1340 boolean first = true;
 264  1340 while (t == null && ids.hasNext()) {
 265  454 if (!first) { name += "."; }
 266  1794 first = false;
 267  1794 name += ids.next().image();
 268   
 269  1794 try {
 270  1794 DJClass c = context.getTopLevelClass(name, ts);
 271  1156 if (c != null) { t = ts.makeClassType(c); }
 272    else {
 273  638 t = context.getTypeVariable(name, ts);
 274  638 if (t == null) {
 275  454 Type outer = context.typeContainingMemberClass(name, ts);
 276  0 if (outer != null) { t = ts.lookupClass(outer, name, IterUtil.<Type>empty(), context.accessModule()); }
 277    }
 278    }
 279    }
 280    catch (AmbiguousNameException e) {
 281  0 setErrorStrings(node, name);
 282  0 throw new ExecutionError("ambiguous.name", node);
 283    }
 284  0 catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
 285    catch (UnmatchedLookupException e) {
 286  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 287    else {
 288  0 setErrorStrings(node, name);
 289  0 throw new ExecutionError("ambiguous.name", node);
 290    }
 291    }
 292    }
 293  1340 while (ids.hasNext()) {
 294  0 String nextId = ids.next().image();
 295  0 try {
 296  0 ClassType memberType = ts.lookupClass(t, nextId, IterUtil.<Type>empty(), context.accessModule());
 297  0 t = memberType;
 298    }
 299  0 catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
 300    catch (UnmatchedLookupException e) {
 301  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 302    else {
 303  0 setErrorStrings(node, nextId);
 304  0 throw new ExecutionError("ambiguous.name", node);
 305    }
 306    }
 307    }
 308   
 309  1340 if (t == null) {
 310  0 setErrorStrings(node, node.getRepresentation());
 311  0 throw new ExecutionError("undefined.class", node);
 312    }
 313  1340 return setType(node, t);
 314    }
 315   
 316    /**
 317    * Visits a GenericReferenceTypeName
 318    * @return The type of the TypeName
 319    */
 320  507 @Override public Type visit(GenericReferenceTypeName node) {
 321  507 Iterator<? extends IdentifierToken> ids = node.getIdentifiers().iterator();
 322  507 Iterator<? extends List<? extends TypeName>> allTargs = node.getTypeArguments().iterator();
 323  507 String name = "";
 324  507 Type t = null;
 325   
 326  507 boolean first = true;
 327  507 while (t == null && ids.hasNext()) {
 328  14 if (!first) { name += "."; }
 329  521 first = false;
 330  521 name += ids.next().image();
 331  521 List<? extends TypeName> targsNames = allTargs.next();
 332  521 Iterable<Type> targs = checkStructureForList(targsNames);
 333   
 334  521 try {
 335  521 DJClass c = context.getTopLevelClass(name, ts);
 336  521 t = (c == null) ? null : ts.makeClassType(c, targs);
 337  521 if (t == null) {
 338  14 Type outer = context.typeContainingMemberClass(name, ts);
 339  0 if (outer != null) { t = ts.lookupClass(outer, name, targs, context.accessModule()); }
 340    }
 341  521 if (t == null) {
 342  14 if (!IterUtil.isEmpty(targs)) {
 343  0 setErrorStrings(node, name);
 344  0 throw new ExecutionError("undefined.class", node);
 345    }
 346  14 t = context.getTypeVariable(name, ts);
 347    }
 348    }
 349    catch (AmbiguousNameException e) {
 350  0 setErrorStrings(node, name);
 351  0 throw new ExecutionError("ambiguous.name", node);
 352    }
 353  0 catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
 354    catch (UnmatchedLookupException e) {
 355  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 356    else {
 357  0 setErrorStrings(node, name);
 358  0 throw new ExecutionError("ambiguous.name", node);
 359    }
 360    }
 361    }
 362   
 363  507 while (ids.hasNext()) {
 364  0 String nextId = ids.next().image();
 365  0 try {
 366  0 Iterable<Type> targs = checkStructureForList(allTargs.next());
 367  0 ClassType memberType = ts.lookupClass(t, nextId, targs, context.accessModule());
 368  0 t = memberType;
 369    }
 370  0 catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument", node); }
 371    catch (UnmatchedLookupException e) {
 372  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 373    else {
 374  0 setErrorStrings(node, nextId);
 375  0 throw new ExecutionError("ambiguous.name", node);
 376    }
 377    }
 378    }
 379   
 380  507 if (t == null) {
 381  0 setErrorStrings(node, node.getRepresentation());
 382  0 throw new ExecutionError("undefined.class", node);
 383    }
 384  507 return setType(node, t);
 385    }
 386   
 387    /**
 388    * Visits a HookTypeName
 389    * @return The type of the TypeName
 390    */
 391  51 @Override public Type visit(HookTypeName node) {
 392  51 Type upper = TypeSystem.OBJECT;
 393  51 if (node.getUpperBound().isSome()) {
 394  32 upper = checkStructure(node.getUpperBound().unwrap());
 395  32 if (!ts.isReference(upper)) {
 396  0 setErrorStrings(node, ts.typePrinter().print(upper));
 397  0 throw new ExecutionError("wildcard.bound", node);
 398    }
 399    }
 400   
 401  51 Type lower = TypeSystem.NULL;
 402  51 if (node.getLowerBound().isSome()) {
 403  22 lower = checkStructure(node.getLowerBound().unwrap());
 404  22 if (!ts.isReference(lower)) {
 405  0 setErrorStrings(node, ts.typePrinter().print(lower));
 406  0 throw new ExecutionError("wildcard.bound", node);
 407    }
 408    }
 409   
 410  51 return setType(node, new Wildcard(new BoundedSymbol(node, upper, lower)));
 411    }
 412   
 413    /**
 414    * Visits an ArrayTypeName
 415    * @return The type of the TypeName
 416    */
 417  116 @Override public Type visit(ArrayTypeName node) {
 418  116 Type elementType = checkStructure(node.getElementType());
 419  116 Type arrayT = node.isVararg() ? new VarargArrayType(elementType) :
 420    new SimpleArrayType(elementType);
 421  116 return setType(node, arrayT);
 422    }
 423   
 424    }
 425   
 426    }