roslyn icon indicating copy to clipboard operation
roslyn copied to clipboard

Fix reference finding for tuple fields and anonymous type properties

Open Rekkonnect opened this issue 2 years ago • 1 comments

Fixes #24268 Fixes #52621

Related issues: #20115

Summary

The symbol that is bound to an expression that implies the decared tuple field is always the expression itself. See the tests and the linked issues for examples.

Also discovered a bad case with anonymous type properties, where assigning an expression accessing a name equal to the property of the anonymous type would result in binding to that anonymous type property. For example:

string a = string.Empty;
var q = new { a, a.Length };

Hovering over Length would show the property Length of the anonymous type of q, and not that of the type string.

Note: the above works by ignoring the result of the result of semanticModel.GetDeclaredSymbol on the a.Length expression, which does yield the property of the anonymous type. We only want that overriding behavior to be local for the purposes of this fix.

Related

Rename is not tested currently.

Rekkonnect avatar Sep 02 '23 22:09 Rekkonnect

@CyrusNajmabadi ptal, I'll check the failing checks soon

Rekkonnect avatar Oct 19 '24 08:10 Rekkonnect

@CyrusNajmabadi ready for review pass

Nevermind, just noticed there's a conflict. Sorry for the eager ping.

Rekkonnect avatar Dec 03 '24 01:12 Rekkonnect

@CyrusNajmabadi this time it's actually good for review

Rekkonnect avatar Dec 03 '24 11:12 Rekkonnect

After offline discussion with @CyrusNajmabadi, we concluded on the following approach:

  • We dont cascade to all implied symbols deriving from the target symbol.
  • If we find references on a symbol triggered on the expression that defines the implicitly-named symbol (for example a.$$Length defining Length in the anon type), we want to find all references for both definitions.
    • This means that we will have up to two definitions that we FAR on, one on the original symbol and another on the implicitly-named symbol.
  • Renaming symbols that define the name of an implicitly-named symbol must remain correct, without renaming the implicitly-named symbols. So for example:
(int x, int y) F(int x, int y)
{
    return (x, y);
}

if we rename the parameters to a, b, the result should be:

(int x, int y) F(int a, int b)
{
    return (x: a, y: b);
}

Following the above re-design, this PR closes as it's too out of scope to build upon it.

Rekkonnect avatar Dec 14 '24 17:12 Rekkonnect