Skip to content

Commit

Permalink
Add custom refactoring
Browse files Browse the repository at this point in the history
Will help to fix [cargo-issue]

[cargo-issue]: rust-lang/cargo#2693
  • Loading branch information
matklad committed May 15, 2016
1 parent 0c9a1f7 commit 5dcadcb
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
69 changes: 69 additions & 0 deletions src/main/kotlin/org/rust/ide/inspections/CargoTestInspection.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.rust.ide.inspections

import com.intellij.codeInspection.LocalQuickFixBase
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.util.childOfType

val macroRe = """^\[\w+\].*""".toRegex()

class CargoTestInspection : RustLocalInspectionTool() {
override fun getDisplayName(): String = "Fix Cargo test"

override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : RustVisitor() {
override fun visitMethodCallExpr(o: RustMethodCallExpr) {
if (o.identifier?.text != "with_stdout") return
val firstArg = o.argList?.exprList?.firstOrNull() ?: return
val stringLit = firstArg.childOfType<RustLitExpr>(strict = false) ?: return
if (stringLit.text.lines().any { it.matches(macroRe) }) {
holder.registerProblem(o, "Status is printed to stdout", WithStdout2WithStderr(o, stringLit))

}

}
}
}

class WithStdout2WithStderr(val o: RustMethodCallExpr, val stringLit: PsiElement) : LocalQuickFixBase("Fix Cargo test") {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val (stderr, stdout) = stringLit.text.trim('"').lines().partition { it.matches(macroRe) }
val stderrText = "\\\n" + stderr.joinToString("\n")
val stderrLiteral = stringLiteral(stderrText)
var stdoutText = stdout.joinToString("\n")
if (stdoutText.startsWith("\\\n\n")) {
stdoutText = stdoutText.drop(2)
}
val stdoutLiteral = stringLiteral(stdoutText)
stringLit.replace(stderrLiteral)
o.identifier!!.replace(identifier("with_stderr"))

val newExpr = methodCall(o, "with_stdout", stdoutLiteral)
o.replace(newExpr)
}

private fun identifier(text: String): PsiElement {
val fileText = "struct $text;"
return elementFromText<RustStructItem>(fileText).identifier
}

private fun methodCall(o: RustMethodCallExpr, methodName: String, arg: PsiElement): PsiElement {
val fileText = "fn main() { ${o.text}.$methodName(${arg.text})}}"
return elementFromText<RustMethodCallExpr>(fileText)
}

private fun stringLiteral(text: String): PsiElement {
return elementFromText<RustLiteral.Text>("fn main() { \"$text\" }")
}

private inline fun<reified T: PsiElement> elementFromText(text: String): T {
val file = RustElementFactory.createFileFromText(o.project, text)
return file!!.childOfType<T>()!!
}
}

}
7 changes: 6 additions & 1 deletion src/main/kotlin/org/rust/lang/core/grammar/rust.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,7 @@ item_like_macro ::= macro_invocation item_macro_arg

try_macro ::= try_macro_invocation try_macro_args { pin = 1 }
format_like_macro ::= format_like_macro_invocation format_macro_args { pin = 1 }
cargo_test_macro ::= cargo_test_macro_invocation cargo_test_macro_args { pin = 1 }

macro_definition ::= macro_rules_invocation IDENTIFIER item_macro_arg {
pin = 1
Expand All @@ -1019,7 +1020,7 @@ private build_in_macro ::= try_macro
| format_like_macro

private zz_macro_call ::= build_in_macro | expr_like_macro { pin(".*") = macro_invocation }
private zz_macro_item ::= macro_definition | item_like_macro { pin(".*") = macro_invocation }
private zz_macro_item ::= cargo_test_macro ';' | macro_definition | item_like_macro { pin(".*") = macro_invocation }

// Invocations
macro_invocation ::= IDENTIFIER '!'
Expand All @@ -1041,6 +1042,8 @@ format_like_macro_invocation ::= ( "format"
| "trace"
| "warn" ) '!'

cargo_test_macro_invocation ::= "test" '!'

// Arguments
macro_arg ::= <<macro_args_delim token_trees>>

Expand All @@ -1056,6 +1059,8 @@ try_macro_args ::= <<macro_args_delim any_expr>>
format_macro_args ::= <<macro_args_delim [ <<comma_separated_list format_macro_arg>> ] >>
format_macro_arg ::= [ IDENTIFIER '=' ] any_expr

cargo_test_macro_args ::= <<macro_args_delim (IDENTIFIER block) >>

private meta macro_args_delim ::= '(' <<param>> ')'
| '{' <<param>> '}'
| '[' <<param>> ']' { pin = 1 }
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@

<localInspection language="RUST" enabledByDefault="true" level="ERROR"
implementationClass="org.rust.ide.inspections.UnresolvedModuleDeclarationInspection"/>
<localInspection language="RUST" enabledByDefault="true" level="ERROR"
implementationClass="org.rust.ide.inspections.CargoTestInspection"/>

<!-- Surrounder -->
<lang.surroundDescriptor language="RUST"
Expand Down

0 comments on commit 5dcadcb

Please sign in to comment.