Skip to content

Prevent member name collisions in PowerShell classes#8372

Open
IISResetMe wants to merge 12 commits intoPowerShell:masterfrom
IISResetMe:patch/class-member-name-collisions
Open

Prevent member name collisions in PowerShell classes#8372
IISResetMe wants to merge 12 commits intoPowerShell:masterfrom
IISResetMe:patch/class-member-name-collisions

Conversation

@IISResetMe
Copy link
Collaborator

@IISResetMe IISResetMe commented Nov 30, 2018

PR Summary

Fix #8235, #7736

PowerShell currently allows definition of class with overlapping property and method names without warning, like so:

class TestDuplicateMembers
{
  $A
  A(){}
}

Unlike the C# compiler (which throws a compilation error), we allow compilation of the above type definition, and ETS then implicitly hides the property behind the method at runtime - making the property implementation completely useless.

This change fixes that by making duplicate member name checks mutual between DefineMethod()/DefineProperty() - so that if a method with name X is already defined, an attempt to define property X will throw a ParserError (and vice versa) just like we already do for duplicate member names of the same member type

TODO:

  • Regression tests

PR Checklist

I'd consider this a bucket 3 breaking change (we'll start failing on defining types that are already broken but partially functional).

Change is obviously user-facing but I don't believe it warrants a documentation update since the previous documentation doesn't address the existing buggy behavior

As per @lzybkr's advice, duplicate member names should not be a parser concern since it's not a syntax violation.
This also avoids LINQ queries in the parser.
@iSazonov iSazonov requested a review from lzybkr November 30, 2018 15:04
@iSazonov iSazonov self-assigned this Nov 30, 2018
@IISResetMe
Copy link
Collaborator Author

Marked PR WIP to block merge since linked issue is still awaiting committee review

@IISResetMe
Copy link
Collaborator Author

@SteveL-MSFT can you include this (or the linked issue) in the next committee review?

@SteveL-MSFT SteveL-MSFT added the Review - Committee The PR/Issue needs a review from the PowerShell Committee label Dec 20, 2018
@SteveL-MSFT
Copy link
Member

@IISResetMe to set expectation, due to the holidays and unavailability of many committee members, this won't be reviewed until after the new year (and probably 2nd week of Jan at the earliest)

@SteveL-MSFT
Copy link
Member

@PowerShell/powershell-committee reviewed this, although .Net allows this, no language supports it and PowerShell should not either. It is a technical breaking change although unlikely any customer is dependent on this since they would have defined a duplicate name member and not have used it. We agree PowerShell should prevent this and have a parse time error.

@SteveL-MSFT SteveL-MSFT added Breaking-Change breaking change that may affect users Committee-Reviewed PS-Committee has reviewed this and made a decision and removed Review - Committee The PR/Issue needs a review from the PowerShell Committee labels Jan 16, 2019
Fix CodeFactor issue
@IISResetMe
Copy link
Collaborator Author

Thanks @SteveL-MSFT, will add regression tests for this then and we can move ahead! :)

The following class definition should still be valid (as in any other .NET language):

```
class A
{
  $A
  A(){}
}
```
private void DefineProperty(PropertyMemberAst propertyMemberAst)
{
if (_definedProperties.ContainsKey(propertyMemberAst.Name))
if (_definedProperties.ContainsKey(propertyMemberAst.Name) || _definedMethods.ContainsKey(propertyMemberAst.Name) && !_definedMethods[propertyMemberAst.Name].Any(m => m.Item1.IsConstructor))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (_definedProperties.ContainsKey(propertyMemberAst.Name) || _definedMethods.ContainsKey(propertyMemberAst.Name) && !_definedMethods[propertyMemberAst.Name].Any(m => m.Item1.IsConstructor))
if (_definedProperties.ContainsKey(propertyMemberAst.Name) || (_definedMethods.ContainsKey(propertyMemberAst.Name) && !_definedMethods[propertyMemberAst.Name].Any(m => m.Item1.IsConstructor)))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already fixed 😅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we avoid LINQ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move it into a separate method (like for the method overload check), but TBH I'm not so worried about the use of LINQ here since that code path is part of the compile-time routine, it's not triggered at parse-time

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we can avoid LINQ altogether - IsConstructor is name-bound, so if any m satisfies IsConstructor == true, they all will. We can simply inspect the first item in the list

iSazonov and others added 2 commits January 18, 2019 14:17
Since IsConstructor is already tied to the method name, we can safely assume that either all or none of them satisfy IsConstructor == true, so only checking the first list item is sufficient
@iSazonov iSazonov added the CL-BreakingChange Indicates that a PR should be marked as a breaking change in the Change Log label Jan 18, 2019
@IISResetMe
Copy link
Collaborator Author

@iSazonov I think that was it! Do we need review from @daxian-dbw or @BrucePay still?

@iSazonov
Copy link
Collaborator

Yes, we are waiting.

@SteveL-MSFT SteveL-MSFT requested a review from rjmholt January 22, 2019 18:26
@IISResetMe
Copy link
Collaborator Author

IISResetMe commented Feb 22, 2019

Can we turn off the "variable name looks like hungarian notation" rule (SA1305) flagged by CodeFactor? It's super noisy, and a cursory glance at S.M.A shows that we have over 900 parameter names alone that look like hungarian notation to StyleCop, but I went through the list of name and only ~50 of them are actually named using hungarian notation:

PS ~> $parameterNames = [psobject].Assembly.GetTypes().GetMethods().GetParameters().Name
PS ~> $looksHungarian = $parameterNames -cmatch '^[a-z]{2,3}[A-Z]+'
PS ~> $actuallyHungarian = $looksHungarian -notmatch '^(?:add|arg|ast|bad|do|eat|for|has|if|is|job|max|min|my|new|no|old|out|pre|ps|raw|run|set|sub|to|try|ui|use|yes)'
PS ~> $looksHungarian.Count
935
PS ~> $actuallyHungarian.Count
46

@iSazonov
Copy link
Collaborator

@IISResetMe We already have a PR to disable some CodeFactor rules.

@IISResetMe
Copy link
Collaborator Author

@iSazonov are we still waiting for the build pipeline to be fixed (CodeFactor issues)? Or do I need to address anything?

@iSazonov
Copy link
Collaborator

iSazonov commented Mar 8, 2019

@IISResetMe Feel free to ignore CodeFactor issues if they is not in your changed code. Maintainers will ask you to fix style issues before merge if they deem it necessary.

@stale
Copy link

stale bot commented Apr 17, 2019

This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days.
Thank you for your contributions.
Community members are welcome to grab these works.

@stale stale bot added the Stale label Apr 17, 2019
@IISResetMe
Copy link
Collaborator Author

@daxian-dbw can you review this? :)

@stale stale bot removed the Stale label Apr 17, 2019
@daxian-dbw
Copy link
Member

@IISResetMe Sure, will do the review today.

// $C
// }
//
if (_definedProperties.ContainsKey(propertyMemberAst.Name) || (_definedMethods.ContainsKey(propertyMemberAst.Name) && !_definedMethods[propertyMemberAst.Name][0].Item1.IsConstructor))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can you please define a local variable to hold propertyMemberAst.Name and replace propertyMemberAst.Name with that local variable in this method?
That will make this check less cumbersome and a bit more readable.

@daxian-dbw
Copy link
Member

@IISResetMe Your change doesn't fix the case where class A derives from class B:

class Bar { $c }
class Foo : Bar { c() {} }
$s = [Foo]::new()
$s.c()

Method invocation failed because [Foo] does not contain a method named 'c'.
At line:1 char:1
+ $s.c()
+ ~~~~~~
+ CategoryInfo          : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

But to be honest, I don't know if it's worth the effort to fix that ...

@vexx32
Copy link
Collaborator

vexx32 commented Apr 18, 2019

@IISResetMe are you gonna take that sitting down? 😄

That does look like a very interesting case to try to figure out, though. Kind of looks like it might be a bit of a maze of recursively checking inherited members... Fun times!

@daxian-dbw
Copy link
Member

daxian-dbw commented Apr 19, 2019

@IISResetMe worked on something similar before -- flatten all implemented interfaces.
I know we need to fix the inheritance scenario for the sake of completeness, but personally, I just don't feel it's worth to do it ... :) because it will impose a lot more checks on most of the usages that actually don't need those checks at all.

@vexx32
Copy link
Collaborator

vexx32 commented Apr 19, 2019

Oh, that's right, he did. Should be a walk in the park, then. 😉

But I get where you're coming from too, it might not be worth it... but then again, it might end up being necessary -- after all, one of those members you're accidentally hiding might come from up the inheritance chain quite a ways, and it could potentially be very confusing if you hit that by accident.

Could this happen if you attempted to inherit from two disparate classes? Do PS classes even support that? 🤔

@IISResetMe
Copy link
Collaborator Author

Could this happen if you attempted to inherit from two disparate classes? Do PS classes even support that?

No, and I can't think of a language that compiles against .NET that does... Multiple inheritance opens up a whole new can of worms wrt member resolution ambiguity, so maybe let's not try and solve that as part of this PR ^__^

@daxian-dbw we can indeed leverage the same approach as with the interface flattening code for this. The extra lookups would be dependent on the user specifying a base class so it doesn't have to be super expensive for types that just inherit from Object. Will take a stab at it over the weekend

@rjmholt
Copy link
Collaborator

rjmholt commented Apr 19, 2019

Yeah, the CLR doesn't support multiple inheritance, even for C++

@stale
Copy link

stale bot commented May 19, 2019

This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days.
Thank you for your contributions.
Community members are welcome to grab these works.

@stale stale bot added the Stale label May 19, 2019
@stale
Copy link

stale bot commented May 29, 2019

This PR has been automatically closed because it is stale. If you wish to continue working on the PR, please first update the PR, then reopen it.
Thanks again for your contribution.
Community members are welcome to grab these works.

@stale stale bot closed this May 29, 2019
@powercode powercode reopened this Nov 5, 2025
@powercode powercode added KeepOpen The bot will ignore these and not auto-close and removed Stale labels Nov 5, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot added the Review - Needed The PR is being reviewed label Nov 12, 2025
@microsoft-github-policy-service
Copy link
Contributor

This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days.
Maintainer, please provide feedback and/or mark it as Waiting on Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Breaking-Change breaking change that may affect users CL-BreakingChange Indicates that a PR should be marked as a breaking change in the Change Log Committee-Reviewed PS-Committee has reviewed this and made a decision KeepOpen The bot will ignore these and not auto-close Review - Needed The PR is being reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Class : Methods and properties can't have the same name

8 participants