fb-contrib
fb-contrib copied to clipboard
False positive on URV_CHANGE_RETURN_TYPE with constrained code
URV_CHANGE_RETURN_TYPE sometimes doesn't take account of all the constraints that may exist on code. For example, when creating a custom Hibernate UserType, we have code like the following:
@Override
public <X> X unwrap(Money value, Class<X> type, WrapperOptions options) {
if (value == null) {
return null;
}
if (BigInteger.class.isAssignableFrom(type)) {
return (X) value.getAmountInCents();
}
if (Long.class.isAssignableFrom(type)) {
return (X) Long.valueOf(value.getAmountInCents().longValue());
}
throw unknownUnwrap(type);
}
The detector notes that all the possible return types are Numbers and flags it. However, the superclass method signature obligates us to return type X, which theoretically doesn't have to be a Number when the method is called.
can you add this class, and the super classes descriptor to this?
The superclass is from a third party (Hibernate), but I can provide javap output for ours:
Classfile /osidt/common/target/classes/au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.class
Last modified 16/08/2019; size 3687 bytes
MD5 checksum 82d479344260a00d53a8b7129d5df83a
Compiled from "MoneyUserType.java"
public class au.gov.qld.ssq.common.repository.MoneyUserType$MoneyTypeDescriptor extends org.hibernate.type.descriptor.java.AbstractTypeDescriptor<au.gov.qld.ssq.common.money.Money>
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #69 // au/gov/qld/ssq/common/money/Money
#2 = Methodref #27.#70 // org/hibernate/type/descriptor/java/AbstractTypeDescriptor."<init>":(Ljava/lang/Class;)V
#3 = Methodref #71.#72 // java/util/Optional.ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
#4 = Fieldref #1.#73 // au/gov/qld/ssq/common/money/Money.ZERO:Lau/gov/qld/ssq/common/money/Money;
#5 = Methodref #71.#74 // java/util/Optional.orElse:(Ljava/lang/Object;)Ljava/lang/Object;
#6 = Methodref #1.#75 // au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
#7 = Methodref #8.#76 // java/math/BigInteger.toString:()Ljava/lang/String;
#8 = Class #77 // java/math/BigInteger
#9 = Methodref #8.#78 // java/math/BigInteger."<init>":(Ljava/lang/String;)V
#10 = Methodref #1.#79 // au/gov/qld/ssq/common/money/Money.inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
#11 = Methodref #80.#81 // java/lang/Class.isAssignableFrom:(Ljava/lang/Class;)Z
#12 = Class #82 // java/lang/Long
#13 = Methodref #8.#83 // java/math/BigInteger.longValue:()J
#14 = Methodref #12.#84 // java/lang/Long.valueOf:(J)Ljava/lang/Long;
#15 = Methodref #26.#85 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.unknownUnwrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
#16 = Methodref #80.#86 // java/lang/Class.isInstance:(Ljava/lang/Object;)Z
#17 = Class #87 // java/lang/Number
#18 = Methodref #17.#83 // java/lang/Number.longValue:()J
#19 = Methodref #1.#88 // au/gov/qld/ssq/common/money/Money.inCents:(J)Lau/gov/qld/ssq/common/money/Money;
#20 = Methodref #89.#90 // java/lang/Object.getClass:()Ljava/lang/Class;
#21 = Methodref #26.#91 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.unknownWrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
#22 = Methodref #26.#92 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.wrap:(Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
#23 = Methodref #26.#93 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.unwrap:(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
#24 = Methodref #26.#94 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.fromString:(Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
#25 = Methodref #26.#95 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.toString:(Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
#26 = Class #97 // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor
#27 = Class #98 // org/hibernate/type/descriptor/java/AbstractTypeDescriptor
#28 = Utf8 <init>
#29 = Utf8 ()V
#30 = Utf8 Code
#31 = Utf8 LineNumberTable
#32 = Utf8 LocalVariableTable
#33 = Utf8 this
#34 = Utf8 MoneyTypeDescriptor
#35 = Utf8 InnerClasses
#36 = Utf8 Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
#37 = Utf8 toString
#38 = Utf8 (Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
#39 = Utf8 value
#40 = Utf8 Lau/gov/qld/ssq/common/money/Money;
#41 = Utf8 MethodParameters
#42 = Utf8 fromString
#43 = Utf8 (Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
#44 = Utf8 string
#45 = Utf8 Ljava/lang/String;
#46 = Utf8 unwrap
#47 = Utf8 (Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
#48 = Utf8 type
#49 = Utf8 Ljava/lang/Class;
#50 = Utf8 options
#51 = Utf8 Lorg/hibernate/type/descriptor/WrapperOptions;
#52 = Utf8 LocalVariableTypeTable
#53 = Utf8 Ljava/lang/Class<TX;>;
#54 = Utf8 StackMapTable
#55 = Utf8 Signature
#56 = Utf8 <X:Ljava/lang/Object;>(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class<TX;>;Lorg/hibernate/type/descriptor/WrapperOptions;)TX;
#57 = Utf8 wrap
#58 = Utf8 (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
#59 = Utf8 Ljava/lang/Object;
#60 = Utf8 TX;
#61 = Utf8 <X:Ljava/lang/Object;>(TX;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
#62 = Utf8 (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
#63 = Utf8 (Ljava/lang/Object;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
#64 = Utf8 (Ljava/lang/String;)Ljava/lang/Object;
#65 = Utf8 (Ljava/lang/Object;)Ljava/lang/String;
#66 = Utf8 Lorg/hibernate/type/descriptor/java/AbstractTypeDescriptor<Lau/gov/qld/ssq/common/money/Money;>;
#67 = Utf8 SourceFile
#68 = Utf8 MoneyUserType.java
#69 = Utf8 au/gov/qld/ssq/common/money/Money
#70 = NameAndType #28:#99 // "<init>":(Ljava/lang/Class;)V
#71 = Class #100 // java/util/Optional
#72 = NameAndType #101:#102 // ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
#73 = NameAndType #103:#40 // ZERO:Lau/gov/qld/ssq/common/money/Money;
#74 = NameAndType #104:#105 // orElse:(Ljava/lang/Object;)Ljava/lang/Object;
#75 = NameAndType #106:#107 // getAmountInCents:()Ljava/math/BigInteger;
#76 = NameAndType #37:#108 // toString:()Ljava/lang/String;
#77 = Utf8 java/math/BigInteger
#78 = NameAndType #28:#109 // "<init>":(Ljava/lang/String;)V
#79 = NameAndType #110:#111 // inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
#80 = Class #112 // java/lang/Class
#81 = NameAndType #113:#114 // isAssignableFrom:(Ljava/lang/Class;)Z
#82 = Utf8 java/lang/Long
#83 = NameAndType #115:#116 // longValue:()J
#84 = NameAndType #117:#118 // valueOf:(J)Ljava/lang/Long;
#85 = NameAndType #119:#120 // unknownUnwrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
#86 = NameAndType #121:#122 // isInstance:(Ljava/lang/Object;)Z
#87 = Utf8 java/lang/Number
#88 = NameAndType #110:#123 // inCents:(J)Lau/gov/qld/ssq/common/money/Money;
#89 = Class #124 // java/lang/Object
#90 = NameAndType #125:#126 // getClass:()Ljava/lang/Class;
#91 = NameAndType #127:#120 // unknownWrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
#92 = NameAndType #57:#58 // wrap:(Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
#93 = NameAndType #46:#47 // unwrap:(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
#94 = NameAndType #42:#43 // fromString:(Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
#95 = NameAndType #37:#38 // toString:(Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
#96 = Class #128 // au/gov/qld/ssq/common/repository/MoneyUserType
#97 = Utf8 au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor
#98 = Utf8 org/hibernate/type/descriptor/java/AbstractTypeDescriptor
#99 = Utf8 (Ljava/lang/Class;)V
#100 = Utf8 java/util/Optional
#101 = Utf8 ofNullable
#102 = Utf8 (Ljava/lang/Object;)Ljava/util/Optional;
#103 = Utf8 ZERO
#104 = Utf8 orElse
#105 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object;
#106 = Utf8 getAmountInCents
#107 = Utf8 ()Ljava/math/BigInteger;
#108 = Utf8 ()Ljava/lang/String;
#109 = Utf8 (Ljava/lang/String;)V
#110 = Utf8 inCents
#111 = Utf8 (Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
#112 = Utf8 java/lang/Class
#113 = Utf8 isAssignableFrom
#114 = Utf8 (Ljava/lang/Class;)Z
#115 = Utf8 longValue
#116 = Utf8 ()J
#117 = Utf8 valueOf
#118 = Utf8 (J)Ljava/lang/Long;
#119 = Utf8 unknownUnwrap
#120 = Utf8 (Ljava/lang/Class;)Lorg/hibernate/HibernateException;
#121 = Utf8 isInstance
#122 = Utf8 (Ljava/lang/Object;)Z
#123 = Utf8 (J)Lau/gov/qld/ssq/common/money/Money;
#124 = Utf8 java/lang/Object
#125 = Utf8 getClass
#126 = Utf8 ()Ljava/lang/Class;
#127 = Utf8 unknownWrap
#128 = Utf8 au/gov/qld/ssq/common/repository/MoneyUserType
{
public au.gov.qld.ssq.common.repository.MoneyUserType$MoneyTypeDescriptor();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: ldc #1 // class au/gov/qld/ssq/common/money/Money
3: invokespecial #2 // Method org/hibernate/type/descriptor/java/AbstractTypeDescriptor."<init>":(Ljava/lang/Class;)V
6: return
LineNumberTable:
line 46: 0
line 47: 6
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
public java.lang.String toString(au.gov.qld.ssq.common.money.Money);
descriptor: (Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: invokestatic #3 // Method java/util/Optional.ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
4: getstatic #4 // Field au/gov/qld/ssq/common/money/Money.ZERO:Lau/gov/qld/ssq/common/money/Money;
7: invokevirtual #5 // Method java/util/Optional.orElse:(Ljava/lang/Object;)Ljava/lang/Object;
10: checkcast #1 // class au/gov/qld/ssq/common/money/Money
13: invokevirtual #6 // Method au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
16: invokevirtual #7 // Method java/math/BigInteger.toString:()Ljava/lang/String;
19: areturn
LineNumberTable:
line 51: 0
LocalVariableTable:
Start Length Slot Name Signature
0 20 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
0 20 1 value Lau/gov/qld/ssq/common/money/Money;
MethodParameters:
Name Flags
value
public au.gov.qld.ssq.common.money.Money fromString(java.lang.String);
descriptor: (Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: new #8 // class java/math/BigInteger
3: dup
4: aload_1
5: invokespecial #9 // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
8: invokestatic #10 // Method au/gov/qld/ssq/common/money/Money.inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
11: areturn
LineNumberTable:
line 56: 0
LocalVariableTable:
Start Length Slot Name Signature
0 12 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
0 12 1 string Ljava/lang/String;
MethodParameters:
Name Flags
string
public <X extends java.lang.Object> X unwrap(au.gov.qld.ssq.common.money.Money, java.lang.Class<X>, org.hibernate.type.descriptor.WrapperOptions);
descriptor: (Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=4
0: aload_1
1: ifnonnull 6
4: aconst_null
5: areturn
6: ldc #8 // class java/math/BigInteger
8: aload_2
9: invokevirtual #11 // Method java/lang/Class.isAssignableFrom:(Ljava/lang/Class;)Z
12: ifeq 20
15: aload_1
16: invokevirtual #6 // Method au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
19: areturn
20: ldc #12 // class java/lang/Long
22: aload_2
23: invokevirtual #11 // Method java/lang/Class.isAssignableFrom:(Ljava/lang/Class;)Z
26: ifeq 40
29: aload_1
30: invokevirtual #6 // Method au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
33: invokevirtual #13 // Method java/math/BigInteger.longValue:()J
36: invokestatic #14 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
39: areturn
40: aload_0
41: aload_2
42: invokevirtual #15 // Method unknownUnwrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
45: athrow
LineNumberTable:
line 61: 0
line 62: 4
line 64: 6
line 65: 15
line 67: 20
line 68: 29
line 71: 40
LocalVariableTable:
Start Length Slot Name Signature
0 46 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
0 46 1 value Lau/gov/qld/ssq/common/money/Money;
0 46 2 type Ljava/lang/Class;
0 46 3 options Lorg/hibernate/type/descriptor/WrapperOptions;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 46 2 type Ljava/lang/Class<TX;>;
StackMapTable: number_of_entries = 3
frame_type = 6 /* same */
frame_type = 13 /* same */
frame_type = 19 /* same */
MethodParameters:
Name Flags
value
type
options
Signature: #56 // <X:Ljava/lang/Object;>(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class<TX;>;Lorg/hibernate/type/descriptor/WrapperOptions;)TX;
public <X extends java.lang.Object> au.gov.qld.ssq.common.money.Money wrap(X, org.hibernate.type.descriptor.WrapperOptions);
descriptor: (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_1
1: ifnonnull 6
4: aconst_null
5: areturn
6: ldc #8 // class java/math/BigInteger
8: aload_1
9: invokevirtual #16 // Method java/lang/Class.isInstance:(Ljava/lang/Object;)Z
12: ifeq 23
15: aload_1
16: checkcast #8 // class java/math/BigInteger
19: invokestatic #10 // Method au/gov/qld/ssq/common/money/Money.inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
22: areturn
23: ldc #17 // class java/lang/Number
25: aload_1
26: invokevirtual #16 // Method java/lang/Class.isInstance:(Ljava/lang/Object;)Z
29: ifeq 43
32: aload_1
33: checkcast #17 // class java/lang/Number
36: invokevirtual #18 // Method java/lang/Number.longValue:()J
39: invokestatic #19 // Method au/gov/qld/ssq/common/money/Money.inCents:(J)Lau/gov/qld/ssq/common/money/Money;
42: areturn
43: aload_0
44: aload_1
45: invokevirtual #20 // Method java/lang/Object.getClass:()Ljava/lang/Class;
48: invokevirtual #21 // Method unknownWrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
51: athrow
LineNumberTable:
line 76: 0
line 77: 4
line 80: 6
line 81: 15
line 83: 23
line 84: 32
line 87: 43
LocalVariableTable:
Start Length Slot Name Signature
0 52 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
0 52 1 value Ljava/lang/Object;
0 52 2 options Lorg/hibernate/type/descriptor/WrapperOptions;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 52 1 value TX;
StackMapTable: number_of_entries = 3
frame_type = 6 /* same */
frame_type = 16 /* same */
frame_type = 19 /* same */
MethodParameters:
Name Flags
value
options
Signature: #61 // <X:Ljava/lang/Object;>(TX;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
public java.lang.Object wrap(java.lang.Object, org.hibernate.type.descriptor.WrapperOptions);
descriptor: (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=3, locals=3, args_size=3
0: aload_0
1: aload_1
2: aload_2
3: invokevirtual #22 // Method wrap:(Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
6: areturn
LineNumberTable:
line 43: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
MethodParameters:
Name Flags
value synthetic
options synthetic
public java.lang.Object unwrap(java.lang.Object, java.lang.Class, org.hibernate.type.descriptor.WrapperOptions);
descriptor: (Ljava/lang/Object;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=4, locals=4, args_size=4
0: aload_0
1: aload_1
2: checkcast #1 // class au/gov/qld/ssq/common/money/Money
5: aload_2
6: aload_3
7: invokevirtual #23 // Method unwrap:(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
10: areturn
LineNumberTable:
line 43: 0
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
MethodParameters:
Name Flags
value synthetic
type synthetic
options synthetic
public java.lang.Object fromString(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokevirtual #24 // Method fromString:(Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
5: areturn
LineNumberTable:
line 43: 0
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
MethodParameters:
Name Flags
string synthetic
public java.lang.String toString(java.lang.Object);
descriptor: (Ljava/lang/Object;)Ljava/lang/String;
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #1 // class au/gov/qld/ssq/common/money/Money
5: invokevirtual #25 // Method toString:(Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
8: areturn
LineNumberTable:
line 43: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
MethodParameters:
Name Flags
value synthetic
}
Signature: #66 // Lorg/hibernate/type/descriptor/java/AbstractTypeDescriptor<Lau/gov/qld/ssq/common/money/Money;>;
SourceFile: "MoneyUserType.java"
InnerClasses:
public static #34= #26 of #96; //MoneyTypeDescriptor=class au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor of class au/gov/qld/ssq/common/repository/MoneyUserType