-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Go to base: support metadata references and bug fixes #39055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
||
| var found = false; | ||
|
|
||
| foreach (var baseSymbol in bases) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this copying code elsewhere? can we share? #Resolved
| { | ||
| content = _entries[index]; | ||
| return true; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to prevous line. #Resolved
|
Thank you for the review, @CyrusNajmabadi ! Feedback addressed. @jasonmalinowski and @JoeRobich , please take a look. #Resolved |
JoeRobich
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
jasonmalinowski
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"not"? #Resolved
| metadataDefinitions = {} | ||
| End If | ||
|
|
||
| Assert.Equal(actualDefintionsWithoutSpans.Count, metadataDefinitions.Count) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm worried this is actually a bug in ExplicitOrImplicitInterfaceImplementations:
| memberInInterface => symbol.Equals(containingType.FindImplementationForInterfaceMember(memberInInterface))); |
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a constant being shared with something else? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.