public static MethodReference GetCacheGetterMethod(ClassWeavingContext classWeavingContext) { if (classWeavingContext == null) { throw new ArgumentNullException(nameof(classWeavingContext)); } // TODO: Check if this can be inherited, extract to class level List <PropertyDefinition> propertyDefinitions = classWeavingContext.TypeDefinition.TryGetCacheGetterProperty(classWeavingContext.References); // TODO: Also check fields if (propertyDefinitions == null || propertyDefinitions.Count != 1) { throw new WeavingException("Cache Property not found or multiple properties found."); } MethodReference methodDefinition = classWeavingContext.TypeDefinition.Module.ImportReference(propertyDefinitions.Single().GetMethod); if (methodDefinition.DeclaringType.GenericParameters.Any()) { return(methodDefinition.MakeHostInstanceGeneric(methodDefinition.DeclaringType.GenericParameters.Cast <TypeReference>() .ToArray())); } return(methodDefinition); }
public override void Execute() { References references = Fody.References.Init(this); foreach (WeavingCandidate weavingCandidate in ModuleDefinition.GetWeavingCandidates(references)) { if (weavingCandidate.ClassDefinition.HasCacheAttribute(references) && !weavingCandidate.MethodDefinitions .Where(x => !x.HasNoCacheAttribute(references)) .Any(x => x.IsEligibleForWeaving(references))) { WriteWarning( $"Class {weavingCandidate.ClassDefinition.Resolve().FullName} contains [Cache] attribute but does not contain eligible methods for caching"); continue; } if (!weavingCandidate.ClassDefinition.IsEligibleForWeaving(references)) { WriteWarning( $"Class {weavingCandidate.ClassDefinition.Name} contains [Cache] attribute but does not contain a single property implementing IMemoryCache interface"); continue; } ClassWeavingContext classWeavingContext = new ClassWeavingContext(weavingCandidate.ClassDefinition, references); classWeavingContext.CacheGetterMethod = MemoryCache.GetCacheGetterMethod(classWeavingContext); foreach (MethodDefinition methodDefinition in weavingCandidate.MethodDefinitions) { if (!methodDefinition.IsEligibleForWeaving(references)) { // Show warning if test was marked explicitly if (methodDefinition.HasCacheAttribute(references)) { WriteWarning($"Method {methodDefinition.FullName} contains [Cache] attribute but is not eligible for weaving"); break; } continue; } if (methodDefinition.HasNoCacheAttribute(references)) { continue; } MethodWeavingContext methodWeavingContext = new MethodWeavingContext(classWeavingContext, methodDefinition); MemoryCache.AddMethodVariables(methodWeavingContext); ILProcessorContext processorContext = MemoryCache.WeaveCreateKey(methodWeavingContext); MemoryCache.WeaveTryGetValueAndReturn(methodWeavingContext, processorContext); MemoryCache.WeaveSetBeforeReturns(methodWeavingContext); } } }
public static MethodReference GetCacheGetterMethod(ClassWeavingContext classWeavingContext) { if (classWeavingContext == null) { throw new ArgumentNullException(nameof(classWeavingContext)); } // TODO: Check if this can be inherited, extract to class level List <PropertyDefinition> propertyDefinitions = classWeavingContext.TypeDefinition.Properties.Where(definition => { TypeDefinition typeDefinition = definition.PropertyType.Resolve(); TypeDefinition memoryCacheInterface = classWeavingContext.References.MemoryCacheInterface.Resolve(); if (definition.GetMethod.IsStatic) { return(false); } if (typeDefinition.IsInterface && typeDefinition.Equals(memoryCacheInterface)) { return(true); } if (typeDefinition.Interfaces.Any(x => x.InterfaceType == memoryCacheInterface)) { return(true); } return(false); }) .ToList(); // TODO: Also check fields if (propertyDefinitions.Count != 1) { throw new WeavingException("Property not found"); } MethodDefinition methodDefinition = propertyDefinitions.Single().GetMethod; if (methodDefinition.DeclaringType.GenericParameters.Any()) { return(methodDefinition.MakeHostInstanceGeneric(methodDefinition.DeclaringType.GenericParameters.Cast <TypeReference>() .ToArray())); } return(methodDefinition); }
public override void Execute() { References references = Fody.References.Init(this); // TODO: Extract to method var elementsToCache = ModuleDefinition.Types.Select(type => { if (type.HasCacheAttribute(references)) { return(new { Type = type, Methods = type.Methods.ToList() }); } return(new { Type = type, Methods = type.Methods.Where(method => method.HasCacheAttribute(references)).ToList(), }); }) .Where(x => x.Methods.Any()) .ToList(); foreach (var elementToCache in elementsToCache) { if (!elementToCache.Type.IsEligibleForWeaving(references)) { // TODO: Create warning continue; } ClassWeavingContext classWeavingContext = new ClassWeavingContext(elementToCache.Type, references); classWeavingContext.CacheGetterMethod = MemoryCache.GetCacheGetterMethod(classWeavingContext); foreach (MethodDefinition methodDefinition in elementToCache.Methods) { if (!methodDefinition.IsEligibleForWeaving(references)) { // TODO: Create warning if marked explicit for weaving continue; } MethodWeavingContext methodWeavingContext = new MethodWeavingContext(classWeavingContext, methodDefinition); MemoryCache.AddMethodVariables(methodWeavingContext); ILProcessorContext processorContext = MemoryCache.WeaveCreateKey(methodWeavingContext); MemoryCache.WeaveTryGetValueAndReturn(methodWeavingContext, processorContext); MemoryCache.WeaveSetBeforeReturns(methodWeavingContext); } } }
public MethodWeavingContext(ClassWeavingContext classWeavingContext, MethodDefinition methodDefinition) { ClassWeavingContext = classWeavingContext; MethodDefinition = methodDefinition; }