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

Redo pubternalyzer with Roslyn Operations #21996

Merged
merged 13 commits into from
Aug 16, 2020
Merged

Redo pubternalyzer with Roslyn Operations #21996

merged 13 commits into from
Aug 16, 2020

Conversation

roji
Copy link
Member

@roji roji commented Aug 8, 2020

  • Rewrite most of the analyzer using Operations, for much better perf and VB.NET support.
  • Support some extra language scenarios which weren't being detected.

Fixes #19648
Fixes #20206

* Rewrite most of the analyzer using Operations, for much better
  perf and VB.NET support.
* Support some extra language scenarios which weren't being detected.

Fixes #19648
Fixes #20206
@@ -365,9 +365,12 @@ private BlockExpression AddIncludes(BlockExpression shaperBlock)
var includeMethod = navigation.IsCollection ? _includeCollectionMethodInfo : _includeReferenceMethodInfo;
var includingClrType = navigation.DeclaringEntityType.ClrType;
var relatedEntityClrType = navigation.TargetEntityType.ClrType;
#pragma warning disable EF1001 // Internal EF Core API usage.
Copy link
Member Author

Choose a reason for hiding this comment

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

I think you already know about these internal usages @AndriySvyryd, but just in case.

@@ -88,7 +88,9 @@ public class MigrationsModelDiffer : IMigrationsModelDiffer
{
Check.NotNull(typeMappingSource, nameof(typeMappingSource));
Check.NotNull(migrationsAnnotations, nameof(migrationsAnnotations));
#pragma warning disable EF1001 // Internal EF Core API usage.
Copy link
Member Author

Choose a reason for hiding this comment

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

/cc @bricelam

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll defer to @AndriySvyryd on these since they're here for seed data

Copy link
Member

Choose a reason for hiding this comment

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

Filed #22063
Let's just say that the current approach is not as robust as it should be

@roji
Copy link
Member Author

roji commented Aug 9, 2020

/cc @mvasani and @sharwell in case you're interested in taking a look

@roji roji requested a review from a team August 9, 2020 05:25
@roji roji requested a review from dougbu as a code owner August 11, 2020 13:36
@roji
Copy link
Member Author

roji commented Aug 11, 2020

@sharwell and @mavasani would it be possible to get a quick review of this analyzer after these changes are done? I'm particularly interested in any perf issues which stand out (this PR resolves some severe problems from before), but also interested in any general feedback.

BTW this takes a dependency on the recently-released 3.7.0 packages, does that have any possible bad consequences? Any idea which minimum VS version is required by this?

@AndriySvyryd I've done some considerable improvements after your review, you may want to check it out again.

@@ -137,7 +139,9 @@ public class MigrationsModelDiffer : IMigrationsModelDiffer
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
#pragma warning disable EF1001 // Internal EF Core API usage.
Copy link
Member Author

Choose a reason for hiding this comment

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

@bricelam same

Comment on lines +249 to +266
CSharpSyntax.InvocationExpressionSyntax s
when s.Expression is CSharpSyntax.MemberAccessExpressionSyntax memberAccessSyntax
=> memberAccessSyntax.Name,
CSharpSyntax.MemberAccessExpressionSyntax s => s.Name,
CSharpSyntax.ObjectCreationExpressionSyntax s => s.Type,
CSharpSyntax.PropertyDeclarationSyntax s => s.Type,
CSharpSyntax.VariableDeclaratorSyntax declarator
=> declarator.Parent is CSharpSyntax.VariableDeclarationSyntax declaration
? declaration.Type
: (SyntaxNode)declarator,
CSharpSyntax.TypeOfExpressionSyntax s => s.Type,

VBSyntax.InvocationExpressionSyntax s
when s.Expression is VBSyntax.MemberAccessExpressionSyntax memberAccessSyntax
=> memberAccessSyntax.Name,
VBSyntax.MemberAccessExpressionSyntax s => s.Name,
VBSyntax.ObjectCreationExpressionSyntax s => s.Type,
VBSyntax.TypeOfExpressionSyntax s => s.Type,

Choose a reason for hiding this comment

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

It seems it would be better if you have different language specific analyzer assemblies for language specific code. Otherwise, your analyzer will cause a C# only solution to load all VB Roslyn assemblies and vice versa, which has an unnecessary assembly load overhead.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good point - even if the assembly load overhead would only apply at build time...

The problem is that our analyzers package - Microsoft.EntityFrameworkCore.Analyzers - isn't typically referenced directly by user, but is brought in transitively as a dependency of Microsoft.EntityFrameworkCore. I know that ASP.NET also have a similar pattern, do you have any guidance on this, or any particular reason why the additional VB assembly load should be avoided?

If this is a big issue, we can drop the VB dependency altogether - it's only used to produce better/narrower diagnostic locations - the warnings themselves would still appear as we're using language-independent APIs here.

Choose a reason for hiding this comment

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

Normally the way this would be done is that your analyzer package will have 3 assemblies - Core, C# specific and VB specific. Then the MSBuild/SDK machinery will ensure that C# projects have analyzer references to first two and VB projects to the first and third. This way if someone has a C# only solution or a VB only solution, they do not get penalized by loading non-required language Roslyn assemblies (which can be quite a few as most of Roslyn layers are divided the same way). @jmarolf can probably help with setting up/guiding on the SDK pieces.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh nice, was not aware of this... Any pointer to an analyzer package which does this would be sufficient!

Choose a reason for hiding this comment

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

@jmarolf did this work for the Microsoft.CodeAnalysis.NetAnalyzers nuget package that we now insert into the .NET SDK. He can give pointers on how you can match his apporoach.

Copy link
Member Author

Choose a reason for hiding this comment

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

Scoping this out to #22085

Copy link
Member

Choose a reason for hiding this comment

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

Otherwise, your analyzer will cause a C# only solution to load all VB Roslyn assemblies and vice versa, which has an unnecessary assembly load overhead.

Note that it's slightly worse than this implies. Csc does not provide the VB assemblies, and vbc does not provide the C# assemblies. Command line use of an analyzer that references both will work if and only if the shared compiler server VBCSCompiler.exe is used, but that will occasionally fail to process a request and silently fall back to the language-specific executables, at which point the analyzers will silently fail to run.

private static void AnalyzeInvocation(OperationAnalysisContext context, IInvocationOperation invocation)
{
// First check for any internal type parameters
foreach (var a in invocation.TargetMethod.TypeArguments)

Choose a reason for hiding this comment

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

Do we do similar analysis for generic type arguments of named types?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not at the moment. Do you have guidance on how to get the generic type arguments of an ITypeSymbol?

Copy link
Member Author

Choose a reason for hiding this comment

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

Scoping out to #22086, any guidance on this would be appreciated.

@roji
Copy link
Member Author

roji commented Aug 16, 2020

This seems in a good enough state to merge, I've scoped out some possible additional work to external issues.

@Youssef1313
Copy link
Member

@roji, There was a performance complaint for this analyzer. See https://github.com/dotnet/core/issues/5672#issuecomment-776802704.

@roji
Copy link
Member Author

roji commented Feb 11, 2021

@Youssef1313 thanks for pinging me, I was unaware of this. Let's wait to see what Jared's suggestion does - it's very likely to be the issue indeed.

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