Skip to content

Commit

Permalink
add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
damien-o committed Feb 17, 2024
1 parent 6c3e1ba commit 671c610
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 121 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_namespace_declarations = file_scoped:suggestion
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
Expand Down
1 change: 1 addition & 0 deletions EnumConstraints.Fody.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnumConstraints.Fody", "src\EnumConstraints.Fody\EnumConstraints.Fody.csproj", "{C563D4BE-6991-4D74-A070-706507193E0D}"
Expand Down
126 changes: 125 additions & 1 deletion README.md
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).
Binary file added package_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions package_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
145 changes: 75 additions & 70 deletions src/EnumConstraints.Fody/ClassProcessor.cs
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;
}
}
}
12 changes: 6 additions & 6 deletions src/EnumConstraints.Fody/EnumConstraints.Fody.csproj
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>
Loading

0 comments on commit 671c610

Please sign in to comment.