Go to base: support metadata references and bug fixes#39055
Go to base: support metadata references and bug fixes#39055ivanbasov merged 12 commits intodotnet:masterfrom
Conversation
|
|
||
| var found = false; | ||
|
|
||
| foreach (var baseSymbol in bases) |
There was a problem hiding this comment.
doc what this is doing. #Resolved
| <Fact, Trait(Traits.Feature, Traits.Features.GoToBase)> | ||
| Public Async Function TestWithSingleClass() As Task | ||
| Await TestAsync("class $$C { }") | ||
| Await TestAsync("class $$C { }", , metadataDefinitions:={"mscorlib:Object"}) |
There was a problem hiding this comment.
not a fan of passing an omitted arg. #Resolved
| var inlines = DefinitionBucket.DefinitionItem.DisplayParts | ||
| .ToInlines(_presenter.ClassificationFormatMap, _presenter.TypeMap); | ||
|
|
||
| var textBlock = inlines.ToTextBlock(_presenter.ClassificationFormatMap, wrap: false); |
There was a problem hiding this comment.
is this copying code elsewhere? can we share? #Resolved
| { | ||
| content = _entries[index]; | ||
| return true; | ||
| } |
There was a problem hiding this comment.
who calls into this with this value? #Resolved
| return await ConvertToSymbolAndProjectIdsAsync(typesAndInterfaces.CastArray<ISymbol>(), project, cancellationToken).ConfigureAwait(false); | ||
| } | ||
| public static ImmutableArray<ISymbol> FindBaseTypesAndInterfaces( | ||
| INamedTypeSymbol type) |
There was a problem hiding this comment.
move to prevous line. #Resolved
|
Thank you for the review, @CyrusNajmabadi ! Feedback addressed. @jasonmalinowski and @JoeRobich , please take a look. #Resolved |
jasonmalinowski
left a comment
There was a problem hiding this comment.
@ivanbasov I know I'm late to the party, but looking at the PR I'm wondering if there's actually a compiler bug around the "new"/hidden method case? Or are we misunderstanding something else here about the language behavior?
| Next | ||
|
|
||
| Dim actualDefintionsWithoutSpans = context.GetDefinitions(). | ||
| Where(Function(d) d.SourceSpans.IsDefaultOrEmpty). |
There was a problem hiding this comment.
Indenting is off here, and usually we always do a _ at the end of a previous line here so the . stays on the next line. #Resolved
| var found = false; | ||
|
|
||
| // For each potential base, try to find its definition in sources. | ||
| // If found, add its' definitionItem to the context. |
There was a problem hiding this comment.
"it's" (and everywhere else) #Resolved
| var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync( | ||
| SymbolAndProjectId.Create(baseSymbol, projectId), solution, cancellationToken).ConfigureAwait(false); | ||
| if (sourceDefinition.Symbol != null && | ||
| sourceDefinition.Symbol.Locations.Any(l => l.IsInSource)) |
There was a problem hiding this comment.
FindSourceDefinitionAsync should only be returning symbols from source in the first place... #Resolved
| Public Async Function TestWithVirtualMethodHiddenAndInterfaceImplementedOnDerivedType() As Task | ||
| ' We should not find a hidden method. | ||
| ' We should not find hidden methods. | ||
| ' We should not find methods of interfaces no implemented by the method symbol. |
| metadataDefinitions = {} | ||
| End If | ||
|
|
||
| Assert.Equal(actualDefintionsWithoutSpans.Count, metadataDefinitions.Count) |
There was a problem hiding this comment.
Just do Assert.Equal -- there's an overload that compares to IEnumerables item by item, and if the count differs will also show you the actual contents which is a lot easier to debug than this. #Resolved
| { | ||
| foreach (var member in type.GetMembers(symbol.Name)) | ||
| { | ||
| var sourceMember = await SymbolFinder.FindSourceDefinitionAsync( |
There was a problem hiding this comment.
Now that this returns metadata symbols, do we expose this anywhere as a public API that this is a breaking change of? #Resolved
There was a problem hiding this comment.
We didn't change FindSourceDefinitionAsync. Only in case, where we cannot get sources by it; we go to metadata.
In reply to: 335223864 [](ancestors = 335223864)
There was a problem hiding this comment.
Methods changed belong to internal classes and should not be involved in public APIs
In reply to: 335726193 [](ancestors = 335726193,335223864)
| // We need to start from each base class for cases like N() Implements I.M() | ||
| // where N() can be hidden or overwritten in a nested class later on. | ||
| interfaceImplementations.AddRange(member.ExplicitOrImplicitInterfaceImplementations()); | ||
| // We should add implementations only for overridden members but not for hidden ones. |
There was a problem hiding this comment.
I'm not understanding how this is working now: if you just have the simple case of:
interface I { void M(); }
class A : I { public void M(); }
M() isn't an override of anything, but it implements A -- is the SymbolFinder.IsOverride still being fired? #Resolved
There was a problem hiding this comment.
In the case, we will add the interface method above on line 22. Then, we will find that A is inherited from object. We will try to find "M" in the object but will not find it here and will not call SymbolFinder.IsOverride.
In reply to: 335224638 [](ancestors = 335224638)
| // will call the method from B. We should find the base for B.M in this case. | ||
| // And if we change 'new' to 'override' in the original code and add 'virtual' where needed, | ||
| // we should find I.M as a base for B.M(). And the next line helps with this scenario. | ||
| results.AddRange(member.ExplicitOrImplicitInterfaceImplementations()); |
There was a problem hiding this comment.
I'm worried this is actually a bug in ExplicitOrImplicitInterfaceImplementations:
It looks like this is finding B, seeing it implements I, and then asks I what the explicit implementation is in B -- is it returning A.M or nothing at all? #Resolved
There was a problem hiding this comment.
I think that Explicit in this context means VB implementations and C# ones like void I.M(). And implicit are all other.
Then, in the scenario
abstract class C : I { public abstract void |M| { } }
class D : C { public override void $$M() { } }
interface I { void |M|; }
In the line you mentioned
containingType.FindImplementationForInterfaceMember(memberInInterface))
is called for containingType = "D" and memberInInterface = "I.M()".
And it returns "C.M()" not "D.M()". Then it is rejected by symbol.Equals.
In reply to: 335224689 [](ancestors = 335224689)
| { | ||
| private abstract class AbstractItemEntry : Entry | ||
| { | ||
| protected readonly StreamingFindUsagesPresenter _presenter; |
There was a problem hiding this comment.
Protected members shouldn't be prefixed with _ -- make this a property. #Resolved
| internal partial class StreamingFindUsagesPresenter | ||
| { | ||
| // Name of the key used to retireve the whole entry object. | ||
| internal const string SelfKeyName = "self"; |
There was a problem hiding this comment.
Is this a constant being shared with something else? #Resolved
There was a problem hiding this comment.
It is just introduced and shared between FindUsagesTableControlEventProcessorProvider and StreamingFindUsagesPresenter
In reply to: 335225827 [](ancestors = 335225827)
Fixes #38700
here
calls
C.M()notD.M(). Therefore,I.M()is not a base forD.M(). Fixed this.3. Fixed a issue with overloads and interfaces.