Repository: dotnet/roslyn
File: src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs (C#)

Code before:
        }

        SymbolUsageInfo GetSymbolUsageInfoCommon()
        {
            if (semanticFacts.IsInOutContext(semanticModel, node, cancellationToken))
            {
                return SymbolUsageInfo.Create(ValueUsageInfo.WritableReference);
            }
            else if (semanticFacts.IsInRefContext(semanticModel, node, cancellationToken))
            {
                return SymbolUsageInfo.Create(ValueUsageInfo.ReadableWritableReference);
            }
            else if (semanticFacts.IsInInContext(semanticModel, node, cancellationToken))
            {
                return SymbolUsageInfo.Create(ValueUsageInfo.ReadableReference);
            }
            else if (semanticFacts.IsOnlyWrittenTo(semanticModel, node, cancellationToken))
            {
                return SymbolUsageInfo.Create(ValueUsageInfo.Write);
            }
            else
            {
                // Walk up out of the member access expression. This way if we have something like
                // nameof(C.Goo()), we ensure that operation.Parent is the INameOfOperation. 
                var operationNode = node;
                while (syntaxFacts.IsMemberAccessExpression(operationNode.Parent))
                    operationNode = operationNode.Parent;

                var operation = semanticModel.GetOperation(operationNode, cancellationToken);
                if (operation is IObjectCreationOperation)
                    return SymbolUsageInfo.Create(TypeOrNamespaceUsageInfo.ObjectCreation);

                // Note: sizeof/typeof also return 'name', but are handled above in GetSymbolUsageInfo.
                if (operation?.Parent is INameOfOperation)
                    return SymbolUsageInfo.Create(ValueUsageInfo.Name);

                if (node.IsPartOfStructuredTrivia())
                    return SymbolUsageInfo.Create(ValueUsageInfo.Name);

                var symbolInfo = semanticModel.GetSymbolInfo(node, cancellationToken);
                if (symbolInfo.Symbol != null)
                {
                    switch (symbolInfo.Symbol.Kind)
                    {
                        case SymbolKind.Namespace:
                            var namespaceUsageInfo = TypeOrNamespaceUsageInfo.None;
                            if (isInNamespaceNameContext)
                                namespaceUsageInfo |= TypeOrNamespaceUsageInfo.NamespaceDeclaration;

                            if (IsNodeOrAnyAncestorLeftSideOfDot(node, syntaxFacts))
                                namespaceUsageInfo |= TypeOrNamespaceUsageInfo.Qualified;

Review comment (suggestion):
It seems like this walk upwards will break the logic below about it something is read it written. For example `a.b.c = 5`. B is read, while c is written.  Your change will now make it seem as if b is written. 

Please add tests and show this didn't break. 

Code after:
    protected abstract void FindReferencesInDocument<TData>(
        TSymbol symbol, FindReferencesDocumentState state,
        Action<FinderLocation, TData> processResult, TData processResultData,
        FindReferencesSearchOptions options, CancellationToken cancellationToken);

    protected virtual Task<ImmutableArray<string>> DetermineGlobalAliasesAsync(
        TSymbol symbol, Project project, CancellationToken cancellationToken)
    {
        return SpecializedTasks.EmptyImmutableArray<string>();
    }

    public sealed override Task<ImmutableArray<string>> DetermineGlobalAliasesAsync(
        ISymbol symbol, Project project, CancellationToken cancellationToken)
    {
        return symbol is TSymbol typedSymbol && CanFind(typedSymbol)
            ? DetermineGlobalAliasesAsync(typedSymbol, project, cancellationToken)
            : SpecializedTasks.EmptyImmutableArray<string>();
    }

    public sealed override Task DetermineDocumentsToSearchAsync<TData>(
        ISymbol symbol, HashSet<string>? globalAliases, Project project,
        IImmutableSet<Document>? documents, Action<Document, TData> processResult,
        TData processResultData, FindReferencesSearchOptions options, CancellationToken cancellationToken)
    {
        if (symbol is TSymbol typedSymbol && CanFind(typedSymbol))
            return DetermineDocumentsToSearchAsync(typedSymbol, globalAliases, project, documents, processResult, processResultData, options, cancellationToken);

        return Task.CompletedTask;
    }

    public sealed override void FindReferencesInDocument<TData>(
        ISymbol symbol, FindReferencesDocumentState state, Action<FinderLocation, TData> processResult, TData processResultData, FindReferencesSearchOptions options, CancellationToken cancellationToken)
    {
        if (symbol is TSymbol typedSymbol && CanFind(typedSymbol))
            FindReferencesInDocument(typedSymbol, state, processResult, processResultData, options, cancellationToken);
    }

    public sealed override ValueTask<ImmutableArray<ISymbol>> DetermineCascadedSymbolsAsync(
        ISymbol symbol, Solution solution, FindReferencesSearchOptions options, CancellationToken cancellationToken)
    {
        if (options.Cascade &&
            symbol is TSymbol typedSymbol &&
            CanFind(typedSymbol))
        {
            return DetermineCascadedSymbolsAsync(typedSymbol, solution, options, cancellationToken);
        }

        return new([]);
    }

    protected virtual ValueTask<ImmutableArray<ISymbol>> DetermineCascadedSymbolsAsync(