-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
260 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,125 @@ | ||
# EnumConstraints | ||
# <img src="/package_icon.png" height="30px"> EnumConstraints.Fody | ||
|
||
[![Chat on Gitter](https://img.shields.io/gitter/room/fody/fody.svg)](https://gitter.im/Fody/Fody) | ||
[![NuGet Status](https://img.shields.io/nuget/v/EnumConstraints.Fody.svg)](https://www.nuget.org/packages/Janitor.Fody/) | ||
|
||
Validates enum property value. | ||
|
||
**See [Milestones](../../milestones?state=closed) for release notes.** | ||
|
||
|
||
### This is an add-in for [Fody](https://github.com/Fody/Home/) | ||
|
||
**It is expected that all developers using Fody [become a Patron on OpenCollective](https://opencollective.com/fody/contribute/patron-3059). [See Licensing/Patron FAQ](https://github.com/Fody/Home/blob/master/pages/licensing-patron-faq.md) for more information.** | ||
|
||
|
||
## Usage | ||
|
||
See also [Fody usage](https://github.com/Fody/Home/blob/master/pages/usage.md). | ||
|
||
|
||
### NuGet installation | ||
|
||
Install the [EnumConstraints.Fody NuGet package](https://nuget.org/packages/EnumConstraints.Fody/) and update the [Fody NuGet package](https://nuget.org/packages/Fody/): | ||
|
||
```powershell | ||
PM> Install-Package Fody | ||
PM> Install-Package EnumConstraints.Fody | ||
``` | ||
|
||
The `Install-Package Fody` is required since NuGet always defaults to the oldest, and most buggy, version of any dependency. | ||
|
||
|
||
### Add to FodyWeavers.xml | ||
|
||
Add `<EnumConstraints/>` to [FodyWeavers.xml](https://github.com/Fody/Home/blob/master/pages/usage.md#add-fodyweaversxml) | ||
|
||
```xml | ||
<Weavers> | ||
<EnumConstraints/> | ||
</Weavers> | ||
``` | ||
|
||
|
||
## What it does | ||
|
||
* Looks for all classes with Properties. | ||
* Generates a new implementations of Set and Get methods. | ||
* Replaces orginal implementations with the new ones. | ||
* The new implementations are using the originals implementations under the hood | ||
|
||
#### The typed Code | ||
|
||
```cs | ||
|
||
public enum Status | ||
{ | ||
} | ||
|
||
public class Sample | ||
{ | ||
public Status Status { get; set;} | ||
} | ||
``` | ||
|
||
|
||
#### The lowered code | ||
```cs | ||
public class Sample | ||
{ | ||
private Status <Status>k__BackingField; | ||
|
||
public Status Status | ||
{ | ||
get; // Calls get_Status | ||
set; // Calls set_Status | ||
} | ||
|
||
public Status get_Status() | ||
{ | ||
return <Status>k__BackingField; | ||
} | ||
public void set_Status(Status value) | ||
{ | ||
<Status>k__BackingField = value; | ||
} | ||
} | ||
``` | ||
#### What gets compiled | ||
```cs | ||
public class Sample | ||
{ | ||
private StringComparison <Status>k__BackingField; | ||
|
||
public Status Status | ||
{ | ||
get; // Calls get_ConstraintStatus | ||
set; // Calls set_ConstraintStatus | ||
} | ||
|
||
public Status get_ConstraintStatus() | ||
{ | ||
var value = getStatus(); | ||
InvalidEnumValueException.ThrowIfInvalid(value); | ||
return value; | ||
} | ||
|
||
public Status get_ConstraintStatus(Status value) | ||
{ | ||
InvalidEnumValueException.ThrowIfInvalid(value); | ||
return set_Status(value); | ||
} | ||
|
||
public Status get_Status | ||
{ | ||
return <Status>k__BackingField; | ||
} | ||
public void set_Status(Status value) | ||
{ | ||
<Status>k__BackingField = value; | ||
} | ||
} | ||
``` | ||
|
||
## Icon | ||
[Checklist](https://www.onlinewebfonts.com/icon/464401) designed by [>Web Fonts](http://www.onlinewebfonts.com). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,104 @@ | ||
using Mono.Cecil; | ||
using System.Linq; | ||
using Mono.Cecil; | ||
using Mono.Cecil.Cil; | ||
|
||
namespace EnumConstraints.Fody; | ||
|
||
internal class ClassProcessor | ||
namespace EnumConstraints.Fody | ||
{ | ||
private readonly MethodReference _throwIfInvalid; | ||
|
||
public ClassProcessor(ModuleDefinition module) | ||
internal class ClassProcessor | ||
{ | ||
_throwIfInvalid = module.ImportReference( | ||
typeof(InvalidEnumValueException) | ||
.GetMethods() | ||
.Single(m => m.Name == nameof(InvalidEnumValueException.ThrowIfInvalid)) | ||
); | ||
} | ||
private readonly MethodReference _throwIfInvalid; | ||
|
||
internal void Process(TypeDefinition typeDefinition, PropertyDefinition propertyDefinition) | ||
{ | ||
if (propertyDefinition.SetMethod.HasBody) | ||
public ClassProcessor(ModuleDefinition module) | ||
{ | ||
AddSetDecorator(typeDefinition, propertyDefinition); | ||
_throwIfInvalid = module.ImportReference( | ||
typeof(InvalidEnumValueException) | ||
.GetMethods() | ||
.Single(m => m.Name == nameof(InvalidEnumValueException.ThrowIfInvalid)) | ||
); | ||
} | ||
if (propertyDefinition.GetMethod.HasBody) | ||
|
||
internal void ProcessProperties( | ||
TypeDefinition typeDefinition, | ||
PropertyDefinition propertyDefinition | ||
) | ||
{ | ||
AddGetDecorator(typeDefinition, propertyDefinition); | ||
if (propertyDefinition.SetMethod.HasBody) | ||
{ | ||
AddSetDecorator(typeDefinition, propertyDefinition); | ||
} | ||
if (propertyDefinition.GetMethod.HasBody) | ||
{ | ||
AddGetDecorator(typeDefinition, propertyDefinition); | ||
} | ||
} | ||
} | ||
|
||
private void AddGetDecorator(TypeDefinition typeDefinition, PropertyDefinition property) | ||
{ | ||
var getMethod = property.GetMethod; | ||
private void AddGetDecorator(TypeDefinition typeDefinition, PropertyDefinition property) | ||
{ | ||
var getMethod = property.GetMethod; | ||
|
||
var newGetMethod = new MethodDefinition( | ||
"GetConstraint" + getMethod.Name, | ||
getMethod.Attributes, | ||
getMethod.ReturnType | ||
); | ||
var newGetMethod = new MethodDefinition( | ||
"get_Constraint" + getMethod.Name, | ||
getMethod.Attributes, | ||
getMethod.ReturnType | ||
); | ||
|
||
var il = newGetMethod.Body.Instructions; | ||
var il = newGetMethod.Body.Instructions; | ||
|
||
var tempVar = new VariableDefinition( | ||
typeDefinition.Module.ImportReference(getMethod.ReturnType) | ||
); | ||
newGetMethod.Body.Variables.Add(tempVar); | ||
newGetMethod.Body.InitLocals = true; | ||
var tempVar = new VariableDefinition( | ||
typeDefinition.Module.ImportReference(getMethod.ReturnType) | ||
); | ||
newGetMethod.Body.Variables.Add(tempVar); | ||
newGetMethod.Body.InitLocals = true; | ||
|
||
/// call Property; | ||
il.Add(Instruction.Create(OpCodes.Ldarg_0)); | ||
il.Add(Instruction.Create(OpCodes.Call, property.GetMethod)); | ||
/// call Property; | ||
il.Add(Instruction.Create(OpCodes.Ldarg_0)); | ||
il.Add(Instruction.Create(OpCodes.Call, property.GetMethod)); | ||
|
||
il.Add(Instruction.Create(OpCodes.Dup)); | ||
il.Add(Instruction.Create(OpCodes.Dup)); | ||
|
||
// throwIfInvalid(tempVar) | ||
il.Add(Instruction.Create(OpCodes.Stloc, tempVar)); | ||
il.Add(Instruction.Create(OpCodes.Box, getMethod.ReturnType)); | ||
il.Add(Instruction.Create(OpCodes.Call, _throwIfInvalid)); | ||
// throwIfInvalid(tempVar) | ||
il.Add(Instruction.Create(OpCodes.Stloc, tempVar)); | ||
il.Add(Instruction.Create(OpCodes.Box, getMethod.ReturnType)); | ||
il.Add(Instruction.Create(OpCodes.Call, _throwIfInvalid)); | ||
|
||
// return tempVar | ||
il.Add(Instruction.Create(OpCodes.Ldloc, tempVar)); | ||
il.Add(Instruction.Create(OpCodes.Ret)); | ||
typeDefinition.Methods.Add(newGetMethod); | ||
// return tempVar | ||
il.Add(Instruction.Create(OpCodes.Ldloc, tempVar)); | ||
il.Add(Instruction.Create(OpCodes.Ret)); | ||
typeDefinition.Methods.Add(newGetMethod); | ||
|
||
property.GetMethod = newGetMethod; | ||
} | ||
property.GetMethod = newGetMethod; | ||
} | ||
|
||
private void AddSetDecorator(TypeDefinition typeDefinition, PropertyDefinition property) | ||
{ | ||
var setMethod = property.SetMethod; | ||
private void AddSetDecorator(TypeDefinition typeDefinition, PropertyDefinition property) | ||
{ | ||
var setMethod = property.SetMethod; | ||
|
||
var newSetMethod = new MethodDefinition( | ||
"SetConstraint" + setMethod.Name, | ||
setMethod.Attributes, | ||
setMethod.ReturnType | ||
); | ||
var newSetMethod = new MethodDefinition( | ||
"set_Constraint" + setMethod.Name, | ||
setMethod.Attributes, | ||
setMethod.ReturnType | ||
); | ||
|
||
var valueParameter = setMethod.Parameters[0]; | ||
var valueParameter = setMethod.Parameters[0]; | ||
|
||
newSetMethod.Parameters.Add(new ParameterDefinition(valueParameter.ParameterType)); | ||
newSetMethod.Parameters.Add(new ParameterDefinition(valueParameter.ParameterType)); | ||
|
||
var il = newSetMethod.Body.Instructions; | ||
var il = newSetMethod.Body.Instructions; | ||
|
||
/// call _throwIfInvalid; | ||
il.Add(Instruction.Create(OpCodes.Ldarg_1)); | ||
il.Add(Instruction.Create(OpCodes.Box, valueParameter.ParameterType)); | ||
il.Add(Instruction.Create(OpCodes.Call, _throwIfInvalid)); | ||
/// call _throwIfInvalid; | ||
il.Add(Instruction.Create(OpCodes.Ldarg_1)); | ||
il.Add(Instruction.Create(OpCodes.Box, valueParameter.ParameterType)); | ||
il.Add(Instruction.Create(OpCodes.Call, _throwIfInvalid)); | ||
|
||
/// call set property; | ||
il.Add(Instruction.Create(OpCodes.Ldarg_0)); | ||
il.Add(Instruction.Create(OpCodes.Ldarg_1)); | ||
il.Add(Instruction.Create(OpCodes.Call, property.SetMethod)); | ||
/// call set property; | ||
il.Add(Instruction.Create(OpCodes.Ldarg_0)); | ||
il.Add(Instruction.Create(OpCodes.Ldarg_1)); | ||
il.Add(Instruction.Create(OpCodes.Call, property.SetMethod)); | ||
|
||
il.Add(Instruction.Create(OpCodes.Ret)); | ||
typeDefinition.Methods.Add(newSetMethod); | ||
il.Add(Instruction.Create(OpCodes.Ret)); | ||
typeDefinition.Methods.Add(newSetMethod); | ||
|
||
property.SetMethod = newSetMethod; | ||
property.SetMethod = newSetMethod; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<TargetFrameworks>net6.0;netstandard2.1</TargetFrameworks> | ||
<ImplicitUsings>false</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||
<LangVersion>10.0</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="FodyHelpers" Version="6.8.0" /> | ||
<PackageReference Include="FodyHelpers" Version="6.8.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\EnumConstraints\EnumConstraints.csproj" /> | ||
<ProjectReference Include="..\EnumConstraints\EnumConstraints.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Oops, something went wrong.