📄 xfactory.java
字号:
/* * FindBugs - Find Bugs in Java programs * Copyright (C) 2005, University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package edu.umd.cs.findbugs.ba;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;import org.apache.bcel.Constants;import org.apache.bcel.Repository;import org.apache.bcel.classfile.ConstantUtf8;import org.apache.bcel.classfile.Field;import org.apache.bcel.classfile.JavaClass;import org.apache.bcel.classfile.Method;import org.apache.bcel.generic.ConstantPoolGen;import org.apache.bcel.generic.FieldInstruction;import org.apache.bcel.generic.InvokeInstruction;import org.apache.bcel.generic.MethodGen;import edu.umd.cs.findbugs.FieldAnnotation;import edu.umd.cs.findbugs.MethodAnnotation;import edu.umd.cs.findbugs.SystemProperties;import edu.umd.cs.findbugs.annotations.CheckForNull;import edu.umd.cs.findbugs.annotations.CheckReturnValue;import edu.umd.cs.findbugs.annotations.NonNull;import edu.umd.cs.findbugs.visitclass.DismantleBytecode;import edu.umd.cs.findbugs.visitclass.PreorderVisitor;/** * Factory methods for creating XMethod objects. * * @author David Hovemeyer */public class XFactory { public XFactory() {}; private Map<XMethod,XMethod> methods = new HashMap<XMethod,XMethod>(); private Set<ClassMember> deprecated = new HashSet<ClassMember>(); private Set<? extends ClassMember> deprecatedView = Collections.unmodifiableSet(deprecated); private Map<XField,XField> fields = new HashMap<XField,XField>(); private Set<XMethod> methodsView = Collections .unmodifiableSet(methods.keySet()); private Set<XField> fieldsView = Collections .unmodifiableSet(fields.keySet()); private Set<XMethod> calledMethods = new HashSet<XMethod>(); private boolean calledMethodsIsInterned = false; public void addCalledMethod(XMethod m) { if (calledMethods.add(m) && !m.isResolved()) calledMethodsIsInterned = false; } public boolean isCalled(XMethod m) { if (!calledMethodsIsInterned) { Set<XMethod> tmp = new HashSet<XMethod>(); for(XMethod m2 : calledMethods) tmp.add(intern(m2)); calledMethodsIsInterned = true; } return calledMethods.contains(m); } public boolean isInterned(XMethod m) { return methods.containsKey(m); } public @CheckReturnValue @NonNull XMethod intern(XMethod m) { XMethod m2 = methods.get(m); if (m2 != null) return m2; methods.put(m,m); return m; } public @CheckReturnValue @NonNull XField intern(XField f) { XField f2 = fields.get(f); if (f2 != null) return f2; fields.put(f,f); return f; } public Set<XMethod> getMethods() { return methodsView; } public Set<XField> getFields() { return fieldsView; } public static String canonicalizeString(String s) { return ConstantUtf8.getCachedInstance(s).getBytes(); } /** * Create an XMethod object from a BCEL Method. * * @param className the class to which the Method belongs * @param method the Method * @return an XMethod representing the Method */ public static XMethod createXMethod(String className, Method method) { String methodName = method.getName(); String methodSig = method.getSignature(); int accessFlags = method.getAccessFlags(); return createXMethod(className, methodName, methodSig, accessFlags); } public static XMethod createXMethod(String className, String methodName, String methodSig, int accessFlags) { boolean isStatic = (accessFlags & Constants.ACC_STATIC) != 0; XMethod m; XFactory xFactory = AnalysisContext.currentXFactory(); if (isStatic) m = new StaticMethod(className, methodName, methodSig, accessFlags); else m = new InstanceMethod(className, methodName, methodSig, accessFlags); XMethod m2 = xFactory.intern(m); // MUSTFIX: Check this // assert m2.getAccessFlags() == m.getAccessFlags(); ((AbstractMethod) m2).markAsResolved(); return m2; } /** * Create an XMethod object from a BCEL Method. * * @param javaClass the class to which the Method belongs * @param method the Method * @return an XMethod representing the Method */ public static XMethod createXMethod(JavaClass javaClass , Method method) { return createXMethod(javaClass.getClassName(), method); } /** * @param className * @param methodName * @param methodSig * @param isStatic * @return the created XMethod */ public static XMethod createXMethod(String className, String methodName, String methodSig, boolean isStatic) { XMethod m; if (isStatic) m = new StaticMethod(className, methodName, methodSig, Constants.ACC_STATIC); else m = new InstanceMethod(className, methodName, methodSig, 0); XFactory xFactory = AnalysisContext.currentXFactory(); m = xFactory.intern(m); m = xFactory.resolve(m); return m; } public static XMethod createXMethod(MethodAnnotation ma) { return createXMethod(ma.getClassName(), ma.getMethodName(), ma.getMethodSignature(), ma.isStatic()); } static class RecursionDepth { private static final int MAX_DEPTH = 50; private int depth = 0; ArrayList<Object> list = new ArrayList<Object>(); @Override public String toString() { return list.toString(); } public void dump() { System.out.println("Recursive calls" ); for(Object o : list) System.out.println(" resolve " + o); } public boolean enter(Object value) { if (depth > MAX_DEPTH) return false; if (DEBUG_CIRCULARITY) list.add(value); depth++; return true; } public void exit() { depth--; if (DEBUG_CIRCULARITY) list.remove(list.size()-1); assert depth >= 0; } } static ThreadLocal<RecursionDepth> recursionDepth = new ThreadLocal<RecursionDepth>() { @Override public RecursionDepth initialValue() { return new RecursionDepth(); } }; /** * Create an XField object * * @param className * @param fieldName * @param fieldSignature * @param isStatic * @return the created XField */ public static XField createXField(String className, String fieldName, String fieldSignature, boolean isStatic) { XFactory xFactory =AnalysisContext.currentXFactory(); XField f; if (isStatic) { int accessFlags = 0; if (fieldName.toUpperCase().equals(fieldName)) accessFlags = Constants.ACC_FINAL; f = new StaticField(className, fieldName, fieldSignature, accessFlags); } else { int accessFlags = 0; if (fieldName.startsWith("this$")) accessFlags = Constants.ACC_FINAL; f = new InstanceField(className, fieldName, fieldSignature, accessFlags); } f = xFactory.intern(f); f = xFactory.resolve(f); return f; } public final static boolean DEBUG_CIRCULARITY = SystemProperties.getBoolean("circularity.debug"); /** * @param f * @return */ private @NonNull XField resolve(XField f) { if (f.isResolved()) return f; if (f.isStatic()) return f; if (f.getName().startsWith("this$")) return f; try { if (!recursionDepth.get().enter(f)) { fail("recursive cycle trying to resolve " + f, null, null); return f; } XField f2 = f; String classname = f.getClassName(); try { JavaClass superClass = Repository.lookupClass(classname).getSuperClass(); if (superClass == null) return f; if (classname.equals(superClass.getClassName())) return f; f2 = createXField(superClass.getClassName(), f.getName(), f.getSignature(), f.isStatic()); f2 = intern(f2); if (f2.isResolved()) { fields.put(f, f2); return f2; } } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } return f; } finally { recursionDepth.get().exit(); } } private static void fail(String s, @CheckForNull JavaClass jClass, @CheckForNull JavaClass superClass) { AnalysisContext.logError(s); if (DEBUG_CIRCULARITY) { System.out.println(s); recursionDepth.get().dump(); } if (jClass != null) System.out.println(jClass); if (superClass != null) System.out.println(superClass); System.exit(1); } /** * If a method is not marked as resolved, look in superclasses to see if the method can be found there. * Return whatever method is found. * @param m * @return */ private @NonNull XMethod resolve(XMethod m) { if (m.isResolved()) return m; // if (m.isStatic()) return m; try { if (!recursionDepth.get().enter(m)) { fail("recursive cycle trying to resolve " + m, null, null); return m; } String className = m.getClassName(); String methodName = m.getName(); if (className.charAt(0)=='[' || methodName.equals("<init>") || methodName.equals("<clinit>") || methodName.startsWith("access$")) { ((AbstractMethod)m).markAsResolved(); return m; } try { JavaClass javaClass = Repository.lookupClass(className); if (!javaClass.getClassName().equals(className)) { fail("Looked up " + className + ", got a class named " + javaClass.getClassName(), javaClass, null); return m; } JavaClass superClass = javaClass.getSuperClass(); if (superClass == null) return m; String superClassName = superClass.getClassName(); if (!javaClass.getSuperclassName().equals(superClassName)) fail("requested superclass of " + className + ", expecting to get " + javaClass.getSuperclassName() + ", instead got " + superClassName, javaClass, superClass); if (superClass.getSuperclassName().equals(className) || className.equals(superClassName)) { fail("superclass of " + className + " is " + superClassName, javaClass, superClass); return m; } XMethod m2 = createXMethod(superClassName, methodName, m.getSignature(), m.isStatic()); if (m2.isResolved()) { methods.put(m, m2); return m2; } } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } // ((AbstractMethod)m).markAsResolved(); return m; } finally { recursionDepth.get().exit(); } } public static XField createXField(FieldInstruction fieldInstruction, ConstantPoolGen cpg) { String className = fieldInstruction.getClassName(cpg); String fieldName = fieldInstruction.getName(cpg); String fieldSig = fieldInstruction.getSignature(cpg); int opcode = fieldInstruction.getOpcode(); return createXField(className, fieldName, fieldSig, opcode == Constants.GETSTATIC || opcode == Constants.PUTSTATIC ); } public static XField createReferencedXField(DismantleBytecode visitor) { return createXField(visitor.getDottedClassConstantOperand(), visitor.getNameConstantOperand(), visitor.getSigConstantOperand(), visitor.getRefFieldIsStatic()); } public static XMethod createReferencedXMethod(DismantleBytecode visitor) { return createXMethod(visitor.getDottedClassConstantOperand(), visitor.getNameConstantOperand(), visitor.getSigConstantOperand(), visitor.getOpcode() == Constants.INVOKESTATIC); } public static XField createXField(FieldAnnotation f) { return createXField(f.getClassName(), f.getFieldName(), f.getFieldSignature(), f.isStatic()); } public static XField createXField(JavaClass javaClass, Field field) { return createXField(javaClass.getClassName(), field); } /** * Create an XField object from a BCEL Field. * * @param className the name of the Java class containing the field * @param field the Field within the JavaClass * @return the created XField */ public static XField createXField(String className, Field field) { String fieldName = field.getName(); String fieldSig = field.getSignature(); int accessFlags = field.getAccessFlags(); return createXField(className, fieldName, fieldSig, accessFlags); } public static XField createXField(String className, String fieldName, String fieldSig, int accessFlags) { XFactory xFactory = AnalysisContext.currentXFactory(); XField f; if ((accessFlags & Constants.ACC_STATIC) != 0) f = new StaticField(className, fieldName, fieldSig, accessFlags); else f = new InstanceField(className, fieldName, fieldSig, accessFlags); XField f2 = xFactory.intern(f); // MUSTFIX: investigate // assert f.getAccessFlags() == f2.getAccessFlags(); ((AbstractField) f2).markAsResolved(); return f2; } /** * Create an XMethod object from an InvokeInstruction. * * @param invokeInstruction the InvokeInstruction * @param cpg ConstantPoolGen from the class containing the instruction * @return XMethod representing the method called by the InvokeInstruction */ public static XMethod createXMethod(InvokeInstruction invokeInstruction, ConstantPoolGen cpg) { String className = invokeInstruction.getClassName(cpg); String methodName = invokeInstruction.getName(cpg); String methodSig = invokeInstruction.getSignature(cpg); return createXMethod(className, methodName, methodSig, invokeInstruction.getOpcode() == Constants.INVOKESTATIC); } /** * Create an XMethod object from the method currently being visited by * the given PreorderVisitor. * * @param visitor the PreorderVisitor * @return the XMethod representing the method currently being visited */ public static XMethod createXMethod(PreorderVisitor visitor) { JavaClass javaClass = visitor.getThisClass(); Method method = visitor.getMethod(); XMethod m = createXMethod(javaClass, method); return m; } /** * Create an XField object from the field currently being visited by * the given PreorderVisitor. * * @param visitor the PreorderVisitor * @return the XField representing the method currently being visited */ public static XField createXField(PreorderVisitor visitor) { JavaClass javaClass = visitor.getThisClass(); Field field = visitor.getField(); XField f = createXField(javaClass, field); return f; } public static XMethod createXMethod(MethodGen methodGen) { String className = methodGen.getClassName(); String methodName = methodGen.getName(); String methodSig = methodGen.getSignature(); int accessFlags = methodGen.getAccessFlags(); return createXMethod(className, methodName, methodSig, accessFlags); } /** * @param m */ public void deprecate(ClassMember m) { deprecated.add(m); } public Set<? extends ClassMember> getDeprecated() { return deprecatedView; } public static XMethod createXMethod(JavaClassAndMethod classAndMethod) { return createXMethod(classAndMethod.getJavaClass(), classAndMethod.getMethod()); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -