internal static IEnumerable <INamedTypeSymbol> GetAOTGenerators(Compilation compilation) { INamedTypeSymbol egta = compilation.GetTypeByMetadataName(typeof(EmbedGeneratedTypeAttribute).FullName) !; #pragma warning disable RS1024 // Compare symbols correctly HashSet <INamedTypeSymbol> returnedGenerators = new(SymbolEqualityComparer); #pragma warning restore RS1024 foreach (AttributeData attr in compilation.Assembly.GetAttributes()) { if (SymbolEqualityComparer.Equals(attr.AttributeClass, egta)) { Debug.Assert(attr.ConstructorArguments.Length is 1); INamedTypeSymbol generator = (INamedTypeSymbol)attr.ConstructorArguments[0].Value !; if (returnedGenerators.Add(generator)) { yield return(generator); } } } }
private static void LAA1002_DictionarySetEnumeration(OperationAnalysisContext context) { const string ns = "System.Collections"; SymbolDisplayFormat symbolFormat = SymbolDisplayFormat.CSharpErrorMessageFormat; Compilation comp = context.Compilation; SymbolEqualityComparer comparer = SymbolEqualityComparer.Default; bool TypeEquals(ITypeSymbol?valType, string metadataName) => valType is ITypeSymbol a && comp.GetTypeByMetadataName(metadataName) is INamedTypeSymbol b && comparer.Equals(a, b); string[] dictOrSets = { $"{ns}.Generic.IDictionary`2", $"{ns}.Generic.IReadOnlyDictionary`2", $"{ns}.Immutable.IImmutableDictionary`2", $"{ns}.IDictionary", $"{ns}.Generic.ISet`1", $"{ns}.Immutable.IImmutableSet`1", }; string[] sortedTypes = { $"{ns}.Generic.SortedDictionary`2", $"{ns}.Immutable.ImmutableSortedDictionary`2", $"{ns}.Generic.SortedSet`1", $"{ns}.Immutable.ImmutableSortedSet`1", "Bencodex.Types.Dictionary", }; bool IsDictOrSet(ITypeSymbol?valType) => valType is ITypeSymbol t && t.OriginalDefinition.AllInterfaces .OfType <ITypeSymbol>() .Select(ifce => ifce.OriginalDefinition) .OfType <ITypeSymbol>() .Any(i => dictOrSets.Any(dst => TypeEquals(i, dst))); bool IsUnordered(ITypeSymbol?valType) => valType is ITypeSymbol t && IsDictOrSet(t) && !sortedTypes.Any(sortedType => TypeEquals(t.OriginalDefinition, sortedType)); switch (context.Operation) { case IConversionOperation conv: { ITypeSymbol?endType = conv.Type; if (!TypeEquals(endType?.OriginalDefinition, $"{ns}.Generic.IEnumerable`1") && !TypeEquals(endType, $"{ns}.IEnumerable")) { return; } if (conv.Parent is IArgumentOperation arg && arg.Parent is IInvocationOperation invoke && invoke.TargetMethod.IsGenericMethod && invoke.TargetMethod.OriginalDefinition is IMethodSymbol proto) { var method = invoke.TargetMethod.Name; if (method.StartsWith("OrderBy") && TypeEquals(proto.ContainingType, "System.Linq.Enumerable") && TypeEquals( proto.ReturnType.OriginalDefinition, "System.Linq.IOrderedEnumerable`1" )) { // Ignores Linq's .OrderBy()/OrderByDescending() methods. return; } else if (method.StartsWith("To") && (method.EndsWith("Dictionary") || method.EndsWith("Set")) && IsDictOrSet(proto.ReturnType)) { // Ignores .ToDictionary()/ToHashSet() etc. return; } } if (conv.Parent is IArgumentOperation arg1 && arg1.Parent is IObjectCreationOperation @new && IsDictOrSet(@new.Type)) { // Ignores new Dictionary()/new HashSet() etc. return; } ITypeSymbol?valType = conv.Operand?.Type; if (IsUnordered(valType)) { string func = "enumerating"; if (conv.Parent is IArgumentOperation argConv) { func = argConv.Parent switch { IObjectCreationOperation c => $"passing to {c.Constructor.ToDisplayString(symbolFormat)} " + "constructor", IInvocationOperation m => $"passing to {m.TargetMethod.ToDisplayString(symbolFormat)} " + "method", _ => func, }; } Diagnostic diag = Diagnostic.Create( Rules[$"{IdPrefix}1002"], conv.Syntax.GetLocation(), valType !.ToDisplayString(symbolFormat), func ); context.ReportDiagnostic(diag); } break; } case IForEachLoopOperation loop: { IOperation collection = loop.Collection; ITypeSymbol?collType = collection.Type; if (IsUnordered(collType)) { Diagnostic diag = Diagnostic.Create( Rules[$"{IdPrefix}1002"], collection.Syntax.GetLocation(), collType.ToDisplayString(symbolFormat), "iterating via foreach" ); context.ReportDiagnostic(diag); } break; } } }
public bool Equals(ISymbol other, SymbolEqualityComparer equalityComparer) { return(equalityComparer.Equals(this, other)); }