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

.razor: implement the token type metrics #7924

Closed
wants to merge 15 commits into from

Conversation

antonioaversa
Copy link
Contributor

@antonioaversa antonioaversa commented Aug 30, 2023

Fixes #7895
Draft: don't merge, this PR is still based on #7916 by @costin-zaharia-sonarsource, due to dependencies on lines and location span mapping. DONE
Once #7916 is merged to master, this PR should be rebased. DONE
Also, IT should be implemented.

Issue with numeric tokens

The current implementation for the TokenTypeAnalyzer in this branch has an issue: it reports numeric tokens that don't exist in the original razor file. The issue comes from a bug in location mapping.

Take for example line 84 from the RazorTokens.razor file (defined here).

<p>@DateTime.Now</p>

The generated code for that line is the following:

            __builder.OpenElement(8, "p");
#nullable restore
#line (84,5)-(84,17) 24 "C:\dev\TestApp1\RazorClassLibrary1\Template.razor"
__builder.AddContent(9, DateTime.Now);

#line default
#line hidden
#nullable disable
            __builder.CloseElement();
            __builder.AddMarkupContent(10, "\r\n");

Because #line (84,5)-(84,17) 24 is not handled correctly when deriving the original location in the razor file from the location in the generated file, the numeric token 9 (right before DateTime.Now) is considered as coming from the original razor file, and not as a token in the generated code only.

Therefore, the following tokens are reported for line 84:

{ "tokenType": "NUMERIC_LITERAL", "textRange": { "startLine": 84, "endLine": 84, "startOffset": 4, "endOffset": 17 } }
{ "tokenType": "TYPE_NAME", "textRange": { "startLine": 84, "endLine": 84, "startOffset": 5, "endOffset": 13 } }

instead of

{ "tokenType": "TYPE_NAME", "textRange": { "startLine": 84, "endLine": 84, "startOffset": ..., "endOffset": ... } }

The issue basically affects all lines that generate enhanced line directives, and doesn't affect lines that:

  • are entirely C# (e.g. within @code { ... } or @{ ... } etc.)
  • or entirely Razor (e.g. @page "/razor", @namespace MyRazorNamespace, etc.)
  • or entirely HTML (e.g. @@page "/razor" or <p>var x = 42;</p>).

Issue with tokens position asserting

Because:

  • positions are off
  • and wrong numeric tokens are reported, which don't exist in the original razor file, and overlap with other tokens
    we can't effectively use [x:...] syntax, introduced by @martin-strecker-sonarsource to assert tokens existence and positions.

The square brackets for all tokens whose location is mapped with enhanced line directives would need to be placed some columns off, to be reported correctly. Moreover, non-existing, numeric, overlapping tokens would break assertion.

So, for the time being, and while positions are fixed, this PR is only asserting how many tokens are defined per line, and of what type (here).

Performance impact of this change

Tested on local SonarQube Development 10.2.0.76792 on Dell laptop, on power network.
Project tested: https://github.com/MudBlazor/MudBlazor/tree/1e7677c70fefa1ac440e9fadbdf1aed64a336653
sonar-dotnet commit: 392d38b (feature)

Results (total build time):
00:01:28.33
00:01:58.35
00:02:02.40
00:01:50.90
00:01:59.53

sonar-dotnet commit: TBD (merge-base)
TBD

@antonioaversa antonioaversa linked an issue Aug 30, 2023 that may be closed by this pull request
@antonioaversa antonioaversa changed the title Antonio/razor token type .razor: implement the token type metrics Aug 30, 2023
@antonioaversa
Copy link
Contributor Author

@costin-zaharia-sonarsource The PR is still in draft and shouldn't be merged yet.
However, I am assigning this to you already as I would like to have early feedback on these first changes, before proceeding any further.
That will also make handover easier, shouldn't I be able to complete the work before the end of the week.
I have organized the history into 3 commits for an easier per-commit review.
Thanks!

@antonioaversa
Copy link
Contributor Author

@costin-zaharia-sonarsource : Back to you for a second round of review.
UTs added, coverage increased from 93% of the 1st iteration to 100% of the 2nd iteration.
ITs are still missing, for the same reasons of the Symbol metric references and executable LOC metrics.

@antonioaversa
Copy link
Contributor Author

@cristian-ambrosini-sonarsource As discussed offline, adding you for a first review of the second round of review. @costin-zaharia-sonarsource will then take over when I am off.

@antonioaversa antonioaversa changed the base branch from master to costin/syntax-ref-mapping August 31, 2023 15:34
@sonarcloud
Copy link

sonarcloud bot commented Aug 31, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

var span = token.GetLocation().GetMappedLineSpanIfAvailable();
return tokenType == TokenType.UnknownTokentype
|| (string.IsNullOrWhiteSpace(token.Text) && tokenType != TokenType.StringLiteral)
|| !(string.IsNullOrWhiteSpace(filePath) || string.Equals(span.Path, filePath, StringComparison.OrdinalIgnoreCase))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't return null if the filePath is null or whitespace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made that choice for two reasons:

  1. convenience: ClassifierTestHarness.AssertTokenTypes instantiates a TokenClassifier instance and a TriviaClassifier instance without having at hand the file path, which is implicitly created by ParseTokens
  2. safety: while it seems indeed reasonable, to always return null in absence of filePath, I didn't know whether a SyntaxTree may have, for any reason, no file path (as it was somehow fully compiled in-memory), and I didn't want to alter the behavior the TokenTypeAnalyzer had before these changes

If we can/want to assume that the TokenTypeAnalyzer should always require filePath, we should do some refactoring to the ParseTokens, to basically return snippet0.cs, which would then be passed to the classifier.

// Handle preprocessor directives here
_ => null,
};
string.IsNullOrWhiteSpace(filePath)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, I think we should ignore tokens if they don't have a file path. Do you have maybe an example of when this happens?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered here

@costin-zaharia-sonarsource
Copy link
Member

costin-zaharia-sonarsource commented Sep 1, 2023

It looks good to me so far. As you mentioned, the test cases need to be finished, and we need to make some decisions about what we do with locations since they are wrongly mapped by Roslyn.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! I left only one super nitpick comment

@antonioaversa
Copy link
Contributor Author

@costin-zaharia-sonarsource @cristian-ambrosini-sonarsource I have addressed/replied to the comments made in the second round of review. I hand the PR over to @costin-zaharia-sonarsource for the next steps, which are described in the description of the PR.

@costin-zaharia-sonarsource costin-zaharia-sonarsource force-pushed the costin/syntax-ref-mapping branch 9 times, most recently from 57be89d to 6ab3261 Compare September 5, 2023 11:35
Base automatically changed from costin/syntax-ref-mapping to master September 5, 2023 12:06
@antonioaversa antonioaversa marked this pull request as ready for review September 19, 2023 17:44
@sonarcloud
Copy link

sonarcloud bot commented Sep 19, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@antonioaversa antonioaversa marked this pull request as draft September 21, 2023 08:34
@antonioaversa
Copy link
Contributor Author

antonioaversa commented Sep 21, 2023

Update: moved back to be a draft, since location mapping for nested Razor expressions should be fixed first, for the reasons expressed here.

@antonioaversa
Copy link
Contributor Author

I am closing the PR, given that

  • this effort was paused in 2023, waiting for the Roslyn team to change the mapping strategy
  • the razor syntax highlighting has been de-prioritized afterward
  • this PR has now a lot of conflicts, due to the many changes happened

I am adding a reference to the text in the description in the issue, so that a new implementation can benefit of the analysis done while implementing this PR.

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.

.razor: implement the token type metrics
4 participants