Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[READY] Fix empty location extent after missing semicolon #860

Merged
merged 3 commits into from
Oct 22, 2017

Conversation

micbou
Copy link
Collaborator

@micbou micbou commented Oct 20, 2017

We currently use the following (convoluted) method to compute the location extent of a diagnostic i.e. the range of the identifier where the diagnostic occurred:

  • obtain a range from the clang_getCursorExtent function, which is supposed to contain our identifier;
  • extract all the tokens from that range with clang_tokenize;
  • find the token with the same starting position as the diagnostic;
  • use the length of that token to get the ending position;
  • compute the range.

Unfortunately, this doesn't always work as shown in issue #859, In that case, clang_getCursorExtent returns an empty range for all diagnostics after the missing semicolon.

This PR fixes that issue by extracting the tokens from the diagnostic position to the immediate next character then using clang_getTokenExtent to get the range of the identifier (multiline identifiers are supported).

Fixes #859.


This change is Reviewable

@micbou micbou force-pushed the fix-empty-location-extent branch from 8cb4844 to 6d7addd Compare October 20, 2017 21:28
@micbou
Copy link
Collaborator Author

micbou commented Oct 20, 2017

In fact, we don't need to compute the location of the next character for the end of the range. We can use the same position for the start and the end.


Reviewed 3 of 3 files at r1.
Review status: all files reviewed at latest revision, all discussions resolved.


Comments from Reviewable

@codecov-io
Copy link

codecov-io commented Oct 21, 2017

Codecov Report

Merging #860 into master will decrease coverage by 0.02%.
The diff coverage is 85.71%.

@@            Coverage Diff             @@
##           master     #860      +/-   ##
==========================================
- Coverage   94.78%   94.76%   -0.03%     
==========================================
  Files          79       79              
  Lines        5431     5427       -4     
  Branches      170      171       +1     
==========================================
- Hits         5148     5143       -5     
  Misses        235      235              
- Partials       48       49       +1

@joelhock
Copy link

Thank you for the quick response, I can verify that this does indeed fix the issue I reported in #859

I hesitate to complicate this further with a much more minor nit, but perhaps there's a quick fix since you're already thinking about this: both with and without this PR, ycmd will take this code:

class A {
    A()// extent of missing semicolon is this whole comment if no space before it
};

and, if there is no space before the comment, as shown, ycmd will report the entire comment length as the extent for the missing semicolon diagnostic.

[
    {
        "kind": "ERROR",
        "text": "expected ';' at end of declaration list",
        "ranges": [],
        "location": {
            "filepath": "mysource.cpp",
            "column_num": 8,
            "line_num": 2
        },
        "location_extent": {
            "start": {
                "filepath": "mysource.cpp",
                "column_num": 8,
                "line_num": 2
            },
            "end": {
                "filepath": "mysource.cpp",
                "column_num": 82,
                "line_num": 2
            }
        },
        "fixit_available": true
    }
]

@micbou
Copy link
Collaborator Author

micbou commented Oct 22, 2017

Comments are now ignored when computing the location extent. I think this makes sense as comments are not a functional part of the code.


Reviewed 2 of 2 files at r2.
Review status: all files reviewed at latest revision, all discussions resolved.


Comments from Reviewable

@puremourning
Copy link
Member

Review status: all files reviewed at latest revision, 2 unresolved discussions.


cpp/ycm/ClangCompleter/ClangHelpers.cpp, line 174 at r2 (raw file):

  for ( size_t i = 0; i < num_tokens; ++i ) {
    CXToken token = tokens[ i ];
    if ( clang_getTokenKind( token ) == CXToken_Comment )

IIRC there are parser errors that can happen within comments. For example, I feel like clang can diagnose /* within comment (in fact, i'm certain it can):

Screen Shot 2017-10-22 at 17.05.34.png

Also with -pedantic you can get errors about multi-line // comments (yep, seriously):

Screen Shot 2017-10-22 at 17.07.12.png

Does this therefore make that not work, or work less well?


ycmd/tests/clang/diagnostics_test.py, line 275 at r2 (raw file):

        'filepath': '/foo'
      } ),
      # NOTE: we always return a location extent even if we can't find one since

In this scenario, i feel like the right thing to do is to put the squiggle under the character that is the "location" of the diagnostic. Is that what happens ? If not, would it be possible to return a range which was just that one character? In the case of missing semi-colon, the squiggle should be the place where the semi-colon would be written (which i think is the position returned in the location entry?


Comments from Reviewable

@micbou
Copy link
Collaborator Author

micbou commented Oct 22, 2017

Reviewed 2 of 2 files at r3.
Review status: all files reviewed at latest revision, 2 unresolved discussions.


cpp/ycm/ClangCompleter/ClangHelpers.cpp, line 174 at r2 (raw file):

Previously, puremourning (Ben Jackson) wrote…

IIRC there are parser errors that can happen within comments. For example, I feel like clang can diagnose /* within comment (in fact, i'm certain it can):

Screen Shot 2017-10-22 at 17.05.34.png

Also with -pedantic you can get errors about multi-line // comments (yep, seriously):

Screen Shot 2017-10-22 at 17.07.12.png

Does this therefore make that not work, or work less well?

No, the behavior is identical because, with or without these changes, there is no location extent and so the location itself is used (at least in YCM). However, if we don't ignore the comments, we get

location-extent-comments.png

which doesn't feel right.


ycmd/tests/clang/diagnostics_test.py, line 275 at r2 (raw file):

Previously, puremourning (Ben Jackson) wrote…

In this scenario, i feel like the right thing to do is to put the squiggle under the character that is the "location" of the diagnostic. Is that what happens ? If not, would it be possible to return a range which was just that one character? In the case of missing semi-colon, the squiggle should be the place where the semi-colon would be written (which i think is the position returned in the location entry?

If there is no location extent, YCM falls back to the location itself but that may not be the case for other clients so I think your suggestion is sound. Done.


Comments from Reviewable

@puremourning
Copy link
Member

:lgtm: nice work!


Review status: all files reviewed at latest revision, 2 unresolved discussions.


cpp/ycm/ClangCompleter/ClangHelpers.cpp, line 174 at r2 (raw file):

Previously, micbou wrote…

No, the behavior is identical because, with or without these changes, there is no location extent and so the location itself is used (at least in YCM). However, if we don't ignore the comments, we get

location-extent-comments.png

which doesn't feel right.

OK makes sense, thanks!


ycmd/tests/clang/diagnostics_test.py, line 275 at r2 (raw file):

Previously, micbou wrote…

If there is no location extent, YCM falls back to the location itself but that may not be the case for other clients so I think your suggestion is sound. Done.

Great!


Comments from Reviewable

@puremourning
Copy link
Member

Reviewed 1 of 2 files at r2, 2 of 2 files at r3.
Review status: all files reviewed at latest revision, 2 unresolved discussions.


Comments from Reviewable

@micbou
Copy link
Collaborator Author

micbou commented Oct 22, 2017

Review status: all files reviewed at latest revision, 2 unresolved discussions.


cpp/ycm/ClangCompleter/ClangHelpers.cpp, line 174 at r2 (raw file):

Previously, puremourning (Ben Jackson) wrote…

OK makes sense, thanks!

Wait, the second example in my screenshot still happens if we ignore comments. Looks like libclang returns multiple as an identifier token. Well, I guess we can't do much about it.


Comments from Reviewable

@Valloric
Copy link
Member

Thanks for the PR!

@zzbot r=puremourning


Review status: all files reviewed at latest revision, 2 unresolved discussions, some commit checks failed.


Comments from Reviewable

@zzbot
Copy link
Contributor

zzbot commented Oct 22, 2017

📌 Commit dff5163 has been approved by puremourning

@zzbot
Copy link
Contributor

zzbot commented Oct 22, 2017

⌛ Testing commit dff5163 with merge 2657b65...

zzbot added a commit that referenced this pull request Oct 22, 2017
[READY] Fix empty location extent after missing semicolon

We currently use the following (convoluted) method to compute the location extent of a diagnostic i.e. the range of the identifier where the diagnostic occurred:
 - obtain a range from [the `clang_getCursorExtent` function](https://clang.llvm.org/doxygen/group__CINDEX__CURSOR__SOURCE.html#ga79f6544534ab73c78a8494c4c0bc2840), which is supposed to contain our identifier;
 - extract all the tokens from that range with [`clang_tokenize`](https://clang.llvm.org/doxygen/group__CINDEX__LEX.html#ga6b315a71102d4f6c95eb68894a3bda8a);
 - find the token with the same starting position as the diagnostic;
 - use the length of that token to get the ending position;
 - compute the range.

Unfortunately, this doesn't always work as shown in issue #859, In that case, `clang_getCursorExtent` returns an empty range for all diagnostics after the missing semicolon.

This PR fixes that issue by extracting the tokens from the diagnostic position to the immediate next character then using `clang_getTokenExtent` to get the range of the identifier (multiline identifiers are supported).

Fixes #859.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/ycmd/860)
<!-- Reviewable:end -->
@zzbot
Copy link
Contributor

zzbot commented Oct 22, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: puremourning
Pushing 2657b65 to master...

@zzbot zzbot merged commit dff5163 into ycm-core:master Oct 22, 2017
@micbou micbou deleted the fix-empty-location-extent branch October 26, 2017 22:48
zzbot added a commit to ycm-core/YouCompleteMe that referenced this pull request Dec 3, 2017
[READY] Update ycmd

Include the following changes:
 - PR ycm-core/ycmd#856: update JediHTTP;
 - PR ycm-core/ycmd#860: improve diagnostics location in C-family languages;
 - PR ycm-core/ycmd#865: use Objective-C triggers for Objective-C++;
 - PR ycm-core/ycmd#869: support TypeScript 2.6.1;
 - PR ycm-core/ycmd#875: allow switching to a different JavaScript project with `RestartServer`;
 - PR ycm-core/ycmd#877: support `-idirafter` include flag in C-family languages.

Update the JavaScript documentation on how to switch to a different project. We only mention the `:YcmCompleter RestartServer` way as other methods involve restarting ycmd and losing all its data like stored identifiers.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2839)
<!-- Reviewable:end -->
snakeleon added a commit to snakeleon/YouCompleteMe-x64 that referenced this pull request Dec 4, 2017
Include the following changes:
 - PR ycm-core/ycmd#856: update JediHTTP;
 - PR ycm-core/ycmd#860: improve diagnostics location in C-family languages;
 - PR ycm-core/ycmd#865: use Objective-C triggers for Objective-C++;
 - PR ycm-core/ycmd#869: support TypeScript 2.6.1;
 - PR ycm-core/ycmd#875: allow switching to a different JavaScript project with `RestartServer`;
 - PR ycm-core/ycmd#877: support `-idirafter` include flag in C-family languages.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

clang diagnostics location_extent zeros when source has a certain type of error
6 participants