mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 05:21:29 +07:00
[http-client, microservices-jvm] IJPL-179625 The URL part of MicroservicesJvm was moved to Java
Because HttpClient will be in Android Studio. It needs access to this API to have implementations of HTTP clients (Ktor, Retrofit, OkHttp) in Android Studio. GitOrigin-RevId: 30771b08ec0a1642ca010cde8513703abc0f7b0f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6a2baf2c5a
commit
f3df8ba421
@@ -33,5 +33,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.editor.ex" />
|
||||
<orderEntry type="module" module-name="intellij.java.codeserver.highlighting" />
|
||||
<orderEntry type="module" module-name="intellij.java.codeserver.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.refactoring" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -353,5 +353,17 @@
|
||||
<optionController implementation="com.intellij.codeInsight.NullableNotNullManagerImpl$Provider"/>
|
||||
|
||||
<lang.jvm.annotations.marker.suppressor implementation="com.intellij.java.JavaNonCodeAnnotationsMarkerSuppressor"/>
|
||||
|
||||
<!--Microservices Url-->
|
||||
<microservices.urlInlayLanguagesProvider implementation="com.intellij.microservices.jvm.url.UastUrlPathInlayLanguagesProvider"/>
|
||||
|
||||
<completion.contributor language="UAST"
|
||||
implementationClass="com.intellij.microservices.jvm.url.RenameableSemElementCompletionContributor"/>
|
||||
|
||||
<nameSuggestionProvider implementation="com.intellij.microservices.jvm.url.RenameableSemElementNameSuggestionProvider"/>
|
||||
|
||||
<referenceInjector implementation="com.intellij.microservices.jvm.url.HttpUrlReferenceInjector"/>
|
||||
<referenceInjector implementation="com.intellij.microservices.jvm.url.WSUrlReferenceInjector"/>
|
||||
<referenceInjector implementation="com.intellij.microservices.jvm.url.HttpMethodReferenceInjector"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
inject.http.url.reference=HTTP URL Reference
|
||||
inject.http.ws.reference=WebSocket URL Reference
|
||||
inject.http.method.reference=HTTP Method Reference
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.microservices.http.HttpMethodReference
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.ElementManipulators
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.injection.ReferenceInjector
|
||||
import com.intellij.util.ProcessingContext
|
||||
import javax.swing.Icon
|
||||
|
||||
internal class HttpMethodReferenceInjector : ReferenceInjector() {
|
||||
override fun getId(): String = "http-method-reference"
|
||||
|
||||
override fun getDisplayName(): String = MicroservicesJvmUrlBundle.message("inject.http.method.reference")
|
||||
|
||||
override fun getIcon(): Icon = AllIcons.Nodes.PpWeb
|
||||
|
||||
override fun getReferences(element: PsiElement, context: ProcessingContext, range: TextRange): Array<PsiReference> {
|
||||
return arrayOf(HttpMethodReference(element, ElementManipulators.getValueTextRange(element)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.DynamicBundle
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
import java.util.function.Supplier
|
||||
|
||||
@NonNls
|
||||
private const val BUNDLE = "messages.MicroservicesJvmUrlBundle"
|
||||
|
||||
internal object MicroservicesJvmUrlBundle {
|
||||
private val instance = DynamicBundle(MicroservicesJvmUrlBundle::class.java, BUNDLE)
|
||||
|
||||
fun message(key: @PropertyKey(resourceBundle = BUNDLE) String, vararg params: Any ): @Nls String {
|
||||
return instance.getMessage(key, *params)
|
||||
}
|
||||
|
||||
fun lazyMessage(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): Supplier<@Nls String> {
|
||||
return instance.getLazyMessage(key, *params)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.microservices.url.parameters.RenameableSemElement
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parents
|
||||
import com.intellij.semantic.SemService
|
||||
import com.intellij.util.Plow
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
class RenameableSemElementCompletionContributor : CompletionContributor() {
|
||||
init {
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), object : CompletionProvider<CompletionParameters>() {
|
||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||
val position = parameters.position
|
||||
getParameterNameVariants(position)
|
||||
?.processWith { e -> result.addElement(e); !result.isStopped }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getParameterNameVariants(position: PsiElement): Plow<LookupElement>? {
|
||||
val semService = SemService.getSemService(position.project)
|
||||
return position.parents(true).take(2)
|
||||
.mapNotNull { semService.getSemElement(RenameableSemElement.RENAMEABLE_SEM_KEY, it) }
|
||||
.firstOrNull()
|
||||
?.nameVariants
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo
|
||||
import com.intellij.refactoring.rename.NameSuggestionProvider
|
||||
|
||||
internal class RenameableSemElementNameSuggestionProvider : NameSuggestionProvider {
|
||||
override fun getSuggestedNames(element: PsiElement, nameSuggestionContext: PsiElement?, result: MutableSet<String>): SuggestedNameInfo? {
|
||||
getParameterNameVariants(element)?.map { it.lookupString }?.collectTo(result)
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:JvmName("UastReferenceInjectorUtils")
|
||||
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.microservices.url.references.UrlPathReferenceInjector
|
||||
import com.intellij.microservices.url.references.UrlPksParser
|
||||
import com.intellij.microservices.url.references.UrlSegmentReferenceTarget
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.UastReferenceProvider
|
||||
import com.intellij.psi.getRequestedPsiElement
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.expressions.UStringConcatenationsFacade
|
||||
|
||||
@JvmOverloads
|
||||
fun uastUrlPathReferenceInjectorForScheme(schemes: List<String>,
|
||||
parser: UrlPksParser = UrlPksParser()): UrlPathReferenceInjector<UExpression> =
|
||||
UrlPathReferenceInjector.forPartialStringFrom<UExpression>(parser) { uElement ->
|
||||
val context = getContextExpression(uElement) ?: return@forPartialStringFrom null
|
||||
UStringConcatenationsFacade.createFromUExpression(context)?.asPartiallyKnownString()
|
||||
}.withSchemesSupport(schemes)
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun getContextExpression(uExpression: UExpression): UExpression? =
|
||||
uExpression.withContainingElements.take(2).firstOrNull { child ->
|
||||
child.uastParent.let {
|
||||
it is UCallExpression
|
||||
|| it is UNamedExpression
|
||||
|| it is UVariable
|
||||
|| it is UBinaryExpression && it.operator == UastBinaryOperator.ASSIGN
|
||||
|| (it is UQualifiedReferenceExpression && it.selector is UCallExpression)
|
||||
}
|
||||
} as? UExpression
|
||||
|
||||
fun uastUrlReferenceProvider(schemes: List<String>): UastReferenceProvider {
|
||||
return uastUrlReferenceProvider(
|
||||
uastUrlPathReferenceInjectorForScheme(schemes))
|
||||
}
|
||||
|
||||
fun uastUrlReferenceProvider(injector: UrlPathReferenceInjector<UExpression>): UastReferenceProvider {
|
||||
return UastUrlPathReferenceProvider { uExpression, psiElement ->
|
||||
injector.buildReferences(uExpression).forPsiElement(psiElement)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This provider implements performance-optimisation in order to not contribute UrlPath references when the target element is known and
|
||||
* it is not UrlSegmentReferenceTarget.
|
||||
*/
|
||||
class UastUrlPathReferenceProvider(val provider: (UExpression, PsiElement) -> Array<PsiReference>)
|
||||
: UastReferenceProvider(UExpression::class.java) {
|
||||
|
||||
override fun getReferencesByElement(element: UElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return provider(UExpression::class.java.cast(element), getRequestedPsiElement(context))
|
||||
}
|
||||
|
||||
override fun acceptsTarget(target: PsiElement): Boolean {
|
||||
return target is UrlSegmentReferenceTarget
|
||||
}
|
||||
|
||||
override fun toString(): String = "UastUrlPathReferenceProvider($provider)"
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.microservices.url.inlay.UrlPathInlayLanguagesProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.uast.UastMetaLanguage
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.UastFacade.getPossiblePsiSourceTypes
|
||||
|
||||
private const val SEARCH_LIMIT = 3
|
||||
|
||||
internal class UastUrlPathInlayLanguagesProvider : UrlPathInlayLanguagesProvider {
|
||||
|
||||
private val jamPsiSourceTypes = getPossiblePsiSourceTypes(UClass::class.java, UMethod::class.java)
|
||||
|
||||
private val blockedUExpressionTypes: Collection<Class<*>> = listOf(
|
||||
UQualifiedReferenceExpression::class.java,
|
||||
UClassLiteralExpression::class.java,
|
||||
ULambdaExpression::class.java,
|
||||
UJumpExpression::class.java,
|
||||
UIfExpression::class.java,
|
||||
ULoopExpression::class.java,
|
||||
UTypeReferenceExpression::class.java
|
||||
)
|
||||
|
||||
override val languages: Collection<Language>
|
||||
get() = Language.findInstance(UastMetaLanguage::class.java).matchingLanguages
|
||||
|
||||
override fun getPotentialElementsWithHintsProviders(element: PsiElement): List<PsiElement> {
|
||||
// for JAM
|
||||
if (jamPsiSourceTypes.contains(element.javaClass)) { // do not try to convert every element in big files
|
||||
val uDeclaration = element.toUElementOfExpectedTypes(UClass::class.java, UMethod::class.java)
|
||||
if (uDeclaration != null) {
|
||||
if (uDeclaration.sourcePsi != element) return emptyList()
|
||||
|
||||
val javaPsiElement = uDeclaration.javaPsi
|
||||
if (element == javaPsiElement) {
|
||||
return listOf(element)
|
||||
}
|
||||
return listOfNotNull(element, javaPsiElement)
|
||||
}
|
||||
}
|
||||
|
||||
val uExpression = element.toUElementOfType<UExpression>() ?: return emptyList()
|
||||
if (blockedUExpressionTypes.any { it.isAssignableFrom(uExpression.javaClass) }) {
|
||||
// performance optimization: do not query SEM for `receiver.selector()`, `() -> {}`, control flow expressions
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// currently arguments of call expressions and values of fields are supported
|
||||
if (hasFieldOrExpressionParent(uExpression)) {
|
||||
val uastParent = uExpression.uastParent
|
||||
if (uastParent is UTypeReferenceExpression
|
||||
|| uastParent is UCallableReferenceExpression
|
||||
|| uExpression is ULiteralExpression && (uExpression.isBoolean || uExpression.isNull)) {
|
||||
// no URLs inlay in types, booleans and nulls
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return listOf(element)
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun hasFieldOrExpressionParent(uExpression: UExpression): Boolean {
|
||||
if (uExpression.getUCallExpression(searchLimit = SEARCH_LIMIT) != null) return true
|
||||
|
||||
var u: UElement = uExpression
|
||||
repeat(SEARCH_LIMIT) {
|
||||
if (u is UField) return true
|
||||
u = u.uastParent ?: return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.microservices.url.HTTP_SCHEMES
|
||||
import com.intellij.microservices.url.WS_SCHEMES
|
||||
import com.intellij.microservices.url.references.UrlPathReferenceInjector
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.ElementManipulators
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.injection.ReferenceInjector
|
||||
import com.intellij.psi.util.PartiallyKnownString
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.expressions.UStringConcatenationsFacade
|
||||
import org.jetbrains.uast.toUElementOfType
|
||||
import javax.swing.Icon
|
||||
|
||||
internal abstract class UrlPathReferenceContextInjector : ReferenceInjector() {
|
||||
|
||||
abstract val schemes: List<String>
|
||||
|
||||
protected val injector by lazy {
|
||||
UrlPathReferenceInjector.forPartialStringFrom<PsiElement> { host ->
|
||||
host.toUElementOfType<UExpression>()?.let { uExpression ->
|
||||
return@forPartialStringFrom buildUastPartialString(uExpression)
|
||||
}
|
||||
PartiallyKnownString(ElementManipulators.getValueText(host), host, ElementManipulators.getValueTextRange(host))
|
||||
}.withSchemesSupport(schemes)
|
||||
}
|
||||
|
||||
private fun buildUastPartialString(uExpression: UExpression): PartiallyKnownString? {
|
||||
val uContext = getContextExpression(uExpression) ?: uExpression
|
||||
return UStringConcatenationsFacade.createFromUExpression(uContext)?.asPartiallyKnownString()
|
||||
}
|
||||
|
||||
override fun getReferences(host: PsiElement, context: ProcessingContext, range: TextRange): Array<PsiReference> =
|
||||
injector.buildAbsoluteOrRelativeReferences(host, host)
|
||||
}
|
||||
|
||||
internal class HttpUrlReferenceInjector : UrlPathReferenceContextInjector() {
|
||||
override fun getId(): String = "http-url-reference"
|
||||
|
||||
override fun getDisplayName(): String = MicroservicesJvmUrlBundle.message("inject.http.url.reference")
|
||||
|
||||
override fun getIcon(): Icon = AllIcons.Nodes.PpWeb
|
||||
|
||||
override val schemes: List<String> get() = HTTP_SCHEMES
|
||||
}
|
||||
|
||||
internal class WSUrlReferenceInjector : UrlPathReferenceContextInjector() {
|
||||
override fun getId(): String = "ws-reference"
|
||||
|
||||
override fun getDisplayName(): String = MicroservicesJvmUrlBundle.message("inject.http.ws.reference")
|
||||
|
||||
override val schemes: List<String> get() = WS_SCHEMES
|
||||
|
||||
override fun getIcon(): Icon = AllIcons.Webreferences.WebSocket
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@ApiStatus.Experimental
|
||||
package com.intellij.microservices.jvm.url;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:JvmName("UastUrlInlayHintsUtils")
|
||||
@file:ApiStatus.Experimental
|
||||
|
||||
package com.intellij.microservices.jvm.url
|
||||
|
||||
import com.intellij.microservices.url.inlay.PsiElementUrlPathInlayHint
|
||||
import com.intellij.microservices.url.inlay.UrlPathInlayHint
|
||||
import com.intellij.microservices.url.inlay.UrlPathInlayHintsProviderSemElement
|
||||
import com.intellij.microservices.url.references.UrlPathReferenceInjector
|
||||
import com.intellij.microservices.url.references.forbidExpensiveUrlContext
|
||||
import com.intellij.psi.UastSemProvider
|
||||
import com.intellij.psi.uastSemElementProvider
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.UReferenceExpression
|
||||
import org.jetbrains.uast.expressions.UInjectionHost
|
||||
|
||||
fun urlInlayHintProvider(injector: UrlPathReferenceInjector<UExpression>): UastSemProvider<UrlPathInlayHintsProviderSemElement> {
|
||||
return uastSemElementProvider(listOf(UInjectionHost::class.java, UReferenceExpression::class.java)) { uExpression, _ ->
|
||||
val context = forbidExpensiveUrlContext {
|
||||
val rootContext = injector.defaultRootContextProvider(uExpression)
|
||||
if (!injector.ignoreSubPathContext) rootContext.subContext(injector.toUrlPath(uExpression))
|
||||
else rootContext
|
||||
}
|
||||
|
||||
object : UrlPathInlayHintsProviderSemElement {
|
||||
override val inlayHints: List<UrlPathInlayHint>
|
||||
get() = listOf(PsiElementUrlPathInlayHint(uExpression.sourcePsi!!, context))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user