@Override public void endVisit(JMethodCall x, Context ctx) { JMethod target = x.getTarget(); JDeclaredType type = target.getEnclosingType(); if (type instanceof JClassType) { JClassType cType = (JClassType) type; if (target == enumNameMethod || target == enumToStringMethod || target == enumValueOfMethod) { warn(x); } else if (cType.isEnumOrSubclass() != null) { if ("valueOf".equals(target.getName())) { /* * Check for calls to the auto-generated * EnumSubType.valueOf(String). Note, the check of the signature for * the single String arg version is to avoid flagging user-defined * overloaded versions of the method, which are presumably ok. */ List<JParameter> jParameters = target.getParams(); if (jParameters.size() == 1 && jParameters.get(0).getType() == stringType) { warn(x); } } } } }
/** Traverse from all methods starting from a set of types. */ private void traverseTypes(ControlFlowAnalyzer livenessAnalyzer, List<JClassType> types) { for (JClassType type : types) { livenessAnalyzer.traverseFromReferenceTo(type); for (JMethod method : type.getMethods()) { if (method instanceof JConstructor) { livenessAnalyzer.traverseFromInstantiationOf(type); } livenessAnalyzer.traverseFrom(method); } } }
private int countSuperTypes(JClassType type) { int count = 0; while ((type = type.getSuperClass()) != null) { ++count; } return count; }
/** Called to set this class's trivial initializer to point to a superclass. */ void setClinitTarget(JDeclaredType newClinitTarget) { if (clinitTarget == newClinitTarget) { return; } if (newClinitTarget != null && getClass().desiredAssertionStatus()) { // Make sure this is a pure upgrade to a superclass or null. for (JClassType current = (JClassType) clinitTarget; current != newClinitTarget; current = current.getSuperClass()) { Preconditions.checkNotNull( current.getSuperClass(), "Null super class for: %s (currentTarget: %s; newTarget: %s) in %s", current, clinitTarget, newClinitTarget, this); } } clinitTarget = newClinitTarget; }
private JReferenceType generalizeClasses(JClassType thisClass, JClassType thatClass) { /* * see how far each type is from object; walk the one who's farther up * until they're even; then walk them up together until they meet (worst * case at Object) */ int distance1 = countSuperTypes(thisClass); int distance2 = countSuperTypes(thatClass); for (; distance1 > distance2; --distance1) { thisClass = thisClass.getSuperClass(); } for (; distance1 < distance2; --distance2) { thatClass = thatClass.getSuperClass(); } while (thisClass != thatClass) { thisClass = thisClass.getSuperClass(); thatClass = thatClass.getSuperClass(); } return thisClass; }
/** * For each member with the given name, find the most derived members for each JSNI reference that * match it. For wildcard JSNI references, there will in general be more than one match. This * method does not ignore synthetic methods. */ private static void findMostDerivedMembers( LinkedHashMap<String, LinkedHashMap<String, HasEnclosingType>> matchesBySig, JDeclaredType targetType, String memberName, boolean addConstructors) { /* * Analyze superclasses and interfaces first. More derived members will thus * be seen later. */ if (targetType instanceof JClassType) { JClassType targetClass = (JClassType) targetType; if (targetClass.getSuperClass() != null) { findMostDerivedMembers(matchesBySig, targetClass.getSuperClass(), memberName, false); } } for (JDeclaredType intf : targetType.getImplements()) { findMostDerivedMembers(matchesBySig, intf, memberName, false); } // Get the methods on this class/interface. for (JMethod method : targetType.getMethods()) { if (method.getName().equals(memberName)) { if (addConstructors || !method.getName().equals(JsniRef.NEW)) { addMember(matchesBySig, method, getJsniSignature(method, false)); addMember(matchesBySig, method, getJsniSignature(method, true)); } } } // Get the fields on this class/interface. for (JField field : targetType.getFields()) { if (field.getName().equals(memberName)) { addMember(matchesBySig, field, field.getName()); } } }
/** * Returns an instantiation expression for {@code type} using the default constructor, Returns * {@code null} if {@code type} does not have a default constructor. */ public static JExpression createDefaultConstructorInstantiation( SourceInfo info, JClassType type) { /* * Find the appropriate (noArg) constructor. In our AST, constructors are * instance methods that should be qualified with a new expression. */ JConstructor noArgCtor = (JConstructor) FluentIterable.from(type.getMethods()) .firstMatch( new Predicate<JMethod>() { @Override public boolean apply(JMethod method) { return method instanceof JConstructor && method.getOriginalParamTypes().size() == 0; } }) .orNull(); if (noArgCtor == null) { return null; } // Call it, using a new expression as a qualifier return new JNewInstance(info, noArgCtor); }
public ExternalSerializedForm(JClassType classType) { name = classType.getName(); }
/** Resolve an external references during AST stitching. */ public void resolve(JClassType jsoType) { assert jsoType.replaces(this.arrayType); this.arrayType = jsoType; }
public boolean isJavaLangString(JType type) { return type == typeString || type == typeString.getNonNull(); }
/** * Return the least upper bound of two types. That is, the smallest type that is a supertype of * both types. */ public JReferenceType generalizeTypes(JReferenceType type1, JReferenceType type2) { if (type1 == type2) { return type1; } if (type1 instanceof JNonNullType && type2 instanceof JNonNullType) { // Neither can be null. type1 = type1.getUnderlyingType(); type2 = type2.getUnderlyingType(); return generalizeTypes(type1, type2).getNonNull(); } else if (type1 instanceof JNonNullType) { // type2 can be null, so the result can be null type1 = type1.getUnderlyingType(); } else if (type2 instanceof JNonNullType) { // type1 can be null, so the result can be null type2 = type2.getUnderlyingType(); } assert !(type1 instanceof JNonNullType); assert !(type2 instanceof JNonNullType); int classify1 = classifyType(type1); int classify2 = classifyType(type2); if (classify1 == IS_NULL) { return type2; } if (classify2 == IS_NULL) { return type1; } if (classify1 == classify2) { // same basic kind of type if (classify1 == IS_INTERFACE) { if (typeOracle.canTriviallyCast(type1, type2)) { return type2; } if (typeOracle.canTriviallyCast(type2, type1)) { return type1; } // unrelated return typeJavaLangObject; } else if (classify1 == IS_ARRAY) { JArrayType aType1 = (JArrayType) type1; JArrayType aType2 = (JArrayType) type2; int dims1 = aType1.getDims(); int dims2 = aType2.getDims(); int minDims = Math.min(dims1, dims2); /* * At a bare minimum, any two arrays generalize to an Object array with * one less dim than the lesser of the two; that is, int[][][][] and * String[][][] generalize to Object[][]. If minDims is 1, then they * just generalize to Object. */ JReferenceType minimalGeneralType; if (minDims > 1) { minimalGeneralType = getTypeArray(typeJavaLangObject, minDims - 1); } else { minimalGeneralType = typeJavaLangObject; } if (dims1 == dims2) { // Try to generalize by leaf types JType leafType1 = aType1.getLeafType(); JType leafType2 = aType2.getLeafType(); if (!(leafType1 instanceof JReferenceType) || !(leafType2 instanceof JReferenceType)) { return minimalGeneralType; } /* * Both are reference types; the result is the generalization of the * leaf types combined with the number of dims; that is, Foo[] and * Bar[] generalize to X[] where X is the generalization of Foo and * Bar. */ JReferenceType leafRefType1 = (JReferenceType) leafType1; JReferenceType leafRefType2 = (JReferenceType) leafType2; /** * Never generalize arrays to arrays of {@link JNonNullType} as null array initialization * is not accounted for in {@link TypeTightener}. */ JReferenceType leafGeneralization = generalizeTypes(leafRefType1, leafRefType2).getUnderlyingType(); return getTypeArray(leafGeneralization, dims1); } else { // Conflicting number of dims // int[][] and Object[] generalize to Object[] JArrayType lesser = dims1 < dims2 ? aType1 : aType2; if (lesser.getLeafType() == typeJavaLangObject) { return lesser; } // Totally unrelated return minimalGeneralType; } } else { assert (classify1 == IS_CLASS); JClassType class1 = (JClassType) type1; JClassType class2 = (JClassType) type2; /* * see how far each type is from object; walk the one who's farther up * until they're even; then walk them up together until they meet (worst * case at Object) */ int distance1 = countSuperTypes(class1); int distance2 = countSuperTypes(class2); for (; distance1 > distance2; --distance1) { class1 = class1.getSuperClass(); } for (; distance1 < distance2; --distance2) { class2 = class2.getSuperClass(); } while (class1 != class2) { class1 = class1.getSuperClass(); class2 = class2.getSuperClass(); } return class1; } } else { // different kinds of types int lesser = Math.min(classify1, classify2); int greater = Math.max(classify1, classify2); JReferenceType tLesser = classify1 < classify2 ? type1 : type2; JReferenceType tGreater = classify1 > classify2 ? type1 : type2; if (lesser == IS_INTERFACE && greater == IS_CLASS) { // just see if the class implements the interface if (typeOracle.canTriviallyCast(tGreater, tLesser)) { return tLesser; } // unrelated return typeJavaLangObject; } else if (greater == IS_ARRAY && ((tLesser == typeJavaLangCloneable) || (tLesser == typeJavaIoSerializable))) { return tLesser; } else { // unrelated: the best commonality between an interface and array, or // between an array and a class is Object return typeJavaLangObject; } } }