/// <summary> /// Adds a new Warning message. /// </summary> /// <param name="aspect">The aspect writing the Warning message</param> /// <param name="code">The 'code' of this specific message</param> /// <param name="message">The message</param> /// <param name="location">The location where the aspect applies to. Will show full signature.</param> public static void RaiseWarning(this IAspect aspect, int code, string message, MethodBase location) { if (aspect == null || message == null) { return; } Message.Write(SeverityType.Warning, aspect.GetType().Name + "[" + code + "]", location != null ? "[{0}] {1}".F(location.AsSignature(true), message) : "{0}".F(message)); }
///<summary> /// Validate the aspect usage ///</summary> ///<param name="method">The method that the aspect is applied on</param> ///<returns>Returns true if all checks pass</returns> public override bool CompileTimeValidate(MethodBase method) { if (method == null) { this.RaiseError(1, "The PostCompile aspect can only be applied on methods.", method.AsSignature()); return(false); } if (!method.IsStatic) { this.RaiseError(2, "The PostCompile aspect can only be applied on static methods.", method.AsSignature()); return(false); } if (method.GetParameters().Length > 0) { this.RaiseError(3, "The PostCompile aspect can only be applied on methods without arguments.", method.AsSignature()); return(false); } if (method as MethodInfo == null) { this.RaiseError(4, "The PostCompile aspect can not be applied on constructor/deconstructors", method.AsSignature()); return(false); } if (((MethodInfo)method).ReturnType != typeof(void)) { this.RaiseError(5, "The PostCompile aspect can only be applied on methods returning nothing.", method.AsSignature()); return(false); } this.Describe("On compilation, this method will be invoked", method); try { method.Invoke(null, null); this.Describe("Last post-compile run succeeded at {0}".F(DateTime.Now), method); } catch (TargetInvocationException ex) // when this exception is thrown, consider it a success, and optionally check if it has more descriptions to add { if (ex.InnerException is PostCompileSuccessException) { this.Describe("Last post-compile run succeeded at {0}".F(DateTime.Now), method); foreach (var d in (ex.InnerException as PostCompileSuccessException).Descriptions) { this.Describe(d, method); } } else { this.Describe("Last post-compile run failed at {0}".F(DateTime.Now), method); this.Describe(ex.ToString(), method); } } catch (Exception ex) { this.Describe("Last post-compile run failed at {0}".F(DateTime.Now), method); this.Describe(ex.ToString(), method); } return(true); }
/// <summary> /// Add a new description entry. /// </summary> private static void AddDescription <T>(XDocument document, Dictionary <string, string> storage, string description, MethodBase target) { if (document.Root == null) { return; } var aspectSymbol = "T:" + typeof(T).FullName; var methodSymbol = "M:" + target.AsSignature(); var declaringTypeSymbol = "T:" + target.DeclaringType.AsSignature(); // find the target 'Class' node var classNode = document.Root .Elements() .Where(el => el.Name.LocalName == "Class") .Where(el => el.Attribute("Class") != null) .Where(el => GetSymbol(el.Attribute("Class").Value, storage) == aspectSymbol) .FirstOrDefault(); // No node found for the requested aspect, create a new one if (classNode == null) { classNode = new XElement(document.Root.Name.Namespace + "Class"); // Add the 'Class' attribute classNode.Add(new XAttribute("Class", GetSymbolId(aspectSymbol, storage) ?? "#" + GenerateSymbolId(storage) + "=" + aspectSymbol)); //classNode.Add(new XAttribute("ClassX", GenerateSymbolId(storage) + "=" + aspectSymbol)); // Add to the root node document.Root.Add(classNode); } // Get the aspect symbol id (example: #1214) string aspectSymbolId = GetSymbolId(classNode.Attribute("Class").Value, storage) ?? classNode.Attribute("Class").Value.Substring(0, classNode.Attribute("Class").Value.IndexOf("=")); // Get the method symbol id (example: #1214) string methodSymbolId = GetSymbolId(methodSymbol, storage); bool isTypeInstanceNode = true; // find the target 'Instance' node (first check for the declaring type) var instanceNode = classNode .Elements() .Where(el => el.Name.LocalName == "Instance") .Where(el => el.Attribute("Declaration") != null) .Where(el => GetSymbol(el.Attribute("Declaration").Value, storage) == declaringTypeSymbol) .FirstOrDefault(); // if not found, check if there is one for our method if (instanceNode == null) { instanceNode = classNode .Elements() .Where(el => el.Name.LocalName == "Instance") .Where(el => el.Attribute("Declaration") != null) .Where(el => GetSymbol(el.Attribute("Declaration").Value, storage) == methodSymbol) .FirstOrDefault(); isTypeInstanceNode = false; } // Maybe its part of a property? if (instanceNode == null) { instanceNode = classNode .Elements() .Where(el => el.Name.LocalName == "Instance") .Where(el => el.Attribute("Declaration") != null) .Where(el => GetSymbol(el.Attribute("Declaration").Value, storage).StartsWith("P:")) .Where(el => el.Elements().Any(e => e.Name.LocalName == "Target" && e.Attribute("Target") != null && GetSymbol(e.Attribute("Target").Value, storage) == methodSymbol)) .FirstOrDefault(); if (instanceNode != null) { isTypeInstanceNode = true; } } bool isPropertyMethod = false; // if not found, check if there is one for our method @ a JoinPoint (also if it refers to a property) if (instanceNode == null) { instanceNode = classNode .Elements() .Where(el => el.Name.LocalName == "Instance") .Where(el => el.Attribute("Declaration") != null) .Where(el => GetSymbol(el.Attribute("Declaration").Value, storage).StartsWith("P:")) .Where(el => el.Elements().Any(e => e.Name.LocalName == "Target" && e.Attribute("Target") == null && e.Elements().Any(ee => ee.Attribute("Advised") != null && GetSymbol(ee.Attribute("Advised").Value, storage) == methodSymbol) )) .FirstOrDefault(); if (instanceNode != null) { isPropertyMethod = true; } } // no node found for the method, create a new one (for this method) if (instanceNode == null) { instanceNode = new XElement(document.Root.Name.Namespace + "Instance"); // Add the 'Declaration' attribute instanceNode.Add(new XAttribute("Declaration", GetSymbolId(methodSymbol, storage) ?? "#" + GenerateSymbolId(storage) + "=" + methodSymbol)); // Add the 'Token' attribute instanceNode.Add(new XAttribute("Token", GenerateSymbolId(storage))); // Add to the class node classNode.Add(instanceNode); } // find the 'Target' node - first try to find a specific match (one that has a 'Target' attribute) var targetNode = instanceNode .Elements() .Where(el => el.Name.LocalName == "Target") .Where(el => el.Attribute("Target") != null) .Where(el => GetSymbol(el.Attribute("Target").Value, storage) == methodSymbol) .FirstOrDefault(); // None found, try to find a 'Target' node that does not have a target, // but ONLY if the instance node is not a 'type' node if (targetNode == null && !isTypeInstanceNode) { targetNode = instanceNode .Elements() .Where(el => el.Name.LocalName == "Target") .Where(el => el.Attribute("Target") == null) .FirstOrDefault(); } // Still none found, create the node if (targetNode == null) { targetNode = new XElement(document.Root.Name.Namespace + "Target"); // if its an 'type instance node', add a Target attribute if (isTypeInstanceNode) { // Add the 'Declaration' attribute targetNode.Add(new XAttribute("Target", GetSymbolId(methodSymbol, storage) ?? "#" + GenerateSymbolId(storage) + "=" + methodSymbol)); } // Add to the class node instanceNode.Add(targetNode); } // Create the JoinPoint node var joinPoint = new XElement(document.Root.Name.Namespace + "JoinPoint"); if (isPropertyMethod) { // Add the 'Advised' attribute (points to our target) joinPoint.Add(new XAttribute("Advised", methodSymbolId)); } else { if (target.Name.StartsWith("get_") || target.Name.StartsWith("set_")) { isPropertyMethod = true; } else { // Add the 'Advising' attribute (points to our aspect) joinPoint.Add(new XAttribute("Advising", aspectSymbolId)); } } // Add the 'Description' attribute with the message to be shown joinPoint.Add(new XAttribute("Description", "#" + GenerateSymbolId(storage) + "=" + description)); // add Semantic if (isPropertyMethod) { // Add the 'Advised' attribute (points to our target) joinPoint.Add(new XAttribute("Semantic", target.Name.StartsWith("get_") ? "Getter" : "Setter")); var oe = targetNode.Elements().FirstOrDefault(e => e.Attribute("Ordinal") != null); if (oe != null) { joinPoint.Add(new XAttribute("Ordinal", oe.Attribute("Ordinal").Value)); } } // Add it to the Target node targetNode.Add(joinPoint); }