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

Formatting analyzer #28873

Merged
merged 27 commits into from
Oct 16, 2018
Merged

Formatting analyzer #28873

merged 27 commits into from
Oct 16, 2018

Conversation

sharwell
Copy link
Member

@sharwell sharwell commented Jul 27, 2018

No description provided.

@sharwell sharwell added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Jul 27, 2018
@sharwell sharwell requested review from a team as code owners July 27, 2018 17:15
@CyrusNajmabadi
Copy link
Member

Right now, it's hard to tell the effect this would have due to the noisiness of the "trailing whitespace" diagnostics. would it be possible to not have those, and then see what sort of impact this would normally be expected to have?

@CyrusNajmabadi
Copy link
Member

Suppress IDE0051 in Microsoft.CodeAnalysis.VisualBasic

why are we not just suppressing at the project level... having a million line-suppressions just means we have so much noise that interferes with seeing what actually benefits here.

@sharwell
Copy link
Member Author

why are we not just suppressing at the project level... having a million line-suppressions just means we have so much noise that interferes with seeing what actually benefits here.

I'm on a bug hunt, looking for bugs in the formatter and bugs in the Suppress Message feature. Turns out this analyzer is quite good at revealing both.

@heejaechang
Copy link
Contributor

if a fix for this analyzer will fix one diagnostic, then I think reporting diagnostic per change seems right. if a fix for this analyzer will fix whole document, then I think reporting diagnostic per document seems right.

@CyrusNajmabadi
Copy link
Member

if a fix for this analyzer will fix one diagnostic, then I think reporting diagnostic per change seems right. if a fix for this analyzer will fix whole document, then I think reporting diagnostic per document seems right.

Agreed. That's a good way to think about it.

@heejaechang heejaechang added the Need Design Review The end user experience design needs to be reviewed and approved. label Jul 27, 2018
@sharwell
Copy link
Member Author

if a fix for this analyzer will fix one diagnostic, then I think reporting diagnostic per change seems right. if a fix for this analyzer will fix whole document, then I think reporting diagnostic per document seems right.

I'm leaning towards implementing the simple fix as fixing all squiggles on the line where invoked, and the Fix All in Document runs FormatAsync.

@sharwell sharwell force-pushed the formatting-analyzer branch 2 times, most recently from 6753d80 to ea59c4f Compare July 29, 2018 15:18
@CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi Is there a way to validate diagnostic spans? The current test is passing if I change the line the following:

There may be. I'm not certain. Look at the base classes and their public/protected helpers.

I would have expected a test failure because the markup span does not match the reported diagnostic span.

I agree. The original test harness validated this. However, when the rewrite of all the implementations of these analyzers changed, these were changed to be less strict in what they checked (i think to make the porting over easier). But it means they're less effective in terms of validating the experience is working properly.

If you wanted to tighten the check, that would be fine with me. I expect you'd have to go update a whole swath of tests. But i think that would be totally fine to do (and i'd be willing to review for you).

I'm also interested in how I can test multiple diagnostics reported in a single input, such as the following:

You'd have to write a helper for that.

options = options.WithChangedOption(FormattingOptions.AllowConcurrent, false);
var resultTask = GetFormattedTextChangesAsync(node, workspace, options, cancellationToken);
Debug.Assert(resultTask.IsCompleted);
return resultTask.WaitAndGetResult_CanCallOnBackground(cancellationToken);
Copy link
Member Author

Choose a reason for hiding this comment

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

@jasonmalinowski Please make sure to review the new pattern in this method.

Copy link
Member

Choose a reason for hiding this comment

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

This seems like this deserves a comment. Is there a concern here about blocking a thread on a parallelized algorithm?

Copy link
Contributor

Choose a reason for hiding this comment

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

the one who calls this API should set the option, not the API itself set the option.

Copy link
Member Author

@sharwell sharwell Aug 8, 2018

Choose a reason for hiding this comment

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

Is there a concern here about blocking a thread on a parallelized algorithm?

Yes, the analyzer runs in parallel on the thread pool. It would be easy for it to starve the system.

the one who calls this API should set the option

The asynchronous form of this method provides opportunistic parallelization, if desired.

Copy link
Member

Choose a reason for hiding this comment

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

So, i'm somewhat ok with this change. But it would def need to be applied a bit uniformly. We could also consider deprecating this guy. It always worries me when we expose sync entrypoints that immediately block on the async version.

It should also be a warning to us for future API development. It's likely we'll need to default things to being async so we don't end up hurting ourselves here later. A good example of that is around the discussions of Options. Options present a synchronous API, but need to block on async work. If we then make Options async, it virally hits entrypoints like this (which are currently fine being synchronous).

If we had settled on these being async from teh start, we wouldn't have these problems cropping up over time as more core parts of our system become async.

Copy link
Member Author

@sharwell sharwell Oct 4, 2018

Choose a reason for hiding this comment

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

But it would def need to be applied a bit uniformly.

Implementing this for the rest of the synchronous Formatter methods. It's so ugly it makes me sad but implementing the synchronous form all-the-way-down was a huge amount of work and mostly duplicated code.

Copy link
Member

Choose a reason for hiding this comment

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

so the thing i'm missing is: how do you know the returned task iscomplete?

Copy link
Member

Choose a reason for hiding this comment

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

oh, i see. because you pass AllowConcurrent: false. gotcha.

Copy link
Member

Choose a reason for hiding this comment

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

Note: my preference wouldjust be deprecate these methods as we do this.

Copy link
Member Author

@sharwell sharwell Oct 9, 2018

Choose a reason for hiding this comment

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

The diagnostic analyzer code paths are synchronous, and rely on the new synchronous behavior of these methods to avoid thread pool starvation in projects with very large files.

Copy link
Contributor

@mavasani mavasani left a comment

Choose a reason for hiding this comment

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

The core analyzer/fixer changes LGTM.

I would still request adding a unit test to guard the reflection based code and also let someone from @dotnet/roslyn-infrastructure review the changes to Packages.props.

{
OptionSet options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

// The in-IDE workspace supports .editorconfig without special handling. However, the AdhocWorkspace used
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a test-only code? If so, can it be refactored into a test-only method?

Copy link
Member Author

@sharwell sharwell Oct 11, 2018

Choose a reason for hiding this comment

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

It's not strictly test-only code. It's addressing a limitation of the workspace which would naturally go away once we switch the code to using the new .editorconfig support in the compiler.

It could be considered test-only code from the perspective that removing the code would not produce a failure inside the IDE, but it could still produce failures in tools like AnalyzerRunner.

@jinujoseph jinujoseph removed the Need Design Review The end user experience design needs to be reviewed and approved. label Oct 11, 2018
analyzer.InitializeWorker(context);
}

private static Assembly HandleAssemblyResolve(object sender, ResolveEventArgs args)
Copy link
Member

Choose a reason for hiding this comment

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

Where is the bug link tracking the removal of this? Can't imagine this is part of the long term solution here.

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ #30472

@@ -8,16 +8,17 @@
<RootNamespace>Microsoft.CodeAnalysis.CSharp</RootNamespace>
<TargetFramework>netstandard1.3</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisCSharpFixedVersion)" />
Copy link
Member

Choose a reason for hiding this comment

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

Why are we referencing a package here instead of the corresponding source project? Feel like we need a good explanation here. This is extremely odd and I'm not going to be the last person confused by this.

Copy link
Member

Choose a reason for hiding this comment

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

I'm interested in understanding this too. If there's a good reason, it's not obvious.

Copy link
Member Author

Choose a reason for hiding this comment

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

All the hacks for this package exist so we can get feedback from users about the behavior of this analyzer in developer and CI scenarios. To accomplish that, it is installable in and works with 15.7 plus.

Copy link
Member

@jaredpar jaredpar left a comment

Choose a reason for hiding this comment

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

Signing off on the infrastructure side of the change. The core followup item is #30472

@jinujoseph
Copy link
Contributor

test windows_release_vs-integration_prtest

@jinujoseph jinujoseph added this to the 16.0.P1 milestone Oct 15, 2018
@jinujoseph
Copy link
Contributor

Approved to merge when ready

@jinujoseph
Copy link
Contributor

test windows_release_vs-integration_prtest

@sharwell sharwell merged commit 1c8e816 into dotnet:dev16.0.x Oct 16, 2018
@sharwell sharwell deleted the formatting-analyzer branch October 16, 2018 16:41
@MarcoRossignoli
Copy link
Member

Hi guys!
This analyzer will be published as a nuget package?
If so when?

@sharwell
Copy link
Member Author

@MarcoRossignoli I moved your comment to #30541 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants