Skip to content

Commit

Permalink
fix: Expected collections.iterable but got output: false positive
Browse files Browse the repository at this point in the history
Resolves #317
  • Loading branch information
iromeo committed Sep 7, 2020
1 parent 4fa3f4e commit 4c5b73f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Fixed:
- Completion does not suggest top-level keywords in comments (see #178)
- Suppress inspection doesn't work in some cases (see #313)
- Don't show multiline string arg, may be comma is missing for sections with single arg (see #315)
- Expected `collections.iterable` but got `output:` false positive (see #317)

Version 0.8.0 build #0.8.0.214
-------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.impl.ResolveResultList
import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.resolve.RatedResolveResult
import com.jetbrains.python.psi.types.PyType
import com.jetbrains.python.psi.types.PyStructuralType
import com.jetbrains.snakecharm.codeInsight.SnakemakeAPI.UNPACK_FUNCTION
import com.jetbrains.snakecharm.codeInsight.completion.SmkCompletionUtil
import com.jetbrains.snakecharm.codeInsight.resolve.SmkResolveUtil
Expand All @@ -20,9 +20,20 @@ import com.jetbrains.snakecharm.stringLanguage.lang.callSimpleName

class SmkRuleLikeSectionArgsType(
val section: SmkRuleOrCheckpointArgsSection
) : PyType, SmkAvailableForSubscriptionType {
) : PyStructuralType(
getSectionArgsNames(getSectionArgs(section)),
false
), SmkAvailableForSubscriptionType {

companion object {
private fun getSectionArgs(section: SmkRuleOrCheckpointArgsSection)
= section.argumentList?.arguments
private fun getSectionArgsNames(args: Array<PyExpression>?)
= args?.filterIsInstance<PyKeywordArgument>()?.mapNotNull { it.name }?.toSet() ?: emptySet()
}

private val typeName: String = section.sectionKeyword?.let { "$it:" } ?: "section"
private val sectionArgs: Array<out PyExpression>? = getSectionArgs(section)

override fun getName() = typeName

Expand All @@ -42,15 +53,13 @@ class SmkRuleLikeSectionArgsType(
return emptyList()
}

val args = getSectionArgs()

@Suppress("FoldInitializerAndIfToElvis")
if (args == null) {
if (sectionArgs == null) {
return emptyList()
}

val resolveResult = ResolveResultList()
args.filterIsInstance<PyKeywordArgument>()
sectionArgs.filterIsInstance<PyKeywordArgument>()
.filter { it.name == name }
.forEach {
resolveResult.poke(it, SmkResolveUtil.RATE_NORMAL)
Expand All @@ -65,20 +74,16 @@ class SmkRuleLikeSectionArgsType(
direction: AccessDirection,
resolveContext: PyResolveContext
): List<RatedResolveResult> {
val args = getSectionArgs()

if (args != null && isSimpleArgsList(args)) {
if (sectionArgs != null && isSimpleArgsList(sectionArgs)) {
val resolveResult = ResolveResultList()
if (idx in args.indices) {
resolveResult.poke(args[idx], SmkResolveUtil.RATE_NORMAL)
if (idx in sectionArgs.indices) {
resolveResult.poke(sectionArgs[idx], SmkResolveUtil.RATE_NORMAL)
}
return resolveResult
}
return emptyList()
}

private fun getSectionArgs(): Array<out PyExpression>? = section.argumentList?.arguments

override fun getCompletionVariants(
completionPrefix: String?,
location: PsiElement,
Expand Down Expand Up @@ -106,20 +111,19 @@ class SmkRuleLikeSectionArgsType(
}

val results = arrayListOf<LookupElementBuilder>()
val args = getSectionArgs()

@Suppress("FoldInitializerAndIfToElvis")
if (args == null) {
if (sectionArgs == null) {
return emptyList<LookupElementBuilder>() to priority
}

val sectionKeyword = section.sectionKeyword
val typeText = "$sectionKeyword section key"
args.filterIsInstance<PyKeywordArgument>().forEach {
attributeNames.forEach { name ->
val item = LookupElementBuilder
.create(it.name!!)
.create(name)
.withTypeText(typeText)
.withIcon(PlatformIcons.PARAMETER_ICON)
.withIcon(PlatformIcons.FIELD_ICON)
results.add(item)
}

Expand All @@ -134,13 +138,11 @@ class SmkRuleLikeSectionArgsType(
return 0
}

val args = getSectionArgs()

if (args == null || !isSimpleArgsList(args)) {
if (sectionArgs == null || !isSimpleArgsList(sectionArgs)) {
return 0
}

return args.size
return sectionArgs.size
}

private fun isSimpleArgsList(args: Array<out PyExpression>): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Feature: Fixes for PyTypeCheckerInspection related false positives
Scenario Outline: Args Section type is iterable
Given a snakemake project
Given I open a file "foo.smk" with text
"""
rule rule_317_1:
output: "d"
<rule_like> rule_317_2:
input: expand(
[s for s in rules.rule_317_1.output],
[s for s in 1],
key="val"
)
output: "out.txt"
run:
with open(output[0], 'w') as out:
for p in input:
print(p, file=out)
"""
And PyTypeCheckerInspection inspection is enabled
# warning only for `1`, not for `rules.rule_317_1.output` and not for `for p in input`
Then I expect inspection warning on <1> in <[s for s in 1]> with message
"""
Expected 'collections.Iterable', got 'int' instead
"""
When I check highlighting warnings
Examples:
| rule_like |
| rule |
| checkpoint |

0 comments on commit 4c5b73f

Please sign in to comment.