Skip to content

Commit 17c8cdc

Browse files
Dominik Helmmaximilianruesch
authored andcommitted
Use string analysis for more strings in reflect analysis
1 parent ae96b1f commit 17c8cdc

File tree

10 files changed

+203
-271
lines changed

10 files changed

+203
-271
lines changed

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/MatcherUtil.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import org.opalj.br.ClassType
1010
import org.opalj.br.FieldTypes
1111
import org.opalj.br.analyses.SomeProject
1212
import org.opalj.br.fpcf.properties.Context
13+
import org.opalj.br.fpcf.properties.string.StringTreeConst
14+
import org.opalj.br.fpcf.properties.string.StringTreeNode
1315
import org.opalj.fpcf.Entity
1416
import org.opalj.fpcf.PropertyStore
1517

@@ -86,29 +88,27 @@ object MatcherUtil {
8688
* provides allocation sites of Strings to be used as the method name.
8789
*/
8890
private[reflection] def retrieveNameBasedMethodMatcher(
91+
pc: Int,
92+
value: V,
8993
context: Context,
90-
expr: V,
9194
depender: Entity,
92-
pc: Int,
93-
stmts: Array[Stmt[V]],
94-
failure: () => Unit
95+
stmts: Array[Stmt[V]]
9596
)(
9697
implicit
97-
typeIterator: TypeIterator,
9898
state: TypeIteratorState,
9999
ps: PropertyStore,
100100
incompleteCallSites: IncompleteCallSites,
101101
highSoundness: Boolean
102102
): MethodMatcher = {
103-
val names = StringUtil.getPossibleStrings(expr, context, depender, stmts, failure)
104-
retrieveSuitableMatcher[Set[String]](
105-
Some(names),
103+
val names = StringUtil.getPossibleStrings(pc, value, context, depender, stmts)
104+
retrieveSuitableMatcher[StringTreeNode](
105+
names,
106106
pc,
107107
v => new NameBasedMethodMatcher(v)
108108
)
109109
}
110110

111-
private[reflection] val constructorMatcher = new NameBasedMethodMatcher(Set("<init>"))
111+
private[reflection] val constructorMatcher = new NameBasedMethodMatcher(StringTreeConst("<init>"))
112112

113113
/**
114114
* Given an expression that evaluates to a Class<?> object, creates a MethodMatcher to match

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/MethodHandlesUtil.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.opalj.br.MethodDescriptor
1212
import org.opalj.br.ReferenceType
1313
import org.opalj.br.VoidType
1414
import org.opalj.br.analyses.SomeProject
15+
import org.opalj.br.fpcf.properties.string.StringTreeConst
1516

1617
object MethodHandlesUtil {
1718
// TODO what about the case of an constructor?
@@ -36,7 +37,7 @@ object MethodHandlesUtil {
3637
MethodDescriptor(desc.parameterTypes.tail, desc.returnType)
3738
)
3839
),
39-
new NameBasedMethodMatcher(Set(name)),
40+
new NameBasedMethodMatcher(StringTreeConst(name)),
4041
if (receiver.isArrayType)
4142
new ClassBasedMethodMatcher(
4243
Set(ClassType.Object),

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/MethodMatcher.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ package analyses
66
package cg
77
package reflection
88

9+
import java.util.regex.Pattern
910
import scala.collection.immutable.ArraySeq
1011

1112
import org.opalj.br.ClassHierarchy
1213
import org.opalj.br.ClassType
1314
import org.opalj.br.FieldTypes
1415
import org.opalj.br.Method
1516
import org.opalj.br.MethodDescriptor
16-
import org.opalj.br.analyses.ProjectIndexKey
1717
import org.opalj.br.analyses.SomeProject
18+
import org.opalj.br.fpcf.properties.string.StringTreeNode
1819
import org.opalj.value.IsReferenceValue
1920

2021
/**
@@ -30,17 +31,17 @@ trait MethodMatcher {
3031
def contains(m: Method)(implicit p: SomeProject): Boolean
3132
}
3233

33-
final class NameBasedMethodMatcher(val possibleNames: Set[String]) extends MethodMatcher {
34+
final class NameBasedMethodMatcher(val possibleNames: StringTreeNode) extends MethodMatcher {
35+
val pattern = Pattern.compile(possibleNames.regex)
3436

3537
override def initialMethods(implicit p: SomeProject): Iterator[Method] = {
36-
val projectIndex = p.get(ProjectIndexKey)
37-
possibleNames.iterator.flatMap(projectIndex.findMethods)
38+
p.allMethods.filter(m => pattern.matcher(m.name).matches()).iterator
3839
}
3940

4041
override def priority: Int = 2
4142

4243
override def contains(m: Method)(implicit p: SomeProject): Boolean = {
43-
possibleNames.contains(m.name)
44+
pattern.matcher(m.name).matches()
4445
}
4546
}
4647

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/ReflectionRelatedCallsAnalysis.scala

Lines changed: 61 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.opalj.br.fpcf.properties.cg.Callers
3131
import org.opalj.br.fpcf.properties.cg.ForNameClasses
3232
import org.opalj.br.fpcf.properties.cg.LoadedClasses
3333
import org.opalj.br.fpcf.properties.string.StringConstancyProperty
34+
import org.opalj.br.fpcf.properties.string.StringTreeNode
3435
import org.opalj.collection.immutable.IntTrieSet
3536
import org.opalj.collection.immutable.UIDSet
3637
import org.opalj.fpcf.Entity
@@ -254,8 +255,15 @@ class ClassForNameAnalysis private[analyses] (
254255
callContext: ContextType,
255256
stmts: Array[Stmt[V]]
256257
)(implicit state: State): Unit = {
257-
val possibleClasses =
258-
TypesUtil.getPossibleForNameClasses(pc, className, callContext, stmts, project, allowDynamicStringTrees)
258+
val possibleClasses = TypesUtil.getPossibleForNameClasses(
259+
pc,
260+
className,
261+
callContext,
262+
pc.asInstanceOf[Entity],
263+
stmts,
264+
project,
265+
allowDynamicStringTrees
266+
)
259267
state.addNewLoadedClasses(possibleClasses)
260268
}
261269

@@ -750,7 +758,6 @@ class MethodInvokeAnalysis private[analyses] (
750758
Option[(ValueInformation, IntTrieSet)],
751759
Seq[Option[(ValueInformation, IntTrieSet)]],
752760
Set[MethodMatcher],
753-
V,
754761
Array[Stmt[V]],
755762
V,
756763
ContextType
@@ -770,6 +777,8 @@ class MethodInvokeAnalysis private[analyses] (
770777

771778
val epk = eps.toEPK
772779

780+
implicit val highSoundness: Boolean = HighSoundnessMode("method")
781+
773782
if (epk.pk == ForNameClasses.key) {
774783
val (callPC, receiver, params, matchers, _, _) = state.dependersOf(epk).head.asInstanceOf[classDependerType]
775784

@@ -781,9 +790,22 @@ class MethodInvokeAnalysis private[analyses] (
781790
new ClassBasedMethodMatcher(classes, !matchers.contains(PublicMethodMatcher))
782791

783792
addCalls(state.callContext, callPC, _ => receiver, params, allMatchers)
784-
} else {
785-
implicit val highSoundness: Boolean = HighSoundnessMode("method")
793+
} else if (epk.pk == StringConstancyProperty.key) {
794+
state.dependersOf(epk).foreach {
795+
case depender: nameDependerType @unchecked if depender.isInstanceOf[nameDependerType] =>
796+
val (callPC, actualReceiver, actualParams, matchers, _, _, _) = depender
797+
val nameMatcher = retrieveSuitableMatcher[StringTreeNode](
798+
Some(eps.ub.asInstanceOf[StringConstancyProperty].tree),
799+
callPC,
800+
v => new NameBasedMethodMatcher(v)
801+
)
786802

803+
if (nameMatcher ne NoMethodsMatcher) {
804+
val allMatchers = matchers + getClassMatcher(depender, matchers + nameMatcher)
805+
addCalls(state.callContext, callPC, _ => actualReceiver, actualParams, allMatchers)
806+
}
807+
}
808+
} else {
787809
AllocationsUtil.continuationForAllocation[methodDependerType, ContextType](
788810
eps,
789811
state.callContext,
@@ -796,30 +818,6 @@ class MethodInvokeAnalysis private[analyses] (
796818
addCalls(state.callContext, data._1, _ => data._2, data._3, allMatchers)
797819
}
798820

799-
AllocationsUtil.continuationForAllocation[nameDependerType, ContextType](
800-
eps,
801-
state.callContext,
802-
data => (data._5, data._6),
803-
_.isInstanceOf[(_, _, _, _, _, _, _, _)],
804-
data => {
805-
val allMatchers = data._4 + getClassMatcher(data, data._4)
806-
failure("method", data._1, data._2, data._3, allMatchers)
807-
}
808-
) { (data, _, allocationIndex, stmts) =>
809-
val name = StringUtil.getString(allocationIndex, stmts)
810-
811-
val nameMatcher = retrieveSuitableMatcher[Set[String]](
812-
name.map(Set(_)),
813-
data._1,
814-
v => new NameBasedMethodMatcher(v)
815-
)
816-
817-
if (nameMatcher ne NoMethodsMatcher) {
818-
val allMatchers = data._4 + getClassMatcher(data, data._4 + nameMatcher)
819-
addCalls(state.callContext, data._1, _ => data._2, data._3, allMatchers)
820-
}
821-
}
822-
823821
AllocationsUtil.continuationForAllocation[classDependerType, ContextType](
824822
eps,
825823
state.callContext,
@@ -863,11 +861,11 @@ class MethodInvokeAnalysis private[analyses] (
863861
)(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): MethodMatcher = {
864862
implicit val highSoundness: Boolean = HighSoundnessMode("class")
865863
MatcherUtil.retrieveClassBasedMethodMatcher(
866-
data._8,
867864
data._7,
868-
(data._1, data._2, data._3, matchers, data._7, data._6),
869-
data._1,
870865
data._6,
866+
(data._1, data._2, data._3, matchers, data._6, data._5),
867+
data._1,
868+
data._5,
871869
project,
872870
() => failure("class", data._1, data._2, data._3, matchers),
873871
onlyMethodsExactlyInClass = !matchers.contains(PublicMethodMatcher)
@@ -962,27 +960,20 @@ class MethodInvokeAnalysis private[analyses] (
962960
if (isGetMethod)
963961
matchers += PublicMethodMatcher
964962

965-
var failed: String = null
966-
967-
val depender =
968-
(callPC, actualReceiver, actualParams, matchers, params.head.asVar, stmts, receiver.asVar, context)
963+
val depender = (callPC, actualReceiver, actualParams, matchers, stmts, receiver.asVar, context)
969964

970965
if (!matchers.contains(NoMethodsMatcher))
971966
matchers += MatcherUtil.retrieveNameBasedMethodMatcher(
972-
context,
967+
callPC,
973968
params.head.asVar,
969+
context,
974970
depender,
975-
callPC,
976-
stmts,
977-
() => failed = "method"
971+
stmts
978972
)
979973

980974
if (!matchers.contains(NoMethodsMatcher))
981975
matchers += getClassMatcher(depender, matchers)
982976

983-
if (failed ne null)
984-
failure("method", callPC, actualReceiver, actualParams, matchers)
985-
986977
/*case ArrayLoad(_, _, arrayRef) =>*/
987978
// TODO here we can handle getMethods
988979

@@ -1087,7 +1078,6 @@ class MethodHandleInvokeAnalysis private[analyses] (
10871078
Boolean,
10881079
Seq[Option[(ValueInformation, IntTrieSet)]],
10891080
Set[MethodMatcher],
1090-
V,
10911081
Array[Stmt[V]],
10921082
V,
10931083
ContextType
@@ -1101,6 +1091,8 @@ class MethodHandleInvokeAnalysis private[analyses] (
11011091

11021092
val epk = eps.toEPK
11031093

1094+
implicit val highSoundness: Boolean = HighSoundnessMode("method")
1095+
11041096
if (epk.pk == ForNameClasses.key) {
11051097
val (callPC, isVirtual, params, matchers, _, _) = state.dependersOf(epk).head.asInstanceOf[classDependerType]
11061098

@@ -1113,9 +1105,24 @@ class MethodHandleInvokeAnalysis private[analyses] (
11131105
val allMatchers = matchers + new ClassBasedMethodMatcher(classes, false)
11141106

11151107
addCalls(state.callContext, callPC, allMatchers, params)
1116-
} else {
1117-
implicit val highSoundness: Boolean = HighSoundnessMode("method")
1108+
} else if (epk.pk == StringConstancyProperty.key) {
1109+
state.dependersOf(epk).foreach {
1110+
case depender: nameDependerType @unchecked if depender.isInstanceOf[nameDependerType] =>
1111+
val (callPC, _, actualParams, previousMatchers, _, _, _) = depender
11181112

1113+
val nameMatcher = retrieveSuitableMatcher[StringTreeNode](
1114+
Some(eps.ub.asInstanceOf[StringConstancyProperty].tree),
1115+
callPC,
1116+
v => new NameBasedMethodMatcher(v)
1117+
)
1118+
1119+
if (nameMatcher ne NoMethodsMatcher) {
1120+
val matchers = previousMatchers + nameMatcher
1121+
val allMatchers = matchers + getClassMatcher(depender, matchers)
1122+
addCalls(state.callContext, callPC, allMatchers, actualParams)
1123+
}
1124+
}
1125+
} else {
11191126
AllocationsUtil.continuationForAllocation[methodHandleDependerType, ContextType](
11201127
eps,
11211128
state.callContext,
@@ -1136,31 +1143,6 @@ class MethodHandleInvokeAnalysis private[analyses] (
11361143
addCalls(state.callContext, data._1, allMatchers, data._4)
11371144
}
11381145

1139-
AllocationsUtil.continuationForAllocation[nameDependerType, ContextType](
1140-
eps,
1141-
state.callContext,
1142-
data => (data._5, data._6),
1143-
_.isInstanceOf[(_, _, _, _, _, _, _, _)],
1144-
data => {
1145-
val allMatchers = data._4 + getClassMatcher(data, data._4)
1146-
failure("method", data._1, data._3, allMatchers)
1147-
}
1148-
) { (data, _, allocationIndex, stmts) =>
1149-
val name = StringUtil.getString(allocationIndex, stmts)
1150-
1151-
val nameMatcher = retrieveSuitableMatcher[Set[String]](
1152-
name.map(Set(_)),
1153-
data._1,
1154-
v => new NameBasedMethodMatcher(v)
1155-
)
1156-
1157-
if (nameMatcher ne NoMethodsMatcher) {
1158-
val matchers = data._4 + nameMatcher
1159-
val allMatchers = matchers + getClassMatcher(data, matchers)
1160-
addCalls(state.callContext, data._1, allMatchers, data._3)
1161-
}
1162-
}
1163-
11641146
AllocationsUtil.continuationForAllocation[classDependerType, ContextType](
11651147
eps,
11661148
state.callContext,
@@ -1201,11 +1183,11 @@ class MethodHandleInvokeAnalysis private[analyses] (
12011183
)(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): MethodMatcher = {
12021184
implicit val highSoundness: Boolean = HighSoundnessMode("class")
12031185
MatcherUtil.retrieveClassBasedMethodMatcher(
1204-
data._8,
12051186
data._7,
1206-
(data._1, data._2, data._3, matchers, data._7, data._6),
1207-
data._1,
12081187
data._6,
1188+
(data._1, data._2, data._3, matchers, data._6, data._5),
1189+
data._1,
1190+
data._5,
12091191
project,
12101192
() => failure("class", data._1, data._3, matchers),
12111193
onlyMethodsExactlyInClass = false,
@@ -1409,12 +1391,11 @@ class MethodHandleInvokeAnalysis private[analyses] (
14091391
matchers +=
14101392
(if (isConstructor) MatcherUtil.constructorMatcher
14111393
else MatcherUtil.retrieveNameBasedMethodMatcher(
1412-
context,
1413-
name,
1414-
(callPC, isVirtual, persistentActualParams, matchers, name, stmts, refc, context),
14151394
callPC,
1416-
stmts,
1417-
() => failure("method", callPC, persistentActualParams, matchers)
1395+
name,
1396+
context,
1397+
(callPC, isVirtual, persistentActualParams, matchers, stmts, refc, context),
1398+
stmts
14181399
))
14191400
}
14201401
if (!matchers.contains(NoMethodsMatcher))
@@ -1445,7 +1426,7 @@ class MethodHandleInvokeAnalysis private[analyses] (
14451426
onlyMethodsExactlyInClass = false
14461427
)
14471428
else {
1448-
val data = (callPC, isVirtual, persistentActualParams, matchers, name, stmts, refc, context)
1429+
val data = (callPC, isVirtual, persistentActualParams, matchers, stmts, refc, context)
14491430
matchers += getClassMatcher(data, matchers)
14501431
}
14511432
}

0 commit comments

Comments
 (0)