-
Notifications
You must be signed in to change notification settings - Fork 470
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
Simplify AvoidUninstantiatedInternalClasses #6309
Merged
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,7 @@ public sealed override void Initialize(AnalysisContext context) | |
var internalTypes = new ConcurrentDictionary<INamedTypeSymbol, object?>(); | ||
|
||
var compilation = startContext.Compilation; | ||
var entryPointContainingType = compilation.GetEntryPoint(startContext.CancellationToken)?.ContainingType; | ||
var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); | ||
|
||
// If the assembly being built by this compilation exposes its internals to | ||
|
@@ -98,7 +99,8 @@ public sealed override void Initialize(AnalysisContext context) | |
{ | ||
var type = (INamedTypeSymbol)context.Symbol; | ||
if (!type.IsExternallyVisible() && | ||
!IsOkToBeUninstantiated(type, compilation, | ||
!IsOkToBeUninstantiated(type, | ||
entryPointContainingType, | ||
systemAttributeSymbol, | ||
iConfigurationSectionHandlerSymbol, | ||
configurationSectionSymbol, | ||
|
@@ -282,7 +284,7 @@ private bool HasInstantiatedNestedType(INamedTypeSymbol type, IEnumerable<INamed | |
|
||
private static bool IsOkToBeUninstantiated( | ||
INamedTypeSymbol type, | ||
Compilation compilation, | ||
INamedTypeSymbol? entryPointContainingType, | ||
INamedTypeSymbol? systemAttributeSymbol, | ||
INamedTypeSymbol? iConfigurationSectionHandlerSymbol, | ||
INamedTypeSymbol? configurationSectionSymbol, | ||
|
@@ -302,14 +304,8 @@ private static bool IsOkToBeUninstantiated( | |
return true; | ||
} | ||
|
||
// Ignore type generated for holding top level statements | ||
if (type.IsTopLevelStatementsEntryPointType()) | ||
{ | ||
return true; | ||
} | ||
|
||
// The type containing the assembly's entry point is OK. | ||
if (ContainsEntryPoint(type, compilation)) | ||
if (SymbolEqualityComparer.Default.Equals(entryPointContainingType, type)) | ||
{ | ||
return true; | ||
} | ||
|
@@ -351,6 +347,7 @@ private static bool IsOkToBeUninstantiated( | |
|
||
return false; | ||
} | ||
|
||
public static bool IsMefExported( | ||
INamedTypeSymbol type, | ||
INamedTypeSymbol? mef1ExportAttributeSymbol, | ||
|
@@ -360,81 +357,6 @@ public static bool IsMefExported( | |
|| (mef2ExportAttributeSymbol != null && type.HasAttribute(mef2ExportAttributeSymbol)); | ||
} | ||
|
||
private static bool ContainsEntryPoint(INamedTypeSymbol type, Compilation compilation) | ||
{ | ||
// If this type doesn't live in an application assembly (.exe), it can't contain | ||
// the entry point. | ||
if (compilation.Options.OutputKind is not OutputKind.ConsoleApplication and | ||
not OutputKind.WindowsApplication and | ||
not OutputKind.WindowsRuntimeApplication) | ||
{ | ||
return false; | ||
} | ||
|
||
var wellKnowTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); | ||
var taskSymbol = wellKnowTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask); | ||
var genericTaskSymbol = wellKnowTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask1); | ||
|
||
// TODO: Handle the case where Compilation.Options.MainTypeName matches this type. | ||
// TODO: Test: can't have type parameters. | ||
// TODO: Main in nested class? If allowed, what name does it have? | ||
// TODO: Test that parameter is array of int. | ||
Comment on lines
-378
to
-381
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All these should be handled now by the compiler :) |
||
return type.GetMembers("Main") | ||
.Where(m => m is IMethodSymbol) | ||
.Cast<IMethodSymbol>() | ||
.Any(m => IsEntryPoint(m, taskSymbol, genericTaskSymbol)); | ||
} | ||
|
||
private static bool IsEntryPoint(IMethodSymbol method, ITypeSymbol? taskSymbol, ITypeSymbol? genericTaskSymbol) | ||
{ | ||
if (!method.IsStatic) | ||
{ | ||
return false; | ||
} | ||
|
||
if (!IsSupportedReturnType(method, taskSymbol, genericTaskSymbol)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (!method.Parameters.Any()) | ||
{ | ||
return true; | ||
} | ||
|
||
if (method.Parameters.HasMoreThan(1)) | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private static bool IsSupportedReturnType(IMethodSymbol method, ITypeSymbol? taskSymbol, ITypeSymbol? genericTaskSymbol) | ||
{ | ||
if (method.ReturnType.SpecialType == SpecialType.System_Int32) | ||
{ | ||
return true; | ||
} | ||
|
||
if (method.ReturnsVoid) | ||
{ | ||
return true; | ||
} | ||
|
||
if (taskSymbol != null && Equals(method.ReturnType, taskSymbol)) | ||
{ | ||
return true; | ||
} | ||
|
||
if (genericTaskSymbol != null && Equals(method.ReturnType.OriginalDefinition, genericTaskSymbol) && ((INamedTypeSymbol)method.ReturnType).TypeArguments.Single().SpecialType == SpecialType.System_Int32) | ||
{ | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/// <summary> | ||
/// If a type is passed a generic argument to another type or a method that specifies that the type must have a constructor, | ||
/// we presume that the method will be constructing the type, and add it to the list of instantiated types. | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
On roslyn side, this is calculated once for the compilation and cached:
https://github.com/dotnet/roslyn/blob/main/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1676-L1684
@mavasani Do you think this PR can contribute to #6301 ? (the new approach is very likely more efficient, but I'm not sure if the improvement is large enough here)
I'm not sure how much the existing code was expensive. Specifically, we could have been calling
GetMembers
for lots of types. Did the compiler already cached them before invoking the analyzer? or does the analyzer come through this code path:https://github.com/dotnet/roslyn/blob/1100e56a04e144352af43181df077a13957e6a58/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs#L1656-L1665
We also were doing more symbol comparison than with this PR
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.
Regardless of whether or not this addresses #6301, it seems to definitely be more hardened code and should likely also improve performance.