Skip to content

Commit f6888b3

Browse files
authored
Merge pull request #38 from SpringKill-team/feature/mergesink
feature: Update Gradle version to 2024.3 and enhance method reference…
2 parents a680f59 + 6fb3fd1 commit f6888b3

6 files changed

Lines changed: 105 additions & 45 deletions

File tree

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ dependencies {
2323
// Configure Gradle IntelliJ Plugin
2424
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
2525
intellij {
26-
version.set("2022.3")
26+
version.set("2024.3")
2727
type.set("IU") // Target IDE Platform
2828

2929

src/main/kotlin/org/skgroup/securityinspector/actions/SearchAsSinkAction.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import org.skgroup.securityinspector.ui.service.SecurityInspectorProjectService
1818
*
1919
* @author springkill
2020
* @version 1.0
21-
* @since 2025/3/9
2221
*/
2322
class SearchAsSinkAction : AnAction() {
2423
override fun actionPerformed(e: AnActionEvent) {

src/main/kotlin/org/skgroup/securityinspector/analysis/graphs/callgraph/CallGraphBuilder.kt

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.intellij.openapi.application.ApplicationManager
44
import com.intellij.openapi.project.Project
55
import com.intellij.psi.*
66
import com.intellij.psi.search.GlobalSearchScope
7+
import com.intellij.psi.search.searches.ClassInheritorsSearch
78
import com.intellij.psi.search.searches.ReferencesSearch
89
import com.intellij.psi.util.PsiTreeUtil
910
import org.skgroup.securityinspector.analysis.ast.nodes.MethodNode
@@ -46,8 +47,8 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
4647

4748
// 查找对该方法的所有引用,建立反向调用关系
4849
// TODO 这里的逻辑我自己也混乱了,可能会有问题,后面再看
49-
val scope = GlobalSearchScope.projectScope(method.project)
50-
ReferencesSearch.search(method, scope).forEach { reference ->
50+
val projectScope = GlobalSearchScope.projectScope(method.project)
51+
ReferencesSearch.search(method, projectScope).forEach { reference ->
5152
val callerMethod = PsiTreeUtil.getParentOfType(reference.element, PsiMethod::class.java)
5253
?: return@forEach
5354

@@ -88,10 +89,15 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
8889
println("method call expression $expression can not be resolve.")
8990
return
9091
}
91-
val clazz: PsiClass? = resolvedMethod.containingClass
92+
if (resolvedMethod.hasModifierProperty(PsiModifier.ABSTRACT) || resolvedMethod.containingClass?.isInterface == true) {
93+
findConcreteImplementations(resolvedMethod).forEach { implMethod ->
94+
val implNode = GraphUtils.getMethodNode(implMethod, expression)
95+
callGraph.edges.getOrPut(caller) { mutableSetOf() }.add(implNode)
96+
}
97+
}
98+
// val clazz: PsiClass? = resolvedMethod.containingClass
9299
expression.reference?.let {
93100
val calleeMethodNode = GraphUtils.getMethodNode(resolvedMethod, it)
94-
println("expression $expression resolve reference success.")
95101
// 将 callee 加入节点集合
96102
callGraph.nodes.add(calleeMethodNode)
97103
// 在 callGraph 中记录调用关系 (caller -> callee)
@@ -100,21 +106,28 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
100106
.add(calleeMethodNode)
101107
handleIoCContainerCall(expression, caller, calleeMethodNode)
102108
} ?: run {
103-
if (clazz != null) {
104-
if (clazz.isInterface) {
105-
println("$clazz is an interface")
106-
println("and the method call expression $expression can not resolve reference.")
107-
}
108-
if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
109-
println("$clazz is an abstract class")
110-
println("and the method call expression $expression can not resolve reference.")
111-
}
112-
}
109+
// if (clazz != null) {
110+
// if (clazz.isInterface) {
111+
// println("$clazz is an interface")
112+
// println("and the method call expression $expression can not resolve reference.")
113+
// }
114+
// if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
115+
// println("$clazz is an abstract class")
116+
// println("and the method call expression $expression can not resolve reference.")
117+
// }
118+
// }
113119
if (PsiTreeUtil.getParentOfType(expression, PsiLambdaExpression::class.java) != null) {
114120
println("in lambda method call expression $expression can not resolve reference.")
115121
} else {
116122
println("unknown method call expression $expression can not resolve reference.")
117123
}
124+
val calleeMethodNode = GraphUtils.getMethodNode(resolvedMethod, expression)
125+
callGraph.nodes.add(calleeMethodNode)
126+
// 在 callGraph 中记录调用关系 (caller -> callee)
127+
callGraph.edges
128+
.getOrPut(caller) { mutableSetOf() }
129+
.add(calleeMethodNode)
130+
handleIoCContainerCall(expression, caller, calleeMethodNode)
118131
}
119132
super.visitMethodCallExpression(expression)
120133
}
@@ -136,7 +149,7 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
136149
println("new expression $constructor can not be resolve.")
137150
return
138151
}
139-
val clazz: PsiClass? = constructor.containingClass
152+
// val clazz: PsiClass? = constructor.containingClass
140153
expression.reference?.let {
141154
val calleeMethodNode = GraphUtils.getMethodNode(constructor, it)
142155
// 将 callee 加入节点集合
@@ -147,21 +160,27 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
147160
.add(calleeMethodNode)
148161
println("expression $expression resolve reference success.")
149162
} ?: run {
150-
if (clazz != null) {
151-
if (clazz.isInterface) {
152-
println("$clazz is an interface")
153-
println("and the method call expression $expression can not resolve reference.")
154-
}
155-
if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
156-
println("$clazz is an abstract class")
157-
println("and the method call expression $expression can not resolve referencee.")
158-
}
159-
}
163+
// if (clazz != null) {
164+
// if (clazz.isInterface) {
165+
// println("$clazz is an interface")
166+
// println("and the method call expression $expression can not resolve reference.")
167+
// }
168+
// if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
169+
// println("$clazz is an abstract class")
170+
// println("and the method call expression $expression can not resolve referencee.")
171+
// }
172+
// }
160173
if (PsiTreeUtil.getParentOfType(expression, PsiLambdaExpression::class.java) != null) {
161174
println("in lambda method call expression $expression can not resolve reference.")
162175
} else {
163176
println("unknown new expression $constructor can not resolve reference.")
164177
}
178+
val calleeMethodNode = GraphUtils.getMethodNode(constructor, expression)
179+
callGraph.nodes.add(calleeMethodNode)
180+
// 在 callGraph 中记录调用关系 (caller -> callee)
181+
callGraph.edges
182+
.getOrPut(callerMethodNode) { mutableSetOf() }
183+
.add(calleeMethodNode)
165184
}
166185
super.visitNewExpression(expression)
167186
}
@@ -310,4 +329,26 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
310329
return callGraph
311330
}
312331

332+
private fun findConcreteImplementations(abstractMethod: PsiMethod): List<PsiMethod> {
333+
val implementations = mutableListOf<PsiMethod>()
334+
val containingClass = abstractMethod.containingClass ?: return emptyList()
335+
336+
// 查找所有子类或实现类
337+
val inheritors = if (containingClass.isInterface) {
338+
ClassInheritorsSearch.search(containingClass, abstractMethod.useScope, true).toList()
339+
} else {
340+
ClassInheritorsSearch.search(containingClass).toList()
341+
}
342+
343+
inheritors.forEach { implClass ->
344+
implClass.findMethodBySignature(abstractMethod, true)?.let {
345+
if (!it.hasModifierProperty(PsiModifier.ABSTRACT)) {
346+
implementations.add(it)
347+
}
348+
}
349+
}
350+
351+
return implementations
352+
}
353+
313354
}

src/main/kotlin/org/skgroup/securityinspector/ui/renderer/ResultTreeRenderer.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ class ResultTreeRenderer : DefaultTreeCellRenderer() {
3535
RefMode.NEW -> icon = IconUtil.newIcon
3636
else -> {}
3737
}
38-
"$refMode : ${userObject.name}"
38+
"$refMode : ${
39+
userObject.className.substring(userObject.className.lastIndexOf(".") + 1)
40+
} #${userObject.name}"
3941
}
40-
is String ->{
42+
43+
is String -> {
4144
icon = IconUtil.pathIcon
4245
userObject
4346
}
47+
4448
else -> userObject.toString()
4549
}
4650
}

src/main/kotlin/org/skgroup/securityinspector/ui/service/CallGraphGenerator.kt

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.intellij.openapi.progress.ProgressManager
77
import com.intellij.openapi.progress.Task
88
import com.intellij.openapi.project.Project
99
import com.intellij.openapi.ui.ComboBox
10+
import com.intellij.openapi.vfs.VirtualFile
1011
import com.intellij.psi.*
1112
import com.intellij.psi.search.GlobalSearchScope
1213
import com.intellij.psi.search.ProjectScope
@@ -25,6 +26,10 @@ import java.util.concurrent.CompletableFuture
2526
import javax.swing.*
2627

2728
object CallGraphGenerator {
29+
// 全局唯一已检测方法set
30+
private val processedMethods = mutableSetOf<String>()
31+
private val processedFiles = mutableSetOf<PsiFile>()
32+
2833
fun generate(
2934
project: Project,
3035
progressBar: JProgressBar,
@@ -92,7 +97,9 @@ object CallGraphGenerator {
9297

9398
ApplicationManager.getApplication().runReadAction {
9499
if (psiFile is PsiJavaFile) {
95-
psiFile.accept(builder)
100+
if (processedFiles.add(psiFile)) {
101+
psiFile.accept(builder)
102+
}
96103
}
97104
}
98105

@@ -150,6 +157,9 @@ object CallGraphGenerator {
150157
uiComponents: CallGraphUIComponents,
151158
rootListModel: DefaultListModel<MethodNode>,
152159
) {
160+
val signature =
161+
"${method.containingClass?.qualifiedName}" + "#" + method.name + "(${method.parameterList.parameters.joinToString { it.type.presentableText }})"
162+
if (!processedMethods.add(signature)) return
153163
progressBar.apply {
154164
isVisible = true
155165
isIndeterminate = true
@@ -173,22 +183,28 @@ object CallGraphGenerator {
173183
indicator.text = "Analyzing ${method.name}"
174184

175185
val builder = CallGraphBuilder()
176-
ReferencesSearch.search(method, GlobalSearchScope.projectScope(project)).forEach { reference ->
177-
var callerMethod: PsiMethod = method
178-
ApplicationManager.getApplication().runReadAction {
179-
callerMethod = PsiTreeUtil.getParentOfType(reference.element, PsiMethod::class.java)
180-
?: return@runReadAction
186+
ApplicationManager.getApplication().runReadAction {
187+
ReferencesSearch.search(method, method.resolveScope).forEach { reference ->
188+
var callerMethod: PsiMethod = method
189+
ApplicationManager.getApplication().runReadAction {
190+
// callerMethod = reference.resolve() as PsiMethod
191+
callerMethod = PsiTreeUtil.getParentOfType(reference.element, PsiMethod::class.java)
192+
?: return@runReadAction
193+
}
194+
val callee =
195+
"${callerMethod.containingClass?.qualifiedName}" + "#" + callerMethod.name + "(${callerMethod.parameterList.parameters.joinToString { it.type.presentableText }})"
196+
if (callerMethod != method && !processedMethods.contains(callee)) {
197+
generate(project, callerMethod, progressBar, uiComponents, rootListModel)
198+
}
181199
}
182-
if (callerMethod != method) {
183-
generate(project, callerMethod, progressBar, uiComponents, rootListModel)
200+
if (method.containingFile.virtualFile.path.contains("src/test")) return@runReadAction
201+
ApplicationManager.getApplication().runReadAction {
202+
method.accept(builder)
184203
}
185-
}
186-
ApplicationManager.getApplication().runReadAction {
187-
method.accept(builder)
188-
}
189-
progressBar.string = "Building CallGraph for method ${method.name}"
204+
progressBar.string = "Building CallGraph for method ${method.name}"
190205

191-
tempGraph = builder.getCallGraph(project)
206+
tempGraph = builder.getCallGraph(project)
207+
}
192208
}
193209

194210
override fun onSuccess() {

src/main/kotlin/org/skgroup/securityinspector/utils/GraphUtils.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ object GraphUtils {
4949
* @param methodNode 传入一个 MethodNode 对象
5050
* @return 返回一个字符串,表示方法的签名
5151
*/
52-
fun getMethodSignature(methodNode: MethodNode): String {
52+
private fun getMethodSignature(methodNode: MethodNode): String {
5353
val className = methodNode.className
5454
val methodName = methodNode.name
5555

@@ -200,7 +200,7 @@ object GraphUtils {
200200
val path = mutableListOf<MethodNode>()
201201

202202
fun isMatch(n1: MethodNode, n2: MethodNode): Boolean {
203-
return n1.className == n2.className && n1.name == n2.name
203+
return n1 == n2
204204
}
205205

206206
fun dfs(cur: MethodNode): Boolean {

0 commit comments

Comments
 (0)