-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Beginning of work on "Used Assembly References" feature. #39807
Beginning of work on "Used Assembly References" feature. #39807
Conversation
Detect used assembly references from: - explicit references to types in source; - explicit references to namespaces in source; - explicit references to fields in source; - explicit method invocations in source; Usings flagged by the compiler as unused shouldn’t contribute to the set of used references.
@gafter, @dotnet/roslyn-compiler Please review. |
/// For example, if a type declared in a referenced assembly is referenced in source code | ||
/// within this compilation, the reference is considered to be used. Etc. | ||
/// The returned set is a subset of references returned by <see cref="References"/> API. | ||
/// If compilation contains errors, it is valid to consider all assembly references as used for the purpose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If compilation [](start = 12, length = 14)
Nit: If the compilation
#Resolved
========================= | ||
|
||
The *Used Assembly References* feature provides a ```GetUsedAssemblyReferences``` API on a ```Compilation``` to obtain a set | ||
of metadata assembly references that are considered as used by the compilation. For example, if a type declared in a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as [](start = 52, length = 2)
"as" should be "to be". Also in the line below. #Closed
@@ -1397,6 +1397,16 @@ IAssemblySymbol computeContainingAssembly(ISymbol s) | |||
|
|||
internal abstract void GetDiagnostics(CompilationStage stage, bool includeEarlierStages, DiagnosticBag diagnostics, CancellationToken cancellationToken = default); | |||
|
|||
/// <summary> | |||
/// Unique metadata assembly references that are considered as used by this compilation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as [](start = 68, length = 2)
"to be" instead of "as" here and four lines below. #Closed
{ | ||
NamedTypeSymbol container = symbol.ContainingType; | ||
|
||
if (container is null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if [](start = 24, length = 2)
Can you please explain why this whole if statement isn't just Compilation.AddAssembliesUsedByTypeReference((TypeSymbol)symbol);
? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain why this whole if statement isn't just Compilation.AddAssembliesUsedByTypeReference((TypeSymbol)symbol);?
I guess it could be. We would unnecessary visit type arguments for the type, but it is probably not a big deal. I will simplify.
In reply to: 346973383 [](ancestors = 346973383)
if (imported is NamespaceSymbol ns) | ||
{ | ||
Debug.Assert(!ns.IsGlobalNamespace); | ||
compilation.AddAssembliesUsedByNamespaceReference(ns); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compilation [](start = 24, length = 11)
Is this line tested? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
try | ||
{ | ||
var visitor = new UsedAssembliesRecorder(compilation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new UsedAssembliesRecorder(compilation) [](start = 30, length = 39)
It feels like it would be valuable to cache one UsedAssembliesRecorder
per compilation (e.g. in the compilation). #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like it would be valuable to cache one UsedAssembliesRecorder per compilation (e.g. in the compilation).
The base class has state which cannot be shared while walking nodes in parallel.
In reply to: 346980102 [](ancestors = 346980102)
// PROTOTYPE(UsedAssemblyReferences): This error might not be cached, but its presence might affect cached full set of used assemblies. | ||
// We would report all assemblies as used, even though no one will ever see this error and under | ||
// different environment state the pass could succeed causing us to return different set of used assemblies | ||
// with now apparent reason for the difference from the consumer's point of view. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now [](start = 59, length = 3)
Typo #Closed
/// For example, if a type declared in a referenced assembly is referenced in source code | ||
/// within this compilation, the reference is considered to be used. Etc. | ||
/// The returned set is a subset of references returned by <see cref="References"/> API. | ||
/// If compilation contains errors, it is valid to consider all assembly references as used for the purpose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If [](start = 12, length = 2)
I would suggest replacing these two sentences with "The result is undefined if the compilation contains errors." #Closed
Completed review of Iteration 1. #Closed |
@dotnet/roslyn-compiler Please review. |
{ | ||
if (!underlyingDependency.IsLinked && usedAssemblies.Contains(underlyingDependency)) | ||
{ | ||
AssemblySymbol dependency; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIt: could use inline declaration #WontFix
return false; | ||
} | ||
|
||
_lazyUsedAssemblyReferences ??= new ConcurrentSet<AssemblySymbol>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_lazyUsedAssemblyReferences [](start = 12, length = 27)
Given that we're locking on this later, I don't think ??=
provides the correct threading guarantee here. We probably need to use Interlocked.CompareExchange
. #Closed
|
||
namespace Microsoft.CodeAnalysis.CSharp | ||
{ | ||
internal sealed class UsedAssembliesRecorder : BoundTreeWalkerWithStackGuard |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about:
- typeof
- default
- events
- exception variable declarations #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about:
I believe PR description clearly says what is in scope for this PR. BTW, typeof
and "exception variable declarations" do not need special handling because the types are referred to explicitly in syntax and will be intercepted by Binder.ResultSymbol
.
In reply to: 347628028 [](ancestors = 347628028)
class C2 | ||
{ | ||
/// <summary> | ||
/// <see cref=""C1{C0}.E1.F1""/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C0 [](start = 23, length = 2)
I'm not understanding why this wouldn't count as a reference to comp0 when parsing documentation? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not understanding why this wouldn't count as a reference to comp0 when parsing documentation?
Because it is treated as a definition of a type parameter, that could be referred to later. You don't see cref parsing working this way?
In reply to: 347630679 [](ancestors = 347630679)
@@ -1922,6 +1922,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic | |||
End Get | |||
End Property | |||
|
|||
Friend Overrides Function GetUsedAssemblyReferences(Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of MetadataReference) | |||
Throw New System.NotImplementedException() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this planned on being implemented for VB? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this planned on being implemented for VB?
Yes, I'll add a prototype comment.
In reply to: 347633548 [](ancestors = 347633548)
Done review pass (commit 3) #Resolved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (commit 4)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ivanbasov FYI |
This is a beginning of work on #37768.
Detect used assembly references from:
Usings flagged by the compiler as unused shouldn’t contribute to the set of used references.