Jshint: Tab indentation breaks multiple rules

Created on 23 Jun 2017  ·  29Comments  ·  Source: jshint/jshint

It seems that indentation using tabs breaks the position reported by at least 3 rules, likely more.

All of the following was linted using this .jshintrc file:

{
  "strict": "global",
  "unused": true
}

The JSHint version tested is v2.9.5.

If you want me to refile these as separate issues I can do that as well.

W032

If you lint this code:

'use strict';

    function foo() {
    };

foo();

There is an error reported on line 4, col 6, but line 4 only has 4 characters in it.

W098

If you lint this code:

'use strict';

    function foobar(
        $foo
    ) {
        return 'foo';
    }

foobar();

There is an error reported on line 4, col 9, but line 4 only has 7 characters in it.

W117

If you lint this code:

'use strict';

    function foobar() {
        if (true) {
            fun1();
        }
    }

foobar();

There is an error reported on line 5, col 13, but line 4 only has 11 characters in it.


The character position reported seems to go further and further out the more tabs there are at the beginning of the line in question.

Raw files can be found here: linter-jshint_GH416.zip

Originally discovered while investigating https://github.com/AtomLinter/linter-jshint/issues/416.

Rules known to be affected:

  • W009
  • W014
  • E015
  • W024
  • W027
  • W030
  • W032
  • W033
  • W040
  • W043
  • W069
  • W075
  • W098
  • W116
  • W119
  • W140
  • E041
  • Many others...
Needs Discussion

Most helpful comment

PLEASE ALL YOUR SOLUTIONS SUCK IVE SPENT THE PAST FUCKING 5 HOURS TRYING TO LINT A FUCKING JAVASCRIPT FILE ITS FUCKING 2017 WHY AM I HAVING THIS PROBLEM ATOM IS THE FUCKING BANE OF MY FUCKING LIFE FIX YOURSELF YOU STUPID IDE

AND WHO THE FUCK DOESN'T USE TABS TO INDENT LITERALLY WTF WHY WOULD YOU RELEASE A BROKEN PACKAGE TO THE MILLIONS THAT LINT JS???????

All 29 comments

Thanks for the report! The problem stems from line 1610 of lex.js:

this.input = this.input.replace(/\t/g, state.tab);

This seems pretty fundamental to how many of the style-related linting rules are implemented. Those have been deprecated for some time now, but we're still not ready to move on a new major version. So in the mean time, we'll need to design a solution that preserves that behavior.

My initial thought is to track this "effective offset" as a new property of the token object named column. This can be used for those style-related warnings. Then, the character attribute could be re-implemented to describe the "true" character offset, where each code point (tab or otherwise) increments the count by exactly 1. This value would be used to issue warnings. Reporter plugins would then be in control of how they rendered the tab character, and they could interpret the reported "column" number accordingly.

Does that sound good to you, @Arcanemagus?

That sounds perfect to me, at least on the surface with no real knowledge of JSHint's internals 😛. Ideally I just need some method of getting the true column count (where each code point counts as one column).

This was hidden for a while due to this warning essentially being ignored due to a workaround for some old parser bug with a semi-common error. When I re-implemented the warning to users in a much nicer manner I had accidentally _hidden_ them, and just recently fixed it making this visible again.

Looks like W030, W033, and W009 are also affected. From your description I'm assuming _all_ rules are affected?

I'm also experiencing this issue and am able to replicate on both errors and warnings. Rule/Error type doesn't seem to matter.

Here's an example of jshint attempting to warn me my '==' should be '==='. Note the erroneous location of the orange underline:
erroneoustargeting

Hopefully this confirms your thoughts on the issue.

I got some time to do some digging today, and I believe setting the indent option to 1 will produce the desired results.

@Arcanemagus Are you able to over-ride the value of the indent option for your consumers? If this is possible, I'd rather do that, since I'm not sure how changing the default value in JSHint itself could effect its consumers.

Hmmm, currently this project uses the CLI interface it looks like. It's possible to rewrite it to use the Node.js API which would make that possible.

  • Would forcing the indent value change the results consumers see? The goal of that package is to be as close to possible as it can be of running jshint themselves, but getting the results integrated in the editor.
  • Does the JSHint API have a hidden method to grab the configuration for a file, or would that need to be implemented? The current documentation doesn't show such a function.

How about adding a command line argument that allows to override values from the configuration?
Something like that is common in tools like -g in nginx, -o in ssh, -c in git and many more I guess.

$ jshint -o "indent = 1" -o "-W034 = true" -o "globals.require = false" -o "globals.$ = null"

Does anyone know what version this was introduced in? 2.9.5?

At least then we could downgrade for the moment as a temp. fix.

@jaredatch Back in https://github.com/AtomLinter/linter-jshint/pull/386 (released in v3.1.0 of linter-jshint) all of the workarounds for JSHint's buggy point reporting were removed. The entire point of that check is to find bugs like this were the linter is reporting invalid points so it can get reported and fixed for _everyone_ using the linter. (After all, if you can't trust the linter to give you accurate data, why use it?)

There _may_ be a "sweet spot" before this tab bug was introduced and after the major parser bugs that caused those workarounds to be put in place in the first place.

@Arcanemagus gotcha, really appreciate the insight. Keep up the great work 👍

If you have a better / more useful message idea for how linter-jshint reports these invalid points feel free to file an issue / submit a PR over there 😉.

PLEASE ALL YOUR SOLUTIONS SUCK IVE SPENT THE PAST FUCKING 5 HOURS TRYING TO LINT A FUCKING JAVASCRIPT FILE ITS FUCKING 2017 WHY AM I HAVING THIS PROBLEM ATOM IS THE FUCKING BANE OF MY FUCKING LIFE FIX YOURSELF YOU STUPID IDE

AND WHO THE FUCK DOESN'T USE TABS TO INDENT LITERALLY WTF WHY WOULD YOU RELEASE A BROKEN PACKAGE TO THE MILLIONS THAT LINT JS???????

Who doesn't use periods literally wth why do you release this broken english to the millions that english is?

Oh. And capitalized characters go at the start of a sentence. Not everywhere.

/Troll (sry, couldn't help myself)

Well, I guess the solution will be deactivating this for the time being...
Who needs linters anyway?

@jugglinmike Can you answer the questions in https://github.com/jshint/jshint/issues/3151#issuecomment-312512856?

I've got 20 unique issues open for different cases of this getting triggered, as it looks like fixing this here will take a while I'd like to move forward with the workaround, assuming that it won't change the results for users.

This issue slipped off my radar; I'm sorry about that, @Arcanemagus. Unfortunately, I don't think I'll be able to give this the attention it deserves until this weekend. Will that work for you?

@jugglinmike Of course 😉

I put in some checks for existing issues, so for the most part people are being filtered to the already open issues pointing here.

@cobexer I like that idea because in addition to giving us a way forward, it
might be useful to folks in other contexts. That said, to my knowledge there
has never been a request for that kind of functionality, and I'm reluctant to
commit to any new feature just because it seems nice. And there's reason to
discourage that feature in particular: between "rc" files, in-line
configuration, and the Node.js API, users already get tripped up when they want
to understand why a given option is enabled. Adding another vector for config
management would tend to exacerbate this problem.

I think most viable solution here is based on my earlier
proposal
.
However, we have to consider the character property as public API--the Atom
Editor plugin is itself built on it, after all. So instead of modifying that
property and defining a new one that has the semantics of the current, I think
we need to leave character as-is and expose the requested data on a new
property name.

I started work on the new feature this weekend. I want to avoid regressions at
all costs, so we need to extend the project's tests to consistently assert the
expected character number. As I began doing this, I found deficiencies in the
test suite that need to be addressed first. gh-3174 is the first step toward
that goal.

All this is to say: it looks like this may take some time. @Arcanemagus I know
you are bearing the brunt of this bug, and I appreciate your taking this as an
opportunity to see JSHint improved. I also like that you are interested in
avoiding any solution that is not transparent for your users. In the short
term, have you had any luck recommending users set the indent option to 1?
It's not ideal, but doing so should resolve their short-term problem in a way
that will continue to work even after we get this patched up.

@Arcanemagus I know you are bearing the brunt of this bug, and I appreciate your taking this as an
opportunity to see JSHint improved.

The entire reason I added the check to the generic library used by most of the Linter providers for Atom is so bugs like this can be caught in the source linters and reported/fixed 😉. This actually would have been caught earlier, but there was a check in linter-jshint that basically hid all invalid point errors from _way_ back when the parser completely failed on most documents and we didn't have a nice way of reporting it to users or of de-duplicating issue reports. Now that those have been figured out I removed that check and here we are 😛.

I also like that you are interested in avoiding any solution that is not transparent for your users.

Actually, a transparent solution for this particular issue would be fine, I just don't know if forcing the indent setting to 1 would change the results they are seeing compared to what they would get from running jshint themselves.

In the short term, have you had any luck recommending users set the indent option to 1?

That's... an excellent idea that I actually hadn't thought of posting in those issues. I'll make sure to mention that in the more commented on of the issues!

Oh, yes, setting the 'indent' property to 1 in the .jshintrc is an excellent workaround. I wish I knew about that sooner. I already have a .jshintrc because jshint doesn't default to es6, so this is simple to add. 👍

Glad to hear it, @tustin2121!

Update: I'm still working to shore up the JSHint test suite to avoid regressions. The latest in that effort is gh-3176.

Any update on this issue?
image

Looks like we're at at least 40 different rules affected by this bug now 😛.

Any updates on this, it's some months since I'm having this errors, driving me nuts :)

Hi @xcrap! I just checked the comment thread, and it doesn't look like anyone has posted any updates. The good news is that JSHint is an open source project, so you can help fix the problem if it's causing you stress! Would you like to lend a hand? I'd be happy to advise you.

@jugglinmike I wish! I always try in tiny projects but my js skills are super basic and limited :)

I placed a $50 bounty on this bug, others can contribute to increase the bounty via this link: https://www.bountysource.com/issues/46533252-tab-indentation-breaks-multiple-rules

Pulling in @tzvipm's fork locally and rebuilding jshint worked to fix the issue for me if anyone else is stumbling across this:

git clone https://github.com/tzvipm/jshint
git remote add upstream [email protected]:jshint/jshint.git
git fetch upstream
git stash
git merge upstream/master
git mergetool --tool=opendiff
npm run build
Was this page helpful?
0 / 5 - 0 ratings

Related issues

timdown picture timdown  ·  7Comments

arian picture arian  ·  7Comments

damyanpetev picture damyanpetev  ·  4Comments

Guichaguri picture Guichaguri  ·  8Comments

TheSavior picture TheSavior  ·  3Comments