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

Filter trees to only those containing global-usings or attributes prior to analyzing them. #62444

Merged
merged 10 commits into from
Jul 7, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.SourceGeneration;
using Microsoft.CodeAnalysis.PooledObjects;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.SourceGeneration;
using Roslyn.Utilities;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.CodeAnalysis.CSharp
{
Expand Down Expand Up @@ -112,5 +112,48 @@ public override void AddAliases(CompilationOptions compilation, ArrayBuilder<(st
// C# doesn't have global aliases at the compilation level.
return;
}

public override bool ContainsGlobalAliases(SyntaxNode root, CancellationToken cancellationToken)
{
// Walk down the green tree to avoid unnecessary allocations of red nodes.
var compilationUnit = (Syntax.InternalSyntax.CompilationUnitSyntax)root.Green;

return usingsContainGlobalAliases(compilationUnit.Usings) ||
membersContainGlobalAliases(compilationUnit.Members);

bool usingsContainGlobalAliases(CodeAnalysis.Syntax.InternalSyntax.SyntaxList<Syntax.InternalSyntax.UsingDirectiveSyntax> usings)
{
foreach (var directive in usings)
{
if (directive.GlobalKeyword != null &&
directive.Alias != null)
{
return true;
}
}

return false;
}

bool membersContainGlobalAliases(CodeAnalysis.Syntax.InternalSyntax.SyntaxList<Syntax.InternalSyntax.MemberDeclarationSyntax> members)
{
foreach (var member in members)
{
if (member is Syntax.InternalSyntax.BaseNamespaceDeclarationSyntax baseNamespace &&
namespaceContainsGlobalAliases(baseNamespace))
{
return true;
}
}

return false;
}

bool namespaceContainsGlobalAliases(Syntax.InternalSyntax.BaseNamespaceDeclarationSyntax baseNamespace)
{
return usingsContainGlobalAliases(baseNamespace.Usings) ||
membersContainGlobalAliases(baseNamespace.Members);
}
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1023,8 +1023,8 @@ class C { }
Assert.Collection(runResult.TrackedSteps["result_ForAttribute"],
step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" }));

Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute"));
Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Expand Down Expand Up @@ -1063,8 +1063,8 @@ class C { }
Assert.Collection(runResult.TrackedSteps["result_ForAttribute"],
step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" }));

Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute"));
Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Expand Down Expand Up @@ -1106,14 +1106,13 @@ class C { }

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Removed, s.Outputs.Single().Reason));
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));

// the per-file global aliases get changed (because the last file is removed).
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

// however, the collected global aliases stays the same.
Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs,
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
Expand Down Expand Up @@ -1161,16 +1160,15 @@ class C { }

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason));
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs,
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason);
}

Expand Down Expand Up @@ -1211,17 +1209,16 @@ class C { }

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason));
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs,
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.New, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason);

Assert.Collection(runResult.TrackedSteps["result_ForAttribute"],
step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" }));
Expand Down Expand Up @@ -1266,7 +1263,6 @@ class Dummy {}

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Expand Down Expand Up @@ -1312,19 +1308,13 @@ class C { }
compilation.SyntaxTrees.First()));
runResult = driver.GetRunResult().Results[0];

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Modified, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Removed, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.False(runResult.TrackedSteps.ContainsKey("individualFileGlobalAliases_ForAttribute"));
Assert.False(runResult.TrackedSteps.ContainsKey("collectedGlobalAliases_ForAttribute"));
Assert.False(runResult.TrackedSteps.ContainsKey("allUpGlobalAliases_ForAttribute"));

Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs,
o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason),
o => Assert.Equal(IncrementalStepRunReason.Modified, o.Reason),
o => Assert.Equal(IncrementalStepRunReason.Removed, o.Reason));
Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["compilationUnitAndGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Removed, runResult.TrackedSteps["result_ForAttribute"].Single().Outputs.Single().Reason);
Assert.False(runResult.TrackedSteps.ContainsKey("compilationUnit_ForAttribute"));
Assert.False(runResult.TrackedSteps.ContainsKey("compilationUnitAndGlobalAliases_ForAttribute"));
Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttribute"));
Copy link
Member Author

Choose a reason for hiding this comment

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

@chsienki i need help here. for some reason the incremental generator is not tracking any steps here when the list filters down to the empty set. Can you help me debug through this to find out why that is?

Copy link
Member

Choose a reason for hiding this comment

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

I looked at this, and I see whats going on. I think I have a fix for it, but its a little involved. I think we should open an issue here, and take the fix as a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do.

Copy link
Member Author

Choose a reason for hiding this comment

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

Tracked with #62468

}

[Fact]
Expand Down Expand Up @@ -1358,7 +1348,6 @@ class C { }
runResult = driver.GetRunResult().Results[0];

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Expand Down Expand Up @@ -1403,7 +1392,6 @@ class C { }
runResult = driver.GetRunResult().Results[0];

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Expand Down Expand Up @@ -1454,11 +1442,9 @@ class D { }"))));

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs,
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
Expand Down Expand Up @@ -1506,11 +1492,9 @@ class D { }"))));

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.New, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Modified, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Unchanged, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

Assert.Collection(runResult.TrackedSteps["compilationUnit_ForAttribute"].Single().Outputs,
o => Assert.Equal(IncrementalStepRunReason.Unchanged, o.Reason),
Expand Down Expand Up @@ -1567,8 +1551,7 @@ class D { }"))));

Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"],
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason),
s => Assert.Equal(IncrementalStepRunReason.Unchanged, s.Outputs.Single().Reason));
s => Assert.Equal(IncrementalStepRunReason.Cached, s.Outputs.Single().Reason));
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["collectedGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);
Assert.Equal(IncrementalStepRunReason.Cached, runResult.TrackedSteps["allUpGlobalAliases_ForAttribute"].Single().Outputs.Single().Reason);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.PooledObjects;

namespace Microsoft.CodeAnalysis.SourceGeneration
Expand Down Expand Up @@ -36,6 +37,8 @@ internal interface ISyntaxHelper
/// </summary>
void AddAliases(GreenNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global);
void AddAliases(CompilationOptions options, ArrayBuilder<(string aliasName, string symbolName)> aliases);

bool ContainsGlobalAliases(SyntaxNode root, CancellationToken cancellationToken);
}

internal abstract class AbstractSyntaxHelper : ISyntaxHelper
Expand All @@ -60,5 +63,7 @@ internal abstract class AbstractSyntaxHelper : ISyntaxHelper

public abstract void AddAliases(GreenNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global);
public abstract void AddAliases(CompilationOptions options, ArrayBuilder<(string aliasName, string symbolName)> aliases);

public abstract bool ContainsGlobalAliases(SyntaxNode root, CancellationToken cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not part of your change, but wondering why we have both interface and abstract class flavors of this? Looks like the abstract class doesn't really add functionality 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.

So this is a pattern i follow when doing thigns with C# and VB. If you don't do this, then the VB side is more obnoxious as every impl has to include the interface information. the abstract approach means that both C# and VB just need to override.

Copy link
Contributor

Choose a reason for hiding this comment

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

One developer's awesome feature that makes it clear when a method implements an interface method is another developer's annoying requirement to make me restate things that can be implicit ;)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,10 @@ public NodeStateTable<T> ToImmutableAndFree()
}

#if DEBUG
// If the caller requested a specific capacity, then we should have added exactly that amount of items.
Debug.Assert(_requestedTableCapacity == null || _requestedTableCapacity == _states.Count);
// If the caller requested a specific capacity, then we should have added either that amount, or some
// amount less than that. It's possible to have added less as a Where clause will mean some amount of
// states are filtered out.
Debug.Assert(_requestedTableCapacity == null || _states.Count <= _requestedTableCapacity);
#endif

// if we added the exact same entries as before, then we can directly embed previous' entry array,
Expand Down
Loading