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

Complete 'file' support for SyntaxGenerator #62413

Merged
merged 7 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,9 @@ private static SyntaxTokenList AsModifierList(Accessibility accessibility, Decla
break;
}

if (modifiers.IsFile)
list.Add(SyntaxFactory.Token(SyntaxKind.FileKeyword));
Copy link
Member

Choose a reason for hiding this comment

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

if we have .IsFile can we not add any accessibility above? one of the goals of SyntaxGenerator is to add smarts like that to generate the most likely thing wanted.


if (modifiers.IsAbstract)
list.Add(SyntaxFactory.Token(SyntaxKind.AbstractKeyword));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2284,6 +2284,84 @@ public void TestWithModifiers_AllowedModifiers()
Generator.GetModifiers(Generator.WithModifiers(SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration), allModifiers)));
}

[Fact]
public void TestAddPublicToStaticConstructor()
{
var ctor = Generator.ConstructorDeclaration("C", modifiers: DeclarationModifiers.Static);
VerifySyntax<ConstructorDeclarationSyntax>(ctor, @"static C()
{
}");

var publicCtor = Generator.WithAccessibility(ctor, Accessibility.Public);
// Yes, it's correct that static constructors cannot have accessibility, but why not static is "replaced" with public?
// The same issue exists for file types that cannot have accessibility. Should attempting to make them public do "nothing"?
VerifySyntax<ConstructorDeclarationSyntax>(publicCtor, @"static C()
{
}");
}

[Fact]
public void TestAddStaticToPublicConstructor()
{
var ctor = Generator.ConstructorDeclaration("C", accessibility: Accessibility.Public);
VerifySyntax<ConstructorDeclarationSyntax>(ctor, @"public C()
{
}");

var staticCtor = Generator.WithModifiers(ctor, DeclarationModifiers.Static);
VerifySyntax<ConstructorDeclarationSyntax>(staticCtor, @"public static C()
{
}");
}

[Fact]
public void TestAddAbstractToFileClass()
{
var fileClass = (ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration("file class C { }");
var fileAbstractClass = Generator.WithModifiers(fileClass, Generator.GetModifiers(fileClass).WithIsAbstract(true));
VerifySyntax<ClassDeclarationSyntax>(fileAbstractClass, @"file abstract class C
{
}");
}

[Fact]
public void TestAddPublicToFileClass()
{
var fileClass = (ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration("file class C { }");
var filePublicClass = Generator.WithAccessibility(fileClass, Accessibility.Public);
// bad output. It will be fixed in a later commit.
// This commit just demonstrates the *current* behavior (test is passing currently, while it shouldn't).
// What 's the expected behavior is unclear given an existing behavior for static constructors demonstrated in this commit (the new test is passing)
// The current behavior might be correct if we'll follow the static constructors behavior.
VerifySyntax<ClassDeclarationSyntax>(filePublicClass, @"file class C
{
}");
}

[Fact]
public void TestAddFileModifierToAbstractClass()
{
var abstractClass = (ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration("abstract class C { }");
var fileAbstractClass = Generator.WithModifiers(abstractClass, Generator.GetModifiers(abstractClass).WithIsFile(true));
VerifySyntax<ClassDeclarationSyntax>(fileAbstractClass, @"file abstract class C
{
}");
}

[Fact]
public void TestAddFileModifierToPublicClass()
{
var publicClass = (ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration("public class C { }");
var filePublicClass = Generator.WithModifiers(publicClass, Generator.GetModifiers(publicClass).WithIsFile(true));
// bad output. It will be fixed in a later commit.
// This commit just demonstrates the *current* behavior (test is passing currently, while it shouldn't).
// note, behavior changed here in this commit since we supported file, but the most correct behavior is to eliminate public completely.
// note 2, the correct behavior here is actually not very clear given the constructor case and the opposite case of this.
VerifySyntax<ClassDeclarationSyntax>(filePublicClass, @"public file class C
{
}");
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This is even more confusing for a case where the class originally didn't have any accessibility or modifiers (ie, a plain class C), and WithModifiers is called with DeclarationModifiers.Public | DeclarationModifiers.File. Yes it's weird that someone do this, but.. it's a public API.

Copy link
Member

Choose a reason for hiding this comment

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

i'm ok with this just throwing away public modifiers in that case. we did similar things with interface members (prior to them supporting accessibility or method bodies).

Copy link
Member Author

Choose a reason for hiding this comment

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

This is actually my bad. There is no DeclarationModifiers.Public 😄

The way to say both public and file will be two calls, one to WithModifiers and one to WithAccessibility. The second call will overwrite the first in this case.


[Fact]
public void TestGetType()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ public static void GetAccessibilityAndModifiers(SyntaxTokenList modifierList, ou
SyntaxKind.RefKeyword => DeclarationModifiers.Ref,
SyntaxKind.VolatileKeyword => DeclarationModifiers.Volatile,
SyntaxKind.ExternKeyword => DeclarationModifiers.Extern,
SyntaxKind.FileKeyword => DeclarationModifiers.File,
_ => DeclarationModifiers.None,
};

Expand Down