Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jadx
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open-source
jadx
Commits
0ee499c5
Commit
0ee499c5
authored
Apr 15, 2013
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add generic types for classes and fields
parent
3b84aec5
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
503 additions
and
91 deletions
+503
-91
Consts.java
src/main/java/jadx/Consts.java
+2
-0
AnnotationGen.java
src/main/java/jadx/codegen/AnnotationGen.java
+5
-20
ClassGen.java
src/main/java/jadx/codegen/ClassGen.java
+51
-10
MethodGen.java
src/main/java/jadx/codegen/MethodGen.java
+4
-1
AttributesList.java
src/main/java/jadx/dex/attributes/AttributesList.java
+10
-0
Annotation.java
...main/java/jadx/dex/attributes/annotations/Annotation.java
+4
-0
ClassInfo.java
src/main/java/jadx/dex/info/ClassInfo.java
+1
-0
FieldInfo.java
src/main/java/jadx/dex/info/FieldInfo.java
+1
-2
ArgType.java
src/main/java/jadx/dex/instructions/args/ArgType.java
+95
-11
ClassNode.java
src/main/java/jadx/dex/nodes/ClassNode.java
+64
-13
FieldNode.java
src/main/java/jadx/dex/nodes/FieldNode.java
+32
-2
MethodNode.java
src/main/java/jadx/dex/nodes/MethodNode.java
+40
-18
ClassModifier.java
src/main/java/jadx/dex/visitors/ClassModifier.java
+12
-6
Utils.java
src/main/java/jadx/utils/Utils.java
+53
-8
TestGenerics.java
src/samples/java/jadx/samples/TestGenerics.java
+129
-0
No files found.
src/main/java/jadx/Consts.java
View file @
0ee499c5
...
@@ -12,4 +12,6 @@ public class Consts {
...
@@ -12,4 +12,6 @@ public class Consts {
public
static
final
String
CLASS_CLASS
=
"java.lang.Class"
;
public
static
final
String
CLASS_CLASS
=
"java.lang.Class"
;
public
static
final
String
CLASS_THROWABLE
=
"java.lang.Throwable"
;
public
static
final
String
CLASS_THROWABLE
=
"java.lang.Throwable"
;
public
static
final
String
CLASS_ENUM
=
"java.lang.Enum"
;
public
static
final
String
CLASS_ENUM
=
"java.lang.Enum"
;
public
static
final
String
DALVIK_SIGNATURE
=
"dalvik.annotation.Signature"
;
}
}
src/main/java/jadx/codegen/AnnotationGen.java
View file @
0ee499c5
...
@@ -12,7 +12,6 @@ import jadx.dex.nodes.ClassNode;
...
@@ -12,7 +12,6 @@ import jadx.dex.nodes.ClassNode;
import
jadx.dex.nodes.FieldNode
;
import
jadx.dex.nodes.FieldNode
;
import
jadx.dex.nodes.MethodNode
;
import
jadx.dex.nodes.MethodNode
;
import
jadx.utils.StringUtils
;
import
jadx.utils.StringUtils
;
import
jadx.utils.Utils
;
import
jadx.utils.exceptions.JadxRuntimeException
;
import
jadx.utils.exceptions.JadxRuntimeException
;
import
java.util.Iterator
;
import
java.util.Iterator
;
...
@@ -62,13 +61,7 @@ public class AnnotationGen {
...
@@ -62,13 +61,7 @@ public class AnnotationGen {
String
aCls
=
a
.
getAnnotationClass
();
String
aCls
=
a
.
getAnnotationClass
();
if
(
aCls
.
startsWith
(
"dalvik.annotation."
))
{
if
(
aCls
.
startsWith
(
"dalvik.annotation."
))
{
// skip
// skip
if
(
aCls
.
equals
(
"dalvik.annotation.Signature"
))
{
if
(
Consts
.
DEBUG
)
{
if
(!(
node
instanceof
MethodNode
))
{
String
sign
=
Utils
.
mergeSignature
((
List
<
String
>)
a
.
getValues
().
get
(
"value"
));
List
<
ArgType
>
types
=
ArgType
.
parseSignatureList
(
sign
);
code
.
startLine
(
"// signature: "
+
Utils
.
listToString
(
types
));
}
}
else
if
(
Consts
.
DEBUG
)
{
code
.
startLine
(
"// "
+
a
);
code
.
startLine
(
"// "
+
a
);
}
}
}
else
{
}
else
{
...
@@ -104,13 +97,9 @@ public class AnnotationGen {
...
@@ -104,13 +97,9 @@ public class AnnotationGen {
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
public
void
addThrows
(
MethodNode
mth
,
CodeWriter
code
)
{
public
void
addThrows
(
MethodNode
mth
,
CodeWriter
code
)
{
AnnotationsList
anList
=
(
AnnotationsList
)
mth
.
getAttributes
().
get
(
AttributeType
.
ANNOTATION_LIST
);
Annotation
an
=
mth
.
getAttributes
().
getAnnotation
(
"dalvik.annotation.Throws"
);
if
(
anList
==
null
||
anList
.
size
()
==
0
)
return
;
Annotation
an
=
anList
.
get
(
"dalvik.annotation.Throws"
);
if
(
an
!=
null
)
{
if
(
an
!=
null
)
{
Object
exs
=
an
.
get
Values
().
get
(
"value"
);
Object
exs
=
an
.
get
DefaultValue
(
);
code
.
add
(
" throws "
);
code
.
add
(
" throws "
);
for
(
Iterator
<
ArgType
>
it
=
((
List
<
ArgType
>)
exs
).
iterator
();
it
.
hasNext
();)
{
for
(
Iterator
<
ArgType
>
it
=
((
List
<
ArgType
>)
exs
).
iterator
();
it
.
hasNext
();)
{
ArgType
ex
=
it
.
next
();
ArgType
ex
=
it
.
next
();
...
@@ -122,13 +111,9 @@ public class AnnotationGen {
...
@@ -122,13 +111,9 @@ public class AnnotationGen {
}
}
public
Object
getAnnotationDefaultValue
(
String
name
)
{
public
Object
getAnnotationDefaultValue
(
String
name
)
{
AnnotationsList
anList
=
(
AnnotationsList
)
cls
.
getAttributes
().
get
(
AttributeType
.
ANNOTATION_LIST
);
Annotation
an
=
cls
.
getAttributes
().
getAnnotation
(
"dalvik.annotation.AnnotationDefault"
);
if
(
anList
==
null
||
anList
.
size
()
==
0
)
return
null
;
Annotation
an
=
anList
.
get
(
"dalvik.annotation.AnnotationDefault"
);
if
(
an
!=
null
)
{
if
(
an
!=
null
)
{
Annotation
defAnnotation
=
(
Annotation
)
an
.
get
Values
().
get
(
"value"
);
Annotation
defAnnotation
=
(
Annotation
)
an
.
get
DefaultValue
(
);
return
defAnnotation
.
getValues
().
get
(
name
);
return
defAnnotation
.
getValues
().
get
(
name
);
}
}
return
null
;
return
null
;
...
...
src/main/java/jadx/codegen/ClassGen.java
View file @
0ee499c5
...
@@ -22,6 +22,8 @@ import java.util.Collections;
...
@@ -22,6 +22,8 @@ import java.util.Collections;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Set
;
import
java.util.Set
;
import
com.android.dx.rop.code.AccessFlags
;
import
com.android.dx.rop.code.AccessFlags
;
...
@@ -105,19 +107,22 @@ public class ClassGen {
...
@@ -105,19 +107,22 @@ public class ClassGen {
clsCode
.
add
(
"class "
);
clsCode
.
add
(
"class "
);
}
}
clsCode
.
add
(
cls
.
getShortName
());
clsCode
.
add
(
cls
.
getShortName
());
ClassInfo
sup
=
cls
.
getSuperClass
();
makeGenericMap
(
clsCode
,
cls
.
getGenericMap
());
clsCode
.
add
(
' '
);
ClassInfo
sup
=
cls
.
getSuperClass
();
if
(
sup
!=
null
if
(
sup
!=
null
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_OBJECT
)
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_OBJECT
)
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_ENUM
))
{
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_ENUM
))
{
clsCode
.
add
(
"
extends "
).
add
(
useClass
(
sup
)
);
clsCode
.
add
(
"
extends "
).
add
(
useClass
(
sup
)).
add
(
' '
);
}
}
if
(
cls
.
getInterfaces
().
size
()
>
0
&&
!
af
.
isAnnotation
())
{
if
(
cls
.
getInterfaces
().
size
()
>
0
&&
!
af
.
isAnnotation
())
{
if
(
cls
.
getAccessFlags
().
isInterface
())
if
(
cls
.
getAccessFlags
().
isInterface
())
clsCode
.
add
(
"
extends "
);
clsCode
.
add
(
"extends "
);
else
else
clsCode
.
add
(
"
implements "
);
clsCode
.
add
(
"implements "
);
for
(
Iterator
<
ClassInfo
>
it
=
cls
.
getInterfaces
().
iterator
();
it
.
hasNext
();)
{
for
(
Iterator
<
ClassInfo
>
it
=
cls
.
getInterfaces
().
iterator
();
it
.
hasNext
();)
{
ClassInfo
interf
=
it
.
next
();
ClassInfo
interf
=
it
.
next
();
...
@@ -125,11 +130,41 @@ public class ClassGen {
...
@@ -125,11 +130,41 @@ public class ClassGen {
if
(
it
.
hasNext
())
if
(
it
.
hasNext
())
clsCode
.
add
(
", "
);
clsCode
.
add
(
", "
);
}
}
if
(!
cls
.
getInterfaces
().
isEmpty
())
clsCode
.
add
(
' '
);
}
}
public
void
makeGenericMap
(
CodeWriter
code
,
Map
<
ArgType
,
List
<
ArgType
>>
gmap
)
{
if
(
gmap
==
null
||
gmap
.
isEmpty
())
return
;
code
.
add
(
'<'
);
int
i
=
0
;
for
(
Entry
<
ArgType
,
List
<
ArgType
>>
e
:
gmap
.
entrySet
())
{
ArgType
type
=
e
.
getKey
();
List
<
ArgType
>
list
=
e
.
getValue
();
if
(
i
!=
0
)
{
code
.
add
(
", "
);
}
code
.
add
(
useClass
(
type
));
if
(
list
!=
null
&&
!
list
.
isEmpty
())
{
code
.
add
(
" extends "
);
for
(
Iterator
<
ArgType
>
it
=
list
.
iterator
();
it
.
hasNext
();)
{
ArgType
g
=
it
.
next
();
code
.
add
(
useClass
(
g
));
if
(
it
.
hasNext
())
{
code
.
add
(
" & "
);
}
}
}
i
++;
}
}
code
.
add
(
'>'
);
}
}
public
void
makeClassBody
(
CodeWriter
clsCode
)
throws
CodegenException
{
public
void
makeClassBody
(
CodeWriter
clsCode
)
throws
CodegenException
{
clsCode
.
add
(
"
{"
);
clsCode
.
add
(
"{"
);
CodeWriter
mthsCode
=
makeMethods
(
clsCode
,
cls
.
getMethods
());
CodeWriter
mthsCode
=
makeMethods
(
clsCode
,
cls
.
getMethods
());
clsCode
.
add
(
makeFields
(
clsCode
,
cls
,
cls
.
getFields
()));
clsCode
.
add
(
makeFields
(
clsCode
,
cls
,
cls
.
getFields
()));
...
@@ -248,9 +283,15 @@ public class ClassGen {
...
@@ -248,9 +283,15 @@ public class ClassGen {
}
}
public
String
useClass
(
ArgType
clsType
)
{
public
String
useClass
(
ArgType
clsType
)
{
String
baseClass
=
useClass
(
ClassInfo
.
fromType
(
cls
.
dex
(),
clsType
));
if
(
clsType
.
isGenericType
())
{
return
clsType
.
getObject
();
}
return
useClass
(
ClassInfo
.
fromType
(
cls
.
dex
(),
clsType
));
}
ArgType
[]
generics
=
clsType
.
getGenericTypes
();
public
String
useClass
(
ClassInfo
classInfo
)
{
String
baseClass
=
useClassInner
(
classInfo
);
ArgType
[]
generics
=
classInfo
.
getType
().
getGenericTypes
();
if
(
generics
!=
null
)
{
if
(
generics
!=
null
)
{
StringBuilder
sb
=
new
StringBuilder
();
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
baseClass
);
sb
.
append
(
baseClass
);
...
@@ -262,7 +303,7 @@ public class ClassGen {
...
@@ -262,7 +303,7 @@ public class ClassGen {
}
}
ArgType
gt
=
generics
[
i
];
ArgType
gt
=
generics
[
i
];
if
(
gt
.
isTypeKnown
())
if
(
gt
.
isTypeKnown
())
sb
.
append
(
useClass
(
gt
));
sb
.
append
(
TypeGen
.
translate
(
this
,
gt
));
else
else
sb
.
append
(
'?'
);
sb
.
append
(
'?'
);
}
}
...
@@ -273,9 +314,9 @@ public class ClassGen {
...
@@ -273,9 +314,9 @@ public class ClassGen {
}
}
}
}
p
ublic
String
useClass
(
ClassInfo
classInfo
)
{
p
rivate
String
useClassInner
(
ClassInfo
classInfo
)
{
if
(
parentGen
!=
null
)
if
(
parentGen
!=
null
)
return
parentGen
.
useClass
(
classInfo
);
return
parentGen
.
useClass
Inner
(
classInfo
);
String
clsStr
=
classInfo
.
getFullName
();
String
clsStr
=
classInfo
.
getFullName
();
if
(
fallback
)
if
(
fallback
)
...
...
src/main/java/jadx/codegen/MethodGen.java
View file @
0ee499c5
...
@@ -76,8 +76,11 @@ public class MethodGen {
...
@@ -76,8 +76,11 @@ public class MethodGen {
if
(
mth
.
getParentClass
().
getAccessFlags
().
isInterface
())
{
if
(
mth
.
getParentClass
().
getAccessFlags
().
isInterface
())
{
ai
=
ai
.
remove
(
AccessFlags
.
ACC_ABSTRACT
);
ai
=
ai
.
remove
(
AccessFlags
.
ACC_ABSTRACT
);
}
}
code
.
startLine
(
ai
.
makeString
());
code
.
startLine
(
ai
.
makeString
());
classGen
.
makeGenericMap
(
code
,
mth
.
getGenericMap
());
code
.
add
(
' '
);
if
(
mth
.
getAccessFlags
().
isConstructor
())
{
if
(
mth
.
getAccessFlags
().
isConstructor
())
{
code
.
add
(
classGen
.
getClassNode
().
getShortName
());
// constructor
code
.
add
(
classGen
.
getClassNode
().
getShortName
());
// constructor
}
else
{
}
else
{
...
...
src/main/java/jadx/dex/attributes/AttributesList.java
View file @
0ee499c5
package
jadx
.
dex
.
attributes
;
package
jadx
.
dex
.
attributes
;
import
jadx.dex.attributes.annotations.Annotation
;
import
jadx.dex.attributes.annotations.AnnotationsList
;
import
jadx.utils.Utils
;
import
jadx.utils.Utils
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
...
@@ -90,6 +92,14 @@ public class AttributesList {
...
@@ -90,6 +92,14 @@ public class AttributesList {
}
}
}
}
public
Annotation
getAnnotation
(
String
cls
)
{
AnnotationsList
aList
=
(
AnnotationsList
)
get
(
AttributeType
.
ANNOTATION_LIST
);
if
(
aList
==
null
||
aList
.
size
()
==
0
)
return
null
;
return
aList
.
get
(
cls
);
}
public
List
<
IAttribute
>
getAll
(
AttributeType
type
)
{
public
List
<
IAttribute
>
getAll
(
AttributeType
type
)
{
assert
type
.
notUniq
();
assert
type
.
notUniq
();
...
...
src/main/java/jadx/dex/attributes/annotations/Annotation.java
View file @
0ee499c5
...
@@ -36,6 +36,10 @@ public class Annotation {
...
@@ -36,6 +36,10 @@ public class Annotation {
return
values
;
return
values
;
}
}
public
Object
getDefaultValue
()
{
return
values
.
get
(
"value"
);
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"Annotation["
+
visibility
+
", "
+
atype
+
", "
+
values
+
"]"
;
return
"Annotation["
+
visibility
+
", "
+
atype
+
", "
+
values
+
"]"
;
...
...
src/main/java/jadx/dex/info/ClassInfo.java
View file @
0ee499c5
...
@@ -49,6 +49,7 @@ public final class ClassInfo {
...
@@ -49,6 +49,7 @@ public final class ClassInfo {
}
}
private
ClassInfo
(
DexNode
dex
,
ArgType
type
)
{
private
ClassInfo
(
DexNode
dex
,
ArgType
type
)
{
assert
type
.
isObject
()
:
"Not class type: "
+
type
;
this
.
type
=
type
;
this
.
type
=
type
;
String
fullObjectName
=
type
.
getObject
();
String
fullObjectName
=
type
.
getObject
();
...
...
src/main/java/jadx/dex/info/FieldInfo.java
View file @
0ee499c5
package
jadx
.
dex
.
info
;
package
jadx
.
dex
.
info
;
import
jadx.dex.attributes.AttrNode
;
import
jadx.dex.instructions.args.ArgType
;
import
jadx.dex.instructions.args.ArgType
;
import
jadx.dex.nodes.DexNode
;
import
jadx.dex.nodes.DexNode
;
import
com.android.dx.io.FieldId
;
import
com.android.dx.io.FieldId
;
public
class
FieldInfo
extends
AttrNode
{
public
class
FieldInfo
{
private
final
String
name
;
private
final
String
name
;
private
final
ArgType
type
;
private
final
ArgType
type
;
...
...
src/main/java/jadx/dex/instructions/args/ArgType.java
View file @
0ee499c5
...
@@ -5,9 +5,16 @@ import jadx.utils.Utils;
...
@@ -5,9 +5,16 @@ import jadx.utils.Utils;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
abstract
class
ArgType
{
public
abstract
class
ArgType
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ArgType
.
class
);
public
static
final
ArgType
INT
=
primitive
(
PrimitiveType
.
INT
);
public
static
final
ArgType
INT
=
primitive
(
PrimitiveType
.
INT
);
public
static
final
ArgType
BOOLEAN
=
primitive
(
PrimitiveType
.
BOOLEAN
);
public
static
final
ArgType
BOOLEAN
=
primitive
(
PrimitiveType
.
BOOLEAN
);
public
static
final
ArgType
BYTE
=
primitive
(
PrimitiveType
.
BYTE
);
public
static
final
ArgType
BYTE
=
primitive
(
PrimitiveType
.
BYTE
);
...
@@ -43,6 +50,10 @@ public abstract class ArgType {
...
@@ -43,6 +50,10 @@ public abstract class ArgType {
return
new
ObjectArg
(
obj
);
return
new
ObjectArg
(
obj
);
}
}
public
static
ArgType
genericType
(
String
type
)
{
return
new
GenericTypeArg
(
type
);
}
public
static
ArgType
generic
(
String
sign
)
{
public
static
ArgType
generic
(
String
sign
)
{
return
parseSignature
(
sign
);
return
parseSignature
(
sign
);
}
}
...
@@ -119,6 +130,17 @@ public abstract class ArgType {
...
@@ -119,6 +130,17 @@ public abstract class ArgType {
}
}
}
}
private
static
final
class
GenericTypeArg
extends
ObjectArg
{
public
GenericTypeArg
(
String
obj
)
{
super
(
obj
);
}
@Override
public
boolean
isGenericType
()
{
return
true
;
}
}
private
static
final
class
GenericObjectArg
extends
ObjectArg
{
private
static
final
class
GenericObjectArg
extends
ObjectArg
{
private
final
ArgType
[]
generics
;
private
final
ArgType
[]
generics
;
...
@@ -249,6 +271,10 @@ public abstract class ArgType {
...
@@ -249,6 +271,10 @@ public abstract class ArgType {
return
false
;
return
false
;
}
}
public
boolean
isGenericType
()
{
return
false
;
}
public
ArgType
[]
getGenericTypes
()
{
public
ArgType
[]
getGenericTypes
()
{
return
null
;
return
null
;
}
}
...
@@ -355,13 +381,15 @@ public abstract class ArgType {
...
@@ -355,13 +381,15 @@ public abstract class ArgType {
}
}
public
static
ArgType
parse
(
String
type
)
{
public
static
ArgType
parse
(
String
type
)
{
assert
type
.
length
()
>
0
:
"Empty type"
;
char
f
=
type
.
charAt
(
0
);
char
f
=
type
.
charAt
(
0
);
if
(
f
==
'L'
)
{
switch
(
f
)
{
case
'L'
:
return
object
(
type
);
return
object
(
type
);
}
else
if
(
f
==
'['
)
{
case
'T'
:
return
genericType
(
type
.
substring
(
1
,
type
.
length
()
-
1
));
case
'['
:
return
array
(
parse
(
type
.
substring
(
1
)));
return
array
(
parse
(
type
.
substring
(
1
)));
}
else
{
default
:
return
parse
(
f
);
return
parse
(
f
);
}
}
}
}
...
@@ -374,11 +402,22 @@ public abstract class ArgType {
...
@@ -374,11 +402,22 @@ public abstract class ArgType {
String
obj
=
sign
.
substring
(
0
,
b
);
String
obj
=
sign
.
substring
(
0
,
b
);
String
genericsStr
=
sign
.
substring
(
b
+
1
,
sign
.
length
()
-
2
);
String
genericsStr
=
sign
.
substring
(
b
+
1
,
sign
.
length
()
-
2
);
List
<
ArgType
>
generics
=
parseSignatureList
(
genericsStr
);
List
<
ArgType
>
generics
=
parseSignatureList
(
genericsStr
);
ArgType
res
=
generic
(
obj
+
";"
,
generics
.
toArray
(
new
ArgType
[
generics
.
size
()]));
if
(
generics
!=
null
)
return
res
;
return
generic
(
obj
+
";"
,
generics
.
toArray
(
new
ArgType
[
generics
.
size
()]));
else
return
object
(
obj
+
";"
);
}
}
public
static
List
<
ArgType
>
parseSignatureList
(
String
str
)
{
public
static
List
<
ArgType
>
parseSignatureList
(
String
str
)
{
try
{
return
parseSignatureListInner
(
str
,
true
);
}
catch
(
Throwable
e
)
{
LOG
.
warn
(
"Signature parse exception: {}"
,
str
,
e
);
return
null
;
}
}
private
static
List
<
ArgType
>
parseSignatureListInner
(
String
str
,
boolean
parsePrimitives
)
{
List
<
ArgType
>
signs
=
new
ArrayList
<
ArgType
>(
3
);
List
<
ArgType
>
signs
=
new
ArrayList
<
ArgType
>(
3
);
if
(
str
.
equals
(
"*"
))
{
if
(
str
.
equals
(
"*"
))
{
signs
.
add
(
UNKNOWN
);
signs
.
add
(
UNKNOWN
);
...
@@ -396,6 +435,7 @@ public abstract class ArgType {
...
@@ -396,6 +435,7 @@ public abstract class ArgType {
char
c
=
str
.
charAt
(
pos
);
char
c
=
str
.
charAt
(
pos
);
switch
(
c
)
{
switch
(
c
)
{
case
'L'
:
case
'L'
:
case
'T'
:
if
(
obj
==
0
&&
gen
==
0
)
{
if
(
obj
==
0
&&
gen
==
0
)
{
obj
++;
obj
++;
objStart
=
pos
;
objStart
=
pos
;
...
@@ -410,6 +450,15 @@ public abstract class ArgType {
...
@@ -410,6 +450,15 @@ public abstract class ArgType {
}
}
break
;
break
;
case
':'
:
// generic types map separator
if
(
gen
==
0
)
{
obj
=
0
;
String
o
=
str
.
substring
(
objStart
,
pos
);
if
(
o
.
length
()
>
0
)
type
=
genericType
(
o
);
}
break
;
case
'<'
:
case
'<'
:
gen
++;
gen
++;
break
;
break
;
...
@@ -418,11 +467,13 @@ public abstract class ArgType {
...
@@ -418,11 +467,13 @@ public abstract class ArgType {
break
;
break
;
case
'['
:
case
'['
:
if
(
obj
==
0
&&
gen
==
0
)
{
arr
++;
arr
++;
}
break
;
break
;
default
:
default
:
if
(
obj
==
0
&&
gen
==
0
)
{
if
(
parsePrimitives
&&
obj
==
0
&&
gen
==
0
)
{
type
=
parse
(
c
);
type
=
parse
(
c
);
}
}
break
;
break
;
...
@@ -439,12 +490,45 @@ public abstract class ArgType {
...
@@ -439,12 +490,45 @@ public abstract class ArgType {
arr
=
0
;
arr
=
0
;
}
}
type
=
null
;
type
=
null
;
objStart
=
pos
+
1
;
}
}
pos
++;
pos
++;
}
}
return
signs
;
return
signs
;
}
}
public
static
Map
<
ArgType
,
List
<
ArgType
>>
parseGenericMap
(
String
gen
)
{
try
{
Map
<
ArgType
,
List
<
ArgType
>>
genericMap
=
null
;
List
<
ArgType
>
genTypes
=
parseSignatureListInner
(
gen
,
false
);
if
(
genTypes
!=
null
)
{
genericMap
=
new
LinkedHashMap
<
ArgType
,
List
<
ArgType
>>(
2
);
ArgType
prev
=
null
;
List
<
ArgType
>
genList
=
new
ArrayList
<
ArgType
>(
2
);
for
(
ArgType
arg
:
genTypes
)
{
if
(
arg
.
isGenericType
())
{
if
(
prev
!=
null
)
{
genericMap
.
put
(
prev
,
genList
);
genList
=
new
ArrayList
<
ArgType
>();
}
prev
=
arg
;
}
else
{
if
(!
arg
.
getObject
().
equals
(
Consts
.
CLASS_OBJECT
))
genList
.
add
(
arg
);
}
}
if
(
prev
!=
null
)
{
genericMap
.
put
(
prev
,
genList
);
}
// LOG.debug("sign: {} -> {}", gen, genericMap);
}
return
genericMap
;
}
catch
(
Throwable
e
)
{
LOG
.
warn
(
"Generic map parse exception: {}"
,
gen
,
e
);
return
null
;
}
}
private
static
ArgType
parse
(
char
f
)
{
private
static
ArgType
parse
(
char
f
)
{
switch
(
f
)
{
switch
(
f
)
{
case
'Z'
:
case
'Z'
:
...
...
src/main/java/jadx/dex/nodes/ClassNode.java
View file @
0ee499c5
package
jadx
.
dex
.
nodes
;
package
jadx
.
dex
.
nodes
;
import
jadx.Consts
;
import
jadx.dex.attributes.AttrNode
;
import
jadx.dex.attributes.AttrNode
;
import
jadx.dex.attributes.AttributeType
;
import
jadx.dex.attributes.AttributeType
;
import
jadx.dex.attributes.IAttribute
;
import
jadx.dex.attributes.annotations.Annotation
;
import
jadx.dex.attributes.annotations.Annotation
;
import
jadx.dex.attributes.annotations.AnnotationsList
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo.AFType
;
import
jadx.dex.info.AccessInfo.AFType
;
import
jadx.dex.info.ClassInfo
;
import
jadx.dex.info.ClassInfo
;
...
@@ -14,6 +13,7 @@ import jadx.dex.instructions.args.ArgType;
...
@@ -14,6 +13,7 @@ import jadx.dex.instructions.args.ArgType;
import
jadx.dex.nodes.parser.AnnotationsParser
;
import
jadx.dex.nodes.parser.AnnotationsParser
;
import
jadx.dex.nodes.parser.FieldValueAttr
;
import
jadx.dex.nodes.parser.FieldValueAttr
;
import
jadx.dex.nodes.parser.StaticValuesParser
;
import
jadx.dex.nodes.parser.StaticValuesParser
;
import
jadx.utils.Utils
;
import
jadx.utils.exceptions.DecodeException
;
import
jadx.utils.exceptions.DecodeException
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
...
@@ -31,13 +31,13 @@ import com.android.dx.io.ClassData.Method;
...
@@ -31,13 +31,13 @@ import com.android.dx.io.ClassData.Method;
import
com.android.dx.io.ClassDef
;
import
com.android.dx.io.ClassDef
;
public
class
ClassNode
extends
AttrNode
implements
ILoadable
{
public
class
ClassNode
extends
AttrNode
implements
ILoadable
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ClassNode
.
class
);
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ClassNode
.
class
);
private
final
DexNode
dex
;
private
final
DexNode
dex
;
private
final
ClassInfo
clsInfo
;
private
final
ClassInfo
clsInfo
;
private
final
ClassInfo
superClass
;
private
ClassInfo
superClass
;
private
final
List
<
ClassInfo
>
interfaces
;
private
List
<
ClassInfo
>
interfaces
;
private
Map
<
ArgType
,
List
<
ArgType
>>
genericMap
;
private
final
List
<
MethodNode
>
methods
=
new
ArrayList
<
MethodNode
>();
private
final
List
<
MethodNode
>
methods
=
new
ArrayList
<
MethodNode
>();
private
final
List
<
FieldNode
>
fields
=
new
ArrayList
<
FieldNode
>();
private
final
List
<
FieldNode
>
fields
=
new
ArrayList
<
FieldNode
>();
...
@@ -82,15 +82,15 @@ public class ClassNode extends AttrNode implements ILoadable {
...
@@ -82,15 +82,15 @@ public class ClassNode extends AttrNode implements ILoadable {
loadAnnotations
(
cls
);
loadAnnotations
(
cls
);
int
accFlagsValue
=
cls
.
getAccessFlags
();
parseClassSignature
();
setFieldsTypesFromSignature
();
IAttribute
annotations
=
getAttributes
().
get
(
AttributeType
.
ANNOTATION_LIST
);
int
accFlagsValue
;
if
(
annotations
!=
null
)
{
Annotation
a
=
getAttributes
().
getAnnotation
(
"dalvik.annotation.InnerClass"
);
AnnotationsList
list
=
(
AnnotationsList
)
annotations
;
if
(
a
!=
null
)
Annotation
iCls
=
list
.
get
(
"dalvik.annotation.InnerClass"
);
accFlagsValue
=
(
Integer
)
a
.
getValues
().
get
(
"accessFlags"
);
if
(
iCls
!=
null
)
else
accFlagsValue
=
(
Integer
)
iCls
.
getValues
().
get
(
"accessFlags"
);
accFlagsValue
=
cls
.
getAccessFlags
();
}
this
.
accessFlags
=
new
AccessInfo
(
accFlagsValue
,
AFType
.
CLASS
);
this
.
accessFlags
=
new
AccessInfo
(
accFlagsValue
,
AFType
.
CLASS
);
...
@@ -134,6 +134,53 @@ public class ClassNode extends AttrNode implements ILoadable {
...
@@ -134,6 +134,53 @@ public class ClassNode extends AttrNode implements ILoadable {
}
}
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
parseClassSignature
()
{
Annotation
a
=
this
.
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
a
==
null
)
return
;
String
sign
=
Utils
.
mergeSignature
((
List
<
String
>)
a
.
getDefaultValue
());
// parse generic map
int
end
=
Utils
.
getGenericEnd
(
sign
);
if
(
end
!=
-
1
)
{
String
gen
=
sign
.
substring
(
1
,
end
);
genericMap
=
ArgType
.
parseGenericMap
(
gen
);
sign
=
sign
.
substring
(
end
+
1
);
}
// parse super class signature and interfaces
List
<
ArgType
>
list
=
ArgType
.
parseSignatureList
(
sign
);
if
(
list
!=
null
&&
!
list
.
isEmpty
())
{
try
{
ArgType
st
=
list
.
remove
(
0
);
this
.
superClass
=
ClassInfo
.
fromType
(
dex
,
st
);
int
i
=
0
;
for
(
ArgType
it
:
list
)
{
ClassInfo
interf
=
ClassInfo
.
fromType
(
dex
,
it
);
interfaces
.
set
(
i
,
interf
);
i
++;
}
}
catch
(
Throwable
e
)
{
LOG
.
warn
(
"Can't set signatures for class: {}, sign: {}"
,
this
,
sign
,
e
);
}
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
setFieldsTypesFromSignature
()
{
for
(
FieldNode
field
:
fields
)
{
Annotation
a
=
field
.
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
a
==
null
)
continue
;
String
sign
=
Utils
.
mergeSignature
((
List
<
String
>)
a
.
getDefaultValue
());
ArgType
gType
=
ArgType
.
parseSignature
(
sign
);
if
(
gType
!=
null
)
field
.
setType
(
gType
);
}
}
@Override
@Override
public
void
load
()
throws
DecodeException
{
public
void
load
()
throws
DecodeException
{
for
(
MethodNode
mth
:
getMethods
())
{
for
(
MethodNode
mth
:
getMethods
())
{
...
@@ -162,6 +209,10 @@ public class ClassNode extends AttrNode implements ILoadable {
...
@@ -162,6 +209,10 @@ public class ClassNode extends AttrNode implements ILoadable {
return
interfaces
;
return
interfaces
;
}
}
public
Map
<
ArgType
,
List
<
ArgType
>>
getGenericMap
()
{
return
genericMap
;
}
public
List
<
MethodNode
>
getMethods
()
{
public
List
<
MethodNode
>
getMethods
()
{
return
methods
;
return
methods
;
}
}
...
...
src/main/java/jadx/dex/nodes/FieldNode.java
View file @
0ee499c5
package
jadx
.
dex
.
nodes
;
package
jadx
.
dex
.
nodes
;
import
jadx.dex.attributes.AttrNode
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo.AFType
;
import
jadx.dex.info.AccessInfo.AFType
;
import
jadx.dex.info.ClassInfo
;
import
jadx.dex.info.FieldInfo
;
import
jadx.dex.info.FieldInfo
;
import
jadx.dex.instructions.args.ArgType
;
import
com.android.dx.io.ClassData.Field
;
import
com.android.dx.io.ClassData.Field
;
public
class
FieldNode
extends
FieldInfo
{
public
class
FieldNode
extends
AttrNode
{
private
final
AccessInfo
accFlags
;
private
final
AccessInfo
accFlags
;
private
final
String
name
;
private
final
ClassInfo
declClass
;
private
ArgType
type
;
public
FieldNode
(
ClassNode
cls
,
Field
field
)
{
public
FieldNode
(
ClassNode
cls
,
Field
field
)
{
super
(
cls
.
dex
(),
field
.
getFieldIndex
());
FieldInfo
f
=
FieldInfo
.
fromDex
(
cls
.
dex
(),
field
.
getFieldIndex
());
this
.
name
=
f
.
getName
();
this
.
type
=
f
.
getType
();
this
.
declClass
=
f
.
getDeclClass
();
this
.
accFlags
=
new
AccessInfo
(
field
.
getAccessFlags
(),
AFType
.
FIELD
);
this
.
accFlags
=
new
AccessInfo
(
field
.
getAccessFlags
(),
AFType
.
FIELD
);
}
}
...
@@ -19,4 +29,24 @@ public class FieldNode extends FieldInfo {
...
@@ -19,4 +29,24 @@ public class FieldNode extends FieldInfo {
return
accFlags
;
return
accFlags
;
}
}
public
String
getName
()
{
return
name
;
}
public
ArgType
getType
()
{
return
type
;
}
public
void
setType
(
ArgType
type
)
{
this
.
type
=
type
;
}
public
ClassInfo
getDeclClass
()
{
return
declClass
;
}
@Override
public
String
toString
()
{
return
declClass
+
"."
+
name
+
" "
+
type
;
}
}
}
src/main/java/jadx/dex/nodes/MethodNode.java
View file @
0ee499c5
package
jadx
.
dex
.
nodes
;
package
jadx
.
dex
.
nodes
;
import
jadx.Consts
;
import
jadx.dex.attributes.AttrNode
;
import
jadx.dex.attributes.AttrNode
;
import
jadx.dex.attributes.AttributeFlag
;
import
jadx.dex.attributes.AttributeFlag
;
import
jadx.dex.attributes.AttributeType
;
import
jadx.dex.attributes.JumpAttribute
;
import
jadx.dex.attributes.JumpAttribute
;
import
jadx.dex.attributes.annotations.Annotation
;
import
jadx.dex.attributes.annotations.Annotation
;
import
jadx.dex.attributes.annotations.AnnotationsList
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo.AFType
;
import
jadx.dex.info.AccessInfo.AFType
;
import
jadx.dex.info.ClassInfo
;
import
jadx.dex.info.ClassInfo
;
...
@@ -29,6 +28,7 @@ import java.util.ArrayList;
...
@@ -29,6 +28,7 @@ import java.util.ArrayList;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Set
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
...
@@ -54,6 +54,7 @@ public class MethodNode extends AttrNode implements ILoadable {
...
@@ -54,6 +54,7 @@ public class MethodNode extends AttrNode implements ILoadable {
private
ArgType
retType
;
private
ArgType
retType
;
private
RegisterArg
thisArg
;
private
RegisterArg
thisArg
;
private
List
<
RegisterArg
>
argsList
;
private
List
<
RegisterArg
>
argsList
;
private
Map
<
ArgType
,
List
<
ArgType
>>
genericMap
;
private
List
<
BlockNode
>
blocks
;
private
List
<
BlockNode
>
blocks
;
private
BlockNode
enterBlock
;
private
BlockNode
enterBlock
;
...
@@ -131,35 +132,52 @@ public class MethodNode extends AttrNode implements ILoadable {
...
@@ -131,35 +132,52 @@ public class MethodNode extends AttrNode implements ILoadable {
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
private
boolean
parseSignature
()
{
private
boolean
parseSignature
()
{
AnnotationsList
aList
=
(
AnnotationsList
)
getAttributes
().
get
(
AttributeType
.
ANNOTATION_LIST
);
Annotation
a
=
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
aList
==
null
||
aList
.
size
()
==
0
)
return
false
;
Annotation
a
=
aList
.
get
(
"dalvik.annotation.Signature"
);
if
(
a
==
null
)
if
(
a
==
null
)
return
false
;
return
false
;
String
sign
=
Utils
.
mergeSignature
((
List
<
String
>)
a
.
getValues
().
get
(
"value"
));
String
sign
=
Utils
.
mergeSignature
((
List
<
String
>)
a
.
getDefaultValue
());
int
lastBracket
=
sign
.
indexOf
(
')'
);
String
argsTypesStr
=
sign
.
substring
(
1
,
lastBracket
);
// parse generic map
int
end
=
Utils
.
getGenericEnd
(
sign
);
if
(
end
!=
-
1
)
{
String
gen
=
sign
.
substring
(
1
,
end
);
genericMap
=
ArgType
.
parseGenericMap
(
gen
);
sign
=
sign
.
substring
(
end
+
1
);
}
int
firstBracket
=
sign
.
indexOf
(
'('
);
int
lastBracket
=
sign
.
lastIndexOf
(
')'
);
String
argsTypesStr
=
sign
.
substring
(
firstBracket
+
1
,
lastBracket
);
String
returnType
=
sign
.
substring
(
lastBracket
+
1
);
String
returnType
=
sign
.
substring
(
lastBracket
+
1
);
retType
=
ArgType
.
parseSignature
(
returnType
);
retType
=
ArgType
.
parseSignature
(
returnType
);
if
(
retType
==
null
)
{
LOG
.
warn
(
"Signature parse error: {}"
,
returnType
);
return
false
;
}
if
(
mthInfo
.
getArgumentsTypes
().
isEmpty
())
{
if
(
mthInfo
.
getArgumentsTypes
().
isEmpty
())
{
argsList
=
Collections
.
emptyList
();
argsList
=
Collections
.
emptyList
();
return
true
;
return
true
;
}
}
List
<
ArgType
>
argsTypes
=
ArgType
.
parseSignatureList
(
argsTypesStr
);
List
<
ArgType
>
argsTypes
=
ArgType
.
parseSignatureList
(
argsTypesStr
);
if
(
argsTypes
==
null
)
return
false
;
if
(
argsTypes
.
size
()
!=
mthInfo
.
getArgumentsTypes
().
size
())
{
if
(
argsTypes
.
size
()
!=
mthInfo
.
getArgumentsTypes
().
size
())
{
if
(!
getParentClass
().
getAccessFlags
().
isEnum
()
&&
!
mthInfo
.
isConstructor
())
{
if
(!
mthInfo
.
isConstructor
())
{
// error parsing signature
LOG
.
warn
(
"Wrong signature parse result: "
+
sign
+
" -> "
+
argsTypes
LOG
.
error
(
"Wrong parse result: "
+
sign
+
" -> "
+
argsTypes
+
", not generic version: "
+
mthInfo
.
getArgumentsTypes
());
+
" must be: "
+
mthInfo
.
getArgumentsTypes
()
// + " in method " + this
);
}
return
false
;
return
false
;
}
else
if
(
getParentClass
().
getAccessFlags
().
isEnum
())
{
// TODO:
argsTypes
.
add
(
0
,
mthInfo
.
getArgumentsTypes
().
get
(
1
));
argsTypes
.
add
(
1
,
mthInfo
.
getArgumentsTypes
().
get
(
1
));
}
else
{
// add synthetic arg for outer class
argsTypes
.
add
(
0
,
mthInfo
.
getArgumentsTypes
().
get
(
0
));
}
}
}
initArguments
(
argsTypes
);
initArguments
(
argsTypes
);
return
true
;
return
true
;
...
@@ -213,7 +231,11 @@ public class MethodNode extends AttrNode implements ILoadable {
...
@@ -213,7 +231,11 @@ public class MethodNode extends AttrNode implements ILoadable {
return
retType
;
return
retType
;
}
}
// move to external class
public
Map
<
ArgType
,
List
<
ArgType
>>
getGenericMap
()
{
return
genericMap
;
}
// TODO: move to external class
private
void
initTryCatches
(
Code
mthCode
,
InsnNode
[]
insnByOffset
)
{
private
void
initTryCatches
(
Code
mthCode
,
InsnNode
[]
insnByOffset
)
{
CatchHandler
[]
catchBlocks
=
mthCode
.
getCatchHandlers
();
CatchHandler
[]
catchBlocks
=
mthCode
.
getCatchHandlers
();
Try
[]
tries
=
mthCode
.
getTries
();
Try
[]
tries
=
mthCode
.
getTries
();
...
...
src/main/java/jadx/dex/visitors/ClassModifier.java
View file @
0ee499c5
package
jadx
.
dex
.
visitors
;
package
jadx
.
dex
.
visitors
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.AccessInfo
;
import
jadx.dex.info.MethodInfo
;
import
jadx.dex.nodes.BlockNode
;
import
jadx.dex.nodes.BlockNode
;
import
jadx.dex.nodes.ClassNode
;
import
jadx.dex.nodes.ClassNode
;
import
jadx.dex.nodes.MethodNode
;
import
jadx.dex.nodes.MethodNode
;
...
@@ -23,7 +24,7 @@ public class ClassModifier extends AbstractVisitor {
...
@@ -23,7 +24,7 @@ public class ClassModifier extends AbstractVisitor {
// remove bridge methods
// remove bridge methods
if
(
af
.
isBridge
()
&&
af
.
isSynthetic
())
{
if
(
af
.
isBridge
()
&&
af
.
isSynthetic
())
{
if
(!
isMethod
Id
Uniq
(
cls
,
mth
))
{
if
(!
isMethodUniq
(
cls
,
mth
))
{
// TODO add more checks before method deletion
// TODO add more checks before method deletion
it
.
remove
();
it
.
remove
();
}
}
...
@@ -42,13 +43,18 @@ public class ClassModifier extends AbstractVisitor {
...
@@ -42,13 +43,18 @@ public class ClassModifier extends AbstractVisitor {
return
false
;
return
false
;
}
}
private
boolean
isMethod
Id
Uniq
(
ClassNode
cls
,
MethodNode
mth
)
{
private
boolean
isMethodUniq
(
ClassNode
cls
,
MethodNode
mth
)
{
String
shortId
=
mth
.
getMethodInfo
().
getShortId
();
MethodInfo
mi
=
mth
.
getMethodInfo
();
for
(
MethodNode
otherMth
:
cls
.
getMethods
())
{
for
(
MethodNode
otherMth
:
cls
.
getMethods
())
{
if
(
otherMth
.
getMethodInfo
().
getShortId
().
equals
(
shortId
)
MethodInfo
omi
=
otherMth
.
getMethodInfo
();
&&
otherMth
!=
mth
)
if
(
omi
.
getName
().
equals
(
mi
.
getName
())
&&
otherMth
!=
mth
)
{
if
(
omi
.
getArgumentsTypes
().
size
()
==
mi
.
getArgumentsTypes
().
size
())
{
// TODO: check to args objects types
return
false
;
return
false
;
}
}
}
}
return
true
;
return
true
;
}
}
}
}
src/main/java/jadx/utils/Utils.java
View file @
0ee499c5
...
@@ -28,13 +28,35 @@ public class Utils {
...
@@ -28,13 +28,35 @@ public class Utils {
}
}
public
static
String
escape
(
String
str
)
{
public
static
String
escape
(
String
str
)
{
return
str
.
replace
(
'.'
,
'_'
)
int
len
=
str
.
length
();
.
replace
(
'/'
,
'_'
)
StringBuilder
sb
=
new
StringBuilder
(
len
);
.
replace
(
';'
,
'_'
)
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
.
replace
(
'$'
,
'_'
)
char
c
=
str
.
charAt
(
i
);
.
replace
(
'<'
,
'_'
)
switch
(
c
)
{
.
replace
(
'>'
,
'_'
)
case
'.'
:
.
replace
(
"[]"
,
"_A"
);
case
'/'
:
case
';'
:
case
'$'
:
case
'<'
:
case
'['
:
sb
.
append
(
'_'
);
break
;
case
']'
:
sb
.
append
(
'A'
);
break
;
case
'>'
:
case
','
:
case
' '
:
break
;
default
:
sb
.
append
(
c
);
break
;
}
}
return
sb
.
toString
();
}
}
public
static
String
listToString
(
Iterable
<?>
list
)
{
public
static
String
listToString
(
Iterable
<?>
list
)
{
...
@@ -44,7 +66,7 @@ public class Utils {
...
@@ -44,7 +66,7 @@ public class Utils {
StringBuilder
str
=
new
StringBuilder
();
StringBuilder
str
=
new
StringBuilder
();
for
(
Iterator
<?>
it
=
list
.
iterator
();
it
.
hasNext
();)
{
for
(
Iterator
<?>
it
=
list
.
iterator
();
it
.
hasNext
();)
{
Object
o
=
it
.
next
();
Object
o
=
it
.
next
();
str
.
append
(
o
.
toString
()
);
str
.
append
(
o
);
if
(
it
.
hasNext
())
if
(
it
.
hasNext
())
str
.
append
(
", "
);
str
.
append
(
", "
);
}
}
...
@@ -52,6 +74,9 @@ public class Utils {
...
@@ -52,6 +74,9 @@ public class Utils {
}
}
public
static
String
arrayToString
(
Object
[]
array
)
{
public
static
String
arrayToString
(
Object
[]
array
)
{
if
(
array
==
null
)
return
""
;
StringBuilder
sb
=
new
StringBuilder
();
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
array
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
array
.
length
;
i
++)
{
if
(
i
!=
0
)
if
(
i
!=
0
)
...
@@ -76,6 +101,26 @@ public class Utils {
...
@@ -76,6 +101,26 @@ public class Utils {
return
sb
.
toString
();
return
sb
.
toString
();
}
}
public
static
int
getGenericEnd
(
String
sign
)
{
int
end
=
-
1
;
if
(
sign
.
startsWith
(
"<"
))
{
int
pair
=
1
;
for
(
int
pos
=
1
;
pos
<
sign
.
length
();
pos
++)
{
char
c
=
sign
.
charAt
(
pos
);
if
(
c
==
'<'
)
pair
++;
else
if
(
c
==
'>'
)
pair
--;
if
(
pair
==
0
)
{
end
=
pos
;
break
;
}
}
}
return
end
;
}
public
static
String
getJadxVersion
()
{
public
static
String
getJadxVersion
()
{
try
{
try
{
Enumeration
<
URL
>
resources
=
Enumeration
<
URL
>
resources
=
...
...
src/samples/java/jadx/samples/TestGenerics.java
View file @
0ee499c5
...
@@ -7,6 +7,134 @@ import java.util.Map;
...
@@ -7,6 +7,134 @@ import java.util.Map;
public
class
TestGenerics
extends
AbstractTest
{
public
class
TestGenerics
extends
AbstractTest
{
public
List
<
String
>
strings
;
public
static
class
GenericClass
implements
Comparable
<
String
>
{
@Override
public
int
compareTo
(
String
o
)
{
return
0
;
}
}
public
static
class
Box
<
T
>
{
private
T
t
;
public
void
set
(
T
t
)
{
this
.
t
=
t
;
}
public
T
get
()
{
return
t
;
}
}
public
static
Box
<
Integer
>
integerBox
=
new
Box
<
Integer
>();
public
interface
Pair
<
K
,
LongGenericType
>
{
public
K
getKey
();
public
LongGenericType
getValue
();
}
public
static
class
OrderedPair
<
K
,
V
>
implements
Pair
<
K
,
V
>
{
private
final
K
key
;
private
final
V
value
;
public
OrderedPair
(
K
key
,
V
value
)
{
this
.
key
=
key
;
this
.
value
=
value
;
}
@Override
public
K
getKey
()
{
return
key
;
}
@Override
public
V
getValue
()
{
return
value
;
}
}
Pair
<
String
,
Integer
>
p1
=
new
OrderedPair
<
String
,
Integer
>(
"8"
,
8
);
OrderedPair
<
String
,
Box
<
Integer
>>
p
=
new
OrderedPair
<
String
,
Box
<
Integer
>>(
"primes"
,
new
Box
<
Integer
>());
public
static
class
Util
{
// Generic static method
public
static
<
K
,
V
>
boolean
compare
(
Pair
<
K
,
V
>
p1
,
Pair
<
K
,
V
>
p2
)
{
return
p1
.
getKey
().
equals
(
p2
.
getKey
())
&&
p1
.
getValue
().
equals
(
p2
.
getValue
());
}
}
public
static
boolean
use
()
{
Pair
<
Integer
,
String
>
p1
=
new
OrderedPair
<
Integer
,
String
>(
1
,
"str1"
);
Pair
<
Integer
,
String
>
p2
=
new
OrderedPair
<
Integer
,
String
>(
2
,
"str2"
);
boolean
same
=
Util
.<
Integer
,
String
>
compare
(
p1
,
p2
);
return
same
;
}
public
class
NaturalNumber
<
T
extends
Integer
>
{
private
final
T
n
;
public
NaturalNumber
(
T
n
)
{
this
.
n
=
n
;
}
public
boolean
isEven
()
{
return
n
.
intValue
()
%
2
==
0
;
}
}
class
A
{
}
interface
B
{
}
interface
C
{
}
class
D
<
T
extends
A
&
B
&
C
>
{
}
public
static
<
T
extends
Comparable
<
T
>>
int
countGreaterThan
(
T
[]
anArray
,
T
elem
)
{
int
count
=
0
;
for
(
T
e
:
anArray
)
if
(
e
.
compareTo
(
elem
)
>
0
)
++
count
;
return
count
;
}
public
static
void
process
(
List
<?
extends
A
>
list
)
{
}
public
static
void
printList
(
List
<?>
list
)
{
for
(
Object
elem
:
list
)
System
.
out
.
print
(
elem
+
" "
);
System
.
out
.
println
();
}
public
static
void
addNumbers
(
List
<?
super
Integer
>
list
)
{
for
(
int
i
=
1
;
i
<=
10
;
i
++)
{
list
.
add
(
i
);
}
}
public
class
Node
<
T
extends
Comparable
<
T
>>
{
private
final
T
data
;
private
final
Node
<
T
>
next
;
public
Node
(
T
data
,
Node
<
T
>
next
)
{
this
.
data
=
data
;
this
.
next
=
next
;
}
public
T
getData
()
{
return
data
;
}
}
private
List
<
String
>
test1
(
Map
<
String
,
String
>
map
)
{
private
List
<
String
>
test1
(
Map
<
String
,
String
>
map
)
{
List
<
String
>
list
=
new
ArrayList
<
String
>();
List
<
String
>
list
=
new
ArrayList
<
String
>();
String
str
=
map
.
get
(
"key"
);
String
str
=
map
.
get
(
"key"
);
...
@@ -26,6 +154,7 @@ public class TestGenerics extends AbstractTest {
...
@@ -26,6 +154,7 @@ public class TestGenerics extends AbstractTest {
@Override
@Override
public
boolean
testRun
()
throws
Exception
{
public
boolean
testRun
()
throws
Exception
{
assertTrue
(
test1
(
new
HashMap
<
String
,
String
>())
!=
null
);
assertTrue
(
test1
(
new
HashMap
<
String
,
String
>())
!=
null
);
// TODO: add other checks
return
true
;
return
true
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment