Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
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
47d65fcd
Commit
47d65fcd
authored
Mar 01, 2014
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: improve signature parser
parent
85ab0956
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
632 additions
and
304 deletions
+632
-304
ClassGen.java
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
+26
-19
MethodGen.java
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
+8
-3
ArgType.java
...rc/main/java/jadx/core/dex/instructions/args/ArgType.java
+102
-164
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+27
-33
FieldNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java
+1
-1
MethodNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
+31
-51
SignatureParser.java
...main/java/jadx/core/dex/nodes/parser/SignatureParser.java
+288
-0
Utils.java
jadx-core/src/main/java/jadx/core/utils/Utils.java
+2
-33
TestSignatureParser.java
.../java/jadx/core/dex/nodes/parser/TestSignatureParser.java
+108
-0
TestGenerics.java
.../test/java/jadx/tests/internal/generics/TestGenerics.java
+39
-0
No files found.
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
View file @
47d65fcd
...
...
@@ -338,28 +338,35 @@ public class ClassGen {
public
String
useClass
(
ClassInfo
classInfo
)
{
String
baseClass
=
useClassInternal
(
cls
.
getClassInfo
(),
classInfo
);
ArgType
[]
generics
=
classInfo
.
getType
().
getGenericTypes
();
if
(
generics
!=
null
)
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
baseClass
);
sb
.
append
(
'<'
);
int
len
=
generics
.
length
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
if
(
i
!=
0
)
{
sb
.
append
(
", "
);
}
ArgType
gt
=
generics
[
i
];
if
(
gt
.
isTypeKnown
())
{
sb
.
append
(
TypeGen
.
translate
(
this
,
gt
));
}
else
{
sb
.
append
(
'?'
);
ArgType
type
=
classInfo
.
getType
();
ArgType
[]
generics
=
type
.
getGenericTypes
();
if
(
generics
==
null
)
{
return
baseClass
;
}
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
baseClass
);
sb
.
append
(
'<'
);
int
len
=
generics
.
length
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
if
(
i
!=
0
)
{
sb
.
append
(
", "
);
}
ArgType
gt
=
generics
[
i
];
ArgType
wt
=
gt
.
getWildcardType
();
if
(
wt
!=
null
)
{
sb
.
append
(
'?'
);
int
bounds
=
gt
.
getWildcardBounds
();
if
(
bounds
!=
0
)
{
sb
.
append
(
bounds
==
-
1
?
" super "
:
" extends "
);
sb
.
append
(
TypeGen
.
translate
(
this
,
wt
));
}
}
else
{
sb
.
append
(
TypeGen
.
translate
(
this
,
gt
));
}
sb
.
append
(
'>'
);
return
sb
.
toString
();
}
else
{
return
baseClass
;
}
sb
.
append
(
'>'
);
return
sb
.
toString
();
}
private
String
useClassInternal
(
ClassInfo
useCls
,
ClassInfo
classInfo
)
{
...
...
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
View file @
47d65fcd
...
...
@@ -279,15 +279,20 @@ public class MethodGen {
mth
.
load
();
DepthTraverser
.
visit
(
new
FallbackModeVisitor
(),
mth
);
}
catch
(
DecodeException
e
)
{
// ignore
code
.
startLine
(
"
Can't loadFile method instructions"
);
LOG
.
error
(
"Error reload instructions in fallback mode:"
,
e
);
code
.
startLine
(
"
// Can't loadFile method instructions: "
+
e
.
getMessage
()
);
return
;
}
}
List
<
InsnNode
>
insns
=
mth
.
getInstructions
();
if
(
insns
==
null
)
{
code
.
startLine
(
"// Can't load method instructions."
);
return
;
}
if
(
mth
.
getThisArg
()
!=
null
)
{
code
.
startLine
(
getFallbackMethodGen
(
mth
).
makeArgName
(
mth
.
getThisArg
())).
add
(
" = this;"
);
}
addFallbackInsns
(
code
,
mth
,
mth
.
getInstructions
()
,
true
);
addFallbackInsns
(
code
,
mth
,
insns
,
true
);
}
public
static
void
addFallbackInsns
(
CodeWriter
code
,
MethodNode
mth
,
List
<
InsnNode
>
insns
,
boolean
addLabels
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java
View file @
47d65fcd
...
...
@@ -2,20 +2,14 @@ package jadx.core.dex.instructions.args;
import
jadx.core.Consts
;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.dex.nodes.parser.SignatureParser
;
import
jadx.core.utils.Utils
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
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
BOOLEAN
=
primitive
(
PrimitiveType
.
BOOLEAN
);
...
...
@@ -59,19 +53,31 @@ public abstract class ArgType {
}
public
static
ArgType
object
(
String
obj
)
{
return
new
Object
Arg
(
obj
);
return
new
Object
Type
(
obj
);
}
public
static
ArgType
genericType
(
String
type
)
{
return
new
GenericTypeArg
(
type
);
return
new
GenericType
(
type
);
}
public
static
ArgType
wildcard
()
{
return
new
WildcardType
(
OBJECT
,
0
);
}
public
static
ArgType
wildcard
(
ArgType
obj
,
int
bound
)
{
return
new
WildcardType
(
obj
,
bound
);
}
public
static
ArgType
generic
(
String
sign
)
{
return
parseSignature
(
sign
);
return
new
SignatureParser
(
sign
).
consumeType
(
);
}
public
static
ArgType
generic
(
String
obj
,
ArgType
[]
generics
)
{
return
new
GenericObjectArg
(
obj
,
generics
);
return
new
GenericObject
(
obj
,
generics
);
}
public
static
ArgType
genericInner
(
ArgType
genericType
,
String
innerName
,
ArgType
[]
generics
)
{
return
new
GenericObject
((
GenericObject
)
genericType
,
innerName
,
generics
);
}
public
static
ArgType
array
(
ArgType
vtype
)
{
...
...
@@ -82,14 +88,14 @@ public abstract class ArgType {
return
new
UnknownArg
(
types
);
}
private
abstract
static
class
KnownType
Arg
extends
ArgType
{
private
abstract
static
class
KnownType
extends
ArgType
{
@Override
public
boolean
isTypeKnown
()
{
return
true
;
}
}
private
static
final
class
PrimitiveArg
extends
KnownType
Arg
{
private
static
final
class
PrimitiveArg
extends
KnownType
{
private
final
PrimitiveType
type
;
public
PrimitiveArg
(
PrimitiveType
type
)
{
...
...
@@ -118,10 +124,10 @@ public abstract class ArgType {
}
}
private
static
class
Object
Arg
extends
KnownTypeArg
{
private
static
class
Object
Type
extends
KnownType
{
private
final
String
object
;
public
Object
Arg
(
String
obj
)
{
public
Object
Type
(
String
obj
)
{
this
.
object
=
Utils
.
cleanObjectName
(
obj
);
this
.
hash
=
object
.
hashCode
();
}
...
...
@@ -143,7 +149,7 @@ public abstract class ArgType {
@Override
boolean
internalEquals
(
Object
obj
)
{
return
object
.
equals
(((
Object
Arg
)
obj
).
object
);
return
object
.
equals
(((
Object
Type
)
obj
).
object
);
}
@Override
...
...
@@ -152,8 +158,8 @@ public abstract class ArgType {
}
}
private
static
final
class
GenericType
Arg
extends
ObjectArg
{
public
GenericType
Arg
(
String
obj
)
{
private
static
final
class
GenericType
extends
ObjectType
{
public
GenericType
(
String
obj
)
{
super
(
obj
);
}
...
...
@@ -163,24 +169,82 @@ public abstract class ArgType {
}
}
private
static
final
class
GenericObjectArg
extends
ObjectArg
{
private
static
final
class
WildcardType
extends
ObjectType
{
private
final
ArgType
type
;
private
final
int
bounds
;
public
WildcardType
(
ArgType
obj
,
int
bound
)
{
super
(
obj
.
getObject
());
this
.
type
=
obj
;
this
.
bounds
=
bound
;
}
@Override
public
ArgType
getWildcardType
()
{
return
type
;
}
/**
* Return wildcard bounds:
* <ul>
* <li> 1 for upper bound (? extends A) </li>
* <li> 0 no bounds (?) </li>
* <li>-1 for lower bound (? super A) </li>
* </ul>
*/
@Override
public
int
getWildcardBounds
()
{
return
bounds
;
}
@Override
boolean
internalEquals
(
Object
obj
)
{
return
super
.
internalEquals
(
obj
)
&&
bounds
==
((
WildcardType
)
obj
).
bounds
;
}
@Override
public
String
toString
()
{
if
(
bounds
==
0
)
{
return
"?"
;
}
return
"? "
+
(
bounds
==
-
1
?
"super"
:
"extends"
)
+
" "
+
super
.
toString
();
}
}
private
static
class
GenericObject
extends
ObjectType
{
private
final
ArgType
[]
generics
;
private
final
GenericObject
outerType
;
public
GenericObject
Arg
(
String
obj
,
ArgType
[]
generics
)
{
public
GenericObject
(
String
obj
,
ArgType
[]
generics
)
{
super
(
obj
);
this
.
outerType
=
null
;
this
.
generics
=
generics
;
this
.
hash
=
obj
.
hashCode
()
+
31
*
Arrays
.
hashCode
(
generics
);
}
public
GenericObject
(
GenericObject
outerType
,
String
innerName
,
ArgType
[]
generics
)
{
super
(
outerType
.
getObject
()
+
"."
+
innerName
);
this
.
outerType
=
outerType
;
this
.
generics
=
generics
;
this
.
hash
=
outerType
.
hashCode
()
+
31
*
innerName
.
hashCode
()
+
31
*
31
*
Arrays
.
hashCode
(
generics
);
}
@Override
public
ArgType
[]
getGenericTypes
()
{
return
generics
;
}
@Override
public
ArgType
getOuterType
()
{
return
outerType
;
}
@Override
boolean
internalEquals
(
Object
obj
)
{
return
super
.
internalEquals
(
obj
)
&&
Arrays
.
equals
(
generics
,
((
GenericObject
Arg
)
obj
).
generics
);
&&
Arrays
.
equals
(
generics
,
((
GenericObject
)
obj
).
generics
);
}
@Override
...
...
@@ -189,7 +253,7 @@ public abstract class ArgType {
}
}
private
static
final
class
ArrayArg
extends
KnownType
Arg
{
private
static
final
class
ArrayArg
extends
KnownType
{
private
final
ArgType
arrayElement
;
public
ArrayArg
(
ArgType
arrayElement
)
{
...
...
@@ -314,6 +378,21 @@ public abstract class ArgType {
return
null
;
}
public
ArgType
getWildcardType
()
{
return
null
;
}
/**
* @see jadx.core.dex.instructions.args.ArgType.WildcardType#getWildcardBounds()
*/
public
int
getWildcardBounds
()
{
return
0
;
}
public
ArgType
getOuterType
()
{
return
null
;
}
public
boolean
isArray
()
{
return
false
;
}
...
...
@@ -459,148 +538,7 @@ public abstract class ArgType {
}
}
public
static
ArgType
parseSignature
(
String
sign
)
{
int
b
=
sign
.
indexOf
(
'<'
);
if
(
b
==
-
1
)
{
return
parse
(
sign
);
}
if
(
sign
.
charAt
(
0
)
==
'['
)
{
return
array
(
parseSignature
(
sign
.
substring
(
1
)));
}
String
obj
=
sign
.
substring
(
0
,
b
)
+
";"
;
String
genericsStr
=
sign
.
substring
(
b
+
1
,
sign
.
length
()
-
2
);
List
<
ArgType
>
generics
=
parseSignatureList
(
genericsStr
);
if
(
generics
!=
null
)
{
return
generic
(
obj
,
generics
.
toArray
(
new
ArgType
[
generics
.
size
()]));
}
else
{
return
object
(
obj
);
}
}
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
)
{
if
(
str
.
isEmpty
())
{
return
Collections
.
emptyList
();
}
if
(
str
.
equals
(
"*"
))
{
return
Arrays
.
asList
(
UNKNOWN
);
}
List
<
ArgType
>
signs
=
new
ArrayList
<
ArgType
>(
3
);
int
obj
=
0
;
int
objStart
=
0
;
int
gen
=
0
;
int
arr
=
0
;
int
pos
=
0
;
ArgType
type
=
null
;
while
(
pos
<
str
.
length
())
{
char
c
=
str
.
charAt
(
pos
);
switch
(
c
)
{
case
'L'
:
case
'T'
:
if
(
obj
==
0
&&
gen
==
0
)
{
obj
++;
objStart
=
pos
;
}
break
;
case
';'
:
if
(
obj
==
1
&&
gen
==
0
)
{
obj
--;
String
o
=
str
.
substring
(
objStart
,
pos
+
1
);
type
=
parseSignature
(
o
);
}
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
'<'
:
gen
++;
break
;
case
'>'
:
gen
--;
break
;
case
'['
:
if
(
obj
==
0
&&
gen
==
0
)
{
arr
++;
}
break
;
default
:
if
(
parsePrimitives
&&
obj
==
0
&&
gen
==
0
)
{
type
=
parse
(
c
);
}
break
;
}
if
(
type
!=
null
)
{
if
(
arr
==
0
)
{
signs
.
add
(
type
);
}
else
{
for
(
int
i
=
0
;
i
<
arr
;
i
++)
{
type
=
array
(
type
);
}
signs
.
add
(
type
);
arr
=
0
;
}
type
=
null
;
objStart
=
pos
+
1
;
}
pos
++;
}
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
);
}
}
return
genericMap
;
}
catch
(
Throwable
e
)
{
LOG
.
warn
(
"Generic map parse exception: {}"
,
gen
,
e
);
return
null
;
}
}
private
static
ArgType
parse
(
char
f
)
{
public
static
ArgType
parse
(
char
f
)
{
switch
(
f
)
{
case
'Z'
:
return
BOOLEAN
;
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
47d65fcd
...
...
@@ -16,9 +16,10 @@ import jadx.core.dex.instructions.args.LiteralArg;
import
jadx.core.dex.instructions.args.PrimitiveType
;
import
jadx.core.dex.nodes.parser.AnnotationsParser
;
import
jadx.core.dex.nodes.parser.FieldValueAttr
;
import
jadx.core.dex.nodes.parser.SignatureParser
;
import
jadx.core.dex.nodes.parser.StaticValuesParser
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
...
...
@@ -159,48 +160,41 @@ public class ClassNode extends LineAttrNode implements ILoadable {
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
parseClassSignature
()
{
Annotation
a
=
this
.
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
a
==
null
)
{
SignatureParser
sp
=
SignatureParser
.
fromNode
(
this
);
if
(
sp
==
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
(
st
);
int
i
=
0
;
for
(
ArgType
it
:
list
)
{
ClassInfo
interf
=
ClassInfo
.
fromType
(
it
);
interfaces
.
set
(
i
,
interf
);
i
++;
try
{
// parse class generic map
genericMap
=
sp
.
consumeGenericMap
();
// parse super class signature
superClass
=
ClassInfo
.
fromType
(
sp
.
consumeType
());
// parse interfaces signatures
for
(
int
i
=
0
;
i
<
interfaces
.
size
();
i
++)
{
ArgType
type
=
sp
.
consumeType
();
if
(
type
!=
null
)
{
interfaces
.
set
(
i
,
ClassInfo
.
fromType
(
type
));
}
else
{
break
;
}
}
catch
(
Throwable
e
)
{
LOG
.
warn
(
"Can't set signatures for class: {}, sign: {}"
,
this
,
sign
,
e
);
}
}
catch
(
JadxRuntimeException
e
)
{
LOG
.
error
(
"Class signature parse error: "
+
this
,
e
);
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
setFieldsTypesFromSignature
()
{
for
(
FieldNode
field
:
fields
)
{
Annotation
a
=
field
.
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
a
!=
null
)
{
String
sign
=
Utils
.
mergeSignature
((
List
<
String
>)
a
.
getDefaultValue
());
ArgType
gType
=
ArgType
.
parseSignature
(
sign
);
if
(
gType
!=
null
)
{
field
.
setType
(
gType
);
SignatureParser
sp
=
SignatureParser
.
fromNode
(
field
);
if
(
sp
!=
null
)
{
try
{
ArgType
gType
=
sp
.
consumeType
();
if
(
gType
!=
null
)
{
field
.
setType
(
gType
);
}
}
catch
(
JadxRuntimeException
e
)
{
LOG
.
error
(
"Field signature parse error: "
+
field
,
e
);
}
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java
View file @
47d65fcd
...
...
@@ -60,6 +60,6 @@ public class FieldNode extends LineAttrNode {
@Override
public
String
toString
()
{
return
fieldInfo
.
getDeclClass
()
+
"."
+
fieldInfo
.
getName
()
+
" "
+
type
;
return
fieldInfo
.
getDeclClass
()
+
"."
+
fieldInfo
.
getName
()
+
"
:
"
+
type
;
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
View file @
47d65fcd
package
jadx
.
core
.
dex
.
nodes
;
import
jadx.core.Consts
;
import
jadx.core.dex.attributes.AttributeFlag
;
import
jadx.core.dex.attributes.JumpAttribute
;
import
jadx.core.dex.attributes.LineAttrNode
;
import
jadx.core.dex.attributes.LoopAttr
;
import
jadx.core.dex.attributes.annotations.Annotation
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.info.AccessInfo.AFType
;
import
jadx.core.dex.info.ClassInfo
;
...
...
@@ -18,12 +16,14 @@ import jadx.core.dex.instructions.args.ArgType;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.parser.DebugInfoParser
;
import
jadx.core.dex.nodes.parser.SignatureParser
;
import
jadx.core.dex.regions.Region
;
import
jadx.core.dex.trycatch.ExcHandlerAttr
;
import
jadx.core.dex.trycatch.ExceptionHandler
;
import
jadx.core.dex.trycatch.TryCatchBlock
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
...
...
@@ -140,62 +140,42 @@ public class MethodNode extends LineAttrNode implements ILoadable {
noCode
=
true
;
}
@SuppressWarnings
(
"unchecked"
)
private
boolean
parseSignature
()
{
Annotation
a
=
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
a
==
null
)
{
return
false
;
}
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
);
}
int
firstBracket
=
sign
.
indexOf
(
'('
);
int
lastBracket
=
sign
.
lastIndexOf
(
')'
);
String
argsTypesStr
=
sign
.
substring
(
firstBracket
+
1
,
lastBracket
);
String
returnType
=
sign
.
substring
(
lastBracket
+
1
);
retType
=
ArgType
.
parseSignature
(
returnType
);
if
(
retType
==
null
)
{
LOG
.
warn
(
"Signature parse error: {}"
,
returnType
);
return
false
;
}
List
<
ArgType
>
argsTypes
=
ArgType
.
parseSignatureList
(
argsTypesStr
);
if
(
argsTypes
==
null
)
{
SignatureParser
sp
=
SignatureParser
.
fromNode
(
this
);
if
(
sp
==
null
)
{
return
false
;
}
try
{
genericMap
=
sp
.
consumeGenericMap
();
List
<
ArgType
>
argsTypes
=
sp
.
consumeMethodArgs
();
retType
=
sp
.
consumeType
();
List
<
ArgType
>
mthArgs
=
mthInfo
.
getArgumentsTypes
();
if
(
argsTypes
.
size
()
!=
mthArgs
.
size
())
{
if
(
argsTypes
.
isEmpty
())
{
return
false
;
}
if
(!
mthInfo
.
isConstructor
())
{
LOG
.
warn
(
"Wrong signature parse result: "
+
sign
+
" -> "
+
argsTypes
+
", not generic version: "
+
mthArgs
);
return
false
;
}
else
if
(
getParentClass
().
getAccessFlags
().
isEnum
())
{
// TODO:
argsTypes
.
add
(
0
,
mthArgs
.
get
(
0
));
argsTypes
.
add
(
1
,
mthArgs
.
get
(
1
));
}
else
{
// add synthetic arg for outer class
argsTypes
.
add
(
0
,
mthArgs
.
get
(
0
));
}
List
<
ArgType
>
mthArgs
=
mthInfo
.
getArgumentsTypes
();
if
(
argsTypes
.
size
()
!=
mthArgs
.
size
())
{
return
false
;
if
(
argsTypes
.
isEmpty
())
{
return
false
;
}
if
(!
mthInfo
.
isConstructor
())
{
LOG
.
warn
(
"Wrong signature parse result: "
+
sp
+
" -> "
+
argsTypes
+
", not generic version: "
+
mthArgs
);
return
false
;
}
else
if
(
getParentClass
().
getAccessFlags
().
isEnum
())
{
// TODO:
argsTypes
.
add
(
0
,
mthArgs
.
get
(
0
));
argsTypes
.
add
(
1
,
mthArgs
.
get
(
1
));
}
else
{
// add synthetic arg for outer class
argsTypes
.
add
(
0
,
mthArgs
.
get
(
0
));
}
if
(
argsTypes
.
size
()
!=
mthArgs
.
size
())
{
return
false
;
}
}
initArguments
(
argsTypes
);
}
catch
(
JadxRuntimeException
e
)
{
LOG
.
error
(
"Method signature parse error: "
+
this
,
e
);
return
false
;
}
initArguments
(
argsTypes
);
return
true
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java
0 → 100644
View file @
47d65fcd
package
jadx
.
core
.
dex
.
nodes
.
parser
;
import
jadx.core.Consts
;
import
jadx.core.dex.attributes.IAttributeNode
;
import
jadx.core.dex.attributes.annotations.Annotation
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Map
;
public
class
SignatureParser
{
private
static
final
char
STOP_CHAR
=
0
;
private
final
String
sign
;
private
final
int
end
;
private
int
pos
;
private
int
mark
;
public
SignatureParser
(
String
signature
)
{
sign
=
signature
;
pos
=
-
1
;
mark
=
0
;
end
=
sign
.
length
();
}
@SuppressWarnings
(
"unchecked"
)
public
static
SignatureParser
fromNode
(
IAttributeNode
node
)
{
Annotation
a
=
node
.
getAttributes
().
getAnnotation
(
Consts
.
DALVIK_SIGNATURE
);
if
(
a
==
null
)
{
return
null
;
}
return
new
SignatureParser
(
mergeSignature
((
List
<
String
>)
a
.
getDefaultValue
()));
}
private
char
next
()
{
pos
++;
if
(
pos
>=
end
)
{
return
STOP_CHAR
;
}
return
sign
.
charAt
(
pos
);
}
private
boolean
lookAhead
(
char
ch
)
{
int
next
=
pos
+
1
;
return
next
<
end
&&
sign
.
charAt
(
next
)
==
ch
;
}
private
void
mark
()
{
mark
=
pos
;
}
/**
* Exclusive slice.
*
* @return string from 'mark' to current position (not including current character)
*/
private
String
slice
()
{
if
(
mark
>=
pos
)
{
return
""
;
}
return
sign
.
substring
(
mark
,
pos
);
}
/**
* Inclusive slice (includes current character)
*/
private
String
inclusiveSlice
()
{
if
(
mark
>=
pos
)
{
return
""
;
}
return
sign
.
substring
(
mark
,
pos
+
1
);
}
private
boolean
forwardTo
(
char
lastChar
)
{
int
startPos
=
pos
;
char
ch
;
while
((
ch
=
next
())
!=
STOP_CHAR
)
{
if
(
ch
==
lastChar
)
{
return
true
;
}
}
pos
=
startPos
;
return
false
;
}
private
void
consume
(
char
exp
)
{
char
c
=
next
();
if
(
exp
!=
c
)
{
throw
new
JadxRuntimeException
(
"Consume wrong char: '"
+
c
+
"' != '"
+
exp
+
"', sign: "
+
debugString
());
}
}
private
boolean
tryConsume
(
char
exp
)
{
if
(
lookAhead
(
exp
))
{
next
();
return
true
;
}
return
false
;
}
private
String
consumeUntil
(
char
lastChar
)
{
mark
();
return
forwardTo
(
lastChar
)
?
slice
()
:
null
;
}
public
ArgType
consumeType
()
{
char
ch
=
next
();
mark
();
switch
(
ch
)
{
case
'L'
:
ArgType
obj
=
consumeObjectType
(
false
);
if
(
obj
!=
null
)
{
return
obj
;
}
break
;
case
'T'
:
next
();
mark
();
if
(
forwardTo
(
';'
))
{
return
ArgType
.
genericType
(
slice
());
}
break
;
case
'['
:
return
ArgType
.
array
(
consumeType
());
case
STOP_CHAR:
return
null
;
default
:
// primitive type (one char)
ArgType
type
=
ArgType
.
parse
(
ch
);
if
(
type
!=
null
)
{
return
type
;
}
break
;
}
throw
new
JadxRuntimeException
(
"Can't parse type: "
+
debugString
());
}
private
ArgType
consumeObjectType
(
boolean
incompleteType
)
{
mark
();
int
ch
;
do
{
ch
=
next
();
if
(
ch
==
STOP_CHAR
)
{
return
null
;
}
}
while
(
ch
!=
'<'
&&
ch
!=
';'
);
if
(
ch
==
';'
)
{
return
ArgType
.
object
(
incompleteType
?
slice
()
:
inclusiveSlice
());
}
else
{
// generic type start ('<')
String
obj
=
slice
();
if
(!
incompleteType
)
{
obj
+=
";"
;
}
ArgType
[]
genArr
=
consumeGenericArgs
();
consume
(
'>'
);
ArgType
genericType
=
ArgType
.
generic
(
obj
,
genArr
);
if
(
lookAhead
(
'.'
))
{
consume
(
'.'
);
next
();
// type parsing not completed, proceed to inner class
ArgType
inner
=
consumeObjectType
(
true
);
return
ArgType
.
genericInner
(
genericType
,
inner
.
getObject
(),
inner
.
getGenericTypes
());
}
else
{
consume
(
';'
);
return
genericType
;
}
}
}
private
ArgType
[]
consumeGenericArgs
()
{
List
<
ArgType
>
list
=
new
ArrayList
<
ArgType
>(
1
);
ArgType
type
;
do
{
if
(
lookAhead
(
'*'
))
{
next
();
type
=
ArgType
.
wildcard
();
}
else
if
(
lookAhead
(
'+'
))
{
next
();
type
=
ArgType
.
wildcard
(
consumeType
(),
1
);
}
else
if
(
lookAhead
(
'-'
))
{
next
();
type
=
ArgType
.
wildcard
(
consumeType
(),
-
1
);
}
else
{
type
=
consumeType
();
}
if
(
type
!=
null
)
{
list
.
add
(
type
);
}
}
while
(
type
!=
null
&&
!
lookAhead
(
'>'
));
return
list
.
toArray
(
new
ArgType
[
list
.
size
()]);
}
/**
* Map of generic types names to extends classes.
* <p/>
* Example: "<T:Ljava/lang/Exception;:Ljava/lang/Object;>"
*/
public
Map
<
ArgType
,
List
<
ArgType
>>
consumeGenericMap
()
{
if
(!
lookAhead
(
'<'
))
{
return
null
;
}
Map
<
ArgType
,
List
<
ArgType
>>
map
=
new
LinkedHashMap
<
ArgType
,
List
<
ArgType
>>(
2
);
consume
(
'<'
);
while
(
true
)
{
if
(
lookAhead
(
'>'
)
||
next
()
==
STOP_CHAR
)
{
break
;
}
String
id
=
consumeUntil
(
':'
);
tryConsume
(
':'
);
List
<
ArgType
>
types
=
consumeExtendsTypesList
();
map
.
put
(
ArgType
.
genericType
(
id
),
types
);
}
consume
(
'>'
);
return
map
;
}
/**
* List of types separated by ':' last type is 'java.lang.Object'.
* <p/>
* Example: "Ljava/lang/Exception;:Ljava/lang/Object;"
*/
private
List
<
ArgType
>
consumeExtendsTypesList
()
{
List
<
ArgType
>
types
=
Collections
.
emptyList
();
boolean
next
;
do
{
ArgType
argType
=
consumeType
();
if
(!
argType
.
equals
(
ArgType
.
OBJECT
))
{
if
(
types
.
isEmpty
())
{
types
=
new
LinkedList
<
ArgType
>();
}
types
.
add
(
argType
);
}
next
=
lookAhead
(
':'
);
if
(
next
)
{
consume
(
':'
);
}
}
while
(
next
);
return
types
;
}
public
List
<
ArgType
>
consumeMethodArgs
()
{
consume
(
'('
);
if
(
lookAhead
(
')'
))
{
consume
(
')'
);
return
Collections
.
emptyList
();
}
List
<
ArgType
>
args
=
new
LinkedList
<
ArgType
>();
do
{
args
.
add
(
consumeType
());
}
while
(!
lookAhead
(
')'
));
consume
(
')'
);
return
args
;
}
private
static
String
mergeSignature
(
List
<
String
>
list
)
{
if
(
list
.
size
()
==
1
)
{
return
list
.
get
(
0
);
}
StringBuilder
sb
=
new
StringBuilder
();
for
(
String
s
:
list
)
{
sb
.
append
(
s
);
}
return
sb
.
toString
();
}
private
String
debugString
()
{
return
sign
+
" at position "
+
pos
+
" ('"
+
sign
.
charAt
(
pos
)
+
"')"
;
}
@Override
public
String
toString
()
{
if
(
pos
==
-
1
)
{
return
sign
;
}
return
sign
.
substring
(
0
,
mark
)
+
'{'
+
sign
.
substring
(
mark
,
pos
)
+
'}'
+
sign
.
substring
(
pos
);
}
}
jadx-core/src/main/java/jadx/core/utils/Utils.java
View file @
47d65fcd
...
...
@@ -6,13 +6,10 @@ import java.io.File;
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
import
java.util.Iterator
;
import
java.util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
Utils
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
Utils
.
class
);
private
Utils
()
{
}
public
static
String
cleanObjectName
(
String
obj
)
{
int
last
=
obj
.
length
()
-
1
;
...
...
@@ -97,34 +94,6 @@ public class Utils {
return
sw
.
getBuffer
().
toString
();
}
public
static
String
mergeSignature
(
List
<
String
>
list
)
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
String
s
:
list
)
{
sb
.
append
(
s
);
}
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
void
makeDirsForFile
(
File
file
)
{
File
dir
=
file
.
getParentFile
();
if
(!
dir
.
exists
())
{
...
...
jadx-core/src/test/java/jadx/core/dex/nodes/parser/TestSignatureParser.java
0 → 100644
View file @
47d65fcd
package
jadx
.
core
.
dex
.
nodes
.
parser
;
import
jadx.core.dex.instructions.args.ArgType
;
import
java.util.List
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
public
class
TestSignatureParser
{
private
SignatureParser
p
(
String
str
)
{
return
new
SignatureParser
(
str
);
}
@Test
public
void
testType
()
{
assertEquals
(
p
(
""
).
consumeType
(),
null
);
assertEquals
(
p
(
"I"
).
consumeType
(),
ArgType
.
INT
);
assertEquals
(
p
(
"[I"
).
consumeType
(),
ArgType
.
array
(
ArgType
.
INT
));
assertEquals
(
p
(
"Ljava/lang/Object;"
).
consumeType
(),
ArgType
.
OBJECT
);
assertEquals
(
p
(
"[Ljava/lang/Object;"
).
consumeType
(),
ArgType
.
array
(
ArgType
.
OBJECT
));
assertEquals
(
p
(
"[[I"
).
consumeType
(),
ArgType
.
array
(
ArgType
.
array
(
ArgType
.
INT
)));
}
@Test
public
void
testType2
()
{
assertEquals
(
p
(
"TD;"
).
consumeType
(),
ArgType
.
genericType
(
"D"
));
}
@Test
public
void
testGenericType
()
{
assertEquals
(
p
(
"La<TV;Lb;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
genericType
(
"V"
),
ArgType
.
object
(
"b"
)}));
assertEquals
(
p
(
"La<Lb<Lc;>;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
generic
(
"Lb;"
,
new
ArgType
[]{
ArgType
.
object
(
"Lc;"
)})}));
}
@Test
public
void
testGenericInnerType
()
{
assertEquals
(
p
(
"La<TD;>.c;"
).
consumeType
(),
ArgType
.
genericInner
(
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
genericType
(
"D"
)}),
"c"
,
null
));
assertEquals
(
p
(
"La<Lb;>.c<TV;>;"
).
consumeType
(),
ArgType
.
genericInner
(
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
object
(
"Lb;"
)}),
"c"
,
new
ArgType
[]{
ArgType
.
genericType
(
"V"
)}));
assertEquals
(
p
(
"La<TV;>.LinkedHashIterator<Lb$c<Ls;TV;>;>;"
).
consumeType
().
getObject
(),
"a.LinkedHashIterator"
);
}
@Test
public
void
testWildCards
()
{
assertEquals
(
p
(
"La<*>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
()}));
assertEquals
(
p
(
"La<+Lb;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(
ArgType
.
object
(
"b"
),
1
)}));
assertEquals
(
p
(
"La<-Lb;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(
ArgType
.
object
(
"b"
),
-
1
)}));
assertEquals
(
p
(
"La<+TV;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(
ArgType
.
genericType
(
"V"
),
1
)}));
assertEquals
(
p
(
"La<-TV;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(
ArgType
.
genericType
(
"V"
),
-
1
)}));
}
@Test
public
void
testWildCards2
()
{
assertEquals
(
p
(
"La<*>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
()}));
assertEquals
(
p
(
"La<**>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(),
ArgType
.
wildcard
()}));
assertEquals
(
p
(
"La<*Lb;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(),
ArgType
.
object
(
"b"
)}));
assertEquals
(
p
(
"La<*TV;>;"
).
consumeType
(),
ArgType
.
generic
(
"La;"
,
new
ArgType
[]{
ArgType
.
wildcard
(),
ArgType
.
genericType
(
"V"
)}));
}
@Test
public
void
testGenericMap
()
{
assertEquals
(
p
(
"<T:Ljava/lang/Object;>"
).
consumeGenericMap
().
toString
(),
"{T=[]}"
);
assertEquals
(
p
(
"<K:Ljava/lang/Object;LongGenericType:Ljava/lang/Object;>"
).
consumeGenericMap
().
toString
(),
"{K=[], LongGenericType=[]}"
);
assertEquals
(
p
(
"<ResultT:Ljava/lang/Exception;:Ljava/lang/Object;>"
).
consumeGenericMap
().
toString
(),
"{ResultT=[java.lang.Exception]}"
);
}
@Test
public
void
testMethodsArgs
()
{
List
<
ArgType
>
argTypes
=
p
(
"(Ljava/util/List<*>;)V"
).
consumeMethodArgs
();
assertEquals
(
argTypes
.
size
(),
1
);
assertEquals
(
argTypes
.
get
(
0
),
ArgType
.
generic
(
"Ljava/util/List;"
,
new
ArgType
[]{
ArgType
.
wildcard
()}));
}
}
jadx-core/src/test/java/jadx/tests/internal/generics/TestGenerics.java
0 → 100644
View file @
47d65fcd
package
jadx
.
tests
.
internal
.
generics
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
java.util.List
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestGenerics
extends
InternalJadxTest
{
public
static
class
TestCls
{
class
A
{
}
public
static
void
mthWildcard
(
List
<?>
list
)
{
}
public
static
void
mthExtends
(
List
<?
extends
A
>
list
)
{
}
public
static
void
mthSuper
(
List
<?
super
A
>
list
)
{
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
System
.
out
.
println
(
code
);
assertThat
(
code
,
containsString
(
"mthWildcard(List<?> list)"
));
assertThat
(
code
,
containsString
(
"mthExtends(List<? extends A> list)"
));
assertThat
(
code
,
containsString
(
"mthSuper(List<? super A> list)"
));
}
}
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