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

Use the more conventional camel case for generated parameters #59

Merged
merged 17 commits into from
Jul 25, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

* Parameters of generated record methods use camel-casing, as opposed to
Pascal-casing previously, to align with naming conventions in .NET.
* The name of the parameter to `With*` methods now always reads `value`
as opposed to being named after the property verbatim.

### Added

* [`Object.ToString`][objtostr] override for records that follows the same
Expand Down
95 changes: 95 additions & 0 deletions src/Amadevus.RecordGenerator.Generators/CSharpKeyword.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
namespace Amadevus.RecordGenerator.Generators
{
static class CSharpKeyword
{
// The following method was derived from:
// Source https://github.com/dotnet/roslyn/blob/9d80dea7fe1b14043b9b2ac4d0b59ed26f508742/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs#L1821-L1905
//
// Copyright (c) Microsoft. All Rights Reserved.
// Licensed under the Apache License, Version 2.0:
// https://www.apache.org/licenses/LICENSE-2.0

public static bool Is(string name)
{
switch (name)
{
case "bool":
case "byte":
case "sbyte":
case "short":
case "ushort":
case "int":
case "uint":
case "long":
case "ulong":
case "double":
case "float":
case "decimal":
case "string":
case "char":
case "object":
case "typeof":
case "sizeof":
case "null":
case "true":
case "false":
case "if":
case "else":
case "while":
case "for":
case "foreach":
case "do":
case "switch":
case "case":
case "default":
case "lock":
case "try":
case "throw":
case "catch":
case "finally":
case "goto":
case "break":
case "continue":
case "return":
case "public":
case "private":
case "internal":
case "protected":
case "static":
case "readonly":
case "sealed":
case "const":
case "new":
case "override":
case "abstract":
case "virtual":
case "partial":
case "ref":
case "out":
case "in":
case "where":
case "params":
case "this":
case "base":
case "namespace":
case "using":
case "class":
case "struct":
case "interface":
case "delegate":
case "checked":
case "operator":
case "implicit":
case "explicit":
case "fixed":
case "extern":
case "event":
case "enum":
case "unsafe":
return true;
default:
return false;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ private MemberDeclarationSyntax GenerateDeconstruct()
ParameterSyntax CreateParameter(RecordDescriptor.Entry entry)
{
return
Parameter(entry.Identifier)
Parameter(entry.IdentifierInCamelCase)
.WithType(entry.Type)
.AddModifiers(Token(SyntaxKind.OutKeyword));
}
Expand All @@ -47,7 +47,7 @@ StatementSyntax CreateAssignment(RecordDescriptor.Entry entry)
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(entry.Identifier),
IdentifierName(entry.IdentifierInCamelCase),
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ThisExpression(),
Expand Down
2 changes: 2 additions & 0 deletions src/Amadevus.RecordGenerator.Generators/Names.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ internal static class Names
public const string Validate = "Validate";
public new const string ToString = nameof(object.ToString);

public const string Value = "value";

public const string ToolName = "Amadevus.RecordGenerator";
public const string GeneratedCodeAttribute = "System.CodeDom.Compiler.GeneratedCodeAttribute";
}
Expand Down
6 changes: 6 additions & 0 deletions src/Amadevus.RecordGenerator.Generators/RecordDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;

Expand Down Expand Up @@ -29,10 +30,15 @@ public Entry(SyntaxToken Identifier, TypeSyntax Type, PropertyDeclarationSyntax
this.Identifier = Identifier;
this.Type = Type;
this.PropertySyntax = PropertySyntax;
var id = (string)Identifier.Value;
var camelized = char.ToLowerInvariant(id[0]) + id.Substring(1);
IdentifierInCamelCase = SyntaxFactory.Identifier(CSharpKeyword.Is(camelized) ? "@" + camelized : camelized);
}

public SyntaxToken Identifier { get; }

public SyntaxToken IdentifierInCamelCase { get; }

public TypeSyntax Type { get; }

public PropertyDeclarationSyntax PropertySyntax { get; }
Expand Down
17 changes: 10 additions & 7 deletions src/Amadevus.RecordGenerator.Generators/RecordPartialGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ StatementSyntax CreateCtorAssignment(RecordDescriptor.Entry entry)
SyntaxKind.SimpleMemberAccessExpression,
ThisExpression(),
IdentifierName(entry.Identifier)),
IdentifierName(entry.Identifier)));
IdentifierName(entry.IdentifierInCamelCase)));
}
StatementSyntax CreateValidateInvocation()
{
Expand All @@ -70,7 +70,7 @@ ArgumentSyntax CreateValidateArgument(RecordDescriptor.Entry entry)
{
return
Argument(
IdentifierName(entry.Identifier))
IdentifierName(entry.IdentifierInCamelCase))
.WithRefKindKeyword(Token(SyntaxKind.RefKeyword));
}
}
Expand All @@ -80,7 +80,7 @@ private MethodDeclarationSyntax GenerateUpdateMethod()
var arguments = Descriptor.Entries.Select(x =>
{
return Argument(
IdentifierName(x.Identifier));
IdentifierName(x.IdentifierInCamelCase));
});
return MethodDeclaration(Descriptor.Type, Names.Update)
.AddModifiers(SyntaxKind.PublicKeyword)
Expand All @@ -100,19 +100,22 @@ private IEnumerable<MemberDeclarationSyntax> GenerateMutators()
return Descriptor.Entries.Select(CreateRecordMutator);
MethodDeclarationSyntax CreateRecordMutator(RecordDescriptor.Entry entry)
{
var valueIdentifier = Identifier(Names.Value);

var arguments = Descriptor.Entries.Select(x =>
{
return Argument(
IdentifierName(x.Identifier));
IdentifierName(x == entry ? valueIdentifier : x.Identifier));
});

var mutator =
MethodDeclaration(
Descriptor.Type,
GetMutatorIdentifier())
.AddModifiers(SyntaxKind.PublicKeyword)
.WithParameters(
Parameter(
entry.Identifier)
valueIdentifier)
.WithType(entry.Type))
.WithBodyStatements(
ReturnStatement(
Expand Down Expand Up @@ -160,7 +163,7 @@ private MemberDeclarationSyntax GenerateValidatePartialMethod()
ParameterSyntax CreateValidateParameter(RecordDescriptor.Entry entry)
{
return
Parameter(entry.Identifier)
Parameter(entry.IdentifierInCamelCase)
.WithType(entry.Type)
.AddModifiers(Token(SyntaxKind.RefKeyword));
}
Expand All @@ -169,7 +172,7 @@ ParameterSyntax CreateValidateParameter(RecordDescriptor.Entry entry)
private static ParameterSyntax CreateParameter(RecordDescriptor.Entry property)
{
return Parameter(
property.Identifier)
property.IdentifierInCamelCase)
.WithType(property.Type);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit;
using Amadevus.RecordGenerator.TestsBase;

namespace Amadevus.RecordGenerator.Test
{
public class GeneratedTypesNamingConventionsTests : RecordTestsBase
{
public static readonly IEnumerable<object[]> ParameterDataSource =
from t in new[]
{
typeof(Item) , typeof(Item.Builder),
typeof(Container) , typeof(Container.Builder),
typeof(GenericRecord<>), typeof(GenericRecord<>.Builder),
}
from m in t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.Static)
from p in m.GetParameters()
select new[]
{
// Trim namespace if present
t.Namespace is string ns
? t.FullName.Substring(ns.Length + 1 /* dot */)
: t.FullName,
m.Name,
p.Name
};

[Theory]
[MemberData(nameof(ParameterDataSource))]
public void Parameter_Name_Uses_Camel_Case(
#pragma warning disable xUnit1026
string type, string method,
#pragma warning restore xUnit1026
string name)
{
Assert.Matches(@"^[a-z]", name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class RecordConstructorTests : RecordTestsBase
[Fact]
public void Ctor_HasParametersNamedLikeProperties()
{
new Item(Id: ItemId, Name: ItemName);
new Item(id: ItemId, name: ItemName);
amis92 marked this conversation as resolved.
Show resolved Hide resolved
}

[Fact]
Expand Down
7 changes: 3 additions & 4 deletions test/Amadevus.RecordGenerator.Test/RecordFormatterTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System.Collections.Immutable;
using System.Collections.Generic;
using System.Collections.Immutable;
using Xunit;
using Amadevus.RecordGenerator.TestsBase;

namespace Amadevus.RecordGenerator.Test
{
using System.Collections.Generic;
using TestsBase;

public class RecordFormatterTests : RecordTestsBase
{
[Fact]
Expand Down