Пример #1
0
        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);
                    }
                }
            }
        }
Пример #2
0
        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;
            }
            }
        }
Пример #3
0
 public bool Equals(ISymbol other, SymbolEqualityComparer equalityComparer)
 {
     return(equalityComparer.Equals(this, other));
 }