dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.06k stars 4.04k forks source link

Find All References on a constructor, only finds explicit callers via : base() #11049

Open davkean opened 8 years ago

davkean commented 8 years ago

1.

internal abstract class Abstract
{
    protected Abstract()
    {
    }
}

internal abstract class Derived : Abstract
{
    protected Derived()
    {
    }
}

Find all references on Abstract's constructor.

Expected: To find a usage from Derived() Actual: No usages

internal abstract class Abstract
{
    protected Abstract()
    {
    }
}

internal abstract class Derived : Abstract
{
    protected Derived() : base()
    {
    }
}

Find all references on Abstract's constructor.

As expected find expected usage from base() call.

KirillOsenkov commented 8 years ago

@CyrusNajmabadi can correct me if I'm wrong but I think the way FAR was designed is to only count a reference if the token that binds to the symbol is mentioned in the file. Implicit references (such as conversions) are not reported.

Also, are you missing Derived : Abstract in your sample code? ;)

CyrusNajmabadi commented 8 years ago

No, this should work. If it doesn't, then i would consider it a bug.

The rule is: we should find references if there's a reasonably efficient way we could search and find the reference :)

In this case, that happens to be true.

Now, for things like "implicit conversions" it turns out we have no efficient way to find them, so we don't find those. But that's simply because we're not smart enough to figure out how to supply them, not because that's a good user experience :)

CyrusNajmabadi commented 8 years ago

And, to be clear, the algorithm for this is:

If you're searching for a constructor, search immediately derived types and check all their constructors. Now, we're lacking a good compiler API for asking what constructor a derived constructor chains to (in the absence of this/base). We can write some reasonable heuristics, or we can get the compiler to expose this information.

SergeyZhurikhin commented 8 years ago

@CyrusNajmabadi Better if it will last. Otherwise, why do we need the compiler as a service, if the semantic model is not able to answer these questions?...

CyrusNajmabadi commented 8 years ago

Yes. I definitely think we shoudl have an API from the compiler to tell us what chained constructor a constructor calls.

@dotnet/roslyn-compiler

Can we add something like this? We have APIs to tell you this when there is a this/base call (or an invocation in VB). However, when the chaining is implicit, it's not clear which constructor is called. This is an issue especially with wonky constructors (like ones with optional or params parameters).

CyrusNajmabadi commented 8 years ago

Note @dotnet/roslyn-compiler It does look like this information may be obtainable through the IOperation level. Do you think it would be appropriate to expose through the semantic-model/symbol API though?

CyrusNajmabadi commented 3 weeks ago

We would take a targetted fix for this from the community.