Go-tools: ST1017: possible false positive in non-if conditions

Created on 4 Feb 2019  Â·  6Comments  Â·  Source: dominikh/go-tools

I have some code that looks like this:

// Render the tabnav.
err := htmlg.RenderComponents(w, tabnav{
    Tabs: []tab{
        {
            Content:  iconText{Icon: octicon.Person, Text: "Overview"},
            URL:      "/about",
            Selected: "/about" == req.URL.Path,
        },
        {
            Content:  iconText{Icon: octicon.DeviceDesktop, Text: "Setup"},
            URL:      "/about/setup",
            Selected: "/about/setup" == req.URL.Path,
        },
    },
})
if err != nil {
    return err
}

I get don't use Yoda conditions (ST1017) reports on "/about" == req.URL.Path and "/about/setup" == req.URL.Path lines.

I'm not sure if it's a true positive in this case. I can see how yoda conditions in if statements are not worth having, and thus worth reporting. But in this case, having the "/about" and "/about/setup" alignment improves readability IMO.

To me, it's not clear that swapping the comparison order is an improvement:

{
    Content:  iconText{Icon: octicon.Person, Text: "Overview"},
    URL:      "/about",
    Selected: req.URL.Path == "/about",
},
{
    Content:  iconText{Icon: octicon.DeviceDesktop, Text: "Setup"},
    URL:      "/about/setup",
    Selected: req.URL.Path == "/about/setup",
},

What do you think?

If we agree on this being a false positive, maybe a broad fix is to limit scope to if statements that cannot rely on indentation the way struct literals can, and a more narrow one is to ignore struct literals with aligned fields.

noisy-positive

All 6 comments

To be honest, both seem like a bad style to me, as both have magical strings. Better:

// Render the tabnav.
const (
    aboutPath      = "/about"
    aboutSetupPath = "/about/setup"
)
err := htmlg.RenderComponents(w, tabnav{
    Tabs: []tab{
        {
            Content:  iconText{Icon: octicon.Person, Text: "Overview"},
            URL:      aboutPath,
            Selected: aboutPath == req.URL.Path,
        },
        {
            Content:  iconText{Icon: octicon.DeviceDesktop, Text: "Setup"},
            URL:      aboutSetupPath,
            Selected: aboutSetupPath == req.URL.Path,
        },
    },
})
if err != nil {
    return err
}

I didn't expect it to have an effect on ST1017, but using such constants makes staticcheck no longer emit ST1017 on those lines.

I agree using consts for paths is better, and that was the long term plan. Using string literals was a part of the first prototype. Perhaps I'll expedite the process of starting to use consts.

I didn't expect it to have an effect on ST1017

Well, the definition of a yoda condition is <literal> <binop> <non-literal>.

I see. I thought it would be <const> <binop> <non-const>. Why isn’t it?

Why isn’t it?

Well, because that's not the pattern we're trying to flag :-) – lit op non-lit is common in languages where assignment is an expression and pretty much always an anti-pattern in Go (if we ignore your case). Most often you'll see it with very basic literals, such as 0 (if 0 == ret).

What side of an expression a const should be on seems a lot more opinionated, and will depend on things other than trying to avoid an accidental assignment.

I'm going to close this for now. It's a rare and weird enough edge case that I am comfortable recommending a //lint:ignore, writing your code differently, or disabling the check altogether.

I will reconsider this if more people run into the same issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stamm picture stamm  Â·  4Comments

jadekler picture jadekler  Â·  3Comments

ryboe picture ryboe  Â·  3Comments

ainar-g picture ainar-g  Â·  4Comments

dominikh picture dominikh  Â·  3Comments