001: /*
002: * Variable.java
003: *
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
005: *
006: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
007: *
008: * The contents of this file are subject to the terms of either the GNU
009: * General Public License Version 2 only ("GPL") or the Common
010: * Development and Distribution License("CDDL") (collectively, the
011: * "License"). You may not use this file except in compliance with the
012: * License. You can obtain a copy of the License at
013: * http://www.netbeans.org/cddl-gplv2.html
014: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
015: * specific language governing permissions and limitations under the
016: * License. When distributing the software, include this License Header
017: * Notice in each file and include the License file at
018: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
019: * particular file as subject to the "Classpath" exception as provided
020: * by Sun in the GPL Version 2 section of the License file that
021: * accompanied this code. If applicable, add the following below the
022: * License Header, with the fields enclosed by brackets [] replaced by
023: * your own identifying information:
024: * "Portions Copyrighted [year] [name of copyright owner]"
025: *
026: * Contributor(s):
027: *
028: * The Original Software is NetBeans. The Initial Developer of the Original
029: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
030: * Microsystems, Inc. All Rights Reserved.
031: *
032: * If you wish your version of this file to be governed by only the CDDL
033: * or only the GPL Version 2, indicate your decision by adding
034: * "[Contributor] elects to include this software in this distribution
035: * under the [CDDL or GPL Version 2] license." If you do not indicate a
036: * single choice of license, a recipient has the option to distribute
037: * your version of this file under either the CDDL, the GPL Version 2 or
038: * to extend the choice of license to its licensees as provided above.
039: * However, if you add GPL Version 2 code and therefore, elected the GPL
040: * Version 2 license, then the option applies only if the new code is
041: * made subject to such option by the copyright holder.
042: *
043: * Contributor(s): Thomas Ball
044: *
045: * Version: $Revision$
046: */
047:
048: package org.netbeans.modules.classfile;
049:
050: import java.io.*;
051: import java.util.*;
052:
053: /**
054: * A representation of a parameter to a method declaration. A parameter
055: * will not have a name, unless the classfile is compiled with local
056: * variable tables (if not, then the name is an empty string).
057: * A final modifier on a parameter is never reported,
058: * since that modifier is not stored in a classfile.
059: *
060: * @author Thomas Ball
061: */
062: public final class Parameter extends Field {
063:
064: static Parameter[] makeParams(Method method) {
065: List<Parameter> paramList = new ArrayList<Parameter>();
066: for (Iterator<Parameter> it = new ParamIterator(method); it
067: .hasNext();)
068: paramList.add(it.next());
069: return paramList.toArray(new Parameter[paramList.size()]);
070: }
071:
072: private static Parameter createParameter(String name, String type,
073: ClassFile classFile, DataInputStream visibleAnnotations,
074: DataInputStream invisibleAnnotations) {
075: return new Parameter(name, type, classFile, visibleAnnotations,
076: invisibleAnnotations);
077: }
078:
079: /** Creates new Parameter */
080: private Parameter(String name, String type, ClassFile classFile,
081: DataInputStream visibleAnnotations,
082: DataInputStream invisibleAnnotations) {
083: super (name, type, classFile);
084: loadParameterAnnotations(visibleAnnotations,
085: invisibleAnnotations);
086: }
087:
088: private void loadParameterAnnotations(DataInputStream visible,
089: DataInputStream invisible) {
090: super .loadAnnotations();
091: if (annotations == null
092: && (visible != null || invisible != null))
093: annotations = new HashMap<ClassName, Annotation>(2);
094: try {
095: if (visible != null && visible.available() > 0)
096: Annotation.load(visible, classFile.getConstantPool(),
097: true, annotations);
098: } catch (IOException e) {
099: throw new InvalidClassFileAttributeException(
100: "invalid RuntimeVisibleParameterAnnotations attribute",
101: e);
102: }
103: try {
104: if (invisible != null && invisible.available() > 0)
105: Annotation.load(invisible, classFile.getConstantPool(),
106: false, annotations);
107: } catch (IOException e) {
108: throw new InvalidClassFileAttributeException(
109: "invalid RuntimeInvisibleParameterAnnotations attribute",
110: e);
111: }
112: }
113:
114: /**
115: * Return a string in the form "<type> <name>". Class types
116: * are shown in a "short" form; i.e. "Object" instead of
117: * "java.lang.Object"j.
118: *
119: * @return string describing the variable and its type.
120: */
121: public final String getDeclaration() {
122: StringBuffer sb = new StringBuffer();
123: sb.append(CPFieldMethodInfo
124: .getSignature(getDescriptor(), false));
125: String name = getName();
126: if (name != null) {
127: sb.append(' ');
128: sb.append(name);
129: }
130: return sb.toString();
131: }
132:
133: public String toString() {
134: StringBuffer sb = new StringBuffer("name=");
135: sb.append(getName());
136: sb.append(" type="); //NOI18N
137: sb.append(getDescriptor());
138: if (getTypeSignature() != null) {
139: sb.append(", signature="); //NOI18N
140: sb.append(typeSignature);
141: }
142: loadAnnotations();
143: if (annotations.size() > 0) {
144: Iterator iter = annotations.values().iterator();
145: sb.append(", annotations={ ");
146: while (iter.hasNext()) {
147: sb.append(iter.next().toString());
148: if (iter.hasNext())
149: sb.append(", ");
150: }
151: sb.append(" }");
152: }
153: return sb.toString();
154: }
155:
156: private static class ParamIterator implements Iterator<Parameter> {
157: ClassFile classFile;
158: String signature;
159: LocalVariableTableEntry[] localVars;
160:
161: /** the current local variable array position */
162: int ivar;
163:
164: /** the current character in the type signature */
165: int isig;
166:
167: /** annotation attributes */
168: DataInputStream visibleAnnotations;
169: DataInputStream invisibleAnnotations;
170:
171: /**
172: * @param method
173: */
174: ParamIterator(Method method) {
175: classFile = method.getClassFile();
176: signature = method.getDescriptor();
177: assert signature.charAt(0) == '(';
178: isig = 1; // skip '('
179: ivar = method.isStatic() ? 0 : 1;
180: Code code = method.getCode();
181: localVars = code != null ? code.getLocalVariableTable()
182: : new LocalVariableTableEntry[0];
183: AttributeMap attrs = method.getAttributes();
184: try {
185: visibleAnnotations = getParamAttr(attrs,
186: "RuntimeVisibleParameterAnnotations"); //NOI18N
187: } catch (IOException e) {
188: throw new InvalidClassFileAttributeException(
189: "invalid RuntimeVisibleParameterAnnotations attribute",
190: e);
191: }
192: try {
193: invisibleAnnotations = getParamAttr(attrs,
194: "RuntimeInvisibleParameterAnnotations"); //NOI18N
195: } catch (IOException e) {
196: throw new InvalidClassFileAttributeException(
197: "invalid RuntimeInvisibleParameterAnnotations attribute",
198: e);
199: }
200: }
201:
202: private DataInputStream getParamAttr(AttributeMap attrs,
203: String name) throws IOException {
204: DataInputStream in = attrs.getStream(name);
205: if (in != null)
206: in.readByte(); // skip the redundant parameters number
207: return in;
208: }
209:
210: public boolean hasNext() {
211: return signature.charAt(isig) != ')';
212: }
213:
214: public Parameter next() {
215: if (hasNext()) {
216: String name = "";
217: for (int i = 0; i < localVars.length; i++) {
218: LocalVariableTableEntry lvte = localVars[i];
219: // only parameters have a startPC of zero
220: if (lvte.index == ivar && lvte.startPC == 0) {
221: name = localVars[i].getName();
222: break;
223: }
224: }
225: ivar++;
226: int sigStart = isig;
227: while (isig < signature.length()) {
228: char ch = signature.charAt(isig);
229: switch (ch) {
230: case '[':
231: isig++;
232: break;
233: case 'B':
234: case 'C':
235: case 'F':
236: case 'I':
237: case 'S':
238: case 'Z':
239: case 'V': {
240: String type = signature.substring(sigStart,
241: ++isig);
242: return Parameter.createParameter(name, type,
243: classFile, visibleAnnotations,
244: invisibleAnnotations);
245: }
246: case 'D':
247: case 'J': {
248: ivar++; // longs and doubles take two slots
249: String type = signature.substring(sigStart,
250: ++isig);
251: return Parameter.createParameter(name, type,
252: classFile, visibleAnnotations,
253: invisibleAnnotations);
254: }
255: case 'L': {
256: int end = signature.indexOf(';', isig) + 1;
257: String type = signature.substring(isig, end);
258: isig = end;
259: return Parameter.createParameter(name, type,
260: classFile, visibleAnnotations,
261: invisibleAnnotations);
262: }
263:
264: }
265: }
266: }
267: throw new NoSuchElementException();
268: }
269:
270: public void remove() {
271: throw new UnsupportedOperationException();
272: }
273: }
274: }
|