Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MACRO: Fix macro expansion error messages in several cases #9095

Merged
merged 2 commits into from Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 23 additions & 16 deletions src/main/kotlin/org/rust/lang/core/macros/MacroExpansionManager.kt
Expand Up @@ -26,9 +26,9 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.util.io.DataOutputStream
import com.intellij.util.io.createDirectories
import com.intellij.util.io.delete
Expand All @@ -45,16 +45,14 @@ import org.rust.cargo.project.model.cargoProjects
import org.rust.cargo.project.settings.RustProjectSettingsService
import org.rust.cargo.project.settings.rustSettings
import org.rust.cargo.project.workspace.PackageOrigin
import org.rust.ide.experiments.RsExperiments
import org.rust.ide.experiments.RsExperiments.EVALUATE_BUILD_SCRIPTS
import org.rust.ide.experiments.RsExperiments.PROC_MACROS
import org.rust.lang.RsFileType
import org.rust.lang.core.crate.Crate
import org.rust.lang.core.crate.CratePersistentId
import org.rust.lang.core.crate.crateGraph
import org.rust.lang.core.indexing.RsIndexableSetContributor
import org.rust.lang.core.macros.errors.GetMacroExpansionError
import org.rust.lang.core.macros.errors.MacroExpansionAndParsingError
import org.rust.lang.core.macros.errors.ProcMacroExpansionError
import org.rust.lang.core.macros.errors.toExpansionError
import org.rust.lang.core.macros.errors.*
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.RsProcMacroKind.DERIVE
import org.rust.lang.core.psi.RsProcMacroKind.FUNCTION_LIKE
Expand All @@ -65,6 +63,7 @@ import org.rust.lang.core.resolve2.RsModInfoBase.RsModInfo
import org.rust.openapiext.*
import org.rust.stdext.*
import org.rust.stdext.RsResult.Err
import org.rust.stdext.RsResult.Ok
import org.rust.taskQueue
import java.io.IOException
import java.nio.file.Files
Expand Down Expand Up @@ -219,7 +218,7 @@ class MacroExpansionManagerImpl(
val includingFile = call.findIncludingFile()
?: return@run Err(GetMacroExpansionError.IncludingFileNotFound)
val items = includingFile.stubChildrenOfType<RsExpandedElement>()
RsResult.Ok(MacroExpansion.Items(includingFile, items))
Ok(MacroExpansion.Items(includingFile, items))
}
return CachedValueProvider.Result.create(expansion, call.rustStructureOrAnyPsiModificationTracker)
}
Expand Down Expand Up @@ -711,10 +710,10 @@ private class MacroExpansionServiceImplInner(
val info = getModInfo(call.containingMod) as? RsModInfo
?: return everChanged(Err(GetMacroExpansionError.ModDataNotFound))
val macroIndex = info.getMacroIndex(call, info.crate)
?: return everChanged(Err(getReasonWhyExpansionFileNotFound(call, info.defMap, null)))
?: return everChanged(Err(getReasonWhyExpansionFileNotFound(call, info.crate, info.defMap, null)))
val expansionFile = getExpansionFile(info.defMap, macroIndex)
?: return everChanged(Err(getReasonWhyExpansionFileNotFound(call, info.defMap, macroIndex)))
val expansion = RsResult.Ok(getExpansionFromExpandedFile(MacroExpansionContext.ITEM, expansionFile)!!)
?: return everChanged(Err(getReasonWhyExpansionFileNotFound(call, info.crate, info.defMap, macroIndex)))
val expansion = Ok(getExpansionFromExpandedFile(MacroExpansionContext.ITEM, expansionFile)!!)
return if (call is RsMacroCall) {
CachedValueProvider.Result.create(expansion, modificationTracker, call.modificationTracker)
} else {
Expand Down Expand Up @@ -805,17 +804,25 @@ private class MacroExpansionServiceImplInner(

private fun getReasonWhyExpansionFileNotFound(
call: RsPossibleMacroCall,
crate: Crate,
defMap: CrateDefMap,
callIndex: MacroIndex?
): GetMacroExpansionError {
if (!isFeatureEnabled(RsExperiments.EVALUATE_BUILD_SCRIPTS) || !isFeatureEnabled(RsExperiments.PROC_MACROS)) {
return GetMacroExpansionError.ExpansionError(ProcMacroExpansionError.ProcMacroExpansionIsDisabled)
}
if (!call.existsAfterExpansion) {
if (!call.existsAfterExpansion(crate)) {
return GetMacroExpansionError.CfgDisabled
}
call.resolveToMacroWithoutPsiWithErr()
.unwrapOrElse { return it.toExpansionError() }

val resolveResult = call.resolveToMacroWithoutPsiWithErr()

val isProcMacro = resolveResult is Ok && resolveResult.ok.data is RsProcMacroData
|| resolveResult is Err && resolveResult.err is ResolveMacroWithoutPsiError.NoProcMacroArtifact
val procMacroExpansionIsDisabled = isProcMacro
&& (!isFeatureEnabled(EVALUATE_BUILD_SCRIPTS) || !isFeatureEnabled(PROC_MACROS))
if (procMacroExpansionIsDisabled) {
return GetMacroExpansionError.ExpansionError(ProcMacroExpansionError.ProcMacroExpansionIsDisabled)
}

resolveResult.unwrapOrElse { return it.toExpansionError() }

if (callIndex == null) {
return GetMacroExpansionError.NoMacroIndex
Expand Down
10 changes: 6 additions & 4 deletions src/main/kotlin/org/rust/lang/core/psi/ext/CfgUtils.kt
Expand Up @@ -25,10 +25,12 @@ val PsiElement.isEnabledByCfg: Boolean get() = isEnabledByCfgInner(null)
* ```
*/
val PsiElement.existsAfterExpansion: Boolean
get() {
val status = getCodeStatus(null)
return status == RsCodeStatus.CODE || status == RsCodeStatus.CFG_UNKNOWN
}
get() = existsAfterExpansion(null)

fun PsiElement.existsAfterExpansion(crate: Crate?): Boolean {
val status = getCodeStatus(crate)
return status == RsCodeStatus.CODE || status == RsCodeStatus.CFG_UNKNOWN
}

fun PsiElement.isEnabledByCfg(crate: Crate): Boolean = isEnabledByCfgInner(crate)

Expand Down
5 changes: 4 additions & 1 deletion src/test/kotlin/org/rust/RustProjectDescriptors.kt
Expand Up @@ -372,12 +372,14 @@ object WithDependencyRustProjectDescriptor : RustProjectDescriptorBase() {
)
val depProcMacro2 = externalPackage("$contentRoot/dep-proc-macro-2", "lib.rs", "dep-proc-macro-2", libKind = LibKind.PROC_MACRO,
procMacroArtifact = testProcMacroArtifact2)
val depProcMacro3 = externalPackage("$contentRoot/dep-proc-macro-unsuccessfully-compiled", "lib.rs", "dep-proc-unsuccessfully-compiled", libKind = LibKind.PROC_MACRO,
procMacroArtifact = null)
val cyclicDepLibDevDep = externalPackage("$contentRoot/cyclic-dep-lib-dev-dep", "lib.rs", "cyclic-dep-lib-dev-dep")

val packages = listOf(
testPackage, depLib, depLibNew, depLib2, depLibWithCyclicDep, depLibToBeRenamed,
noSrcLib, noSourceLib, transLib, transLib2, transCommonLib, rawIdentifierLib, depProcMacro, depProcMacro2,
cyclicDepLibDevDep
depProcMacro3, cyclicDepLibDevDep
)

return CargoWorkspace.deserialize(Paths.get("/my-crate/Cargo.toml"), CargoWorkspaceData(packages, mapOf(
Expand All @@ -389,6 +391,7 @@ object WithDependencyRustProjectDescriptor : RustProjectDescriptorBase() {
dep(noSourceLib.id),
dep(depProcMacro.id),
dep(depProcMacro2.id),
dep(depProcMacro3.id),
dep(rawIdentifierLib.id),
),
depLib.id to setOf(
Expand Down
@@ -0,0 +1,64 @@
/*
* Use of this source code is governed by the MIT license that can be
* found in the LICENSE file.
*/

package org.rust.lang.core.macros

import org.intellij.lang.annotations.Language
import org.rust.RsTestBase
import org.rust.fileTreeFromText
import org.rust.lang.core.macros.errors.GetMacroExpansionError
import org.rust.lang.core.psi.ext.RsPossibleMacroCall
import org.rust.lang.core.psi.ext.descendantsOfType
import org.rust.lang.core.psi.ext.expansionResult
import org.rust.lang.core.psi.ext.isMacroCall
import org.rust.stdext.RsResult

abstract class RsMacroExpansionErrorTestBase : RsTestBase() {
protected inline fun <reified T : GetMacroExpansionError> checkError(
@Language("Rust") code: String
) {
checkError(code, T::class.java)
}

protected fun checkError(code: String, errorClass: Class<*>) {
InlineFile(code)
doCheck(errorClass)
}

protected inline fun <reified T : GetMacroExpansionError> checkErrorByTree(
@Language("Rust") code: String
) {
checkError(code, T::class.java)
}

protected fun checkErrorByTree(code: String, errorClass: Class<*>) {
fileTreeFromText(code).createAndOpenFileWithCaretMarker()
doCheck(errorClass)
}

private fun doCheck(errorClass: Class<*>) {
val markers = findElementsWithDataAndOffsetInEditor<RsPossibleMacroCall>()
val (macro, expectedErrorMessage) = if (markers.isEmpty()) {
myFixture.file
.descendantsOfType<RsPossibleMacroCall>()
.single { it.isMacroCall } to null
} else {
val (macro, message, _) = markers.single()
check(macro.isMacroCall)
macro to message
}

val err = when (val result = macro.expansionResult) {
is RsResult.Err -> result.err
is RsResult.Ok -> error("Expected a macro expansion error, got a successfully expanded macro")
}

check(errorClass.isInstance(err)) { "Expected error $errorClass, got $err" }

if (expectedErrorMessage != null) {
assertEquals(expectedErrorMessage, err.toUserViewableMessage())
}
}
}
29 changes: 16 additions & 13 deletions src/test/kotlin/org/rust/lang/core/macros/decl/RsMacroErrorTest.kt
Expand Up @@ -5,24 +5,27 @@

package org.rust.lang.core.macros.decl

import org.intellij.lang.annotations.Language
import org.rust.RsTestBase
import org.rust.lang.core.psi.RsMacroCall
import org.rust.lang.core.psi.ext.descendantsOfType
import org.rust.lang.core.psi.ext.expansion

class RsMacroErrorTestBase : RsTestBase() {
private fun checkNotExpanded(@Language("Rust") code: String) {
InlineFile(code)
val calls = myFixture.file.descendantsOfType<RsMacroCall>()
check(calls.all { it.expansion == null })
}
import org.rust.ExpandMacros
import org.rust.MockAdditionalCfgOptions
import org.rust.lang.core.macros.RsMacroExpansionErrorTestBase
import org.rust.lang.core.macros.errors.GetMacroExpansionError

@ExpandMacros
class RsMacroErrorTest : RsMacroExpansionErrorTestBase() {
// https://github.com/intellij-rust/intellij-rust/pull/2583
fun `test empty group definition`() = checkNotExpanded("""
fun `test empty group definition`() = checkError<GetMacroExpansionError.ExpansionError>("""
macro_rules! foo {
($()* $ i:tt) => { }
}
foo! { bar baz }
""")

@MockAdditionalCfgOptions("intellij_rust")
fun `test cfg disabled top level macro call`() = checkError<GetMacroExpansionError.CfgDisabled>("""
macro_rules! foo {
() => { fn foo() {} }
}
#[cfg(not(intellij_rust))]
foo! {}
""")
}
Expand Up @@ -5,18 +5,12 @@

package org.rust.lang.core.macros.proc

import junit.framework.TestCase
import org.intellij.lang.annotations.Language
import org.rust.*
import org.rust.ide.experiments.RsExperiments.EVALUATE_BUILD_SCRIPTS
import org.rust.ide.experiments.RsExperiments.PROC_MACROS
import org.rust.lang.core.macros.MacroExpansionScope
import org.rust.lang.core.macros.RsMacroExpansionErrorTestBase
import org.rust.lang.core.macros.errors.GetMacroExpansionError
import org.rust.lang.core.psi.ext.RsPossibleMacroCall
import org.rust.lang.core.psi.ext.descendantsOfType
import org.rust.lang.core.psi.ext.expansionResult
import org.rust.lang.core.psi.ext.isMacroCall
import org.rust.stdext.RsResult

/**
* A test for [org.rust.lang.core.macros.errors.GetMacroExpansionError.toUserViewableMessage]
Expand All @@ -27,7 +21,7 @@ import org.rust.stdext.RsResult
@ExpandMacros(MacroExpansionScope.WORKSPACE)
@ProjectDescriptor(WithProcMacroRustProjectDescriptor::class)
@WithExperimentalFeatures(EVALUATE_BUILD_SCRIPTS, PROC_MACROS)
class RsProcMacroErrorTest : RsTestBase() {
class RsProcMacroErrorTest : RsMacroExpansionErrorTestBase() {
@WithExperimentalFeatures()
fun `test macro expansion is disabled`() = checkError<GetMacroExpansionError.ExpansionError>("""
use test_proc_macros::attr_as_is;
Expand All @@ -37,6 +31,45 @@ class RsProcMacroErrorTest : RsTestBase() {
fn foo() {}
""")

@ProjectDescriptor(WithDependencyRustProjectDescriptor::class)
@WithExperimentalFeatures()
fun `test macro expansion is disabled with unsuccessfully compiled proc macro crate`() = checkErrorByTree<GetMacroExpansionError.ExpansionError>("""
//- dep-proc-macro-unsuccessfully-compiled/lib.rs
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn attr_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
compile_error!("The crate with the macro is not compiled successfully");
//- main.rs
use dep_proc_macro_unsuccessfully_compiled::attr_as_is;

#[attr_as_is]
//^ procedural macro expansion is not enabled
fn foo() {}
""")

@ProjectDescriptor(WithDependencyRustProjectDescriptor::class)
fun `test unsuccessfully compiled proc macro crate`() = checkErrorByTree<GetMacroExpansionError.NoProcMacroArtifact>("""
//- dep-proc-macro-unsuccessfully-compiled/lib.rs
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn attr_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
compile_error!("The crate with the macro is not compiled successfully");
//- main.rs
use dep_proc_macro_unsuccessfully_compiled::attr_as_is;

#[attr_as_is]
//^ the procedural macro is not compiled successfully
fn foo() {}
""")

fun `test unresolved function-like macro`() = checkError<GetMacroExpansionError.Unresolved>("""
unresolved_macro! {}
""")
Expand Down Expand Up @@ -76,35 +109,4 @@ class RsProcMacroErrorTest : RsTestBase() {
#[function_like_as_is]
fn foo() {} //^ `FUNCTION_LIKE` proc macro can't be called as `ATTRIBUTE`
""")

private inline fun <reified T : GetMacroExpansionError> checkError(
@Language("Rust") code: String
) {
checkError(code, T::class.java)
}

private fun checkError(code: String, errorClass: Class<*>) {
InlineFile(code)
val markers = findElementsWithDataAndOffsetInEditor<RsPossibleMacroCall>()
val (macro, expectedErrorMessage) = if (markers.isEmpty()) {
myFixture.file
.descendantsOfType<RsPossibleMacroCall>()
.single { it.isMacroCall } to null
} else {
val (macro, message, _) = markers.single()
check(macro.isMacroCall)
macro to message
}

val err = when (val result = macro.expansionResult) {
is RsResult.Err -> result.err
is RsResult.Ok -> error("Expected a macro expansion error, got a successfully expanded macro")
}

check(errorClass.isInstance(err)) { "Expected error $errorClass, got $err" }

if (expectedErrorMessage != null) {
TestCase.assertEquals(expectedErrorMessage, err.toUserViewableMessage())
}
}
}