Source Code Cross Referenced for InnerClassAccessMap.java in  » Code-Analyzer » findbugs » edu » umd » cs » findbugs » ba » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Code Analyzer » findbugs » edu.umd.cs.findbugs.ba 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Bytecode Analysis Framework
003:         * Copyright (C) 2003,2004 University of Maryland
004:         * 
005:         * This library is free software; you can redistribute it and/or
006:         * modify it under the terms of the GNU Lesser General Public
007:         * License as published by the Free Software Foundation; either
008:         * version 2.1 of the License, or (at your option) any later version.
009:         * 
010:         * This library is distributed in the hope that it will be useful,
011:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013:         * Lesser General Public License for more details.
014:         * 
015:         * You should have received a copy of the GNU Lesser General Public
016:         * License along with this library; if not, write to the Free Software
017:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018:         */
019:
020:        package edu.umd.cs.findbugs.ba;
021:
022:        import java.util.HashMap;
023:        import java.util.Map;
024:
025:        import org.apache.bcel.Constants;
026:        import org.apache.bcel.Repository;
027:        import org.apache.bcel.classfile.Code;
028:        import org.apache.bcel.classfile.ConstantClass;
029:        import org.apache.bcel.classfile.ConstantFieldref;
030:        import org.apache.bcel.classfile.ConstantNameAndType;
031:        import org.apache.bcel.classfile.ConstantPool;
032:        import org.apache.bcel.classfile.JavaClass;
033:        import org.apache.bcel.classfile.Method;
034:        import org.apache.bcel.generic.ConstantPoolGen;
035:        import org.apache.bcel.generic.INVOKESTATIC;
036:
037:        import edu.umd.cs.findbugs.SystemProperties;
038:
039:        /**
040:         * Determine which methods are accessors used
041:         * by inner classes to access fields in their enclosing classes.
042:         * This has been tested with javac from the Sun JDK 1.4.x,
043:         * but will probably not work with other source to bytecode compilers.
044:         * 
045:         * <p>
046:         * The instance of InnerClassAccessMap should be retrieved
047:         * from the AnalysisContext.
048:         * </p>
049:         *
050:         * @author David Hovemeyer
051:         * @see InnerClassAccess
052:         */
053:        public class InnerClassAccessMap {
054:            private static final boolean DEBUG = SystemProperties
055:                    .getBoolean("icam.debug");
056:
057:            /* ----------------------------------------------------------------------
058:             * Fields
059:             * ---------------------------------------------------------------------- */
060:
061:            /**
062:             * Map of class names to maps of method names to InnerClassAccess objects
063:             * representing access methods.
064:             */
065:            private Map<String, Map<String, InnerClassAccess>> classToAccessMap;
066:
067:            /* ----------------------------------------------------------------------
068:             * Public interface
069:             * ---------------------------------------------------------------------- */
070:
071:            /**
072:             * Create an instance.
073:             * 
074:             * @return a new instance of InnerClassAccessMap
075:             */
076:            public static InnerClassAccessMap create() {
077:                return new InnerClassAccessMap();
078:            }
079:
080:            /**
081:             * Get the InnerClassAccess in given class with the given method name.
082:             *
083:             * @param className  the name of the class
084:             * @param methodName the name of the access method
085:             * @return the InnerClassAccess object for the method, or null if
086:             *         the method doesn't seem to be an inner class access
087:             */
088:            public InnerClassAccess getInnerClassAccess(String className,
089:                    String methodName) throws ClassNotFoundException {
090:                Map<String, InnerClassAccess> map = getAccessMapForClass(className);
091:                return map.get(methodName);
092:            }
093:
094:            /**
095:             * Get the inner class access object for given invokestatic instruction.
096:             * Returns null if the called method is not an inner class access.
097:             *
098:             * @param inv the invokestatic instruction
099:             * @param cpg the ConstantPoolGen for the method
100:             * @return the InnerClassAccess, or null if the call is not an inner class access
101:             */
102:            public InnerClassAccess getInnerClassAccess(INVOKESTATIC inv,
103:                    ConstantPoolGen cpg) throws ClassNotFoundException {
104:                String methodName = inv.getMethodName(cpg);
105:                if (methodName.startsWith("access$")) {
106:                    String className = inv.getClassName(cpg);
107:
108:                    return getInnerClassAccess(className, methodName);
109:                }
110:                return null;
111:            }
112:
113:            /**
114:             * Clear the cache.
115:             */
116:            public void clearCache() {
117:                classToAccessMap.clear();
118:            }
119:
120:            /* ----------------------------------------------------------------------
121:             * Implementation
122:             * ---------------------------------------------------------------------- */
123:
124:            /**
125:             * Constructor.
126:             */
127:            private InnerClassAccessMap() {
128:                this .classToAccessMap = new HashMap<String, Map<String, InnerClassAccess>>();
129:            }
130:
131:            /**
132:             * Convert byte to unsigned int.
133:             */
134:            private static int toInt(byte b) {
135:                int value = b & 0x7F;
136:                if ((b & 0x80) != 0)
137:                    value |= 0x80;
138:                return value;
139:            }
140:
141:            /**
142:             * Get an unsigned 16 bit constant pool index from a byte array.
143:             */
144:            private static int getIndex(byte[] instructionList, int index) {
145:                return (toInt(instructionList[index + 1]) << 8)
146:                        | toInt(instructionList[index + 2]);
147:            }
148:
149:            private static class LookupFailure extends RuntimeException {
150:                /**
151:                 * 
152:                 */
153:                private static final long serialVersionUID = 1L;
154:                private final ClassNotFoundException exception;
155:
156:                public LookupFailure(ClassNotFoundException exception) {
157:                    this .exception = exception;
158:                }
159:
160:                public ClassNotFoundException getException() {
161:                    return exception;
162:                }
163:            }
164:
165:            /**
166:             * Callback to scan an access method to determine what
167:             * field it accesses, and whether the field is loaded or stored.
168:             */
169:            private static class InstructionCallback implements 
170:                    BytecodeScanner.Callback {
171:                private JavaClass javaClass;
172:                private String methodName;
173:                private String methodSig;
174:                private byte[] instructionList;
175:                private InnerClassAccess access;
176:                private int accessCount;
177:
178:                /**
179:                 * Constructor.
180:                 *
181:                 * @param javaClass       the class containing the access method
182:                 * @param methodName      the name of the access method
183:                 * @param methodSig       the signature of the access method
184:                 * @param instructionList the bytecode of the method
185:                 */
186:                public InstructionCallback(JavaClass javaClass,
187:                        String methodName, String methodSig,
188:                        byte[] instructionList) {
189:                    this .javaClass = javaClass;
190:                    this .methodName = methodName;
191:                    this .methodSig = methodSig;
192:                    this .instructionList = instructionList;
193:                    this .access = null;
194:                    this .accessCount = 0;
195:                }
196:
197:                public void handleInstruction(int opcode, int index) {
198:                    switch (opcode) {
199:                    case Constants.GETFIELD:
200:                    case Constants.PUTFIELD:
201:                        setField(getIndex(instructionList, index), false,
202:                                opcode == Constants.GETFIELD);
203:                        break;
204:                    case Constants.GETSTATIC:
205:                    case Constants.PUTSTATIC:
206:                        setField(getIndex(instructionList, index), true,
207:                                opcode == Constants.GETSTATIC);
208:                        break;
209:                    }
210:                }
211:
212:                /**
213:                 * Get the InnerClassAccess object representing the method.
214:                 *
215:                 * @return the InnerClassAccess, or null if the method
216:                 *         was not found to be a simple load or store in the
217:                 *         expected form
218:                 */
219:                public InnerClassAccess getAccess() {
220:                    return access;
221:                }
222:
223:                /**
224:                 * Called to indicate that a field load or store was encountered.
225:                 *
226:                 * @param cpIndex  the constant pool index of the fieldref
227:                 * @param isStatic true if it is a static field access
228:                 * @param isLoad   true if the access is a load
229:                 */
230:                private void setField(int cpIndex, boolean isStatic,
231:                        boolean isLoad) {
232:                    // We only allow one field access for an accessor method.
233:                    accessCount++;
234:                    if (accessCount != 1) {
235:                        access = null;
236:                        return;
237:                    }
238:
239:                    ConstantPool cp = javaClass.getConstantPool();
240:                    ConstantFieldref fieldref = (ConstantFieldref) cp
241:                            .getConstant(cpIndex);
242:
243:                    ConstantClass cls = (ConstantClass) cp.getConstant(fieldref
244:                            .getClassIndex());
245:                    String className = cls.getBytes(cp).replace('/', '.');
246:
247:                    ConstantNameAndType nameAndType = (ConstantNameAndType) cp
248:                            .getConstant(fieldref.getNameAndTypeIndex());
249:                    String fieldName = nameAndType.getName(cp);
250:                    String fieldSig = nameAndType.getSignature(cp);
251:
252:                    try {
253:                        XField xfield = Hierarchy.findXField(className,
254:                                fieldName, fieldSig, isStatic);
255:                        if (xfield != null
256:                                && xfield.isStatic() == isStatic
257:                                && isValidAccessMethod(methodSig, xfield,
258:                                        isLoad)) {
259:                            access = new InnerClassAccess(methodName,
260:                                    methodSig, xfield, isLoad);
261:                        }
262:                    } catch (ClassNotFoundException e) {
263:                        throw new LookupFailure(e);
264:                    }
265:                }
266:
267:                /**
268:                 * Determine if the method appears to be an accessor of the expected form.
269:                 * This has only been tested with the Sun JDK 1.4 javac (definitely)
270:                 * and jikes 1.18 (I think).
271:                 *
272:                 * @param methodSig the method's signature
273:                 * @param field     the field accessed by the method
274:                 * @param isLoad    true if the access is a load
275:                 */
276:                private boolean isValidAccessMethod(String methodSig,
277:                        XField field, boolean isLoad) {
278:
279:                    // Get the method parameters and return type
280:                    // (as they appear in the method signature).
281:                    int paramsEnd = methodSig.indexOf(')');
282:                    if (paramsEnd < 0)
283:                        return false;
284:                    String methodParams = methodSig.substring(0, paramsEnd + 1);
285:                    String methodReturnType = methodSig
286:                            .substring(paramsEnd + 1);
287:
288:                    // Figure out what the expected method parameters should be
289:                    String classSig = "L"
290:                            + javaClass.getClassName().replace('.', '/') + ";";
291:                    StringBuffer buf = new StringBuffer();
292:                    buf.append('(');
293:                    if (!field.isStatic())
294:                        buf.append(classSig); // the OuterClass.this reference
295:                    if (!isLoad)
296:                        buf.append(field.getSignature()); // the value being stored
297:                    buf.append(')');
298:                    String expectedMethodParams = buf.toString();
299:
300:                    // See if params match
301:                    if (!methodParams.equals(expectedMethodParams)) {
302:                        if (DEBUG) {
303:                            System.out.println("In " + javaClass.getClassName()
304:                                    + "." + methodName + " expected params "
305:                                    + expectedMethodParams + ", saw "
306:                                    + methodParams);
307:                            System.out.println(isLoad ? "LOAD" : "STORE");
308:                        }
309:                        return false;
310:                    }
311:
312:                    // Return type can be either the type of the field, or void.
313:                    if (!methodReturnType.equals("V")
314:                            && !methodReturnType.equals(field.getSignature())) {
315:                        if (DEBUG) {
316:                            System.out.println("In " + javaClass.getClassName()
317:                                    + "." + methodName
318:                                    + " expected return type V or "
319:                                    + field.getSignature() + ", saw "
320:                                    + methodReturnType);
321:                            System.out.println(isLoad ? "LOAD" : "STORE");
322:                        }
323:                        return false;
324:                    }
325:
326:                    return true;
327:                }
328:            }
329:
330:            private static final Map<String, InnerClassAccess> emptyMap = new HashMap<String, InnerClassAccess>();
331:
332:            /**
333:             * Return a map of inner-class member access method names to
334:             * the fields that they access for given class name.
335:             *
336:             * @param className the name of the class
337:             * @return map of access method names to the fields they access
338:             */
339:            private Map<String, InnerClassAccess> getAccessMapForClass(
340:                    String className) throws ClassNotFoundException {
341:
342:                Map<String, InnerClassAccess> map = classToAccessMap
343:                        .get(className);
344:                if (map == null) {
345:                    map = new HashMap<String, InnerClassAccess>();
346:
347:                    if (!className.startsWith("[")) {
348:                        JavaClass javaClass = Repository.lookupClass(className);
349:
350:                        Method[] methodList = javaClass.getMethods();
351:                        for (Method method : methodList) {
352:                            String methodName = method.getName();
353:                            if (!methodName.startsWith("access$"))
354:                                continue;
355:
356:                            Code code = method.getCode();
357:                            if (code == null)
358:                                continue;
359:
360:                            if (DEBUG)
361:                                System.out
362:                                        .println("Analyzing "
363:                                                + className
364:                                                + "."
365:                                                + method.getName()
366:                                                + " as an inner-class access method...");
367:
368:                            byte[] instructionList = code.getCode();
369:                            String methodSig = method.getSignature();
370:                            InstructionCallback callback = new InstructionCallback(
371:                                    javaClass, methodName, methodSig,
372:                                    instructionList);
373:                            try {
374:                                new BytecodeScanner().scan(instructionList,
375:                                        callback);
376:                            } catch (LookupFailure lf) {
377:                                throw lf.getException();
378:                            }
379:                            InnerClassAccess access = callback.getAccess();
380:                            if (DEBUG)
381:                                System.out.println((access != null ? "IS"
382:                                        : "IS NOT")
383:                                        + " an inner-class access method");
384:                            if (access != null)
385:                                map.put(methodName, access);
386:                        }
387:                    }
388:
389:                    if (map.size() == 0)
390:                        map = emptyMap;
391:
392:                    classToAccessMap.put(className, map);
393:                }
394:
395:                return map;
396:            }
397:
398:        }
399:
400:        // vim:ts=4
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.