Skip to content

Commit 9a89ebc

Browse files
authored
Merge pull request #39 from SpringKill-team/dev
Dev
2 parents 717cbdd + f6888b3 commit 9a89ebc

43 files changed

Lines changed: 642 additions & 257 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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/BuildCallGraphAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class BuildCallGraphAction : AnAction() {
5656
project,
5757
method,
5858
uiComponents.progressBar,
59-
uiComponents.infoArea,
59+
uiComponents,
6060
uiComponents.rootListModel,
6161
)
6262

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

Lines changed: 1 addition & 2 deletions
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) {
@@ -57,7 +56,7 @@ class SearchAsSinkAction : AnAction() {
5756
CallGraphSearcher.search(
5857
uiComponents.sourceField,
5958
uiComponents.sinkField,
60-
uiComponents.infoArea,
59+
// uiComponents.infoArea,
6160
uiComponents.searchResultRootNode,
6261
uiComponents.searchResultTreeModel,
6362
project

src/main/kotlin/org/skgroup/securityinspector/analysis/ast/nodes/MethodNode.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.skgroup.securityinspector.analysis.ast.nodes
22

33
import org.skgroup.securityinspector.analysis.ast.SourceSpan
4+
import org.skgroup.securityinspector.enums.RefMode
45

56
/**
67
* Method node 是用于表示方法节点
@@ -19,9 +20,14 @@ data class MethodNode(
1920
val returnType: String,
2021
val parameters: List<ParameterNode>,
2122
val body: List<AstNode> = emptyList(),
23+
val refMode: RefMode,
2224
override val sourceSpan: SourceSpan? = null
2325
) : BaseAstNode(
2426
nodeType = "MethodDeclaration",
2527
children = body,
2628
sourceSpan = sourceSpan
27-
)
29+
){
30+
override fun toString(): String {
31+
return "MethodNode(className='$className', name='$name', returnType='$returnType', parameters=$parameters, body=$body, sourceSpan=$sourceSpan)"
32+
}
33+
}

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

Lines changed: 136 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ package org.skgroup.securityinspector.analysis.graphs.callgraph
33
import com.intellij.openapi.application.ApplicationManager
44
import com.intellij.openapi.project.Project
55
import com.intellij.psi.*
6+
import com.intellij.psi.search.GlobalSearchScope
7+
import com.intellij.psi.search.searches.ClassInheritorsSearch
68
import com.intellij.psi.search.searches.ReferencesSearch
79
import com.intellij.psi.util.PsiTreeUtil
810
import org.skgroup.securityinspector.analysis.ast.nodes.MethodNode
911
import org.skgroup.securityinspector.analysis.di.DIProcessor
12+
import org.skgroup.securityinspector.enums.RefMode
1013
import org.skgroup.securityinspector.utils.GraphUtils
1114
import java.util.ArrayDeque
1215

@@ -44,7 +47,8 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
4447

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

@@ -74,26 +78,58 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
7478
* @param expression 方法调用表达式
7579
*/
7680
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
77-
super.visitMethodCallExpression(expression)
78-
if (currentMethodStack.isEmpty()) {
79-
return
80-
}
81+
if (currentMethodStack.isEmpty()) return
82+
expression.methodExpression.qualifierExpression?.accept(this)
8183

8284
val caller = currentMethodStack.peek()
83-
8485
// 解析被调用的方法
85-
val resolvedMethod = expression.resolveMethod() ?: return
86-
val calleeMethodNode = GraphUtils.getMethodNode(resolvedMethod, expression)
87-
88-
// 将 callee 加入节点集合
89-
callGraph.nodes.add(calleeMethodNode)
90-
91-
// 在 callGraph 中记录调用关系 (caller -> callee)
92-
callGraph.edges
93-
.getOrPut(caller) { mutableSetOf() }
94-
.add(calleeMethodNode)
95-
96-
handleIoCContainerCall(expression, caller, calleeMethodNode)
86+
val resolvedMethod = expression.resolveMethod()
87+
// 调试日志
88+
if (resolvedMethod == null) {
89+
println("method call expression $expression can not be resolve.")
90+
return
91+
}
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
99+
expression.reference?.let {
100+
val calleeMethodNode = GraphUtils.getMethodNode(resolvedMethod, it)
101+
// 将 callee 加入节点集合
102+
callGraph.nodes.add(calleeMethodNode)
103+
// 在 callGraph 中记录调用关系 (caller -> callee)
104+
callGraph.edges
105+
.getOrPut(caller) { mutableSetOf() }
106+
.add(calleeMethodNode)
107+
handleIoCContainerCall(expression, caller, calleeMethodNode)
108+
} ?: run {
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+
// }
119+
if (PsiTreeUtil.getParentOfType(expression, PsiLambdaExpression::class.java) != null) {
120+
println("in lambda method call expression $expression can not resolve reference.")
121+
} else {
122+
println("unknown method call expression $expression can not resolve reference.")
123+
}
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)
131+
}
132+
super.visitMethodCallExpression(expression)
97133
}
98134

99135
/**
@@ -102,24 +138,51 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
102138
* @param expression
103139
*/
104140
override fun visitNewExpression(expression: PsiNewExpression) {
105-
super.visitNewExpression(expression)
106-
if (currentMethodStack.isEmpty()) {
107-
return
108-
}
109-
val callerMethodNode = currentMethodStack.peek()
141+
if (currentMethodStack.isEmpty()) return
142+
// expression.methodNewExpression.qualifierExpression?.accept(this)
110143

144+
val callerMethodNode = currentMethodStack.peek()
111145
// 解析构造方法
112-
val constructor = expression.resolveConstructor() ?: return
113-
val calleeMethodNode = GraphUtils.getMethodNode(constructor, expression)
114-
115-
// 将 callee 加入节点集合
116-
callGraph.nodes.add(calleeMethodNode)
117-
118-
// 在 callGraph 中记录 (caller -> callee构造方法)
119-
callGraph
120-
.edges
121-
.getOrPut(callerMethodNode) { mutableSetOf() }
122-
.add(calleeMethodNode)
146+
val constructor = expression.resolveConstructor()
147+
// 调试日志
148+
if (constructor == null) {
149+
println("new expression $constructor can not be resolve.")
150+
return
151+
}
152+
// val clazz: PsiClass? = constructor.containingClass
153+
expression.reference?.let {
154+
val calleeMethodNode = GraphUtils.getMethodNode(constructor, it)
155+
// 将 callee 加入节点集合
156+
callGraph.nodes.add(calleeMethodNode)
157+
// 在 callGraph 中记录 (caller -> callee构造方法)
158+
callGraph.edges
159+
.getOrPut(callerMethodNode) { mutableSetOf() }
160+
.add(calleeMethodNode)
161+
println("expression $expression resolve reference success.")
162+
} ?: run {
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+
// }
173+
if (PsiTreeUtil.getParentOfType(expression, PsiLambdaExpression::class.java) != null) {
174+
println("in lambda method call expression $expression can not resolve reference.")
175+
} else {
176+
println("unknown new expression $constructor can not resolve reference.")
177+
}
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)
184+
}
185+
super.visitNewExpression(expression)
123186
}
124187

125188
/**
@@ -141,15 +204,20 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
141204
super.visitMethodCallExpression(lambdaCall)
142205
val caller = currentMethodStack.peek()
143206
val resolvedMethod = lambdaCall.resolveMethod() ?: return
144-
val calleeMethodNode = GraphUtils.getLambdaMethodNode(resolvedMethod)
145-
146-
// 将 callee 加入图
147-
callGraph.nodes.add(calleeMethodNode)
148-
149-
// 在 callGraph 中记录调用关系 (caller -> callee)
150-
callGraph.edges
151-
.getOrPut(caller) { mutableSetOf() }
152-
.add(calleeMethodNode)
207+
lambdaCall.children.forEach { child ->
208+
val calleeMethodNode = child.reference?.let {
209+
GraphUtils.getMethodNode(resolvedMethod, it)
210+
} ?: run {
211+
GraphUtils.getLambdaMethodNode(resolvedMethod)
212+
}
213+
callGraph.nodes.add(caller)
214+
calleeMethodNode?.let {
215+
callGraph.nodes.add(it)
216+
callGraph.edges
217+
.getOrPut(caller) { mutableSetOf() }
218+
.add(it)
219+
}
220+
}
153221
}
154222

155223
override fun visitMethodReferenceExpression(expression: PsiMethodReferenceExpression) {
@@ -205,7 +273,8 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
205273
// 其他的慢慢加吧
206274
) {
207275
// 如果是构造方法或者带有此注解的方法,可能被框架在运行时调用
208-
val containerMethodNode = MethodNode("Container", "Container", "Framework", emptyList(), emptyList())
276+
val containerMethodNode =
277+
MethodNode("Container", "Container", "Framework", emptyList(), emptyList(), RefMode.CALL)
209278
callGraph.nodes.add(containerMethodNode)
210279

211280
callGraph.edges
@@ -232,7 +301,7 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
232301
if (qualifierExpression != null && methodName == "getBean") {
233302
// 将容器节点与被调用方法或类做额外的链接
234303
val containerMethodNode =
235-
MethodNode("ApplicationContext", "ApplicationContext", "Spring", emptyList(), emptyList())
304+
MethodNode("ApplicationContext", "ApplicationContext", "Spring", emptyList(), emptyList(), RefMode.CALL)
236305
callGraph.nodes.add(containerMethodNode)
237306
// caller -> container
238307
callGraph.edges
@@ -260,4 +329,26 @@ class CallGraphBuilder : JavaRecursiveElementVisitor() {
260329
return callGraph
261330
}
262331

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+
263354
}

src/main/kotlin/org/skgroup/securityinspector/analysis/graphs/processor/DIProcessor.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import com.intellij.openapi.project.Project
44
import com.intellij.psi.*
55
import com.intellij.psi.search.GlobalSearchScope
66
import com.intellij.psi.search.searches.AnnotatedElementsSearch
7-
import com.intellij.psi.search.searches.ClassInheritorsSearch
87
import com.intellij.psi.util.PsiUtil
98
import org.skgroup.securityinspector.analysis.ast.nodes.MethodNode
109
import org.skgroup.securityinspector.analysis.graphs.callgraph.CallGraph
10+
import org.skgroup.securityinspector.enums.RefMode
1111
import org.skgroup.securityinspector.utils.GraphUtils
1212
import java.util.*
1313

@@ -123,7 +123,7 @@ class DIProcessor(
123123
if (injectionAnnotations.contains(annotation.qualifiedName)) {
124124
// 将容器 -> constructor 关系入图
125125
val constructorNode = GraphUtils.getMethodNode(constructor)
126-
val containerMethodNode = MethodNode("Container","Container", "Framework", emptyList(), emptyList())
126+
val containerMethodNode = MethodNode("Container","Container", "Framework", emptyList(), emptyList(), RefMode.CALL)
127127
callGraph.nodes.add(constructorNode)
128128
callGraph.nodes.add(containerMethodNode)
129129

@@ -217,7 +217,7 @@ class DIProcessor(
217217
GraphUtils.getMethodNode(psiClass)
218218
} else {
219219
// 找不到对应类,做一个兜底处理
220-
MethodNode(type.canonicalText ?: "UnknownType",type.canonicalText ?: "UnknownType", "DI", emptyList(), emptyList())
220+
MethodNode(type.canonicalText ?: "UnknownType",type.canonicalText ?: "UnknownType", "DI", emptyList(), emptyList(),RefMode.CALL)
221221
}
222222
}
223223

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.skgroup.securityinspector.enums
2+
3+
/**
4+
* 枚举描述:RefMode 枚举用于。
5+
*
6+
* @author springkill
7+
* @version 1.0
8+
*/
9+
enum class RefMode(val value: String) {
10+
CALL("call"),
11+
DECLARATION("declaration"),
12+
IMPLEMENTATION("implementation"),
13+
NEW("new"),
14+
}

0 commit comments

Comments
 (0)