@@ -18,15 +18,14 @@ package spp.jetbrains.marker.jvm.detect.endpoint
1818
1919import com.intellij.openapi.application.ApplicationManager
2020import com.intellij.openapi.diagnostic.logger
21+ import com.intellij.openapi.util.Key
2122import com.intellij.psi.util.descendants
2223import com.intellij.psi.util.findParentInFile
2324import io.vertx.core.Future
2425import io.vertx.core.Promise
2526import 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
3029import spp.jetbrains.artifact.service.toArtifact
3130import spp.jetbrains.marker.jvm.detect.JVMEndpointDetector
3231import spp.jetbrains.marker.service.getFullyQualifiedName
@@ -38,6 +37,7 @@ class VertxEndpoint : JVMEndpointDetector.JVMEndpointNameDetector {
3837
3938 private val log = logger<VertxEndpoint >()
4039 private val httpMethods = HttpMethod .values().map { it.name() }.toSet()
40+ private val DETECTED_ENDPOINT = Key .create<EndpointDetector .DetectedEndpoint >(" VertxEndpoint.DetectedEndpoint" )
4141
4242 override fun detectEndpointNames (guideMark : GuideMark ): Future <List <EndpointDetector .DetectedEndpoint >> {
4343 if (guideMark !is MethodGuideMark ) {
@@ -52,21 +52,63 @@ class VertxEndpoint : JVMEndpointDetector.JVMEndpointNameDetector {
5252 return @runReadAction
5353 }
5454
55+ var fallbackSearch = false
5556 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 {
5765 it.findParentInFile {
5866 val innerArtifact = it.toArtifact()
5967 if (innerArtifact !is CallArtifact ) return @findParentInFile false
6068 check(innerArtifact)?.let { callers.add(it) }
6169 false
6270 }
6371 }
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+
6483 promise.complete(callers.toSet().toList())
6584 }
6685
6786 return promise.future()
6887 }
6988
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+
70112 private fun check (artifact : CallArtifact ): EndpointDetector .DetectedEndpoint ? {
71113 val routerCall = getRouterCall(artifact) ? : return null
72114 val endpointType = routerCall.getName()!! .uppercase().substringAfter(" ." )
0 commit comments