+ case Kind.LiteralNode:
+ compLoc = checkLocationFromLiteralNode(md, nametable, (LiteralNode) en, loc);
+ break;
+
+ case Kind.MethodInvokeNode:
+ compLoc =
+ checkLocationFromMethodInvokeNode(md, nametable, (MethodInvokeNode) en, loc, constraint);
+ break;
+
+ case Kind.TertiaryNode:
+ compLoc = checkLocationFromTertiaryNode(md, nametable, (TertiaryNode) en, constraint);
+ break;
+
+ case Kind.CastNode:
+ compLoc = checkLocationFromCastNode(md, nametable, (CastNode) en, constraint);
+ break;
+
+ // case Kind.InstanceOfNode:
+ // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
+ // return null;
+
+ // case Kind.ArrayInitializerNode:
+ // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
+ // td);
+ // return null;
+
+ // case Kind.ClassTypeNode:
+ // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
+ // return null;
+
+ // case Kind.OffsetNode:
+ // checkOffsetNode(md, nametable, (OffsetNode)en, td);
+ // return null;
+
+ default:
+ return null;
+
+ }
+ // addTypeLocation(en.getType(), compLoc);
+ return compLoc;
+
+ }
+
+ private CompositeLocation checkLocationFromCastNode(MethodDescriptor md, SymbolTable nametable,
+ CastNode cn, CompositeLocation constraint) {
+
+ ExpressionNode en = cn.getExpression();
+ return checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
+ false);
+
+ }
+
+ private CompositeLocation checkLocationFromTertiaryNode(MethodDescriptor md,
+ SymbolTable nametable, TertiaryNode tn, CompositeLocation constraint) {
+ ClassDescriptor cd = md.getClassDesc();
+
+ CompositeLocation condLoc =
+ checkLocationFromExpressionNode(md, nametable, tn.getCond(), new CompositeLocation(),
+ constraint, false);
+ // addLocationType(tn.getCond().getType(), condLoc);
+ CompositeLocation trueLoc =
+ checkLocationFromExpressionNode(md, nametable, tn.getTrueExpr(), new CompositeLocation(),
+ constraint, false);
+ // addLocationType(tn.getTrueExpr().getType(), trueLoc);
+ CompositeLocation falseLoc =
+ checkLocationFromExpressionNode(md, nametable, tn.getFalseExpr(), new CompositeLocation(),
+ constraint, false);
+ // addLocationType(tn.getFalseExpr().getType(), falseLoc);
+
+ // locations from true/false branches can be TOP when there are only literal
+ // values
+ // in this case, we don't need to check flow down rule!
+
+ // System.out.println("\n#tertiary cond=" + tn.getCond().printNode(0) +
+ // " Loc=" + condLoc);
+ // System.out.println("# true=" + tn.getTrueExpr().printNode(0) + " Loc=" +
+ // trueLoc);
+ // System.out.println("# false=" + tn.getFalseExpr().printNode(0) + " Loc="
+ // + falseLoc);
+
+ // check if condLoc is higher than trueLoc & falseLoc
+ if (!trueLoc.get(0).isTop()
+ && !CompositeLattice.isGreaterThan(condLoc, trueLoc, generateErrorMessage(cd, tn))) {
+ throw new Error(
+ "The location of the condition expression is lower than the true expression at "
+ + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
+ }
+
+ if (!falseLoc.get(0).isTop()
+ && !CompositeLattice.isGreaterThan(condLoc, falseLoc,
+ generateErrorMessage(cd, tn.getCond()))) {
+ throw new Error(
+ "The location of the condition expression is lower than the false expression at "
+ + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
+ }
+
+ // then, return glb of trueLoc & falseLoc
+ Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
+ glbInputSet.add(trueLoc);
+ glbInputSet.add(falseLoc);
+
+ if (glbInputSet.size() == 1) {
+ return trueLoc;
+ } else {
+ return CompositeLattice.calculateGLB(glbInputSet, generateErrorMessage(cd, tn));
+ }
+
+ }
+
+ private CompositeLocation checkLocationFromMethodInvokeNode(MethodDescriptor md,
+ SymbolTable nametable, MethodInvokeNode min, CompositeLocation loc,
+ CompositeLocation constraint) {
+
+ ClassDescriptor cd = md.getClassDesc();
+ MethodDescriptor calleeMethodDesc = min.getMethod();
+
+ NameDescriptor baseName = min.getBaseName();
+ boolean isSystemout = false;
+ if (baseName != null) {
+ isSystemout = baseName.getSymbol().equals("System.out");
+ }
+
+ if (!ssjava.isSSJavaUtil(calleeMethodDesc.getClassDesc())
+ && !ssjava.isTrustMethod(calleeMethodDesc) && !calleeMethodDesc.getModifiers().isNative()
+ && !isSystemout) {
+
+ CompositeLocation baseLocation = null;
+ if (min.getExpression() != null) {
+ baseLocation =
+ checkLocationFromExpressionNode(md, nametable, min.getExpression(),
+ new CompositeLocation(), constraint, false);
+ } else {
+ if (min.getMethod().isStatic()) {
+ String globalLocId = ssjava.getMethodLattice(md).getGlobalLoc();
+ if (globalLocId == null) {
+ throw new Error("Method lattice does not define global variable location at "
+ + generateErrorMessage(md.getClassDesc(), min));
+ }
+ baseLocation = new CompositeLocation(new Location(md, globalLocId));
+ } else {
+ String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
+ baseLocation = new CompositeLocation(new Location(md, thisLocId));
+ }
+ }
+
+ // System.out.println("\n#checkLocationFromMethodInvokeNode=" +
+ // min.printNode(0)
+ // + " baseLocation=" + baseLocation + " constraint=" + constraint);
+
+ // setup the location list of caller's arguments
+ List<CompositeLocation> callerArgList = new ArrayList<CompositeLocation>();
+
+ // setup the location list of callee's parameters
+ MethodLattice<String> calleeLattice = ssjava.getMethodLattice(calleeMethodDesc);
+ List<CompositeLocation> calleeParamList = new ArrayList<CompositeLocation>();
+
+ if (min.numArgs() > 0) {
+ if (!calleeMethodDesc.isStatic()) {
+ callerArgList.add(baseLocation);
+ }
+ for (int i = 0; i < min.numArgs(); i++) {
+ ExpressionNode en = min.getArg(i);
+ CompositeLocation callerArgLoc =
+ checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(),
+ constraint, false);
+ callerArgList.add(callerArgLoc);
+ }
+
+ if (!calleeMethodDesc.isStatic()) {
+ CompositeLocation calleeThisLoc =
+ new CompositeLocation(new Location(calleeMethodDesc, calleeLattice.getThisLoc()));
+ calleeParamList.add(calleeThisLoc);
+ }
+
+ for (int i = 0; i < calleeMethodDesc.numParameters(); i++) {
+ VarDescriptor calleevd = (VarDescriptor) calleeMethodDesc.getParameter(i);
+ CompositeLocation calleeLoc = d2loc.get(calleevd);
+ calleeParamList.add(calleeLoc);
+ }
+ }
+
+ if (constraint != null) {
+ // check whether the PC location is lower than one of the
+ // argument locations. If it is lower, the callee has to have @PCLOC
+ // annotation that declares the program counter that is higher than
+ // corresponding parameter
+
+ CompositeLocation calleePCLOC = ssjava.getPCLocation(calleeMethodDesc);
+
+ for (int idx = 0; idx < callerArgList.size(); idx++) {
+ CompositeLocation argLocation = callerArgList.get(idx);
+
+ // need to check that param is higher than PCLOC
+ if (!argLocation.get(0).isTop()
+ && CompositeLattice.compare(argLocation, constraint, true,
+ generateErrorMessage(cd, min)) == ComparisonResult.GREATER) {
+
+ CompositeLocation paramLocation = calleeParamList.get(idx);
+
+ int paramCompareResult =
+ CompositeLattice.compare(calleePCLOC, paramLocation, true,
+ generateErrorMessage(cd, min));
+
+ if (paramCompareResult == ComparisonResult.GREATER) {
+ throw new Error(
+ "The program counter location "
+ + constraint
+ + " is lower than the argument(idx="
+ + idx
+ + ") location "
+ + argLocation
+ + ". Need to specify that the initial PC location of the callee, which is currently set to "
+ + calleePCLOC + ", is lower than " + paramLocation + " in the method "
+ + calleeMethodDesc.getSymbol() + ":" + min.getNumLine());
+ }
+
+ }
+
+ }
+
+ }
+
+ checkCalleeConstraints(md, nametable, min, baseLocation, constraint);
+
+ // checkCallerArgumentLocationConstraints(md, nametable, min,
+ // baseLocation, constraint);
+
+ if (!min.getMethod().getReturnType().isVoid()) {
+ // If method has a return value, compute the highest possible return
+ // location in the caller's perspective
+ CompositeLocation ceilingLoc =
+ computeCeilingLocationForCaller(md, nametable, min, baseLocation, constraint);
+ return ceilingLoc;
+ }
+ }
+
+ return new CompositeLocation(Location.createTopLocation(md));
+
+ }
+
+ private CompositeLocation translateCallerLocToCalleeLoc(MethodDescriptor calleeMD,
+ CompositeLocation calleeBaseLoc, CompositeLocation constraint) {
+
+ CompositeLocation calleeConstraint = new CompositeLocation();
+
+ // if (constraint.startsWith(calleeBaseLoc)) {
+ // if the first part of constraint loc is matched with callee base loc
+ Location thisLoc = new Location(calleeMD, ssjava.getMethodLattice(calleeMD).getThisLoc());
+ calleeConstraint.addLocation(thisLoc);
+ for (int i = calleeBaseLoc.getSize(); i < constraint.getSize(); i++) {
+ calleeConstraint.addLocation(constraint.get(i));
+ }
+
+ // }
+
+ return calleeConstraint;
+ }
+
+ private void checkCallerArgumentLocationConstraints(MethodDescriptor md, SymbolTable nametable,
+ MethodInvokeNode min, CompositeLocation callerBaseLoc, CompositeLocation constraint) {
+ // if parameter location consists of THIS and FIELD location,
+ // caller should pass an argument that is comparable to the declared
+ // parameter location
+ // and is not lower than the declared parameter location in the field
+ // lattice.
+
+ MethodDescriptor calleemd = min.getMethod();
+
+ List<CompositeLocation> callerArgList = new ArrayList<CompositeLocation>();
+ List<CompositeLocation> calleeParamList = new ArrayList<CompositeLocation>();
+
+ MethodLattice<String> calleeLattice = ssjava.getMethodLattice(calleemd);
+ Location calleeThisLoc = new Location(calleemd, calleeLattice.getThisLoc());
+
+ for (int i = 0; i < min.numArgs(); i++) {
+ ExpressionNode en = min.getArg(i);
+ CompositeLocation callerArgLoc =
+ checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
+ false);
+ callerArgList.add(callerArgLoc);
+ }
+
+ // setup callee params set
+ for (int i = 0; i < calleemd.numParameters(); i++) {
+ VarDescriptor calleevd = (VarDescriptor) calleemd.getParameter(i);
+ CompositeLocation calleeLoc = d2loc.get(calleevd);
+ calleeParamList.add(calleeLoc);
+ }
+
+ String errorMsg = generateErrorMessage(md.getClassDesc(), min);
+
+ // System.out.println("checkCallerArgumentLocationConstraints=" +
+ // min.printNode(0));
+ // System.out.println("base location=" + callerBaseLoc + " constraint=" +
+ // constraint);
+
+ for (int i = 0; i < calleeParamList.size(); i++) {
+ CompositeLocation calleeParamLoc = calleeParamList.get(i);
+ if (calleeParamLoc.get(0).equals(calleeThisLoc) && calleeParamLoc.getSize() > 1) {
+
+ // callee parameter location has field information
+ CompositeLocation callerArgLoc = callerArgList.get(i);
+
+ CompositeLocation paramLocation =
+ translateCalleeParamLocToCaller(md, calleeParamLoc, callerBaseLoc, errorMsg);
+
+ Set<CompositeLocation> inputGLBSet = new HashSet<CompositeLocation>();
+ if (constraint != null) {
+ inputGLBSet.add(callerArgLoc);
+ inputGLBSet.add(constraint);
+ callerArgLoc =
+ CompositeLattice.calculateGLB(inputGLBSet,
+ generateErrorMessage(md.getClassDesc(), min));
+ }
+
+ if (!CompositeLattice.isGreaterThan(callerArgLoc, paramLocation, errorMsg)) {
+ throw new Error("Caller argument '" + min.getArg(i).printNode(0) + " : " + callerArgLoc
+ + "' should be higher than corresponding callee's parameter : " + paramLocation
+ + " at " + errorMsg);
+ }
+
+ }
+ }
+
+ }
+
+ private CompositeLocation translateCalleeParamLocToCaller(MethodDescriptor md,
+ CompositeLocation calleeParamLoc, CompositeLocation callerBaseLocation, String errorMsg) {
+
+ CompositeLocation translate = new CompositeLocation();
+
+ for (int i = 0; i < callerBaseLocation.getSize(); i++) {
+ translate.addLocation(callerBaseLocation.get(i));
+ }
+
+ for (int i = 1; i < calleeParamLoc.getSize(); i++) {
+ translate.addLocation(calleeParamLoc.get(i));
+ }
+
+ // System.out.println("TRANSLATED=" + translate + " from calleeParamLoc=" +
+ // calleeParamLoc);
+
+ return translate;
+ }
+
+ private CompositeLocation computeCeilingLocationForCaller(MethodDescriptor md,
+ SymbolTable nametable, MethodInvokeNode min, CompositeLocation baseLocation,
+ CompositeLocation constraint) {
+ List<CompositeLocation> argList = new ArrayList<CompositeLocation>();
+
+ // by default, method has a THIS parameter
+ argList.add(baseLocation);
+
+ for (int i = 0; i < min.numArgs(); i++) {
+ ExpressionNode en = min.getArg(i);
+ CompositeLocation callerArg =
+ checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
+ false);
+ argList.add(callerArg);
+ }
+
+ // System.out.println("\n## computeReturnLocation=" + min.getMethod() +
+ // " argList=" + argList);
+ CompositeLocation ceilLoc = md2ReturnLocGen.get(min.getMethod()).computeReturnLocation(argList);
+ // System.out.println("## ReturnLocation=" + ceilLoc);
+
+ return ceilLoc;
+
+ }
+
+ private void checkCalleeConstraints(MethodDescriptor md, SymbolTable nametable,
+ MethodInvokeNode min, CompositeLocation callerBaseLoc, CompositeLocation constraint) {
+
+ // System.out.println("checkCalleeConstraints=" + min.printNode(0));
+
+ MethodDescriptor calleemd = min.getMethod();
+
+ MethodLattice<String> calleeLattice = ssjava.getMethodLattice(calleemd);
+ CompositeLocation calleeThisLoc =
+ new CompositeLocation(new Location(calleemd, calleeLattice.getThisLoc()));
+
+ List<CompositeLocation> callerArgList = new ArrayList<CompositeLocation>();
+ List<CompositeLocation> calleeParamList = new ArrayList<CompositeLocation>();
+
+ if (min.numArgs() > 0) {
+ // caller needs to guarantee that it passes arguments in regarding to
+ // callee's hierarchy
+
+ // setup caller args set
+ // first, add caller's base(this) location
+ callerArgList.add(callerBaseLoc);
+ // second, add caller's arguments
+ for (int i = 0; i < min.numArgs(); i++) {
+ ExpressionNode en = min.getArg(i);
+ CompositeLocation callerArgLoc =
+ checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
+ false);
+ callerArgList.add(callerArgLoc);
+ }
+
+ // setup callee params set
+ // first, add callee's this location
+ calleeParamList.add(calleeThisLoc);
+ // second, add callee's parameters
+ for (int i = 0; i < calleemd.numParameters(); i++) {
+ VarDescriptor calleevd = (VarDescriptor) calleemd.getParameter(i);
+ CompositeLocation calleeLoc = d2loc.get(calleevd);
+ // System.out.println("calleevd=" + calleevd + " loc=" + calleeLoc);
+ calleeParamList.add(calleeLoc);
+ }
+
+ // here, check if ordering relations among caller's args respect
+ // ordering relations in-between callee's args
+ CHECK: for (int i = 0; i < calleeParamList.size(); i++) {
+ CompositeLocation calleeLoc1 = calleeParamList.get(i);
+ CompositeLocation callerLoc1 = callerArgList.get(i);
+
+ for (int j = 0; j < calleeParamList.size(); j++) {
+ if (i != j) {
+ CompositeLocation calleeLoc2 = calleeParamList.get(j);
+ CompositeLocation callerLoc2 = callerArgList.get(j);
+
+ if (callerLoc1.get(callerLoc1.getSize() - 1).isTop()
+ || callerLoc2.get(callerLoc2.getSize() - 1).isTop()) {
+ continue CHECK;
+ }
+
+ // System.out.println("calleeLoc1=" + calleeLoc1);
+ // System.out.println("calleeLoc2=" + calleeLoc2 +
+ // "calleeParamList=" + calleeParamList);
+
+ int callerResult =
+ CompositeLattice.compare(callerLoc1, callerLoc2, true,
+ generateErrorMessage(md.getClassDesc(), min));
+ // System.out.println("callerResult=" + callerResult);
+ int calleeResult =
+ CompositeLattice.compare(calleeLoc1, calleeLoc2, true,
+ generateErrorMessage(md.getClassDesc(), min));
+ // System.out.println("calleeResult=" + calleeResult);
+
+ if (callerResult == ComparisonResult.EQUAL) {
+ if (ssjava.isSharedLocation(callerLoc1.get(callerLoc1.getSize() - 1))
+ && ssjava.isSharedLocation(callerLoc2.get(callerLoc2.getSize() - 1))) {
+ // if both of them are shared locations, promote them to
+ // "GREATER relation"
+ callerResult = ComparisonResult.GREATER;
+ }
+ }
+
+ if (calleeResult == ComparisonResult.GREATER
+ && callerResult != ComparisonResult.GREATER) {
+ // If calleeLoc1 is higher than calleeLoc2
+ // then, caller should have same ordering relation in-bet
+ // callerLoc1 & callerLoc2
+
+ String paramName1, paramName2;
+
+ if (i == 0) {
+ paramName1 = "'THIS'";
+ } else {
+ paramName1 = "'parameter " + calleemd.getParamName(i - 1) + "'";
+ }
+
+ if (j == 0) {
+ paramName2 = "'THIS'";
+ } else {
+ paramName2 = "'parameter " + calleemd.getParamName(j - 1) + "'";
+ }
+
+ throw new Error(
+ "Caller doesn't respect an ordering relation among method arguments: callee expects that "
+ + paramName1 + " should be higher than " + paramName2 + " in " + calleemd
+ + " at " + md.getClassDesc().getSourceFileName() + ":" + min.getNumLine());
+ }
+ }
+
+ }
+ }
+
+ }
+
+ }
+
+ private CompositeLocation checkLocationFromArrayAccessNode(MethodDescriptor md,
+ SymbolTable nametable, ArrayAccessNode aan, CompositeLocation constraint, boolean isLHS) {
+
+ ClassDescriptor cd = md.getClassDesc();
+
+ CompositeLocation arrayLoc =
+ checkLocationFromExpressionNode(md, nametable, aan.getExpression(),
+ new CompositeLocation(), constraint, isLHS);
+
+ // addTypeLocation(aan.getExpression().getType(), arrayLoc);
+ CompositeLocation indexLoc =
+ checkLocationFromExpressionNode(md, nametable, aan.getIndex(), new CompositeLocation(),
+ constraint, isLHS);
+ // addTypeLocation(aan.getIndex().getType(), indexLoc);
+
+ if (isLHS) {
+ if (!CompositeLattice.isGreaterThan(indexLoc, arrayLoc, generateErrorMessage(cd, aan))) {
+ throw new Error("Array index value is not higher than array location at "
+ + generateErrorMessage(cd, aan));
+ }
+ return arrayLoc;
+ } else {
+ Set<CompositeLocation> inputGLB = new HashSet<CompositeLocation>();
+ inputGLB.add(arrayLoc);
+ inputGLB.add(indexLoc);
+ return CompositeLattice.calculateGLB(inputGLB, generateErrorMessage(cd, aan));
+ }
+
+ }
+
+ private CompositeLocation checkLocationFromCreateObjectNode(MethodDescriptor md,
+ SymbolTable nametable, CreateObjectNode con) {
+
+ ClassDescriptor cd = md.getClassDesc();
+
+ CompositeLocation compLoc = new CompositeLocation();
+ compLoc.addLocation(Location.createTopLocation(md));
+ return compLoc;
+
+ }
+
+ private CompositeLocation checkLocationFromOpNode(MethodDescriptor md, SymbolTable nametable,
+ OpNode on, CompositeLocation constraint) {
+
+ ClassDescriptor cd = md.getClassDesc();
+ CompositeLocation leftLoc = new CompositeLocation();
+ leftLoc =
+ checkLocationFromExpressionNode(md, nametable, on.getLeft(), leftLoc, constraint, false);
+ // addTypeLocation(on.getLeft().getType(), leftLoc);
+
+ CompositeLocation rightLoc = new CompositeLocation();
+ if (on.getRight() != null) {
+ rightLoc =
+ checkLocationFromExpressionNode(md, nametable, on.getRight(), rightLoc, constraint, false);
+ // addTypeLocation(on.getRight().getType(), rightLoc);
+ }
+
+ // System.out.println("\n# OP NODE=" + on.printNode(0));
+ // System.out.println("# left loc=" + leftLoc + " from " +
+ // on.getLeft().getClass());
+ // if (on.getRight() != null) {
+ // System.out.println("# right loc=" + rightLoc + " from " +
+ // on.getRight().getClass());
+ // }
+
+ Operation op = on.getOp();
+
+ switch (op.getOp()) {
+
+ case Operation.UNARYPLUS:
+ case Operation.UNARYMINUS:
+ case Operation.LOGIC_NOT:
+ // single operand
+ return leftLoc;
+
+ case Operation.LOGIC_OR:
+ case Operation.LOGIC_AND:
+ case Operation.COMP:
+ case Operation.BIT_OR:
+ case Operation.BIT_XOR:
+ case Operation.BIT_AND:
+ case Operation.ISAVAILABLE:
+ case Operation.EQUAL:
+ case Operation.NOTEQUAL:
+ case Operation.LT:
+ case Operation.GT:
+ case Operation.LTE:
+ case Operation.GTE:
+ case Operation.ADD:
+ case Operation.SUB:
+ case Operation.MULT:
+ case Operation.DIV:
+ case Operation.MOD:
+ case Operation.LEFTSHIFT:
+ case Operation.RIGHTSHIFT:
+ case Operation.URIGHTSHIFT:
+
+ Set<CompositeLocation> inputSet = new HashSet<CompositeLocation>();
+ inputSet.add(leftLoc);
+ inputSet.add(rightLoc);
+ CompositeLocation glbCompLoc =
+ CompositeLattice.calculateGLB(inputSet, generateErrorMessage(cd, on));
+ return glbCompLoc;
+
+ default:
+ throw new Error(op.toString());
+ }
+
+ }
+
+ private CompositeLocation checkLocationFromLiteralNode(MethodDescriptor md,
+ SymbolTable nametable, LiteralNode en, CompositeLocation loc) {
+
+ // literal value has the top location so that value can be flowed into any
+ // location
+ Location literalLoc = Location.createTopLocation(md);
+ loc.addLocation(literalLoc);
+ return loc;
+
+ }
+
+ private CompositeLocation checkLocationFromNameNode(MethodDescriptor md, SymbolTable nametable,
+ NameNode nn, CompositeLocation loc, CompositeLocation constraint) {
+
+ NameDescriptor nd = nn.getName();
+ if (nd.getBase() != null) {
+ loc =
+ checkLocationFromExpressionNode(md, nametable, nn.getExpression(), loc, constraint, false);
+ } else {
+ String varname = nd.toString();
+ if (varname.equals("this")) {
+ // 'this' itself!
+ MethodLattice<String> methodLattice = ssjava.getMethodLattice(md);
+ String thisLocId = methodLattice.getThisLoc();
+ if (thisLocId == null) {
+ throw new Error("The location for 'this' is not defined at "
+ + md.getClassDesc().getSourceFileName() + "::" + nn.getNumLine());
+ }
+ Location locElement = new Location(md, thisLocId);
+ loc.addLocation(locElement);
+ return loc;
+
+ }
+
+ Descriptor d = (Descriptor) nametable.get(varname);
+
+ // CompositeLocation localLoc = null;
+ if (d instanceof VarDescriptor) {
+ VarDescriptor vd = (VarDescriptor) d;
+ // localLoc = d2loc.get(vd);
+ // the type of var descriptor has a composite location!
+ loc = ((SSJavaType) vd.getType().getExtension()).getCompLoc().clone();
+ } else if (d instanceof FieldDescriptor) {
+ // the type of field descriptor has a location!
+ FieldDescriptor fd = (FieldDescriptor) d;
+ if (fd.isStatic()) {
+ if (fd.isFinal()) {
+ // if it is 'static final', the location has TOP since no one can
+ // change its value
+ loc.addLocation(Location.createTopLocation(md));
+ return loc;
+ } else {
+ // if 'static', the location has pre-assigned global loc
+ MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
+ String globalLocId = localLattice.getGlobalLoc();
+ if (globalLocId == null) {
+ throw new Error("Global location element is not defined in the method " + md);
+ }
+ Location globalLoc = new Location(md, globalLocId);
+
+ loc.addLocation(globalLoc);
+ }
+ } else {
+ // the location of field access starts from this, followed by field
+ // location
+ MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
+ Location thisLoc = new Location(md, localLattice.getThisLoc());
+ loc.addLocation(thisLoc);
+ }
+
+ Location fieldLoc = (Location) fd.getType().getExtension();
+ loc.addLocation(fieldLoc);
+ } else if (d == null) {
+ // access static field
+ FieldDescriptor fd = nn.getField();
+
+ MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
+ String globalLocId = localLattice.getGlobalLoc();
+ if (globalLocId == null) {
+ throw new Error("Method lattice does not define global variable location at "
+ + generateErrorMessage(md.getClassDesc(), nn));
+ }
+ loc.addLocation(new Location(md, globalLocId));
+
+ Location fieldLoc = (Location) fd.getType().getExtension();
+ loc.addLocation(fieldLoc);
+
+ return loc;
+
+ }
+ }
+ return loc;
+ }
+
+ private CompositeLocation checkLocationFromFieldAccessNode(MethodDescriptor md,
+ SymbolTable nametable, FieldAccessNode fan, CompositeLocation loc,
+ CompositeLocation constraint) {
+
+ ExpressionNode left = fan.getExpression();
+ TypeDescriptor ltd = left.getType();
+
+ FieldDescriptor fd = fan.getField();
+
+ String varName = null;
+ if (left.kind() == Kind.NameNode) {
+ NameDescriptor nd = ((NameNode) left).getName();
+ varName = nd.toString();
+ }
+
+ if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
+ // using a class name directly or access using this
+ if (fd.isStatic() && fd.isFinal()) {
+ loc.addLocation(Location.createTopLocation(md));
+ return loc;
+ }
+ }
+
+ if (left instanceof ArrayAccessNode) {
+ ArrayAccessNode aan = (ArrayAccessNode) left;
+ left = aan.getExpression();
+ }
+
+ loc = checkLocationFromExpressionNode(md, nametable, left, loc, constraint, false);
+ // System.out.println("### checkLocationFromFieldAccessNode=" +
+ // fan.printNode(0));
+ // System.out.println("### left=" + left.printNode(0));
+
+ if (!left.getType().isPrimitive()) {
+
+ if (fd.getSymbol().equals("length")) {
+ // array.length access, return the location of the array
+ return loc;
+ }
+
+ Location fieldLoc = getFieldLocation(fd);
+ loc.addLocation(fieldLoc);
+ }
+ return loc;
+ }
+
+ private Location getFieldLocation(FieldDescriptor fd) {
+
+ // System.out.println("### getFieldLocation=" + fd);
+ // System.out.println("### fd.getType().getExtension()=" +
+ // fd.getType().getExtension());
+
+ Location fieldLoc = (Location) fd.getType().getExtension();
+
+ // handle the case that method annotation checking skips checking field
+ // declaration
+ if (fieldLoc == null) {
+ fieldLoc = checkFieldDeclaration(fd.getClassDescriptor(), fd);
+ }
+
+ return fieldLoc;
+
+ }
+
+ private FieldDescriptor getFieldDescriptorFromExpressionNode(ExpressionNode en) {
+
+ if (en.kind() == Kind.NameNode) {
+ NameNode nn = (NameNode) en;
+ if (nn.getField() != null) {
+ return nn.getField();
+ }
+
+ if (nn.getName() != null && nn.getName().getBase() != null) {
+ return getFieldDescriptorFromExpressionNode(nn.getExpression());
+ }
+
+ } else if (en.kind() == Kind.FieldAccessNode) {
+ FieldAccessNode fan = (FieldAccessNode) en;
+ return fan.getField();
+ }
+
+ return null;
+ }
+
+ private CompositeLocation checkLocationFromAssignmentNode(MethodDescriptor md,
+ SymbolTable nametable, AssignmentNode an, CompositeLocation loc, CompositeLocation constraint) {
+
+ ClassDescriptor cd = md.getClassDesc();
+
+ Set<CompositeLocation> inputGLBSet = new HashSet<CompositeLocation>();
+
+ boolean postinc = true;
+ if (an.getOperation().getBaseOp() == null
+ || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
+ .getBaseOp().getOp() != Operation.POSTDEC))
+ postinc = false;
+
+ // if LHS is array access node, need to check if array index is higher
+ // than array itself
+ CompositeLocation destLocation =
+ checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation(),
+ constraint, true);
+
+ CompositeLocation rhsLocation;
+ CompositeLocation srcLocation;
+
+ if (!postinc) {
+
+ checkOwnership(md, an, an.getSrc());
+
+ rhsLocation =
+ checkLocationFromExpressionNode(md, nametable, an.getSrc(), new CompositeLocation(),
+ constraint, false);
+
+ if (an.getOperation().getOp() >= 2 && an.getOperation().getOp() <= 12) {
+ // if assignment contains OP+EQ operator, need to merge location types
+ // of LHS & RHS into the RHS
+ Set<CompositeLocation> srcGLBSet = new HashSet<CompositeLocation>();
+ srcGLBSet.add(rhsLocation);
+ srcGLBSet.add(destLocation);
+ srcLocation = CompositeLattice.calculateGLB(srcGLBSet, generateErrorMessage(cd, an));
+ } else {
+ srcLocation = rhsLocation;
+ }
+
+ if (constraint != null) {
+ inputGLBSet.add(srcLocation);
+ inputGLBSet.add(constraint);
+ srcLocation = CompositeLattice.calculateGLB(inputGLBSet, generateErrorMessage(cd, an));
+ }
+
+ if (!CompositeLattice.isGreaterThan(srcLocation, destLocation, generateErrorMessage(cd, an))) {
+
+ String context = "";
+ if (constraint != null) {
+ context = " and the current context constraint is " + constraint;
+ }
+
+ throw new Error("The value flow from " + srcLocation + " to " + destLocation
+ + " does not respect location hierarchy on the assignment " + an.printNode(0) + context
+ + " at " + cd.getSourceFileName() + "::" + an.getNumLine());
+ }
+
+ if (srcLocation.equals(destLocation)) {
+ // keep it for definitely written analysis
+ Set<FlatNode> flatNodeSet = ssjava.getBuildFlat().getFlatNodeSet(an);
+ for (Iterator iterator = flatNodeSet.iterator(); iterator.hasNext();) {
+ FlatNode fn = (FlatNode) iterator.next();
+ ssjava.addSameHeightWriteFlatNode(fn);
+ }
+
+ }
+
+ } else {
+ destLocation =
+ rhsLocation =
+ checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation(),
+ constraint, false);
+
+ if (constraint != null) {
+ inputGLBSet.add(rhsLocation);
+ inputGLBSet.add(constraint);
+ srcLocation = CompositeLattice.calculateGLB(inputGLBSet, generateErrorMessage(cd, an));
+ } else {
+ srcLocation = rhsLocation;
+ }
+
+ if (!CompositeLattice.isGreaterThan(srcLocation, destLocation, generateErrorMessage(cd, an))) {
+
+ if (srcLocation.equals(destLocation)) {
+ throw new Error("Location " + srcLocation
+ + " is not allowed to have the value flow that moves within the same location at '"
+ + an.printNode(0) + "' of " + cd.getSourceFileName() + "::" + an.getNumLine());
+ } else {
+ throw new Error("The value flow from " + srcLocation + " to " + destLocation
+ + " does not respect location hierarchy on the assignment " + an.printNode(0)
+ + " at " + cd.getSourceFileName() + "::" + an.getNumLine());
+ }
+
+ }
+
+ if (srcLocation.equals(destLocation)) {
+ // keep it for definitely written analysis
+ Set<FlatNode> flatNodeSet = ssjava.getBuildFlat().getFlatNodeSet(an);
+ for (Iterator iterator = flatNodeSet.iterator(); iterator.hasNext();) {
+ FlatNode fn = (FlatNode) iterator.next();
+ ssjava.addSameHeightWriteFlatNode(fn);
+ }
+ }
+
+ }
+
+ return destLocation;
+ }
+
+ private void assignLocationOfVarDescriptor(VarDescriptor vd, MethodDescriptor md,
+ SymbolTable nametable, TreeNode n) {
+
+ ClassDescriptor cd = md.getClassDesc();
+ Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
+
+ // currently enforce every variable to have corresponding location
+ if (annotationVec.size() == 0) {
+ throw new Error("Location is not assigned to variable '" + vd.getSymbol()
+ + "' in the method '" + md + "' of the class " + cd.getSymbol() + " at "
+ + generateErrorMessage(cd, n));
+ }
+
+ int locDecCount = 0;
+ for (int i = 0; i < annotationVec.size(); i++) {
+ AnnotationDescriptor ad = annotationVec.elementAt(i);
+
+ if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
+
+ if (ad.getMarker().equals(SSJavaAnalysis.LOC)) {
+ locDecCount++;
+ if (locDecCount > 1) {// variable can have at most one location
+ throw new Error(vd.getSymbol() + " has more than one location declaration.");
+ }
+ String locDec = ad.getValue(); // check if location is defined
+
+ if (locDec.startsWith(SSJavaAnalysis.DELTA)) {
+ DeltaLocation deltaLoc = parseDeltaDeclaration(md, n, locDec);
+ d2loc.put(vd, deltaLoc);
+ addLocationType(vd.getType(), deltaLoc);
+ } else {
+ CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec);
+
+ Location lastElement = compLoc.get(compLoc.getSize() - 1);
+ if (ssjava.isSharedLocation(lastElement)) {
+ ssjava.mapSharedLocation2Descriptor(lastElement, vd);
+ }
+
+ d2loc.put(vd, compLoc);
+ addLocationType(vd.getType(), compLoc);
+ }
+
+ }
+ }
+ }
+
+ }
+
+ private DeltaLocation parseDeltaDeclaration(MethodDescriptor md, TreeNode n, String locDec) {
+
+ int deltaCount = 0;
+ int dIdx = locDec.indexOf(SSJavaAnalysis.DELTA);
+ while (dIdx >= 0) {
+ deltaCount++;
+ int beginIdx = dIdx + 6;
+ locDec = locDec.substring(beginIdx, locDec.length() - 1);
+ dIdx = locDec.indexOf(SSJavaAnalysis.DELTA);
+ }
+
+ CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec);
+ DeltaLocation deltaLoc = new DeltaLocation(compLoc, deltaCount);
+
+ return deltaLoc;
+ }
+
+ private Location parseFieldLocDeclaraton(String decl, String msg) throws Exception {
+
+ int idx = decl.indexOf(".");
+
+ String className = decl.substring(0, idx);
+ String fieldName = decl.substring(idx + 1);
+
+ className.replaceAll(" ", "");
+ fieldName.replaceAll(" ", "");
+
+ Descriptor d = state.getClassSymbolTable().get(className);
+
+ if (d == null) {
+ // System.out.println("state.getClassSymbolTable()=" +
+ // state.getClassSymbolTable());
+ throw new Error("The class in the location declaration '" + decl + "' does not exist at "
+ + msg);
+ }
+
+ assert (d instanceof ClassDescriptor);
+ SSJavaLattice<String> lattice = ssjava.getClassLattice((ClassDescriptor) d);
+ if (!lattice.containsKey(fieldName)) {
+ throw new Error("The location " + fieldName + " is not defined in the field lattice of '"
+ + className + "' at " + msg);
+ }
+
+ return new Location(d, fieldName);
+ }
+
+ private CompositeLocation parseLocationDeclaration(MethodDescriptor md, TreeNode n, String locDec) {
+
+ CompositeLocation compLoc = new CompositeLocation();
+
+ StringTokenizer tokenizer = new StringTokenizer(locDec, ",");
+ List<String> locIdList = new ArrayList<String>();
+ while (tokenizer.hasMoreTokens()) {
+ String locId = tokenizer.nextToken();
+ locIdList.add(locId);
+ }
+
+ // at least,one location element needs to be here!
+ assert (locIdList.size() > 0);
+
+ // assume that loc with idx 0 comes from the local lattice
+ // loc with idx 1 comes from the field lattice
+
+ String localLocId = locIdList.get(0);
+ SSJavaLattice<String> localLattice = CompositeLattice.getLatticeByDescriptor(md);
+ Location localLoc = new Location(md, localLocId);
+ if (localLattice == null || (!localLattice.containsKey(localLocId))) {
+ throw new Error("Location " + localLocId
+ + " is not defined in the local variable lattice at "
+ + md.getClassDesc().getSourceFileName() + "::" + (n != null ? n.getNumLine() : md) + ".");
+ }
+ compLoc.addLocation(localLoc);
+
+ for (int i = 1; i < locIdList.size(); i++) {
+ String locName = locIdList.get(i);
+ try {
+ Location fieldLoc =
+ parseFieldLocDeclaraton(locName, generateErrorMessage(md.getClassDesc(), n));
+ compLoc.addLocation(fieldLoc);
+ } catch (Exception e) {
+ throw new Error("The location declaration '" + locName + "' is wrong at "
+ + generateErrorMessage(md.getClassDesc(), n));
+ }
+ }
+
+ return compLoc;
+
+ }
+
+ private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
+ VarDescriptor vd = dn.getVarDescriptor();
+ assignLocationOfVarDescriptor(vd, md, nametable, dn);
+ }
+
+ private void checkDeclarationInClass(ClassDescriptor cd) {
+ // Check to see that fields are okay
+ for (Iterator field_it = cd.getFields(); field_it.hasNext();) {
+ FieldDescriptor fd = (FieldDescriptor) field_it.next();
+
+ if (!(fd.isFinal() && fd.isStatic())) {
+ checkFieldDeclaration(cd, fd);
+ } else {
+ // for static final, assign top location by default
+ Location loc = Location.createTopLocation(cd);
+ addLocationType(fd.getType(), loc);
+ }
+ }
+ }
+
+ private Location checkFieldDeclaration(ClassDescriptor cd, FieldDescriptor fd) {
+
+ Vector<AnnotationDescriptor> annotationVec = fd.getType().getAnnotationMarkers();
+
+ // currently enforce every field to have corresponding location
+ if (annotationVec.size() == 0) {
+ throw new Error("Location is not assigned to the field '" + fd.getSymbol()
+ + "' of the class " + cd.getSymbol() + " at " + cd.getSourceFileName());
+ }
+
+ if (annotationVec.size() > 1) {
+ // variable can have at most one location
+ throw new Error("Field " + fd.getSymbol() + " of class " + cd
+ + " has more than one location.");
+ }
+
+ AnnotationDescriptor ad = annotationVec.elementAt(0);
+ Location loc = null;
+
+ if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
+ if (ad.getMarker().equals(SSJavaAnalysis.LOC)) {
+ String locationID = ad.getValue();
+ // check if location is defined
+ SSJavaLattice<String> lattice = ssjava.getClassLattice(cd);
+ if (lattice == null || (!lattice.containsKey(locationID))) {
+ throw new Error("Location " + locationID
+ + " is not defined in the field lattice of class " + cd.getSymbol() + " at"
+ + cd.getSourceFileName() + ".");
+ }
+ loc = new Location(cd, locationID);
+
+ if (ssjava.isSharedLocation(loc)) {
+ ssjava.mapSharedLocation2Descriptor(loc, fd);
+ }
+
+ addLocationType(fd.getType(), loc);
+
+ }
+ }
+
+ return loc;
+ }
+
+ private void addLocationType(TypeDescriptor type, CompositeLocation loc) {
+ if (type != null) {
+ TypeExtension te = type.getExtension();
+ SSJavaType ssType;
+ if (te != null) {
+ ssType = (SSJavaType) te;
+ ssType.setCompLoc(loc);
+ } else {
+ ssType = new SSJavaType(loc);
+ type.setExtension(ssType);
+ }
+ }
+ }
+
+ private void addLocationType(TypeDescriptor type, Location loc) {
+ if (type != null) {
+ type.setExtension(loc);
+ }
+ }
+
+ static class CompositeLattice {
+
+ public static boolean isGreaterThan(CompositeLocation loc1, CompositeLocation loc2, String msg) {
+
+ // System.out.println("\nisGreaterThan=" + loc1 + " " + loc2 + " msg=" +
+ // msg);
+ int baseCompareResult = compareBaseLocationSet(loc1, loc2, true, false, msg);
+ if (baseCompareResult == ComparisonResult.EQUAL) {
+ if (compareDelta(loc1, loc2) == ComparisonResult.GREATER) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (baseCompareResult == ComparisonResult.GREATER) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ public static int compare(CompositeLocation loc1, CompositeLocation loc2, boolean ignore,
+ String msg) {
+
+ // System.out.println("compare=" + loc1 + " " + loc2);
+ int baseCompareResult = compareBaseLocationSet(loc1, loc2, false, ignore, msg);
+
+ if (baseCompareResult == ComparisonResult.EQUAL) {
+ return compareDelta(loc1, loc2);
+ } else {
+ return baseCompareResult;
+ }
+
+ }
+
+ private static int compareDelta(CompositeLocation dLoc1, CompositeLocation dLoc2) {
+
+ int deltaCount1 = 0;
+ int deltaCount2 = 0;
+ if (dLoc1 instanceof DeltaLocation) {
+ deltaCount1 = ((DeltaLocation) dLoc1).getNumDelta();
+ }
+
+ if (dLoc2 instanceof DeltaLocation) {
+ deltaCount2 = ((DeltaLocation) dLoc2).getNumDelta();
+ }
+ if (deltaCount1 < deltaCount2) {
+ return ComparisonResult.GREATER;
+ } else if (deltaCount1 == deltaCount2) {
+ return ComparisonResult.EQUAL;
+ } else {
+ return ComparisonResult.LESS;
+ }
+
+ }
+
+ private static int compareBaseLocationSet(CompositeLocation compLoc1,
+ CompositeLocation compLoc2, boolean awareSharedLoc, boolean ignore, String msg) {
+
+ // if compLoc1 is greater than compLoc2, return true
+ // else return false;
+
+ // compare one by one in according to the order of the tuple
+ int numOfTie = 0;
+ for (int i = 0; i < compLoc1.getSize(); i++) {
+ Location loc1 = compLoc1.get(i);
+ if (i >= compLoc2.getSize()) {
+ if (ignore) {
+ return ComparisonResult.INCOMPARABLE;
+ } else {
+ throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
+ + " because they are not comparable at " + msg);
+ }
+ }
+ Location loc2 = compLoc2.get(i);
+
+ Descriptor descriptor = getCommonParentDescriptor(loc1, loc2, msg);
+ SSJavaLattice<String> lattice = getLatticeByDescriptor(descriptor);
+
+ // check if the shared location is appeared only at the end of the
+ // composite location
+ if (lattice.getSharedLocSet().contains(loc1.getLocIdentifier())) {
+ if (i != (compLoc1.getSize() - 1)) {
+ throw new Error("The shared location " + loc1.getLocIdentifier()
+ + " cannot be appeared in the middle of composite location at" + msg);
+ }
+ }
+
+ if (lattice.getSharedLocSet().contains(loc2.getLocIdentifier())) {
+ if (i != (compLoc2.getSize() - 1)) {
+ throw new Error("The shared location " + loc2.getLocIdentifier()
+ + " cannot be appeared in the middle of composite location at " + msg);
+ }
+ }
+
+ // if (!lattice1.equals(lattice2)) {
+ // throw new Error("Failed to compare two locations of " + compLoc1 +
+ // " and " + compLoc2
+ // + " because they are not comparable at " + msg);
+ // }
+
+ if (loc1.getLocIdentifier().equals(loc2.getLocIdentifier())) {
+ numOfTie++;
+ // check if the current location is the spinning location
+ // note that the spinning location only can be appeared in the last
+ // part of the composite location
+ if (awareSharedLoc && numOfTie == compLoc1.getSize()
+ && lattice.getSharedLocSet().contains(loc1.getLocIdentifier())) {
+ return ComparisonResult.GREATER;
+ }
+ continue;
+ } else if (lattice.isGreaterThan(loc1.getLocIdentifier(), loc2.getLocIdentifier())) {
+ return ComparisonResult.GREATER;
+ } else {
+ return ComparisonResult.LESS;
+ }
+
+ }
+
+ if (numOfTie == compLoc1.getSize()) {
+
+ if (numOfTie != compLoc2.getSize()) {
+
+ if (ignore) {
+ return ComparisonResult.INCOMPARABLE;
+ } else {
+ throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
+ + " because they are not comparable at " + msg);
+ }
+
+ }
+
+ return ComparisonResult.EQUAL;
+ }
+
+ return ComparisonResult.LESS;
+
+ }
+
+ public static CompositeLocation calculateGLB(Set<CompositeLocation> inputSet, String errMsg) {
+
+ // System.out.println("Calculating GLB=" + inputSet);
+ CompositeLocation glbCompLoc = new CompositeLocation();
+
+ // calculate GLB of the first(priority) element
+ Set<String> priorityLocIdentifierSet = new HashSet<String>();
+ Descriptor priorityDescriptor = null;
+
+ Hashtable<String, Set<CompositeLocation>> locId2CompLocSet =
+ new Hashtable<String, Set<CompositeLocation>>();
+ // mapping from the priority loc ID to its full representation by the
+ // composite location
+
+ int maxTupleSize = 0;
+ CompositeLocation maxCompLoc = null;
+
+ Location prevPriorityLoc = null;
+ for (Iterator iterator = inputSet.iterator(); iterator.hasNext();) {
+ CompositeLocation compLoc = (CompositeLocation) iterator.next();
+ if (compLoc.getSize() > maxTupleSize) {
+ maxTupleSize = compLoc.getSize();
+ maxCompLoc = compLoc;
+ }
+ Location priorityLoc = compLoc.get(0);
+ String priorityLocId = priorityLoc.getLocIdentifier();
+ priorityLocIdentifierSet.add(priorityLocId);
+
+ if (locId2CompLocSet.containsKey(priorityLocId)) {
+ locId2CompLocSet.get(priorityLocId).add(compLoc);
+ } else {
+ Set<CompositeLocation> newSet = new HashSet<CompositeLocation>();
+ newSet.add(compLoc);
+ locId2CompLocSet.put(priorityLocId, newSet);
+ }
+
+ // check if priority location are coming from the same lattice
+ if (priorityDescriptor == null) {
+ priorityDescriptor = priorityLoc.getDescriptor();
+ } else {
+ priorityDescriptor = getCommonParentDescriptor(priorityLoc, prevPriorityLoc, errMsg);
+ }
+ prevPriorityLoc = priorityLoc;
+ // else if (!priorityDescriptor.equals(priorityLoc.getDescriptor())) {
+ // throw new Error("Failed to calculate GLB of " + inputSet
+ // + " because they are from different lattices.");
+ // }
+ }
+
+ SSJavaLattice<String> locOrder = getLatticeByDescriptor(priorityDescriptor);
+ String glbOfPriorityLoc = locOrder.getGLB(priorityLocIdentifierSet);
+
+ glbCompLoc.addLocation(new Location(priorityDescriptor, glbOfPriorityLoc));
+ Set<CompositeLocation> compSet = locId2CompLocSet.get(glbOfPriorityLoc);
+
+ if (compSet == null) {
+ // when GLB(x1,x2)!=x1 and !=x2 : GLB case 4
+ // mean that the result is already lower than <x1,y1> and <x2,y2>
+ // assign TOP to the rest of the location elements
+
+ // in this case, do not take care about delta
+ // CompositeLocation inputComp = inputSet.iterator().next();
+ for (int i = 1; i < maxTupleSize; i++) {
+ glbCompLoc.addLocation(Location.createTopLocation(maxCompLoc.get(i).getDescriptor()));
+ }
+ } else {
+
+ // here find out composite location that has a maximum length tuple
+ // if we have three input set: [A], [A,B], [A,B,C]
+ // maximum length tuple will be [A,B,C]
+ int max = 0;
+ CompositeLocation maxFromCompSet = null;
+ for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
+ CompositeLocation c = (CompositeLocation) iterator.next();
+ if (c.getSize() > max) {
+ max = c.getSize();
+ maxFromCompSet = c;
+ }
+ }
+
+ if (compSet.size() == 1) {
+ // if GLB(x1,x2)==x1 or x2 : GLB case 2,3
+ CompositeLocation comp = compSet.iterator().next();
+ for (int i = 1; i < comp.getSize(); i++) {
+ glbCompLoc.addLocation(comp.get(i));
+ }
+
+ // if input location corresponding to glb is a delta, need to apply
+ // delta to glb result
+ if (comp instanceof DeltaLocation) {
+ glbCompLoc = new DeltaLocation(glbCompLoc, 1);
+ }
+
+ } else {
+ // when GLB(x1,x2)==x1 and x2 : GLB case 1
+ // if more than one location shares the same priority GLB
+ // need to calculate the rest of GLB loc
+
+ // setup input set starting from the second tuple item
+ Set<CompositeLocation> innerGLBInput = new HashSet<CompositeLocation>();
+ for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
+ CompositeLocation compLoc = (CompositeLocation) iterator.next();
+ CompositeLocation innerCompLoc = new CompositeLocation();
+ for (int idx = 1; idx < compLoc.getSize(); idx++) {
+ innerCompLoc.addLocation(compLoc.get(idx));
+ }
+ if (innerCompLoc.getSize() > 0) {
+ innerGLBInput.add(innerCompLoc);
+ }
+ }
+
+ if (innerGLBInput.size() > 0) {
+ CompositeLocation innerGLB = CompositeLattice.calculateGLB(innerGLBInput, errMsg);
+ for (int idx = 0; idx < innerGLB.getSize(); idx++) {
+ glbCompLoc.addLocation(innerGLB.get(idx));
+ }
+ }
+
+ // if input location corresponding to glb is a delta, need to apply
+ // delta to glb result
+
+ for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
+ CompositeLocation compLoc = (CompositeLocation) iterator.next();
+ if (compLoc instanceof DeltaLocation) {
+ if (glbCompLoc.equals(compLoc)) {
+ glbCompLoc = new DeltaLocation(glbCompLoc, 1);
+ break;
+ }
+ }
+ }
+
+ }
+ }
+
+ // System.out.println("GLB=" + glbCompLoc);
+ return glbCompLoc;
+
+ }
+
+ static SSJavaLattice<String> getLatticeByDescriptor(Descriptor d) {
+
+ SSJavaLattice<String> lattice = null;
+
+ if (d instanceof ClassDescriptor) {
+ lattice = ssjava.getCd2lattice().get(d);
+ } else if (d instanceof MethodDescriptor) {
+ if (ssjava.getMd2lattice().containsKey(d)) {
+ lattice = ssjava.getMd2lattice().get(d);
+ } else {
+ // use default lattice for the method
+ lattice = ssjava.getCd2methodDefault().get(((MethodDescriptor) d).getClassDesc());
+ }
+ }
+
+ return lattice;
+ }
+
+ static Descriptor getCommonParentDescriptor(Location loc1, Location loc2, String msg) {
+
+ Descriptor d1 = loc1.getDescriptor();
+ Descriptor d2 = loc2.getDescriptor();
+
+ Descriptor descriptor;
+
+ if (d1 instanceof ClassDescriptor && d2 instanceof ClassDescriptor) {
+
+ if (d1.equals(d2)) {
+ descriptor = d1;
+ } else {
+ // identifying which one is parent class
+ Set<Descriptor> d1SubClassesSet = ssjava.tu.getSubClasses((ClassDescriptor) d1);
+ Set<Descriptor> d2SubClassesSet = ssjava.tu.getSubClasses((ClassDescriptor) d2);
+
+ if (d1 == null && d2 == null) {
+ throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2
+ + " because they are not comparable at " + msg);
+ } else if (d1SubClassesSet != null && d1SubClassesSet.contains(d2)) {
+ descriptor = d1;
+ } else if (d2SubClassesSet != null && d2SubClassesSet.contains(d1)) {
+ descriptor = d2;
+ } else {
+ throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2
+ + " because they are not comparable at " + msg);
+ }
+ }
+
+ } else if (d1 instanceof MethodDescriptor && d2 instanceof MethodDescriptor) {
+
+ if (d1.equals(d2)) {
+ descriptor = d1;
+ } else {
+
+ // identifying which one is parent class
+ MethodDescriptor md1 = (MethodDescriptor) d1;
+ MethodDescriptor md2 = (MethodDescriptor) d2;
+
+ if (!md1.matches(md2)) {
+ throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2
+ + " because they are not comparable at " + msg);
+ }
+
+ Set<Descriptor> d1SubClassesSet =
+ ssjava.tu.getSubClasses(((MethodDescriptor) d1).getClassDesc());
+ Set<Descriptor> d2SubClassesSet =
+ ssjava.tu.getSubClasses(((MethodDescriptor) d2).getClassDesc());
+
+ if (d1 == null && d2 == null) {
+ throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2
+ + " because they are not comparable at " + msg);
+ } else if (d1 != null && d1SubClassesSet.contains(d2)) {
+ descriptor = d1;
+ } else if (d2 != null && d2SubClassesSet.contains(d1)) {
+ descriptor = d2;
+ } else {
+ throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2
+ + " because they are not comparable at " + msg);
+ }
+ }
+
+ } else {
+ throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2
+ + " because they are not comparable at " + msg);
+ }
+
+ return descriptor;
+
+ }
+
+ }
+
+ class ComparisonResult {
+
+ public static final int GREATER = 0;
+ public static final int EQUAL = 1;
+ public static final int LESS = 2;
+ public static final int INCOMPARABLE = 3;
+ int result;
+
+ }
+
+}
+
+class ReturnLocGenerator {
+
+ public static final int PARAMISHIGHER = 0;
+ public static final int PARAMISSAME = 1;
+ public static final int IGNORE = 2;
+
+ private Hashtable<Integer, Integer> paramIdx2paramType;
+
+ private CompositeLocation declaredReturnLoc = null;
+
+ public ReturnLocGenerator(CompositeLocation returnLoc, MethodDescriptor md,
+ List<CompositeLocation> params, String msg) {
+
+ CompositeLocation thisLoc = params.get(0);
+ if (returnLoc.get(0).equals(thisLoc.get(0)) && returnLoc.getSize() > 1) {
+ // if the declared return location consists of THIS and field location,
+ // return location for the caller's side has to have same field element
+ this.declaredReturnLoc = returnLoc;
+ } else {
+ // creating mappings
+ paramIdx2paramType = new Hashtable<Integer, Integer>();
+ for (int i = 0; i < params.size(); i++) {
+ CompositeLocation param = params.get(i);
+ int compareResult = CompositeLattice.compare(param, returnLoc, true, msg);
+
+ int type;
+ if (compareResult == ComparisonResult.GREATER) {
+ type = 0;
+ } else if (compareResult == ComparisonResult.EQUAL) {
+ type = 1;
+ } else {
+ type = 2;
+ }
+ paramIdx2paramType.put(new Integer(i), new Integer(type));
+ }
+ }
+
+ }
+
+ public CompositeLocation computeReturnLocation(List<CompositeLocation> args) {
+
+ if (declaredReturnLoc != null) {
+ // when developer specify that the return value is [THIS,field]
+ // needs to translate to the caller's location
+ CompositeLocation callerLoc = new CompositeLocation();
+ CompositeLocation callerBaseLocation = args.get(0);
+
+ for (int i = 0; i < callerBaseLocation.getSize(); i++) {
+ callerLoc.addLocation(callerBaseLocation.get(i));
+ }
+ for (int i = 1; i < declaredReturnLoc.getSize(); i++) {
+ callerLoc.addLocation(declaredReturnLoc.get(i));
+ }
+ return callerLoc;
+ } else {
+ // compute the highest possible location in caller's side
+ assert paramIdx2paramType.keySet().size() == args.size();
+
+ Set<CompositeLocation> inputGLB = new HashSet<CompositeLocation>();
+ for (int i = 0; i < args.size(); i++) {
+ int type = (paramIdx2paramType.get(new Integer(i))).intValue();
+ CompositeLocation argLoc = args.get(i);
+ if (type == PARAMISHIGHER || type == PARAMISSAME) {
+ // return loc is equal to or lower than param
+ inputGLB.add(argLoc);
+ }
+ }
+
+ // compute GLB of arguments subset that are same or higher than return
+ // location
+ if (inputGLB.isEmpty()) {
+ CompositeLocation rtr =
+ new CompositeLocation(Location.createTopLocation(args.get(0).get(0).getDescriptor()));
+ return rtr;
+ } else {
+ CompositeLocation glb = CompositeLattice.calculateGLB(inputGLB, "");
+ return glb;