From 5e842e508bf1446f4669ed8f677f5db07aadfebb Mon Sep 17 00:00:00 2001 From: Roman Chernyatchik Date: Tue, 22 Oct 2024 21:31:16 +0200 Subject: [PATCH] fix: Inspection False Positive: Unresolved reference 'log'. Closes #549 --- CHANGELOG.md | 3 +- .../SmkImplicitPySymbolsProvider.kt | 2 +- .../snakecharm/codeInsight/SnakemakeApi.kt | 1 + .../SmkImplicitPySymbolsResolveProvider.kt | 7 +++- .../snakecharm/lang/SnakemakeNames.kt | 1 + .../features/glue/CompletionResolveSteps.kt | 35 +++++++++++++++++++ .../implicit_py_symbols_completion.feature | 1 + .../implicit_py_symbols_resolve.feature | 31 ++++++++++++++++ 8 files changed, 78 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27017121..018874be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ Released on - [8.0.0-6.8.1] Support for: 'storage', 'github', 'gitfile', 'gitlab' (see [#550](https://github.com/JetBrains-Research/snakecharm/issues/550) - [7.25.0] Support for localrule directive (see [#524](https://github.com/JetBrains-Research/snakecharm/issues/524) - [7.11] Resource scopes support (see [#510](https://github.com/JetBrains-Research/snakecharm/issues/510) - +- Inspection False Positive: Unresolved reference 'log' (see [#549](https://github.com/JetBrains-Research/snakecharm/issues/549) +- ### Fixed - Improve parser error message when rule/module is declared with name but lacks ':' (see [#515](https://github.com/JetBrains-Research/snakecharm/issues/515)) - Support for `update` and `before_update` flags. Update inspection that warns if flag functions from `snakemake.io` is used in a wrong section, added info for all flags up to 8.23.1 version (see [#537](https://github.com/JetBrains-Research/snakecharm/issues/537)) diff --git a/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SmkImplicitPySymbolsProvider.kt b/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SmkImplicitPySymbolsProvider.kt index f0d3d09b..bc685032 100644 --- a/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SmkImplicitPySymbolsProvider.kt +++ b/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SmkImplicitPySymbolsProvider.kt @@ -268,7 +268,7 @@ class SmkImplicitPySymbolsProvider( // self.globals[ruleinfo.func.__name__] = ruleinfo.func //////////////////////////////////////// - // TODO: all modules names acceible by name: + // TODO: all modules names accessible by name: // modules.py // self.workflow.globals[self.namespace] = namespace diff --git a/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SnakemakeApi.kt b/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SnakemakeApi.kt index 71ef1719..16884b16 100644 --- a/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SnakemakeApi.kt +++ b/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/SnakemakeApi.kt @@ -76,6 +76,7 @@ object SnakemakeApi { SnakemakeNames.SMK_VARS_SCATTER to "snakemake.common.Scatter", SnakemakeNames.SMK_VARS_GATHER to "snakemake.common.Gather", SnakemakeNames.SMK_VARS_CLUSTER_ONFIG to null, + SnakemakeNames.SMK_VARS_LOG to null, SnakemakeNames.SMK_VARS_CHECKPOINTS to "snakemake.checkpoints.Checkpoints", SnakemakeNames.SMK_VARS_GITHUB to "snakemake.sourcecache.GithubFile", SnakemakeNames.SMK_VARS_GITLAB to "snakemake.sourcecache.GitlabFile", diff --git a/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/resolve/SmkImplicitPySymbolsResolveProvider.kt b/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/resolve/SmkImplicitPySymbolsResolveProvider.kt index f63b1879..273a0126 100644 --- a/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/resolve/SmkImplicitPySymbolsResolveProvider.kt +++ b/src/main/kotlin/com/jetbrains/snakecharm/codeInsight/resolve/SmkImplicitPySymbolsResolveProvider.kt @@ -105,7 +105,12 @@ object SmkImplicitPySymbolsResolveProviderCompanion { for (l in cache.getSynthetic(symbolScope)) { // TODO: Introduce ImplicitLookupItem class val psi = l.psiElement - if (l.lookupString == referencedName && psi != null && psi.isValid) { + // Allow to resolve to null - just do not show error, e.g. for object like top-level 'log' + // that is just an implicit runtime string and nothing to resolve here + // + // XXX: NB: if some API is missing in SDK it is supposed not to added it in cache in order not to + // show ghosts in completion + if (l.lookupString == referencedName && ((psi != null && psi.isValid) || (psi == null))) { items.add(RatedResolveResult(RATE_IMPLICIT_SYMBOLS, psi)) break } diff --git a/src/main/kotlin/com/jetbrains/snakecharm/lang/SnakemakeNames.kt b/src/main/kotlin/com/jetbrains/snakecharm/lang/SnakemakeNames.kt index b1301e51..32f232be 100644 --- a/src/main/kotlin/com/jetbrains/snakecharm/lang/SnakemakeNames.kt +++ b/src/main/kotlin/com/jetbrains/snakecharm/lang/SnakemakeNames.kt @@ -92,6 +92,7 @@ object SnakemakeNames { const val SMK_VARS_GITLAB = "gitlab" // 6.8.1 const val SMK_VARS_GITFILE = "gitfile" // 7.13.0 const val SMK_VARS_STORAGE = "storage" // 8.0.0: + const val SMK_VARS_LOG = "log" const val SMK_FUN_EXPAND = "expand" const val SMK_FUN_EXPAND_ALIAS_COLLECT = "collect" diff --git a/src/test/kotlin/features/glue/CompletionResolveSteps.kt b/src/test/kotlin/features/glue/CompletionResolveSteps.kt index 5719fede..5af7b79e 100644 --- a/src/test/kotlin/features/glue/CompletionResolveSteps.kt +++ b/src/test/kotlin/features/glue/CompletionResolveSteps.kt @@ -55,6 +55,16 @@ class CompletionResolveSteps { } + @Then("^reference should resolve to NULL$") + fun reeferenceResolvedToNull() { + ApplicationManager.getApplication().invokeAndWait({ + val ref = getReferenceAtOffset() + assertNotNull(ref) + assertReferenceResolvedToNull(ref) + }, ModalityState.nonModal()) + } + + @Then("^reference in injection should not resolve$") fun referenceInInjectionShouldNotResolve() { ApplicationManager.getApplication().invokeAndWait({ @@ -591,6 +601,31 @@ class CompletionResolveSteps { private fun getCompletionListWithTypeText() = getCompletionItemsPresentation().map { it.itemText to it.typeText } + private fun assertReferenceResolvedToNull(ref: PsiReference) { + when (ref) { + is PsiPolyVariantReference -> { + val results = ref.multiResolve(false) + assertNotNull(results) + assertEquals( + 1, results.size.toLong(), + "Unexpected results: ${ + results.joinToString(separator = "\n") { + "${it.element?.javaClass?.simpleName}: [${it.element?.text}]" + } + }" + ) + assertNull( + results.first().element, + "Unexpected results: ${ + results.joinToString(separator = "\n") { + "${it.element?.javaClass?.simpleName}: [${it.element?.text}]" + } + }" + ) + } + else -> TestCase.assertNull(ref.resolve()) + } + } private fun assertUnresolvedReference(ref: PsiReference) { when (ref) { is PsiPolyVariantReference -> { diff --git a/src/test/resources/features/completion/implicit_py_symbols_completion.feature b/src/test/resources/features/completion/implicit_py_symbols_completion.feature index 12ac6a76..429162b3 100644 --- a/src/test/resources/features/completion/implicit_py_symbols_completion.feature +++ b/src/test/resources/features/completion/implicit_py_symbols_completion.feature @@ -34,6 +34,7 @@ Feature: Completion in python part of snakemake file | github | | gitlab | | gitfile | + | log | Scenario: Complete imported python modules/classes at top-level Given a snakemake project diff --git a/src/test/resources/features/resolve/implicit_py_symbols_resolve.feature b/src/test/resources/features/resolve/implicit_py_symbols_resolve.feature index 2e2cdb2b..a7d9a622 100644 --- a/src/test/resources/features/resolve/implicit_py_symbols_resolve.feature +++ b/src/test/resources/features/resolve/implicit_py_symbols_resolve.feature @@ -36,8 +36,14 @@ Feature: Resolve implicitly imported python names | ptn | text | symbol_name | file | | exp | expand() | expand | io.py | + + @ignore Scenario: Do not resolve at top-level if no python sdk + # TODO + + @ignore Scenario: Resolve at top-level if custom python sdk + # TODO Scenario Outline: Resolve at top-level Given a project @@ -140,6 +146,19 @@ Feature: Resolve implicitly imported python names | par | params | | wil | wildcards | + Scenario Outline: Not-resolved at top-level + Given a snakemake project + Given I open a file "foo.smk" with text + """ + + """ + When I put the caret at + Then reference should resolve to NULL + + Examples: + | ptn | text | + | log | log | + Scenario Outline: Resolve inside rule parameters Given a project @@ -424,6 +443,18 @@ Feature: Resolve implicitly imported python names | rule | input | config | | checkpoint | input | rules | + Scenario: Do not warn about unresolved log variable on top-level + Given a snakemake project + Given I open a file "foo.smk" with text + """ + onstart: + print("Log:") + print(log) + """ + And PyUnresolvedReferencesInspection inspection is enabled + Then I expect no inspection warnings + When I check highlighting warnings + Scenario: Warn about unresolved snakemake variable in run section, behaviour differs from scripts Given a snakemake project Given I open a file "foo.smk" with text