package annotations.el;

import checkers.nullness.quals.*;
import checkers.javari.quals.*;

import annotations.util.*;

/**
 * A {@link LocalLocation} holds location information for a local
 * variable: slot index, scope start, and scope length.
 */
public final /*@ReadOnly*/ class LocalLocation {
    /**
     * The slot index of the local variable.
     */
    public final int index;

    /**
     * The start of the local variable's scope (or live range), as an offset
     * from the beginning of the method code in bytes.
     */
    public final int scopeStart;

    /**
     * The length of the local variable's scope (or live range), in bytes.
     */
    public final int scopeLength;

    /**
     * Constructs a new {@link LocalLocation}; the arguments are assigned to
     * the fields of the same names.
     */
    public LocalLocation(int index, int scopeStart, int scopeLength) {
    	this.index = index;
        this.scopeStart = scopeStart;
        this.scopeLength = scopeLength;
        this.varname = null;
    }

    public final String varname;
    
    public LocalLocation(String varname) {
    	this.index = -1;
        this.scopeStart = -1;
        this.scopeLength = -1;
    	this.varname = varname;
    }
    
    
    /**
     * Returns whether this {@link LocalLocation} equals <code>o</code>; a
     * slightly faster variant of {@link #equals(Object)} for when the argument
     * is statically known to be another nonnull {@link LocalLocation}.
     */
    public boolean equals(LocalLocation l) {
        return (index == l.index && scopeStart == l.scopeStart
                && scopeLength == l.scopeLength) ||
                (varname!=null && varname.equals(l.varname));
    }

    /**
     * This {@link LocalLocation} equals <code>o</code> if and only if
     * <code>o</code> is another nonnull {@link LocalLocation} and
     * <code>this</code> and <code>o</code> have equal {@link #index},
     * {@link #scopeStart}, and {@link #scopeLength}.
     */
    @Override
    public boolean equals(/*@ReadOnly*/ Object o) {
        return o instanceof LocalLocation
                && equals((LocalLocation) o);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() /*@ReadOnly*/ {
    	if (varname==null) {
			Hasher h = new Hasher();
			h.mash(index);
			h.mash(scopeStart);
			h.mash(scopeLength);
			return h.hash;
		} else {
    		return varname.hashCode();
		}
    }

    @Override
    public String toString() {
    	if (varname==null) {
    		return "LocalLocation(" + index + ", " + scopeStart + ", " + scopeLength + ")";
    	} else {
    		return "LocalLocation(\"" + varname + "\")";
    	}
    }
}

@@ -1006,25 +1006,25 @@
     this.var
-n
+N
 ame = null;%0A
@@ -1023,16 +1023,44 @@
 = null;%0A
+        this.varIndex = -1;%0A
     %7D%0A%0A 
@@ -1081,28 +1081,59 @@
 l String var
-name
+Name;%0A    public final int varIndex
 ;%0A    %0A    p
@@ -1162,20 +1162,34 @@
 ring var
-n
+N
 ame
+, int varIndex
 ) %7B%0A    
@@ -1280,17 +1280,17 @@
 this.var
-n
+N
 ame = va
@@ -1290,20 +1290,51 @@
 me = var
-name
+Name;%0A    %09this.varIndex = varIndex
 ;%0A    %7D%0A
@@ -1766,17 +1766,17 @@
     (var
-n
+N
 ame!=nul
@@ -1779,25 +1779,25 @@
 =null && var
-n
+N
 ame.equals(l
@@ -1804,13 +1804,37 @@
 .var
-n
+N
 ame)
+ && varIndex==l.varIndex
 );%0A 
@@ -2376,35 +2376,8 @@
 / %7B%0A
-    %09if (varname==null) %7B%0A%09
 %09%09Ha
@@ -2398,16 +2398,42 @@
 asher();
+%0A    %09if (varName==null) %7B
 %0A%09%09%09h.ma
@@ -2496,52 +2496,31 @@
 ;%0A%09%09
-%09return h.hash;%0A%09%09%7D else %7B%0A    %09%09return varn
+%7D else %7B%0A%09%09%09h.mash(varN
 ame.
@@ -2529,21 +2529,60 @@
 shCode()
-;%0A%09%09%7D
+);%0A%09%09%09h.mash(varIndex);%0A%09%09%7D%0A%09%09return h.hash;
 %0A    %7D%0A%0A
@@ -2638,17 +2638,17 @@
 %09if (var
-n
+N
 ame==nul
@@ -2789,17 +2789,17 @@
 %22%22 + var
-n
+N
 ame + %22%5C
@@ -2799,16 +2799,34 @@
 me + %22%5C%22
+ #%22 + varIndex + %22
 )%22;%0A    

Support a local variable index to disambiguate between different variables with the same name.