Skip to content

Commit

Permalink
Features/#384 inspections are enabled for workflows (#391)
Browse files Browse the repository at this point in the history
fix: #384, SmkSectionUnexpectedKeywordArgsInspection, SmkSectionMultipleArgsInspection are enabled for workflow sections

Resolves: #384
Co-authored-by: Roman Chernyatchik <[email protected]>
  • Loading branch information
dakochik and iromeo authored Jul 27, 2021
1 parent b5f6f01 commit b3588f2
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 117 deletions.
175 changes: 100 additions & 75 deletions src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SnakemakeAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_REPORT
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_TEMP
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_TOUCH
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_UNPACK
import com.jetbrains.snakecharm.lang.SnakemakeNames.WORKFLOW_CONTAINERIZED_KEYWORD
import com.jetbrains.snakecharm.lang.SnakemakeNames.WORKFLOW_CONTAINER_KEYWORD
import com.jetbrains.snakecharm.lang.SnakemakeNames.WORKFLOW_SINGULARITY_KEYWORD

/**
* Also see [ImplicitPySymbolsProvider] class
Expand All @@ -59,7 +62,7 @@ object SnakemakeAPI {
)

val FUNCTIONS_BANNED_FOR_WILDCARDS = listOf(
SMK_FUN_EXPAND
SMK_FUN_EXPAND
)

const val SMK_VARS_WILDCARDS = "wildcards"
Expand All @@ -69,53 +72,65 @@ object SnakemakeAPI {
* Also see [ImplicitPySymbolsProvider], it also processes 'InputFiles', etc. symbols
*/
val SECTION_ACCESSOR_CLASSES = mapOf(
"snakemake.io.InputFiles" to "input",
"snakemake.io.OutputFiles" to "output",
"snakemake.io.Params" to "params",
"snakemake.io.Log" to "log",
"snakemake.io.Resources" to "resources"
"snakemake.io.InputFiles" to "input",
"snakemake.io.OutputFiles" to "output",
"snakemake.io.Params" to "params",
"snakemake.io.Log" to "log",
"snakemake.io.Resources" to "resources"
)
const val SNAKEMAKE_MODULE_NAME_IO_PY = "io.py"

val EXECUTION_SECTIONS_KEYWORDS = setOf(
SECTION_SHELL, SECTION_SCRIPT,
SECTION_WRAPPER, SECTION_CWL, SECTION_NOTEBOOK
SECTION_SHELL, SECTION_SCRIPT,
SECTION_WRAPPER, SECTION_CWL, SECTION_NOTEBOOK
)

/**
* Rule or checkpoint sections that allows only single argument
*/
val SINGLE_ARGUMENT_SECTIONS_KEYWORDS = setOf(
SECTION_SHELL, SECTION_SCRIPT, SECTION_WRAPPER,
SECTION_CWL, SECTION_BENCHMARK, SECTION_VERSION,
SECTION_MESSAGE, SECTION_THREADS, SECTION_SINGULARITY,
SECTION_PRIORITY, SECTION_CONDA, SECTION_GROUP,
SECTION_SHADOW, SECTION_CACHE, SECTION_NOTEBOOK, SECTION_CONTAINER,
SECTION_HANDOVER, SECTION_CONTAINERIZED
SECTION_SHELL, SECTION_SCRIPT, SECTION_WRAPPER,
SECTION_CWL, SECTION_BENCHMARK, SECTION_VERSION,
SECTION_MESSAGE, SECTION_THREADS, SECTION_SINGULARITY,
SECTION_PRIORITY, SECTION_CONDA, SECTION_GROUP,
SECTION_SHADOW, SECTION_CACHE, SECTION_NOTEBOOK, SECTION_CONTAINER,
SECTION_HANDOVER, SECTION_CONTAINERIZED
)

/**
* Workflow top-level sections that allows only single argument
*/
val SINGLE_ARGUMENT_WORKFLOWS_KEYWORDS = setOf(
WORKFLOW_CONTAINERIZED_KEYWORD, WORKFLOW_CONTAINER_KEYWORD,
WORKFLOW_SINGULARITY_KEYWORD
)

/**
* For rules parsing
*/
val RULE_OR_CHECKPOINT_ARGS_SECTION_KEYWORDS = setOf(
SECTION_OUTPUT, SECTION_INPUT, SECTION_PARAMS, SECTION_LOG, SECTION_RESOURCES,
SECTION_BENCHMARK, SECTION_VERSION, SECTION_MESSAGE, SECTION_SHELL, SECTION_THREADS, SECTION_SINGULARITY,
SECTION_PRIORITY, SECTION_WILDCARD_CONSTRAINTS, SECTION_GROUP, SECTION_SHADOW,
SECTION_CONDA,
SECTION_SCRIPT, SECTION_WRAPPER, SECTION_CWL, SECTION_NOTEBOOK,
SECTION_CACHE,
SECTION_CONTAINER,
SECTION_CONTAINERIZED,
SECTION_ENVMODULES,
SECTION_NAME,
SECTION_HANDOVER
)
val RULE_OR_CHECKPOINT_SECTION_KEYWORDS = (RULE_OR_CHECKPOINT_ARGS_SECTION_KEYWORDS + setOf(SnakemakeNames.SECTION_RUN))
SECTION_OUTPUT, SECTION_INPUT, SECTION_PARAMS, SECTION_LOG, SECTION_RESOURCES,
SECTION_BENCHMARK, SECTION_VERSION, SECTION_MESSAGE, SECTION_SHELL, SECTION_THREADS, SECTION_SINGULARITY,
SECTION_PRIORITY, SECTION_WILDCARD_CONSTRAINTS, SECTION_GROUP, SECTION_SHADOW,
SECTION_CONDA,
SECTION_SCRIPT, SECTION_WRAPPER, SECTION_CWL, SECTION_NOTEBOOK,
SECTION_CACHE,
SECTION_CONTAINER,
SECTION_CONTAINERIZED,
SECTION_ENVMODULES,
SECTION_NAME,
SECTION_HANDOVER
)
val RULE_OR_CHECKPOINT_SECTION_KEYWORDS =
(RULE_OR_CHECKPOINT_ARGS_SECTION_KEYWORDS + setOf(SnakemakeNames.SECTION_RUN))

/**
* For subworkflows parsing
*/
val SUBWORKFLOW_SECTIONS_KEYWORDS = setOf(
SnakemakeNames.SUBWORKFLOW_WORKDIR_KEYWORD,
SnakemakeNames.SUBWORKFLOW_SNAKEFILE_KEYWORD,
SnakemakeNames.SUBWORKFLOW_CONFIGFILE_KEYWORD
SnakemakeNames.SUBWORKFLOW_WORKDIR_KEYWORD,
SnakemakeNames.SUBWORKFLOW_SNAKEFILE_KEYWORD,
SnakemakeNames.SUBWORKFLOW_CONFIGFILE_KEYWORD
)

/**
Expand All @@ -124,18 +139,18 @@ object SnakemakeAPI {
* to filter these sections for resolve and completion
*/
val RULE_TYPE_ACCESSIBLE_SECTIONS = setOf(
SECTION_INPUT,
SECTION_LOG,
SECTION_OUTPUT,
SECTION_PARAMS,
SECTION_RESOURCES,
SECTION_VERSION,
SECTION_INPUT,
SECTION_LOG,
SECTION_OUTPUT,
SECTION_PARAMS,
SECTION_RESOURCES,
SECTION_VERSION,

SECTION_MESSAGE,
SECTION_WILDCARD_CONSTRAINTS,
SECTION_BENCHMARK,
SECTION_PRIORITY,
SECTION_WRAPPER
SECTION_MESSAGE,
SECTION_WILDCARD_CONSTRAINTS,
SECTION_BENCHMARK,
SECTION_PRIORITY,
SECTION_WRAPPER
)

/**
Expand All @@ -144,21 +159,21 @@ object SnakemakeAPI {
* expand wildcards.
*/
val SMK_SL_INITIAL_TYPE_ACCESSIBLE_SECTIONS = setOf(
SECTION_INPUT,
SECTION_OUTPUT, SECTION_LOG,
SECTION_THREADS, SECTION_PARAMS,
SECTION_RESOURCES,
SECTION_VERSION
SECTION_INPUT,
SECTION_OUTPUT, SECTION_LOG,
SECTION_THREADS, SECTION_PARAMS,
SECTION_RESOURCES,
SECTION_VERSION
)

val SECTIONS_INVALID_FOR_INJECTION = setOf(
SECTION_WILDCARD_CONSTRAINTS,
SECTION_SHADOW,
SECTION_WRAPPER,
SECTION_VERSION, SECTION_THREADS,
SECTION_PRIORITY, SECTION_SINGULARITY, SECTION_CACHE,
SECTION_CONTAINER, SECTION_CONTAINERIZED, SECTION_NOTEBOOK,
SECTION_ENVMODULES, SECTION_HANDOVER
SECTION_WILDCARD_CONSTRAINTS,
SECTION_SHADOW,
SECTION_WRAPPER,
SECTION_VERSION, SECTION_THREADS,
SECTION_PRIORITY, SECTION_SINGULARITY, SECTION_CACHE,
SECTION_CONTAINER, SECTION_CONTAINERIZED, SECTION_NOTEBOOK,
SECTION_ENVMODULES, SECTION_HANDOVER
)

/**
Expand All @@ -167,9 +182,9 @@ object SnakemakeAPI {
* TODO: Consider implementing this as PSI interface in order not to compare keyword string each time
*/
val WILDCARDS_EXPANDING_SECTIONS_KEYWORDS = setOf(
SECTION_INPUT, SECTION_OUTPUT, SECTION_CONDA,
SECTION_RESOURCES, SECTION_GROUP, SECTION_BENCHMARK,
SECTION_LOG, SECTION_PARAMS
SECTION_INPUT, SECTION_OUTPUT, SECTION_CONDA,
SECTION_RESOURCES, SECTION_GROUP, SECTION_BENCHMARK,
SECTION_LOG, SECTION_PARAMS
)

/**
Expand All @@ -178,7 +193,7 @@ object SnakemakeAPI {
* TODO: Consider implementing this as PSI interface in order not to compare keyword string each time
*/
val WILDCARDS_DEFINING_SECTIONS_KEYWORDS = listOf(
SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK
SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK
)

/**
Expand Down Expand Up @@ -206,31 +221,41 @@ object SnakemakeAPI {
SMK_VARS_ATTEMPT
)
)
val SECTION_LAMBDA_ARG_POSSIBLE_PARAMS: Set<String> = ALLOWED_LAMBDA_OR_CALLABLE_ARGS.values.flatMap { it.asIterable() }.toMutableSet().also {
it.addAll(RULE_OR_CHECKPOINT_ARGS_SECTION_KEYWORDS)
}
val SECTION_LAMBDA_ARG_POSSIBLE_PARAMS: Set<String> =
ALLOWED_LAMBDA_OR_CALLABLE_ARGS.values.flatMap { it.asIterable() }.toMutableSet().also {
it.addAll(RULE_OR_CHECKPOINT_ARGS_SECTION_KEYWORDS)
}

/**
* Set of rule\checkpoint sections that does not expect keyword arguments
* Rule/checkpoint sections that does not allow keyword arguments
*/
val SECTIONS_WHERE_KEYWORD_ARGS_PROHIBITED = setOf(
SECTION_BENCHMARK, SECTION_VERSION, SECTION_MESSAGE, SECTION_SHELL, SECTION_THREADS, SECTION_SINGULARITY,
SECTION_PRIORITY, SECTION_GROUP, SECTION_SHADOW, SECTION_CONDA, SECTION_SCRIPT, SECTION_WRAPPER,
SECTION_CWL, SECTION_NOTEBOOK, SECTION_CACHE, SECTION_CONTAINER, SECTION_CONTAINERIZED, SECTION_ENVMODULES,
SECTION_NAME, SECTION_HANDOVER
SECTION_BENCHMARK, SECTION_VERSION, SECTION_MESSAGE, SECTION_SHELL, SECTION_THREADS, SECTION_SINGULARITY,
SECTION_PRIORITY, SECTION_GROUP, SECTION_SHADOW, SECTION_CONDA, SECTION_SCRIPT, SECTION_WRAPPER,
SECTION_CWL, SECTION_NOTEBOOK, SECTION_CACHE, SECTION_CONTAINER, SECTION_CONTAINERIZED, SECTION_ENVMODULES,
SECTION_NAME, SECTION_HANDOVER
)


/**
* Workflow top-level sections that does not allow keyword args
*/
val WORKFLOWS_WHERE_KEYWORD_ARGS_PROHIBITED = setOf(
WORKFLOW_CONTAINERIZED_KEYWORD, WORKFLOW_CONTAINER_KEYWORD,
WORKFLOW_SINGULARITY_KEYWORD
)

val IO_FLAG_2_SUPPORTED_SECTION: HashMap<String, List<String>> = hashMapOf(
SNAKEMAKE_IO_METHOD_ANCIENT to listOf(SECTION_INPUT),
SNAKEMAKE_IO_METHOD_PROTECTED to listOf(SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_DIRECTORY to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_REPORT to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_TEMP to listOf(SECTION_INPUT, SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_TOUCH to listOf(SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_PIPE to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_REPEAT to listOf(SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_UNPACK to listOf(SECTION_INPUT),
SNAKEMAKE_IO_METHOD_DYNAMIC to listOf(SECTION_OUTPUT)
SNAKEMAKE_IO_METHOD_ANCIENT to listOf(SECTION_INPUT),
SNAKEMAKE_IO_METHOD_PROTECTED to listOf(SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_DIRECTORY to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_REPORT to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_TEMP to listOf(SECTION_INPUT, SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_TOUCH to listOf(SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_PIPE to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_REPEAT to listOf(SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_UNPACK to listOf(SECTION_INPUT),
SNAKEMAKE_IO_METHOD_DYNAMIC to listOf(SECTION_OUTPUT)
)

val SMK_API_PKG_NAME_SMK = "snakemake"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,49 @@ import com.intellij.codeInspection.ProblemsHolder
import com.jetbrains.python.psi.PyArgumentList
import com.jetbrains.snakecharm.SnakemakeBundle
import com.jetbrains.snakecharm.codeInsight.SnakemakeAPI.SINGLE_ARGUMENT_SECTIONS_KEYWORDS
import com.jetbrains.snakecharm.codeInsight.SnakemakeAPI.SINGLE_ARGUMENT_WORKFLOWS_KEYWORDS
import com.jetbrains.snakecharm.lang.psi.SmkArgsSection
import com.jetbrains.snakecharm.lang.psi.SmkRuleOrCheckpointArgsSection
import com.jetbrains.snakecharm.lang.psi.SmkSubworkflowArgsSection
import com.jetbrains.snakecharm.lang.psi.SmkWorkflowArgsSection

class SmkSectionMultipleArgsInspection : SnakemakeInspection() {
override fun buildVisitor(
holder: ProblemsHolder,
isOnTheFly: Boolean,
session: LocalInspectionToolSession
holder: ProblemsHolder,
isOnTheFly: Boolean,
session: LocalInspectionToolSession,
) = object : SnakemakeInspectionVisitor(holder, session) {

override fun visitSmkSubworkflowArgsSection(st: SmkSubworkflowArgsSection) {
checkArgumentList(st.argumentList, "subworkflow")
}

override fun visitSmkRuleOrCheckpointArgsSection(st: SmkRuleOrCheckpointArgsSection) {
if (st.name in SINGLE_ARGUMENT_SECTIONS_KEYWORDS) {
checkArgumentList(st.argumentList, st.name!!)
checkArgumentList(st, SINGLE_ARGUMENT_SECTIONS_KEYWORDS)
}

override fun visitSmkWorkflowArgsSection(st: SmkWorkflowArgsSection) {
checkArgumentList(st, SINGLE_ARGUMENT_WORKFLOWS_KEYWORDS)
}

private fun checkArgumentList(st: SmkArgsSection, sectionKeywords: Set<String>) {
val keyword = st.sectionKeyword
if (keyword != null && keyword in sectionKeywords) {
checkArgumentList(st.argumentList, keyword)
}
}

private fun checkArgumentList(
argumentList: PyArgumentList?,
sectionName: String
argumentList: PyArgumentList?,
sectionName: String,
) {
val args = argumentList?.arguments ?: emptyArray()
if (args.size > 1) {
args.forEachIndexed { i, arg ->
if (i > 0) {
registerProblem(
arg,
SnakemakeBundle.message("INSP.NAME.section.multiple.args.message", sectionName)
arg,
SnakemakeBundle.message("INSP.NAME.section.multiple.args.message", sectionName)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,54 @@ import com.jetbrains.python.psi.PyArgumentList
import com.jetbrains.python.psi.PyKeywordArgument
import com.jetbrains.snakecharm.SnakemakeBundle
import com.jetbrains.snakecharm.codeInsight.SnakemakeAPI.SECTIONS_WHERE_KEYWORD_ARGS_PROHIBITED
import com.jetbrains.snakecharm.codeInsight.SnakemakeAPI.WORKFLOWS_WHERE_KEYWORD_ARGS_PROHIBITED
import com.jetbrains.snakecharm.lang.psi.SmkArgsSection
import com.jetbrains.snakecharm.lang.psi.SmkRuleOrCheckpointArgsSection
import com.jetbrains.snakecharm.lang.psi.SmkSubworkflowArgsSection
import com.jetbrains.snakecharm.lang.psi.SmkWorkflowArgsSection

class SmkSectionUnexpectedKeywordArgsInspection : SnakemakeInspection() {
override fun buildVisitor(
holder: ProblemsHolder,
isOnTheFly: Boolean,
session: LocalInspectionToolSession
holder: ProblemsHolder,
isOnTheFly: Boolean,
session: LocalInspectionToolSession,
) = object : SnakemakeInspectionVisitor(holder, session) {

override fun visitSmkSubworkflowArgsSection(st: SmkSubworkflowArgsSection) {
checkArgumentList(st.argumentList, st)
}

override fun visitSmkRuleOrCheckpointArgsSection(st: SmkRuleOrCheckpointArgsSection) {
if (st.sectionKeyword in SECTIONS_WHERE_KEYWORD_ARGS_PROHIBITED) {
checkArgumentList(st, SECTIONS_WHERE_KEYWORD_ARGS_PROHIBITED)
}

override fun visitSmkWorkflowArgsSection(st: SmkWorkflowArgsSection) {
checkArgumentList(st, WORKFLOWS_WHERE_KEYWORD_ARGS_PROHIBITED)
}

private fun checkArgumentList(
st: SmkArgsSection,
sectionKeywords: Set<String>,
) {
val keyword = st.sectionKeyword
if (keyword != null && keyword in sectionKeywords) {
checkArgumentList(st.argumentList, st)
}
}

private fun checkArgumentList(
argumentList: PyArgumentList?,
section: SmkArgsSection
argumentList: PyArgumentList?,
section: SmkArgsSection,
) {
val args = argumentList?.arguments ?: emptyArray()
args.forEach { arg ->
if (arg is PyKeywordArgument) {
registerProblem(
arg,
SnakemakeBundle.message(
"INSP.NAME.section.unexpected.keyword.args.message",
section.sectionKeyword!!
)
arg,
SnakemakeBundle.message(
"INSP.NAME.section.unexpected.keyword.args.message",
section.sectionKeyword!!
)
)
}
}
Expand Down
Loading

0 comments on commit b3588f2

Please sign in to comment.