@@ -18,15 +18,14 @@ package spp.jetbrains.marker.jvm.detect.endpoint
18
18
19
19
import com.intellij.openapi.application.ApplicationManager
20
20
import com.intellij.openapi.diagnostic.logger
21
+ import com.intellij.openapi.util.Key
21
22
import com.intellij.psi.util.descendants
22
23
import com.intellij.psi.util.findParentInFile
23
24
import io.vertx.core.Future
24
25
import io.vertx.core.Promise
25
26
import io.vertx.core.http.HttpMethod
26
- import spp.jetbrains.artifact.model.ArtifactLiteralValue
27
- import spp.jetbrains.artifact.model.CallArtifact
28
- import spp.jetbrains.artifact.model.FunctionArtifact
29
- import spp.jetbrains.artifact.model.getCallerExpressions
27
+ import spp.jetbrains.artifact.model.*
28
+ import spp.jetbrains.artifact.service.ArtifactScopeService
30
29
import spp.jetbrains.artifact.service.toArtifact
31
30
import spp.jetbrains.marker.jvm.detect.JVMEndpointDetector
32
31
import spp.jetbrains.marker.service.getFullyQualifiedName
@@ -38,6 +37,7 @@ class VertxEndpoint : JVMEndpointDetector.JVMEndpointNameDetector {
38
37
39
38
private val log = logger<VertxEndpoint >()
40
39
private val httpMethods = HttpMethod .values().map { it.name() }.toSet()
40
+ private val DETECTED_ENDPOINT = Key .create<EndpointDetector .DetectedEndpoint >(" VertxEndpoint.DetectedEndpoint" )
41
41
42
42
override fun detectEndpointNames (guideMark : GuideMark ): Future <List <EndpointDetector .DetectedEndpoint >> {
43
43
if (guideMark !is MethodGuideMark ) {
@@ -52,21 +52,63 @@ class VertxEndpoint : JVMEndpointDetector.JVMEndpointNameDetector {
52
52
return @runReadAction
53
53
}
54
54
55
+ var fallbackSearch = false
55
56
val callers = mutableListOf<EndpointDetector .DetectedEndpoint >()
56
- artifact.getCallerExpressions().forEach {
57
+ val callerExpressions = try {
58
+ artifact.getCallerExpressions()
59
+ } catch (e: IllegalArgumentException ) {
60
+ log.warn(" Failed to get caller expressions for ${artifact.getFullyQualifiedName()} " , e)
61
+ fallbackSearch = true
62
+ emptyList()
63
+ }
64
+ callerExpressions.forEach {
57
65
it.findParentInFile {
58
66
val innerArtifact = it.toArtifact()
59
67
if (innerArtifact !is CallArtifact ) return @findParentInFile false
60
68
check(innerArtifact)?.let { callers.add(it) }
61
69
false
62
70
}
63
71
}
72
+
73
+ if (fallbackSearch) {
74
+ // won't be able to search for references in files outside current file
75
+ // instead use regex to search for calls to router.post, router.get, etc
76
+ if (artifact.psiElement.getUserData(DETECTED_ENDPOINT ) != null ) {
77
+ callers.add(artifact.psiElement.getUserData(DETECTED_ENDPOINT )!! )
78
+ } else {
79
+ artifact.getCalls().forEach { checkSimple(it) }
80
+ }
81
+ }
82
+
64
83
promise.complete(callers.toSet().toList())
65
84
}
66
85
67
86
return promise.future()
68
87
}
69
88
89
+ private fun checkSimple (artifact : CallArtifact ) {
90
+ val importRegex = Regex (""" import io\.vertx""" )
91
+ importRegex.find(artifact.containingFile.text) ? : return
92
+
93
+ val regex = Regex (""" router\.([a-zA-Z]+)\("([^"]+)"\)\.handler\(this::([a-zA-Z]+)\)""" )
94
+ val match = regex.matchEntire(artifact.text) ? : return
95
+ val httpMethod = match.groupValues[1 ].uppercase()
96
+ val endpointName = match.groupValues[2 ]
97
+ val referenceMethod = match.groupValues[3 ]
98
+
99
+ val fileFunctions = ArtifactScopeService .getFunctions(artifact.containingFile)
100
+ val refFunction = fileFunctions.firstOrNull { it.name == referenceMethod } ? : return
101
+
102
+ val endpoint = EndpointDetector .DetectedEndpoint (
103
+ " $httpMethod :$endpointName " ,
104
+ false ,
105
+ endpointName,
106
+ httpMethod
107
+ )
108
+ refFunction.putUserData(DETECTED_ENDPOINT , endpoint)
109
+ log.info(" Detected endpoint: $endpoint " )
110
+ }
111
+
70
112
private fun check (artifact : CallArtifact ): EndpointDetector .DetectedEndpoint ? {
71
113
val routerCall = getRouterCall(artifact) ? : return null
72
114
val endpointType = routerCall.getName()!! .uppercase().substringAfter(" ." )
0 commit comments