private void RegisterAvaloniaPropertySymbols()

in src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs [116:292]


        private void RegisterAvaloniaPropertySymbols(Compilation compilation, CancellationToken cancellationToken)
        {
            var namespaceStack = new Stack<INamespaceSymbol>();
            namespaceStack.Push(compilation.GlobalNamespace);

            var types = new List<INamedTypeSymbol>();

            while (namespaceStack.Count > 0)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var current = namespaceStack.Pop();

                types.AddRange(current.GetTypeMembers());

                foreach (var child in current.GetNamespaceMembers())
                {
                    namespaceStack.Push(child);
                }
            }

            var avaloniaPropertyStorageSymbols = new ConcurrentBag<ISymbol>();

            var propertyDescriptions = new ConcurrentDictionary<ISymbol, AvaloniaPropertyDescription>(SymbolEqualityComparer.Default);

            // key initializes value
            var fieldInitializations = new ConcurrentDictionary<ISymbol, ISymbol>(SymbolEqualityComparer.Default);

            var parallelOptions = new ParallelOptions() { CancellationToken = cancellationToken };

            var semanticModels = new ConcurrentDictionary<SyntaxTree, SemanticModel>();

            Parallel.ForEach(types, parallelOptions, type =>
            {
                try
                {
                    foreach (var member in type.GetMembers())
                    {
                        switch (member)
                        {
                            case IFieldSymbol fieldSymbol when IsAvaloniaPropertyStorage(fieldSymbol):
                                avaloniaPropertyStorageSymbols.Add(fieldSymbol);
                                break;
                            case IPropertySymbol propertySymbol when IsAvaloniaPropertyStorage(propertySymbol):
                                avaloniaPropertyStorageSymbols.Add(propertySymbol);
                                break;
                        }
                    }

                    foreach (var constructor in type.StaticConstructors)
                    {
                        foreach (var syntaxRef in constructor.DeclaringSyntaxReferences.Where(sr => compilation.ContainsSyntaxTree(sr.SyntaxTree)))
                        {
                            var (node, model) = GetNodeAndModel(syntaxRef);

                            foreach (var descendant in node.DescendantNodes().Where(n => n.IsKind(SyntaxKind.SimpleAssignmentExpression)))
                            {

                                if (model.GetOperation(descendant, cancellationToken) is IAssignmentOperation assignmentOperation &&
                                    GetReferencedFieldOrProperty(assignmentOperation.Target, cancellationToken) is { } target)
                                {
                                    RegisterAssignment(target, assignmentOperation.Value);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    WrapAndThrowIfNotCancellation(ex, $"Failed to find AvaloniaProperty objects in {type}.", cancellationToken);
                    throw;
                }
            });

            Parallel.ForEach(avaloniaPropertyStorageSymbols, parallelOptions, symbol =>
            {
                foreach (var syntaxRef in symbol.DeclaringSyntaxReferences.Where(sr => compilation.ContainsSyntaxTree(sr.SyntaxTree)))
                {
                    var (node, model) = GetNodeAndModel(syntaxRef);

                    var operation = node.ChildNodes().Select(n => model.GetOperation(n, cancellationToken)).OfType<ISymbolInitializerOperation>().FirstOrDefault();

                    if (operation == null)
                    {
                        return;
                    }

                    RegisterAssignment(symbol, operation.Value);
                }
            });

            // we have recorded every Register and AddOwner call. Now follow assignment chains.
            Parallel.ForEach(fieldInitializations.Keys.Intersect(propertyDescriptions.Keys, SymbolEqualityComparer.Default).ToArray(), parallelOptions, root =>
            {
                var propertyDescription = propertyDescriptions[root];
                var owner = propertyDescription.AssignedTo[root];

                var seen = new HashSet<ISymbol>(SymbolEqualityComparer.Default);

                var current = root;
                do
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    if (!seen.Add(current))
                    {
                        break; // self-assignment, just stop processing if this happens
                    }

                    var target = fieldInitializations[current];

                    propertyDescription.SetAssignment(target, new(owner.Type, target.Locations[0])); // This loop handles simple assignment operations, so do NOT change the owner type
                    propertyDescriptions[target] = propertyDescription;

                    fieldInitializations.TryGetValue(target, out current);
                }
                while (current != null);
            });

            var clrPropertyWrapCandidates = new ConcurrentBag<(IPropertySymbol, AvaloniaPropertyDescription)>();

            var propertyDescriptionsByName = propertyDescriptions.Values.ToLookup(p => p.Name, p => (property: p, owners: p.OwnerTypes.Select(t => t.Type).ToImmutableHashSet(SymbolEqualityComparer.Default)));

            // Detect CLR properties that provide syntatic wrapping around an AvaloniaProperty (or potentially multiple, which leads to a warning diagnostic)
            Parallel.ForEach(propertyDescriptions.Values, parallelOptions, propertyDescription =>
            {
                var nameMatches = propertyDescriptionsByName[propertyDescription.Name];

                foreach (var ownerType in propertyDescription.OwnerTypes.Select(o => o.Type).Distinct(SymbolEqualityComparer<ITypeSymbol>.Default))
                {
                    if (ownerType.GetMembers(propertyDescription.Name).OfType<IPropertySymbol>().SingleOrDefault() is not { IsStatic: false } clrProperty)
                    {
                        continue;
                    }

                    propertyDescription.AddPropertyWrapper(clrProperty);
                    clrPropertyWrapCandidates.Add((clrProperty, propertyDescription));

                    var current = ownerType.BaseType;
                    while (current != null)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        foreach (var otherProp in nameMatches.Where(t => t.owners.Contains(current)).Select(t => t.property))
                        {
                            clrPropertyWrapCandidates.Add((clrProperty, otherProp));
                        }

                        current = current.BaseType;
                    }
                }
            });

            // convert our dictionaries to immutable form
            _clrPropertyToAvaloniaProperties = clrPropertyWrapCandidates.ToLookup(t => t.Item1, t => t.Item2, SymbolEqualityComparer<IPropertySymbol>.Default)
                .ToImmutableDictionary(g => g.Key, g => g.Distinct().ToImmutableArray(), SymbolEqualityComparer<IPropertySymbol>.Default);
            _avaloniaPropertyDescriptions = propertyDescriptions.ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value.Seal(), SymbolEqualityComparer.Default);

            void RegisterAssignment(ISymbol target, IOperation value)
            {
                switch (ResolveOperationSource(value, cancellationToken))
                {
                    case IInvocationOperation invocation:
                        RegisterInitializer_Invocation(invocation, target, propertyDescriptions, cancellationToken);
                        break;
                    case IFieldReferenceOperation fieldRef when IsAvaloniaPropertyStorage(fieldRef.Field):
                        fieldInitializations[fieldRef.Field] = target;
                        break;
                    case IPropertyReferenceOperation propRef when IsAvaloniaPropertyStorage(propRef.Property):
                        fieldInitializations[propRef.Property] = target;
                        break;
                }
            }

            (SyntaxNode, SemanticModel) GetNodeAndModel(SyntaxReference syntaxRef) =>
                (syntaxRef.GetSyntax(cancellationToken), semanticModels.GetOrAdd(syntaxRef.SyntaxTree, st => compilation.GetSemanticModel(st)));
        }