Beginning of work on "Used Assembly References" feature.#39807
Beginning of work on "Used Assembly References" feature.#39807AlekseyTs merged 4 commits intodotnet:features/UsedAssemblyReferencesfrom
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.
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.
as [](start = 52, length = 2)
"as" should be "to be". Also in the line below. #Closed
| 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.
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.
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.
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.
compilation [](start = 24, length = 11)
Is this line tested? #Closed
There was a problem hiding this comment.
|
|
||
| try | ||
| { | ||
| var visitor = new UsedAssembliesRecorder(compilation); |
There was a problem hiding this comment.
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.
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.
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.
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.
NIt: could use inline declaration #WontFix
| return false; | ||
| } | ||
|
|
||
| _lazyUsedAssemblyReferences ??= new ConcurrentSet<AssemblySymbol>(); |
There was a problem hiding this comment.
_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.
What about:
- typeof
- default
- events
- exception variable declarations #Closed
There was a problem hiding this comment.
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.
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.
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)
| 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.
Is this planned on being implemented for VB? #Closed
There was a problem hiding this comment.
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 |
|
@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.