1/* 2 * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.jdi; 27import com.sun.jdi.*; 28 29public class LocalVariableImpl extends MirrorImpl 30 implements LocalVariable, ValueContainer 31{ 32 private final Method method; 33 private final int slot; 34 private final Location scopeStart; 35 private final Location scopeEnd; 36 private final String name; 37 private final String signature; 38 private String genericSignature = null; 39 40 LocalVariableImpl(VirtualMachine vm, Method method, 41 int slot, Location scopeStart, Location scopeEnd, 42 String name, String signature, 43 String genericSignature) { 44 super(vm); 45 this.method = method; 46 this.slot = slot; 47 this.scopeStart = scopeStart; 48 this.scopeEnd = scopeEnd; 49 this.name = name; 50 this.signature = signature; 51 if (genericSignature != null && genericSignature.length() > 0) { 52 this.genericSignature = genericSignature; 53 } else { 54 // The Spec says to return null for non-generic types 55 this.genericSignature = null; 56 } 57 } 58 59 public boolean equals(Object obj) { 60 if ((obj != null) && (obj instanceof LocalVariableImpl)) { 61 LocalVariableImpl other = (LocalVariableImpl)obj; 62 return ((slot() == other.slot()) && 63 (scopeStart != null) && 64 (scopeStart.equals(other.scopeStart)) && 65 (super.equals(obj))); 66 } else { 67 return false; 68 } 69 } 70 71 public int hashCode() { 72 /* 73 * TO DO: Better hash code 74 */ 75 return ((scopeStart.hashCode() << 4) + slot()); 76 } 77 78 public int compareTo(LocalVariable object) { 79 LocalVariableImpl other = (LocalVariableImpl)object; 80 81 int rc = scopeStart.compareTo(other.scopeStart); 82 if (rc == 0) { 83 rc = slot() - other.slot(); 84 } 85 return rc; 86 } 87 88 public String name() { 89 return name; 90 } 91 92 /** 93 * @return a text representation of the declared type 94 * of this variable. 95 */ 96 public String typeName() { 97 JNITypeParser parser = new JNITypeParser(signature); 98 return parser.typeName(); 99 } 100 101 public Type type() throws ClassNotLoadedException { 102 return findType(signature()); 103 } 104 105 public Type findType(String signature) throws ClassNotLoadedException { 106 ReferenceTypeImpl enclosing = (ReferenceTypeImpl)method.declaringType(); 107 return enclosing.findType(signature); 108 } 109 110 public String signature() { 111 return signature; 112 } 113 114 public String genericSignature() { 115 return genericSignature; 116 } 117 118 public boolean isVisible(StackFrame frame) { 119 validateMirror(frame); 120 Method frameMethod = frame.location().method(); 121 122 if (!frameMethod.equals(method)) { 123 throw new IllegalArgumentException( 124 "frame method different than variable's method"); 125 } 126 127 // this is here to cover the possibility that we will 128 // allow LocalVariables for native methods. If we do 129 // so we will have to re-examinine this. 130 if (frameMethod.isNative()) { 131 return false; 132 } 133 134 return ((scopeStart.compareTo(frame.location()) <= 0) 135 && (scopeEnd.compareTo(frame.location()) >= 0)); 136 } 137 138 public boolean isArgument() { 139 try { 140 MethodImpl method = (MethodImpl)scopeStart.method(); 141 return (slot < method.argSlotCount()); 142 } catch (AbsentInformationException e) { 143 // If this variable object exists, there shouldn't be absent info 144 throw new InternalException(); 145 } 146 } 147 148 int slot() { 149 return slot; 150 } 151 152 /* 153 * Compilers/VMs can have byte code ranges for variables of the 154 * same names that overlap. This is because the byte code ranges 155 * aren't necessarily scopes; they may have more to do with the 156 * lifetime of the variable's slot, depending on implementation. 157 * 158 * This method determines whether this variable hides an 159 * identically named variable; ie, their byte code ranges overlap 160 * this one starts after the given one. If it returns true this 161 * variable should be preferred when looking for a single variable 162 * with its name when both variables are visible. 163 */ 164 boolean hides(LocalVariable other) { 165 LocalVariableImpl otherImpl = (LocalVariableImpl)other; 166 if (!method.equals(otherImpl.method) || 167 !name.equals(otherImpl.name)) { 168 return false; 169 } else { 170 return (scopeStart.compareTo(otherImpl.scopeStart) > 0); 171 } 172 } 173 174 public String toString() { 175 return name() + " in " + method.toString() + 176 "@" + scopeStart.toString(); 177 } 178} 179