Skip to content

Commit

Permalink
Merge pull request #2874 from microsoft/andrueastman/enumescaping
Browse files Browse the repository at this point in the history
Fixes renaming of enum options in dotnet
  • Loading branch information
andrueastman authored Jul 7, 2023
2 parents 06e9dea + 5081956 commit 0138b6d
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Prevents method overloading for go getters and setters with different values. [#2719](https://github.com/microsoft/kiota/issues/2719)
- Fixed PHP request executor methods that return enums.
- Allow configuration of the number of threads via the environment variable KIOTA_GENERATION_MAXDEGREEOFPARALLELISM.
- Fixes regression where enum options would be renamed in CSharp.

## [1.3.0] - 2023-06-09

Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Refiners/CSharpRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
ReplaceReservedNames(
generatedCode,
new CSharpReservedNamesProvider(), x => $"@{x.ToFirstCharacterUpperCase()}",
new HashSet<Type> { typeof(CodeClass), typeof(ClassDeclaration), typeof(CodeProperty), typeof(CodeUsing), typeof(CodeNamespace), typeof(CodeMethod), typeof(CodeEnum) }
new HashSet<Type> { typeof(CodeClass), typeof(ClassDeclaration), typeof(CodeProperty), typeof(CodeUsing), typeof(CodeNamespace), typeof(CodeMethod), typeof(CodeEnum), typeof(CodeEnumOption) }
);
ReplaceReservedNames(
generatedCode,
Expand Down
24 changes: 7 additions & 17 deletions src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,7 @@ currentProperty.Type is CodeType propertyType &&
!propertyType.IsExternal &&
provider.ReservedNames.Contains(currentProperty.Type.Name))
propertyType.Name = replacement.Invoke(propertyType.Name);
else if (current is CodeEnum currentEnum &&
isNotInExceptions &&
shouldReplace &&
currentEnum.Options.Any(x => provider.ReservedNames.Contains(x.Name)))
ReplaceReservedEnumNames(currentEnum, provider, replacement);

// Check if the current name meets the following conditions to be replaced
// 1. In the list of reserved names
// 2. If it is a reserved name, make sure that the CodeElement type is worth replacing(not on the blocklist)
Expand All @@ -406,6 +402,12 @@ currentProperty.Type is CodeType propertyType &&
{
currentProperty.SerializationName = currentProperty.Name;
}
if (current is CodeEnumOption currentEnumOption &&
string.IsNullOrEmpty(currentEnumOption.SerializationName))
{
currentEnumOption.SerializationName = currentEnumOption.Name;
}

var replacementName = replacement.Invoke(current.Name);
if (current.Parent is IBlock parentBlock)
parentBlock.RenameChildElement(current.Name, replacementName);
Expand All @@ -416,18 +418,6 @@ currentProperty.Type is CodeType propertyType &&
CrawlTree(current, x => ReplaceReservedNames(x, provider, replacement, codeElementExceptions, shouldReplaceCallback));
}

private static void ReplaceReservedEnumNames(CodeEnum currentEnum, IReservedNamesProvider provider, Func<string, string> replacement)
{
currentEnum.Options
.Where(x => provider.ReservedNames.Contains(x.Name))
.ToList()
.ForEach(x =>
{
if (string.IsNullOrEmpty(x.SerializationName))
x.SerializationName = x.Name;
currentEnum.RenameChildElement(x.Name, replacement.Invoke(x.Name));
});
}
private static void ReplaceReservedCodeUsingDeclarationNames(ClassDeclaration currentDeclaration, IReservedNamesProvider provider, Func<string, string> replacement)
{
// replace the using declaration type names that are internally defined by the generator
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Refiners/JavaRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
"set",
string.Empty
);
ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped");
ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped", new HashSet<Type> { typeof(CodeEnumOption) });
ReplaceReservedExceptionPropertyNames(generatedCode, new JavaExceptionsReservedNamesProvider(), x => $"{x}Escaped");
LowerCaseNamespaceNames(generatedCode);
AddPropertiesAndMethodTypesImports(generatedCode, true, false, true);
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Refiners/PhpRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
ConvertUnionTypesToWrapper(generatedCode,
_configuration.UsesBackingStore,
false);
ReplaceReservedNames(generatedCode, new PhpReservedNamesProvider(), reservedWord => $"Escaped{reservedWord.ToFirstCharacterUpperCase()}");
ReplaceReservedNames(generatedCode, new PhpReservedNamesProvider(), reservedWord => $"Escaped{reservedWord.ToFirstCharacterUpperCase()}", new HashSet<Type> { typeof(CodeEnumOption) });
AddQueryParameterFactoryMethod(generatedCode);
CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements);
AddParsableImplementsForModelClasses(generatedCode, "Parsable");
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Refiners/ShellRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
ReplaceReservedNames(
generatedCode,
new CSharpReservedNamesProvider(), x => $"@{x.ToFirstCharacterUpperCase()}",
new HashSet<Type> { typeof(CodeClass), typeof(ClassDeclaration), typeof(CodeProperty), typeof(CodeUsing), typeof(CodeNamespace), typeof(CodeMethod), typeof(CodeEnum) }
new HashSet<Type> { typeof(CodeClass), typeof(ClassDeclaration), typeof(CodeProperty), typeof(CodeUsing), typeof(CodeNamespace), typeof(CodeMethod), typeof(CodeEnum), typeof(CodeEnumOption) }
);
ReplaceReservedNames(
generatedCode,
Expand Down
15 changes: 15 additions & 0 deletions tests/Kiota.Builder.Tests/Refiners/CSharpLanguageRefinerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ public async Task EnumHasEscapedOption_UsesEnumMemberAttribute()

Assert.Contains("EnumMemberAttribute", declaration.Usings.Select(x => x.Name));
}
[Theory]
[InlineData("operator")]
[InlineData("string")]
public async Task EnumWithReservedName_IsNotRenamed(string input)
{
var model = root.AddEnum(new CodeEnum
{
Name = "someenum"
}).First();
var option = new CodeEnumOption { Name = input, SerializationName = input };
model.AddOption(option);
await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.CSharp }, root);

Assert.Equal(input, model.Options.First().Name);
}
[Fact]
public async Task EnumDoesntHaveEscapedOption_DoesntUseEnumMemberAttribute()
{
Expand Down
15 changes: 15 additions & 0 deletions tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ public async Task AddsInnerClasses()
await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Go }, root);
Assert.Equal(2, model.GetChildElements(true).Count());
}
[Theory(Skip = "Fixing this test is a breaking change - https://github.com/microsoft/kiota/issues/2877")]
[InlineData("break")]
[InlineData("case")]
public async Task EnumWithReservedName_IsNotRenamed(string input)
{
var model = root.AddEnum(new CodeEnum
{
Name = "someenum"
}).First();
var option = new CodeEnumOption { Name = input, SerializationName = input };
model.AddOption(option);
await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Go }, root);

Assert.Equal(input, model.Options.First().Name);
}
[Fact]
public async Task TrimsCircularDiscriminatorReferences()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class JavaLanguageRefinerTests
private readonly CodeNamespace root = CodeNamespace.InitRootNamespace();
#region CommonLanguageRefinerTests
[Fact]
public async Task ReplacesReservedEnumOptions()
public async Task DoesNotReplacesReservedEnumOptions()
{
var model = root.AddEnum(new CodeEnum
{
Expand All @@ -25,8 +25,8 @@ public async Task ReplacesReservedEnumOptions()
};
model.AddOption(option);
await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Java }, root);
Assert.Equal("breakEscaped", option.Name);
Assert.Equal("break", option.SerializationName);
Assert.Equal("break", option.Name);
Assert.Empty(option.SerializationName);
}
[Fact]
public async Task AddsExceptionInheritanceOnErrorClasses()
Expand Down
16 changes: 16 additions & 0 deletions tests/Kiota.Builder.Tests/Refiners/PhpLanguageRefinerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ public async Task ReplacesRequestBuilderPropertiesByMethods()
Assert.Equal("userRequestBuilder", model.Name);
}

[Theory]
[InlineData("break")]
[InlineData("case")]
public async Task EnumWithReservedName_IsNotRenamed(string input)
{
var model = root.AddEnum(new CodeEnum
{
Name = "someenum"
}).First();
var option = new CodeEnumOption { Name = input, SerializationName = input };
model.AddOption(option);
await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.PHP }, root);

Assert.Equal(input, model.Options.First().Name);
}

[Fact]
public async Task PrefixReservedWordPropertyNamesWith()
{
Expand Down
15 changes: 15 additions & 0 deletions tests/Kiota.Builder.Tests/Refiners/PythonLanguageRefinerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ public async Task AddsQueryParameterMapperMethodAfterMangling()
Assert.Single(model.Properties.Where(x => x.IsNameEscaped));
Assert.Single(model.Methods.Where(x => x.IsOfKind(CodeMethodKind.QueryParametersMapper)));
}
[Theory]
[InlineData("None")]
[InlineData("while")]
public async Task EnumWithReservedName_IsRenamed(string input)
{
var model = root.AddEnum(new CodeEnum
{
Name = "someenum"
}).First();
var option = new CodeEnumOption { Name = input, SerializationName = input };
model.AddOption(option);
await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Python }, root);

Assert.Equal(input + "_", model.Options.First().Name);// we need to escape this in python
}
[Fact]
public async Task AddsExceptionInheritanceOnErrorClasses()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public void NamesDontDiffer_DoesntWriteEnumMember()
[InlineData("\\", "BackSlash")]
[InlineData("?", "QuestionMark")]
[InlineData("$", "Dollar")]
[InlineData("double", "Double")]
[InlineData("string", "String")]
public void WritesEnumWithSanitizedName(string symbol, string expected)
{
currentEnum.Flags = true;
Expand Down

0 comments on commit 0138b6d

Please sign in to comment.