Merge #10235 #10236

10235: Update compiler features r=neonaot a=intellij-rust-bot



10236: HINT: Show parameter hints in attribute procedural macros r=vlad20012 a=dima74

<img src="https://user-images.githubusercontent.com/6505554/224586683-bb08b28b-eb35-48b3-a089-a16436a8e771.png" width="350">

changelog: Show parameter hints inside attribute procedural macros

Co-authored-by: intellij-rust-bot <intellij.rust@gmail.com>
Co-authored-by: Dmitry Murzin <diralik@yandex.ru>
diff --git a/src/main/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHints.kt b/src/main/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHints.kt
index 1bee223..637109b 100644
--- a/src/main/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHints.kt
+++ b/src/main/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHints.kt
@@ -9,9 +9,11 @@
 import com.intellij.codeInsight.hints.Option
 import com.intellij.psi.PsiElement
 import org.rust.RsBundle
+import org.rust.ide.hints.type.findExpandedByLeaf
 import org.rust.ide.utils.CallInfo
 import org.rust.lang.core.psi.*
-import org.rust.lang.core.psi.ext.existsAfterExpansion
+import org.rust.lang.core.psi.ext.childOfType
+import org.rust.lang.core.psi.ext.elementType
 import org.rust.lang.core.psi.ext.startOffset
 import org.rust.lang.core.types.emptySubstitution
 import org.rust.stdext.buildList
@@ -22,14 +24,14 @@
     val smart: Boolean get() = smartOption.get()
 
     fun provideHints(elem: PsiElement): List<InlayInfo> {
-        val (callInfo, valueArgumentList) = when (elem) {
-            is RsCallExpr -> (CallInfo.resolve(elem) to elem.valueArgumentList)
-            is RsMethodCall -> (CallInfo.resolve(elem) to elem.valueArgumentList)
-            else -> return emptyList()
-        }
-        if (!elem.existsAfterExpansion) return emptyList()
-        if (callInfo == null) return emptyList()
+        val elementExpanded = findExpandedElement(elem) ?: return emptyList()
+        val callInfo = when (elementExpanded) {
+            is RsCallExpr -> CallInfo.resolve(elementExpanded)
+            is RsMethodCall -> CallInfo.resolve(elementExpanded)
+            else -> null
+        } ?: return emptyList()
 
+        val valueArgumentList = elem.childOfType<RsValueArgumentList>() ?: return emptyList()
         val hints = buildList {
             if (callInfo.selfParameter != null && elem is RsCallExpr) {
                 add(callInfo.selfParameter)
@@ -61,6 +63,18 @@
         return hints.map { (hint, arg) -> InlayInfo("$hint:", arg.startOffset) }
     }
 
+    private fun findExpandedElement(element: PsiElement): PsiElement? {
+        val valueArgumentList = when (element) {
+            is RsCallExpr -> element.valueArgumentList
+            is RsMethodCall -> element.valueArgumentList
+            else -> return null
+        }
+        val valueArgumentListExpanded = valueArgumentList.findExpandedByLeaf { it.lparen } ?: return null
+        if (valueArgumentListExpanded == valueArgumentList) return element
+        if (valueArgumentListExpanded.exprList.size != valueArgumentList.exprList.size) return null
+        return valueArgumentListExpanded.parent.takeIf { it.elementType == element.elementType }
+    }
+
     private fun onlyOneParam(hints: List<Pair<String, RsExpr>>, callInfo: CallInfo, elem: PsiElement): Boolean {
         if (callInfo.selfParameter != null && elem is RsCallExpr && hints.size == 2) {
             return true
diff --git a/src/main/kotlin/org/rust/ide/hints/type/RsInlayTypeHintsProvider.kt b/src/main/kotlin/org/rust/ide/hints/type/RsInlayTypeHintsProvider.kt
index 78f9d06..5402e11 100644
--- a/src/main/kotlin/org/rust/ide/hints/type/RsInlayTypeHintsProvider.kt
+++ b/src/main/kotlin/org/rust/ide/hints/type/RsInlayTypeHintsProvider.kt
@@ -21,6 +21,7 @@
 import com.intellij.psi.util.parentOfTypes
 import org.rust.RsBundle
 import org.rust.lang.RsLanguage
+import org.rust.lang.core.crate.Crate
 import org.rust.lang.core.macros.*
 import org.rust.lang.core.psi.*
 import org.rust.lang.core.psi.ext.*
@@ -171,7 +172,7 @@
                     if (typeReference.descendantOfTypeOrSelf<RsInferType>() == null) return
                 }
 
-                val expandedDeclaration = declaration.getExpanded { it.let } ?: return
+                val expandedDeclaration = declaration.findExpandedByLeaf(crate) { it.let } ?: return
                 if (isExpanded) testAssert { declaration == expandedDeclaration }
                 val inferredType = expandedDeclaration.pat?.type ?: return
                 val formalType = expandedDeclaration.typeReference?.rawType ?: return
@@ -231,7 +232,7 @@
             }
 
             private fun presentTypeForBinding(binding: RsPatBinding, isExpanded: Boolean) {
-                val bindingExpanded = binding.getExpanded { it.identifier } ?: return
+                val bindingExpanded = binding.findExpandedByLeaf(crate) { it.identifier } ?: return
                 if (bindingExpanded.reference.resolve()?.isConstantLike == true) return
                 if (bindingExpanded.type is TyUnknown) return
 
@@ -245,16 +246,6 @@
                 val finalPresentation = presentation.withDisableAction(project)
                 sink.addInlineElement(offset, false, finalPresentation, false)
             }
-
-            private inline fun <reified T : PsiElement> T.getExpanded(getLeaf: (T) -> PsiElement): T? =
-                when (getCodeStatus(crate)) {
-                    RsCodeStatus.CFG_DISABLED -> null
-                    RsCodeStatus.ATTR_PROC_MACRO_CALL -> {
-                        val leafExpanded = getLeaf(this).findExpansionElements()?.singleOrNull()
-                        leafExpanded?.parent as? T
-                    }
-                    else -> this
-                }
         }
     }
 
@@ -325,3 +316,13 @@
     if (originalFile.findElementAt(offset1)?.findExpansionElements()?.size != 1) return null
     return offset1
 }
+
+inline fun <reified T : PsiElement> T.findExpandedByLeaf(explicitCrate: Crate? = null, getLeaf: (T) -> PsiElement): T? =
+    when (getCodeStatus(explicitCrate)) {
+        RsCodeStatus.CFG_DISABLED -> null
+        RsCodeStatus.ATTR_PROC_MACRO_CALL -> {
+            val leafExpanded = getLeaf(this).findExpansionElements()?.singleOrNull()
+            leafExpanded?.parent as? T
+        }
+        else -> this
+    }
diff --git a/src/main/resources/compiler-info/compiler-features.json b/src/main/resources/compiler-info/compiler-features.json
index 42f2dd9..ba5277b 100644
--- a/src/main/resources/compiler-info/compiler-features.json
+++ b/src/main/resources/compiler-info/compiler-features.json
@@ -93,6 +93,7 @@
   {"name":"min_const_generics","state":"accepted","since":"1.51.0"},
   {"name":"min_const_unsafe_fn","state":"accepted","since":"1.33.0"},
   {"name":"more_struct_aliases","state":"accepted","since":"1.16.0"},
+  {"name":"movbe_target_feature","state":"accepted","since":"1.70.0"},
   {"name":"move_ref_pattern","state":"accepted","since":"1.49.0"},
   {"name":"native_link_modifiers","state":"accepted","since":"1.61.0"},
   {"name":"native_link_modifiers_bundle","state":"accepted","since":"1.63.0"},
@@ -197,7 +198,6 @@
   {"name":"ermsb_target_feature","state":"active","since":"1.49.0"},
   {"name":"hexagon_target_feature","state":"active","since":"1.27.0"},
   {"name":"mips_target_feature","state":"active","since":"1.27.0"},
-  {"name":"movbe_target_feature","state":"active","since":"1.34.0"},
   {"name":"powerpc_target_feature","state":"active","since":"1.27.0"},
   {"name":"riscv_target_feature","state":"active","since":"1.45.0"},
   {"name":"rtm_target_feature","state":"active","since":"1.35.0"},
diff --git a/src/test/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHintsProviderTest.kt b/src/test/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHintsProviderTest.kt
index 40346d4..4b38937 100644
--- a/src/test/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHintsProviderTest.kt
+++ b/src/test/kotlin/org/rust/ide/hints/parameter/RsInlayParameterHintsProviderTest.kt
@@ -8,11 +8,12 @@
 import com.intellij.codeInsight.daemon.impl.HintRenderer
 import com.intellij.openapi.vfs.VirtualFileFilter
 import org.intellij.lang.annotations.Language
-import org.rust.MockAdditionalCfgOptions
-import org.rust.RsTestBase
-import org.rust.fileTreeFromText
+import org.rust.*
+import org.rust.ide.experiments.RsExperiments.PROC_MACROS
 import org.rust.lang.core.psi.RsMethodCall
 
+@WithExperimentalFeatures(PROC_MACROS)
+@ProjectDescriptor(WithProcMacroRustProjectDescriptor::class)
 class RsInlayParameterHintsProviderTest : RsTestBase() {
     fun `test fn args`() = checkByText("""
         fn foo(arg: u32, arg2: u32) {}
@@ -230,8 +231,15 @@
         check(inlays.size == 1)
     }
 
-    @Suppress("UnstableApiUsage")
     private fun checkByText(@Language("Rust") code: String, smart: Boolean = true) {
+        check("fn main() {" in code) { "Please use hints inside `fn main` function - needed for testing with attr macros" }
+
+        doTest(code, smart)
+        doTest(code.replace("fn main() {", "#[test_proc_macros::attr_as_is] fn main() {"), smart)
+    }
+
+    @Suppress("UnstableApiUsage")
+    private fun doTest(@Language("Rust") code: String, smart: Boolean) {
         InlineFile(code.replace(HINT_COMMENT_PATTERN, "<$1/>"))
 
         RsInlayParameterHints.smartOption.set(smart)
diff --git a/src/test/kotlin/org/rust/ide/hints/type/RsChainMethodTypeHintsProviderTest.kt b/src/test/kotlin/org/rust/ide/hints/type/RsChainMethodTypeHintsProviderTest.kt
index 7e8958d..3551365 100644
--- a/src/test/kotlin/org/rust/ide/hints/type/RsChainMethodTypeHintsProviderTest.kt
+++ b/src/test/kotlin/org/rust/ide/hints/type/RsChainMethodTypeHintsProviderTest.kt
@@ -157,6 +157,7 @@
     fun `test inside attribute macro call body`() = doTest("""
         $types
 
+        #[test_proc_macros::attr_as_is]
         fn main() {
             let foo = A;
             foo