Skip to content
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

Extract Method Bug With Method Directly in Namespace #53031

Merged
merged 27 commits into from
Aug 11, 2021

Conversation

akhera99
Copy link
Member

#44214

Hello!

I worked on a bug in which, if you paste a method directly into a namespace and highlight an expression in the method, ExtractMethod crashes. To fix this, I look at the GetValidSelectionAsync methods in C# and VB. This calls GetInitialSelectionInfo() which returns valid or invalid selections. I added a check to see if the highlighted expression is contained within some block that methods could be contained in, Classes, Records, Structs, Modules, etc. I was going to make this change in UnderValidContext() but the existing code works to short-circuit if the higlighted code is an ExpressionSyntax.

Please let me know if there is a better way to design this that fits with the design of the existing extractmethod code better!

@akhera99 akhera99 self-assigned this Apr 29, 2021
@akhera99 akhera99 requested a review from a team as a code owner April 29, 2021 20:40
@akhera99 akhera99 requested a review from ryzngard April 29, 2021 21:09
@CyrusNajmabadi
Copy link
Member

Bonjour!

{
return new SelectionInfo
{
Status = new OperationStatus(OperationStatusFlag.None, CSharpFeaturesResources.No_valid_selection_to_perform_extraction),
Copy link
Member

Choose a reason for hiding this comment

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

i think we might want to condier a better string message here. SPecifically "Selection was not contained inside a type"

also, do we ahve tests for extracing from local functions inside the root namespace? we don't want to break that (if that works today. ) if it doesn't work prior to your change, tehn no worries.

Copy link
Contributor

Choose a reason for hiding this comment

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

"Selection was not contained inside a type"

This may not be a problem for top level statements right?

"Also, do we ahve tests for extracing from local functions inside the root namespace?"

Is that valid?

Copy link
Member

Choose a reason for hiding this comment

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

yup. top level functions are a thing :)

Copy link
Member Author

Choose a reason for hiding this comment

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

top level functions seem to have been added in C# 9? How can I test if it works?

Copy link
Member Author

Choose a reason for hiding this comment

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

There are no tests for extracting from the root namespace, and I tested it and it has the same error as the bug linked.

@ryzngard
Copy link
Contributor

I should take a look at this soon

Comment on lines 209 to 221
/*var rootGlobalStatement = commonRoot.FirstAncestorOrSelf<SyntaxNode>(node => node is GlobalStatementSyntax);
var commonRootContainer = commonRoot.FirstAncestorOrSelf<SyntaxNode>(node => node is TypeDeclarationSyntax);

if (commonRootContainer is null && rootGlobalStatement is null)
{
return new SelectionInfo
{
Status = new OperationStatus(OperationStatusFlag.None, FeaturesResources.Selection_not_contained_inside_a_type),
OriginalSpan = adjustedSpan,
FirstTokenInOriginalSpan = firstTokenInSelection,
LastTokenInOriginalSpan = lastTokenInSelection
};
}*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this

n is AccessorDeclarationSyntax ||
n is BlockSyntax ||
n is GlobalStatementSyntax)
if (n is BaseMethodDeclarationSyntax or AccessorDeclarationSyntax or BlockSyntax or GlobalStatementSyntax)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (n is BaseMethodDeclarationSyntax or AccessorDeclarationSyntax or BlockSyntax or GlobalStatementSyntax)
if (n is BaseMethodDeclarationSyntax or
AccessorDeclarationSyntax or
BlockSyntax or
GlobalStatementSyntax)

@@ -9188,13 +9188,13 @@ private static K NewMethod()
public async Task Script_ArgumentException()
{
var code = @"using System;
public static void GetNonVirtualMethod<TDelegate>( Type type, string name)
static void GetNonVirtualMethod<TDelegate>( Type type, string name)
Copy link
Member

Choose a reason for hiding this comment

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

please don't update test cases. instead still record the change in behavior for this case, and add a new test for the differnet case you carea bout.

Copy link
Member Author

Choose a reason for hiding this comment

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

to be honest, I do not know why I even touched this method

if (node.FromScript() || node.GetAncestor<TypeDeclarationSyntax>() != null)
{
return true;
}
Copy link
Member

Choose a reason for hiding this comment

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

these checks need comments.

{
Contract.ThrowIfNull(node);

if (IsContainedDirectlyInNamespace(node))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (IsContainedDirectlyInNamespace(node))
return !IsContainedDirectlyInNamespace(node);

immediateParent = true;
}

n = n.Parent!;
Copy link
Member

Choose a reason for hiding this comment

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

i do not know what is going on here. in english what are you trying to express :)

Copy link
Member Author

Choose a reason for hiding this comment

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

if I am a method, or a block, etc. and my immediate parent is a namespace, then bail and do not allow that as a valid selection. Still need to make sure I am handling everything that shouldn't be directly in a namespace

Copy link
Member

Choose a reason for hiding this comment

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

would it suffice to just ask: did i hit a namespace, but i did not hit a type? that seems simpler. or, put another way:

first look if we're contained by a type. if so, great.
then look to see if we're contained by a namespace. if so, bad.
otherwise, we must be global. if so, great.

@@ -332,21 +332,6 @@
<target state="translated">選取範圍無效</target>
<note />
</trans-unit>
<trans-unit id="Selection_doesn_t_contain_any_valid_token">
Copy link
Member

Choose a reason for hiding this comment

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

can you make the loc change in a separate PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

public static bool ContainedInValidType(this SyntaxNode node)
{
Contract.ThrowIfNull(node);
var typeContainer = node.FirstAncestorOrSelf<TypeDeclarationSyntax>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
var typeContainer = node.FirstAncestorOrSelf<TypeDeclarationSyntax>();
foreach (var ancestor in node.AncestorsAndSelf())
{
if (ancestor is TypeDeclarationSyntax)
return true;
if (ancestor is NamespaceDeclarationSyntax)
return false;
}
return true;

@ryzngard
Copy link
Contributor

ryzngard commented Aug 4, 2021

Current changes look good, pending test passing and conflict resolution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants