From 4c11f6e4d762bc3fd8ecd0743a66a51878164dd0 Mon Sep 17 00:00:00 2001 From: Christoph Perger Date: Thu, 10 Dec 2020 21:32:05 +0100 Subject: [PATCH] Added a NoKey-attribute to skip parameter for cache generation, closes #11 --- .../ParameterDefinitionExtension.cs | 31 +++++++++++++++++++ .../MemoryCache.cs | 25 ++++++++++----- .../References.cs | 5 +++ .../MemoryCacheKeyTestClass.cs | 9 ++++++ .../MemoryCacheKeyTests.cs | 24 ++++++++++++++ .../NoKeyAttribute.cs | 16 ++++++++++ 6 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 src/SpatialFocus.MethodCache.Fody/Extensions/ParameterDefinitionExtension.cs create mode 100644 src/SpatialFocus.MethodCache/NoKeyAttribute.cs diff --git a/src/SpatialFocus.MethodCache.Fody/Extensions/ParameterDefinitionExtension.cs b/src/SpatialFocus.MethodCache.Fody/Extensions/ParameterDefinitionExtension.cs new file mode 100644 index 0000000..8efb3ab --- /dev/null +++ b/src/SpatialFocus.MethodCache.Fody/Extensions/ParameterDefinitionExtension.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Spatial Focus GmbH. All rights reserved. +// + +namespace SpatialFocus.MethodCache.Fody.Extensions +{ + using System; + using System.Linq; + using Mono.Cecil; + + public static class ParameterDefinitionExtension + { + public static bool HasNoKeyAttribute(this ParameterDefinition parameterDefinition, References references) + { + if (parameterDefinition == null) + { + throw new ArgumentNullException(nameof(parameterDefinition)); + } + + if (references == null) + { + throw new ArgumentNullException(nameof(references)); + } + + TypeReference noKeyAttributeType = references.NoKeyAttributeType.Resolve(); + + return parameterDefinition.CustomAttributes.Any(classAttribute => + classAttribute.AttributeType.Resolve().Equals(noKeyAttributeType)); + } + } +} \ No newline at end of file diff --git a/src/SpatialFocus.MethodCache.Fody/MemoryCache.cs b/src/SpatialFocus.MethodCache.Fody/MemoryCache.cs index 6b1880e..3f890cd 100644 --- a/src/SpatialFocus.MethodCache.Fody/MemoryCache.cs +++ b/src/SpatialFocus.MethodCache.Fody/MemoryCache.cs @@ -31,7 +31,9 @@ public static void AddMethodVariables(MethodWeavingContext methodWeavingContext) methodWeavingContext.MethodDefinition.DeclaringType.GenericParameters.Count)) .Concat(Enumerable.Repeat(methodWeavingContext.ClassWeavingContext.References.TypeType, methodWeavingContext.MethodDefinition.GenericParameters.Count)) - .Concat(methodWeavingContext.MethodDefinition.Parameters.Select(x => x.ParameterType)) + .Concat(methodWeavingContext.MethodDefinition.Parameters + .Where(x => !x.HasCustomAttributes || !x.HasNoKeyAttribute(methodWeavingContext.ClassWeavingContext.References)) + .Select(x => x.ParameterType)) .ToList(); tupleTypeReferences.ToList().ForEach(tupleTypeReference => methodWeavingContext.CacheKeyParameterTypes.Add(tupleTypeReference)); @@ -60,7 +62,8 @@ public static MethodReference GetCacheGetterMethod(ClassWeavingContext classWeav throw new WeavingException("Cache Property not found or multiple properties found."); } - MethodReference methodDefinition = classWeavingContext.TypeDefinition.Module.ImportReference(propertyDefinitions.Single().GetMethod); + MethodReference methodDefinition = + classWeavingContext.TypeDefinition.Module.ImportReference(propertyDefinitions.Single().GetMethod); if (methodDefinition.DeclaringType.GenericParameters.Any()) { @@ -95,11 +98,15 @@ public static ILProcessorContext WeaveCreateKey(MethodWeavingContext methodWeavi .Append(x => x.Create(OpCodes.Call, methodWeavingContext.ClassWeavingContext.References.GetTypeFromHandleMethod)); } - for (int i = 0; i < methodWeavingContext.MethodDefinition.Parameters.Count; i++) - { - int value = i; + int value = 1; - processorContext = processorContext.Append(x => x.Create(OpCodes.Ldarg, value + 1)); + foreach (ParameterDefinition parameter in methodWeavingContext.MethodDefinition.Parameters) + { + if (!parameter.HasCustomAttributes || !parameter.HasNoKeyAttribute(methodWeavingContext.ClassWeavingContext.References)) + { + processorContext = processorContext.Append(x => x.Create(OpCodes.Ldarg, value)); + value++; + } } return MemoryCache @@ -157,7 +164,8 @@ public static void WeaveSetBeforeReturns(MethodWeavingContext methodWeavingConte .Append(x => x.Create(OpCodes.Newobj, methodWeavingContext.ClassWeavingContext.References.NullableTimeSpanConstructor)) .Append(x => x.Create(OpCodes.Callvirt, - methodWeavingContext.ClassWeavingContext.References.MemoryCacheEntryOptionsAbsoluteExpirationRelativeToNowSetter)); + methodWeavingContext.ClassWeavingContext.References + .MemoryCacheEntryOptionsAbsoluteExpirationRelativeToNowSetter)); break; case "SlidingExpiration": @@ -168,7 +176,8 @@ public static void WeaveSetBeforeReturns(MethodWeavingContext methodWeavingConte .Append(x => x.Create(OpCodes.Newobj, methodWeavingContext.ClassWeavingContext.References.NullableTimeSpanConstructor)) .Append(x => x.Create(OpCodes.Callvirt, - methodWeavingContext.ClassWeavingContext.References.MemoryCacheEntryOptionsSlidingExpirationSetter)); + methodWeavingContext.ClassWeavingContext.References + .MemoryCacheEntryOptionsSlidingExpirationSetter)); break; case "Priority": diff --git a/src/SpatialFocus.MethodCache.Fody/References.cs b/src/SpatialFocus.MethodCache.Fody/References.cs index bc1367f..feb9b8e 100644 --- a/src/SpatialFocus.MethodCache.Fody/References.cs +++ b/src/SpatialFocus.MethodCache.Fody/References.cs @@ -41,6 +41,8 @@ protected References(ModuleWeaver moduleWeaver) public TypeReference NoCacheAttributeType { get; set; } + public TypeReference NoKeyAttributeType { get; set; } + public MethodReference NullableTimeSpanConstructor { get; set; } public MethodReference SetMethod { get; protected set; } @@ -69,6 +71,9 @@ public static References Init(ModuleWeaver moduleWeaver) TypeDefinition cacheAttributeType = moduleWeaver.FindTypeDefinition("SpatialFocus.MethodCache.CacheAttribute"); references.CacheAttributeType = moduleWeaver.ModuleDefinition.ImportReference(cacheAttributeType); + TypeDefinition noKeyAttributeType = moduleWeaver.FindTypeDefinition("SpatialFocus.MethodCache.NoKeyAttribute"); + references.NoKeyAttributeType = moduleWeaver.ModuleDefinition.ImportReference(noKeyAttributeType); + TypeDefinition noCacheAttributeType = moduleWeaver.FindTypeDefinition("SpatialFocus.MethodCache.NoCacheAttribute"); references.NoCacheAttributeType = moduleWeaver.ModuleDefinition.ImportReference(noCacheAttributeType); diff --git a/src/SpatialFocus.MethodCache.TestAssembly/MemoryCacheKeyTestClass.cs b/src/SpatialFocus.MethodCache.TestAssembly/MemoryCacheKeyTestClass.cs index 77c09ab..038a76b 100644 --- a/src/SpatialFocus.MethodCache.TestAssembly/MemoryCacheKeyTestClass.cs +++ b/src/SpatialFocus.MethodCache.TestAssembly/MemoryCacheKeyTestClass.cs @@ -64,6 +64,15 @@ public int WithParameter(int a) { return a; } + +#pragma warning disable IDE0060 // Remove unused parameter +#pragma warning disable CA1801 // Remove unused parameter + public int WithNoKeyParameter(int a, int b, [NoKey] int c) + { + return a + b; + } +#pragma warning restore IDE0060 // Remove unused parameter +#pragma warning restore CA1801 // Remove unused parameter #pragma warning restore CA1822 // Mark members as static } } \ No newline at end of file diff --git a/src/SpatialFocus.MethodCache.Tests/MemoryCacheKeyTests.cs b/src/SpatialFocus.MethodCache.Tests/MemoryCacheKeyTests.cs index 2652ea3..bc615fe 100644 --- a/src/SpatialFocus.MethodCache.Tests/MemoryCacheKeyTests.cs +++ b/src/SpatialFocus.MethodCache.Tests/MemoryCacheKeyTests.cs @@ -276,5 +276,29 @@ public void CacheKeyTest8With15Parameters() Assert.Equal(14, key[14]); Assert.Equal(15, key[15]); } + + [Fact] + public void CacheKeyTest9WithNoKeyParameters() + { + using MockMemoryCache mockMemoryCache = MockMemoryCache.Default; + + dynamic instance = + TestHelpers.CreateInstance(MemoryCacheKeyTests.TestResult.Assembly, mockMemoryCache); + + dynamic result1 = instance.WithNoKeyParameter(1, 2, 3); + dynamic result2 = instance.WithNoKeyParameter(1, 2, 4); + + Assert.Equal(3, result1); + Assert.Equal(3, result2); + + Assert.Equal(1, mockMemoryCache.CountSets); + Assert.Equal(2, mockMemoryCache.CountGets); + + ITuple key = (ITuple)mockMemoryCache.LastCreatedEntryKey; + Assert.Equal(3, key.Length); + Assert.Equal("SpatialFocus.MethodCache.TestAssembly.MemoryCacheKeyTestClass.WithNoKeyParameter", key[0]); + Assert.Equal(1, key[1]); + Assert.Equal(2, key[2]); + } } } \ No newline at end of file diff --git a/src/SpatialFocus.MethodCache/NoKeyAttribute.cs b/src/SpatialFocus.MethodCache/NoKeyAttribute.cs new file mode 100644 index 0000000..d355793 --- /dev/null +++ b/src/SpatialFocus.MethodCache/NoKeyAttribute.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) Spatial Focus GmbH. All rights reserved. +// + +namespace SpatialFocus.MethodCache +{ + using System; + + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class NoKeyAttribute : Attribute + { + public NoKeyAttribute() + { + } + } +} \ No newline at end of file