/// <summary> /// Initializes a new instance of the <see cref="Monobjc.Tools.Generator.Model.Entities.FunctionEntity"/> class. /// </summary> public FunctionEntity(FunctionEntity functionEntity) : this() { this.MinAvailability = functionEntity.MinAvailability; this.Generate = functionEntity.Generate; this.Name = functionEntity.Name; this.ReturnsDocumentation = functionEntity.ReturnsDocumentation; this.ReturnType = functionEntity.ReturnType; this.Selector = functionEntity.Selector; this.Signature = functionEntity.Signature; this.Static = functionEntity.Static; this.Summary = new List<String> (functionEntity.Summary); foreach (MethodParameterEntity methodParameterEntity in functionEntity.Parameters) { MethodParameterEntity parameter = new MethodParameterEntity (methodParameterEntity); this.Parameters.Add (parameter); } this.GenerateConstructor = functionEntity.GenerateConstructor; this.SharedLibrary = functionEntity.SharedLibrary; this.EntryPoint = functionEntity.EntryPoint; }
/// <summary> /// Initializes a new instance of the <see cref="Monobjc.Tools.Generator.Model.Entities.FunctionEntity"/> class. /// </summary> public FunctionEntity(FunctionEntity functionEntity) : this() { this.MinAvailability = functionEntity.MinAvailability; this.Generate = functionEntity.Generate; this.Name = functionEntity.Name; this.ReturnsDocumentation = functionEntity.ReturnsDocumentation; this.ReturnType = functionEntity.ReturnType; this.Selector = functionEntity.Selector; this.Signature = functionEntity.Signature; this.Static = functionEntity.Static; this.Summary = new List <String> (functionEntity.Summary); foreach (MethodParameterEntity methodParameterEntity in functionEntity.Parameters) { MethodParameterEntity parameter = new MethodParameterEntity(methodParameterEntity); this.Parameters.Add(parameter); } this.GenerateConstructor = functionEntity.GenerateConstructor; this.SharedLibrary = functionEntity.SharedLibrary; this.EntryPoint = functionEntity.EntryPoint; }
public FunctionEntity Parse(TypedEntity typedEntity, string name, IEnumerable<XElement> elements) { FunctionEntity functionEntity = new FunctionEntity (); XElement declarationElement = (from el in elements where el.Name == "div" && el.Attribute ("class") != null && el.Attribute ("class").Value == "declaration_indent" select el).FirstOrDefault (); declarationElement = declarationElement ?? (from el in elements where el.Name == "pre" select el).FirstOrDefault (); XElement parameterElement = (from el in elements where el.Name == "div" && el.Attribute ("class") != null && el.Attribute ("class").Value == "param_indent" select el).FirstOrDefault (); XElement returnValueElement = (from el in elements where el.Name == "h5" && el.Value.Trim () == "Return Value" select el).FirstOrDefault (); //XElement discussionElement = (from el in elements // where el.Name == "h5" && el.Value.Trim() == "Discussion" // select el).FirstOrDefault(); XElement availabilityElement = (from el in elements let term = el.Descendants ("dt").FirstOrDefault () let definition = el.Descendants ("dd").FirstOrDefault () where el.Name == "dl" && term != null && term.Value.Trim () == "Availability" select definition).FirstOrDefault (); functionEntity.Name = name; String signature = declarationElement.TrimAll (); if (signature.StartsWith ("#define")) { this.Logger.WriteLine ("SKIPPING define statement: " + name); return null; } if (!signature.Contains ("(")) { // e.g. NS_DURING this.Logger.WriteLine ("SKIPPING non-function statement: " + name); return null; } // Trim down signature while (signature.IndexOf(" ") != -1) { signature = signature.Replace (" ", " "); } functionEntity.Signature = signature; //Console.WriteLine("signature='" + signature + "'"); // Extract abstract IEnumerable<XElement> abstractElements = elements.SkipWhile (el => el.Name != "p").TakeWhile (el => el.Name == "p"); foreach (XElement element in abstractElements) { String line = element.TrimAll (); if (!String.IsNullOrEmpty (line)) { functionEntity.Summary.Add (line); } } //// Extract discussion //if (discussionElement != null) //{ // IEnumerable<XElement> discussionElements = discussionElement.ElementsAfterSelf().TakeWhile(el => el.Name == "p"); // foreach (XElement element in discussionElements) // { // String line = element.TrimAll(); // if (!String.IsNullOrEmpty(line)) // { // methodEntity.Summary.Add(line); // } // } //} // Parse signature signature = signature.Replace ("extern", String.Empty).Trim (); int pos = signature.IndexOf (name); if (pos == -1) { this.Logger.WriteLine ("MISMATCH between name and declaration: " + name); return null; } String returnType = signature.Substring (0, pos).Trim (); int paramsIndex = pos + name.Length; int paramsLength = signature.IndexOf(')') + 1 - paramsIndex; // Stop before getting to function body String parameters = signature.Substring (paramsIndex, paramsLength).Trim (); parameters = parameters.Trim (';', '(', ')').Trim(); if (parameters != "void") { foreach (string parameter in parameters.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries)) { String parameterType = "NOTYPE"; String parameterName = "NONAME"; //Console.WriteLine("parameter='" + parameter + "'"); Match r = PARAMETER_REGEX.Match (parameter); if (r.Success) { parameterType = r.Groups [2].Value.Trim (); parameterName = r.Groups [3].Value.Trim (); } else if (parameter.Trim () == "...") { parameterType = "params Object[]"; parameterName = "values"; } else { this.Logger.WriteLine ("FAILED to parse parameter: " + parameter); return null; } MethodParameterEntity parameterEntity = new MethodParameterEntity (); bool isOut, isByRef, isBlock; parameterEntity.Type = this.TypeManager.ConvertType (parameterType, out isOut, out isByRef, out isBlock, this.Logger); parameterEntity.IsOut = isOut; parameterEntity.IsByRef = isByRef; parameterEntity.IsBlock = isBlock; parameterEntity.Name = TypeManager.ConvertName(parameterName); functionEntity.Parameters.Add (parameterEntity); } } // Extract return type functionEntity.ReturnType = this.TypeManager.ConvertType (returnType, this.Logger); if (functionEntity.Parameters.Count > 0 && parameterElement != null) { XElement termList = parameterElement.Descendants ("dl").FirstOrDefault (); if (termList != null) { IEnumerable<XElement> dtList = from el in termList.Elements ("dt") select el; IEnumerable<XElement> ddList = from el in termList.Elements ("dd") select el; if (dtList.Count () == ddList.Count ()) { // Iterate over definitions for (int i = 0; i < dtList.Count(); i++) { String term = dtList.ElementAt (i).TrimAll (); //String summary = ddList.ElementAt(i).TrimAll(); IEnumerable<String> summaries = ddList.ElementAt (i).Elements ("p").Select (p => p.Value.TrimAll ()); // Find the parameter MethodParameterEntity parameterEntity = functionEntity.Parameters.Find (p => String.Equals (p.Name, term)); if (parameterEntity != null) { //parameterEntity.Summary.Add(summary); foreach (string sum in summaries) { parameterEntity.Summary.Add (sum); } } } } } } // Fix the name only after looking for the documentation for (int i = 0; i < functionEntity.Parameters.Count; i++) { functionEntity.Parameters [i].Name = this.TypeManager.ConvertName (functionEntity.Parameters [i].Name); } // Get the summary for return type if (!String.Equals (functionEntity.ReturnType, "void", StringComparison.OrdinalIgnoreCase) && returnValueElement != null) { IEnumerable<XElement> returnTypeElements = returnValueElement.ElementsAfterSelf ().TakeWhile (el => el.Name == "p"); functionEntity.ReturnsDocumentation = String.Empty; foreach (XElement element in returnTypeElements) { String line = element.TrimAll (); if (!String.IsNullOrEmpty (line)) { functionEntity.ReturnsDocumentation += line; } } } // Get the availability if (availabilityElement != null) { functionEntity.MinAvailability = CommentHelper.ExtractAvailability (availabilityElement.TrimAll ()); } return functionEntity; }
/// <summary> /// Parses the specified method element. /// </summary> /// <param name = "functionElement">The function element.</param> /// <returns></returns> public FunctionEntity Parse(TypedEntity typedEntity, XElement functionElement) { FunctionEntity functionEntity = new FunctionEntity (); // Extract name String name = functionElement.TrimAll (); functionEntity.Name = name; this.Logger.WriteLine (" Function '" + name + "'"); // Extract abstract XElement abstractElement = (from el in functionElement.ElementsAfterSelf ("p") where (String)el.Attribute ("class") == "abstract" select el).FirstOrDefault (); functionEntity.Summary.Add (abstractElement.TrimAll ()); // Extract declaration XElement declarationElement = (from el in functionElement.ElementsAfterSelf ("pre") where (String)el.Attribute ("class") == "declaration" select el).FirstOrDefault (); String signature = declarationElement.TrimAll (); if (signature.StartsWith ("#define")) { this.Logger.WriteLine ("SKIPPING define statement: " + name); return null; } if (signature.StartsWith ("typedef")) { this.Logger.WriteLine ("SKIPPING define statement: " + name); return null; } if (!signature.Contains ("(")) { // e.g. NS_DURING this.Logger.WriteLine ("SKIPPING non-function statement: " + name); return null; } // Trim down signature while (signature.IndexOf(" ") != -1) { signature = signature.Replace (" ", " "); } while (signature.IndexOf(" (") != -1) { signature = signature.Replace (" (", "("); } functionEntity.Signature = signature; //Console.WriteLine("name='" + name + "' signature='" + signature + "'"); // Parse signature int pos = signature.IndexOf (name + "("); if (pos == -1) { this.Logger.WriteLine ("MISMATCH between name and declaration: " + name); return null; } String returnType = signature.Substring (0, pos).Trim (); int paramsIndex = pos + name.Length; int paramsLength = signature.IndexOf(')') + 1 - paramsIndex; // Stop before getting to function body String parameters = signature.Substring (paramsIndex, paramsLength).Trim (); parameters = parameters.Trim (';', '(', ')').Trim(); if (parameters != "void") { foreach (string parameter in parameters.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries)) { String parameterType = "NOTYPE"; String parameterName = "NONAME"; //Console.WriteLine("parameter='" + parameter + "'"); Match r = PARAMETER_REGEX.Match (parameter); if (r.Success) { parameterType = r.Groups [2].Value.Trim (); parameterName = r.Groups [3].Value.Trim (); } else if (parameter.Trim () == "...") { parameterType = "params Object[]"; parameterName = "values"; } else { this.Logger.WriteLine ("FAILED to parse parameter: " + parameter); return null; } parameterType = parameterType.Trim (); MethodParameterEntity parameterEntity = new MethodParameterEntity (); bool isOut, isByRef, isBlock; parameterEntity.Type = this.TypeManager.ConvertType (parameterType, out isOut, out isByRef, out isBlock, this.Logger); parameterEntity.IsOut = isOut; parameterEntity.IsByRef = isByRef; parameterEntity.IsBlock = isBlock; parameterEntity.Name = TypeManager.ConvertName(parameterName); functionEntity.Parameters.Add (parameterEntity); } } // Extract return type functionEntity.ReturnType = this.TypeManager.ConvertType (returnType, this.Logger); // Extract parameter documentation if (functionEntity.Parameters.Count > 0) { XElement termList = (from el in functionElement.Elements ("div").Elements ("dl") where (String)el.Parent.Attribute ("class") == "api parameters" && (String)el.Attribute ("class") == "termdef" select el).FirstOrDefault (); if (termList != null) { IEnumerable<XElement> dtList = from el in termList.Elements ("dt") select el; IEnumerable<XElement> ddList = from el in termList.Elements ("dd") select el; if (dtList.Count () == ddList.Count ()) { // Iterate over definitions for (int i = 0; i < dtList.Count(); i++) { String term = dtList.ElementAt (i).TrimAll (); IEnumerable<String> summaries = ddList.ElementAt (i).Elements ("p").Select (p => p.Value.TrimAll ()); // Find the parameter MethodParameterEntity parameterEntity = functionEntity.Parameters.Find (p => String.Equals (p.Name, term)); if (parameterEntity != null) { foreach (string sum in summaries) { parameterEntity.Summary.Add (sum); } } } } } } // Fix the name only after looking for the documentation for (int i = 0; i < functionEntity.Parameters.Count; i++) { functionEntity.Parameters [i].Name = this.TypeManager.ConvertName (functionEntity.Parameters [i].Name); } // Get the summary for return type if (!String.Equals (functionEntity.ReturnType, "void", StringComparison.OrdinalIgnoreCase)) { XElement returnValueElement = (from el in functionElement.ElementsAfterSelf ("div") where (String)el.Attribute ("class") == "return_value" select el).FirstOrDefault (); if (returnValueElement != null) { IEnumerable<String> documentations = returnValueElement.Elements ("p").Select (p => p.Value.TrimAll ()); functionEntity.ReturnsDocumentation = String.Join (String.Empty, documentations.ToArray ()); } } //// Extract discussion //XElement discussionElement = (from el in functionElement.ElementsAfterSelf("div") // where (String) el.Attribute("class") == "api discussion" // select el).FirstOrDefault(); //if (discussionElement != null) //{ // foreach (XElement paragraph in discussionElement.Elements("p")) // { // functionEntity.Summary.Add(paragraph.TrimAll()); // } //} // Get the availability XElement availabilityElement = (from el in functionElement.ElementsAfterSelf ("div") where (String)el.Attribute ("class") == "api availability" select el).FirstOrDefault (); XElement minAvailabilityElement = null; if (availabilityElement != null) { minAvailabilityElement = availabilityElement.Elements("ul").Elements("li").FirstOrDefault(); } String minAvailability = ""; if (minAvailabilityElement != null) { minAvailability = minAvailabilityElement.TrimAll(); } functionEntity.MinAvailability = CommentHelper.ExtractAvailability (minAvailability); return functionEntity; }
private void GenerateWrapperFunction(TypedEntity typedEntity, FunctionEntity functionEntity, FunctionEntity functionEntity32, FunctionEntity functionEntity64, bool needStorage) { bool useMixedInvocation = functionEntity32 != null && functionEntity64 != null; // Strip name if the prefix is the same String name = functionEntity.Name; if (name.StartsWith (typedEntity.Name)) { name = name.Substring (typedEntity.Name.Length); } StringBuilder signature = new StringBuilder (); signature.AppendFormat ("public static {0} {1}(", functionEntity.ReturnType, name); // Append parameters List<String> parameters = new List<String> (); foreach (MethodParameterEntity methodParameterEntity in functionEntity.Parameters.Where(p => p.Generate)) { parameters.Add (GetTypeSignature (methodParameterEntity)); } signature.Append (String.Join (", ", parameters.ToArray ())); signature.Append (")"); this.Writer.WriteLineFormat (2, signature.ToString ()); this.Writer.WriteLineFormat (2, "{{"); if (useMixedInvocation) { #if MIXED_MODE this.Writer.WriteLineFormat(3, "if (ObjectiveCRuntime.Is64Bits)"); this.Writer.WriteLineFormat(3, "{{"); this.GenerateFunctionBody(4, typedEntity, functionEntity, functionEntity64, needStorage, SUFFIX_64); this.Writer.WriteLineFormat(3, "}}"); this.Writer.WriteLineFormat(3, "else"); this.Writer.WriteLineFormat(3, "{{"); #endif this.GenerateFunctionBody (4, typedEntity, functionEntity, functionEntity32, needStorage, SUFFIX_32); #if MIXED_MODE this.Writer.WriteLineFormat(3, "}}"); #endif } else { this.GenerateFunctionBody (3, typedEntity, functionEntity, null, needStorage, SUFFIX_INNER); } this.Writer.WriteLineFormat (2, "}}"); this.Writer.WriteLine (); }
private void GenerateNativeFunction(TypedEntity typedEntity, FunctionEntity functionEntity, String suffix, bool isPublic) { // Strip name if the prefix is the same String name = functionEntity.Name; if (name.StartsWith (typedEntity.Name)) { name = name.Substring (typedEntity.Name.Length); } // TODO: Compute proper framework path... // TODO: Test with embedded frameworks... this.Writer.WriteLineFormat (2, "[DllImport(\"{0}\", EntryPoint=\"{1}\")]", GetFrameworkPath (typedEntity.Namespace), functionEntity.Name); // Add custom tag for return type if (TypeManager.HasClass (functionEntity.ReturnType)) { this.Writer.WriteLineFormat (2, "[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (IdMarshaler<{0}>))]", functionEntity.ReturnType); } StringBuilder signature = new StringBuilder (); signature.AppendFormat ("{0} static extern {1} {2}(", isPublic ? "public" : "private", functionEntity.ReturnType, name + suffix ?? String.Empty); // Append parameters List<String> parameters = new List<String> (); foreach (MethodParameterEntity methodParameterEntity in functionEntity.Parameters.Where(p => p.Generate)) { if (methodParameterEntity.IsOut || methodParameterEntity.IsByRef) { parameters.Add ("IntPtr " + methodParameterEntity.Name); } else if (methodParameterEntity.IsBlock) { parameters.Add (String.Format ("[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (BlockMarshaler))] Block {0}", methodParameterEntity.Name)); } else { String parameter = GetTypeSignature (methodParameterEntity); if (TypeManager.HasClass (methodParameterEntity.Type)) { parameter = String.Format ("[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (IdMarshaler<{0}>))] {1}", methodParameterEntity.Type, parameter); } parameters.Add (parameter); } } signature.Append (String.Join (", ", parameters.ToArray ())); signature.Append (");"); this.Writer.WriteLineFormat (2, signature.ToString ()); this.Writer.WriteLine (); }
private FunctionEntity DeriveFunctionEntity(FunctionEntity functionEntity, bool is64Bits) { FunctionEntity result = new FunctionEntity (functionEntity); result.ReturnType = this.GetRealType (result.ReturnType, is64Bits); foreach (MethodParameterEntity parameter in result.Parameters) { parameter.Type = GetRealType (parameter.Type, is64Bits); } return result; }
private static string GetFunctionInvocation(TypedEntity typedEntity, FunctionEntity functionEntity, FunctionEntity innerFunctionEntity, String suffix = null) { // Strip name if the prefix is the same String name = functionEntity.Name; if (name.StartsWith (typedEntity.Name)) { name = name.Substring (typedEntity.Name.Length); } StringBuilder builder = new StringBuilder (); builder.AppendFormat ("{0}{1}(", name, suffix ?? String.Empty); builder.Append (GetMessageParameterList (functionEntity, innerFunctionEntity, false)); builder.Append (");"); return builder.ToString (); }
protected void GenerateFunctionBody(int indent, TypedEntity typedEntity, FunctionEntity methodEntity, FunctionEntity innerMethodEntity, bool needStorage, String suffix = null) { bool hasReturn = !String.Equals (methodEntity.ReturnType, "void"); bool mixed = (innerMethodEntity != null); bool mixedReturnType = mixed && !String.Equals (methodEntity.ReturnType, innerMethodEntity.ReturnType); this.GenerateLocalsAllocation (indent, methodEntity, innerMethodEntity); this.GenerateLocalsMarshalling (indent, methodEntity, innerMethodEntity); String invocation = GetFunctionInvocation (typedEntity, methodEntity, innerMethodEntity, suffix); if (hasReturn) { if (needStorage) { String prefix = methodEntity.ReturnType + " __result = "; if (mixedReturnType) { prefix += "(" + methodEntity.ReturnType + ") "; } invocation = prefix + invocation; } else { String prefix = "return "; if (mixedReturnType) { prefix += "(" + methodEntity.ReturnType + ") "; } invocation = prefix + invocation; } } this.Writer.WriteLineFormat (indent, invocation); this.GenerateLocalsUnmarshalling (indent, methodEntity, innerMethodEntity); this.GenerateLocalsDeallocation (indent, methodEntity, innerMethodEntity); if (hasReturn && needStorage) { this.Writer.WriteLineFormat (indent, "return __result;"); } }
// /// <summary> // /// Generates the specified entity. // /// </summary> // /// <param name = "typedEntity">The type entity.</param> // /// <param name = "functionEntity">The function entity.</param> // public void GenerateOpaque (TypedEntity typedEntity, FunctionEntity functionEntity, String opaquePointer) // { // // Don't generate if required // if (!functionEntity.Generate) { // return; // } // // // Append static condition if needed // this.AppendStartCondition (functionEntity); // // // Append documentation // this.AppendDocumentation (functionEntity, false, true); // // // Append Obsolete attribute // this.AppendObsoleteAttribute (functionEntity); // // // Create function signature // StringBuilder signature = new StringBuilder (); // // // Append keywords // String keywords = GetKeywords (functionEntity, true, false, false); // signature.Append (keywords); // // String name = functionEntity.Name; // if (name.StartsWith (typedEntity.Name)) { // name = name.Substring (typedEntity.Name.Length); // } // // // Append return type and name // String returnType = functionEntity.ReturnOpaque ? typedEntity.Name : functionEntity.ReturnType; // signature.AppendFormat ("{0} {1}", returnType, name); // signature.Append ("("); // // // Append parameters // List<String> parameters = new List<String> (); // bool first = true; // foreach (MethodParameterEntity methodParameterEntity in functionEntity.Parameters.Where(p => p.Generate)) { // if (first) { // first = false; // if (methodParameterEntity.IsOpaque) { // continue; // } // } else { // if (methodParameterEntity.IsOpaque) { // methodParameterEntity.Type = typedEntity.Name; // } // } // parameters.Add (GetTypeSignature (methodParameterEntity)); // } // signature.Append (String.Join (", ", parameters.ToArray ())); // signature.Append (")"); // // this.Writer.WriteLineFormat (2, signature.ToString ()); // // // Output the body // this.Writer.WriteLineFormat (2, "{{"); // StringBuilder invocation = new StringBuilder(); // bool hasReturn = !String.Equals (functionEntity.ReturnType, "void"); // if (functionEntity.ReturnOpaque) { // invocation.AppendFormat("IntPtr value = "); // } else if (hasReturn) { // invocation.AppendFormat("return "); // } // invocation.AppendFormat("{0}(", name); // first = true; // foreach (MethodParameterEntity methodParameterEntity in functionEntity.Parameters.Where(p => p.Generate)) { // if (first) { // first = false; // if (methodParameterEntity.IsOpaque) { // invocation.AppendFormat("this.{0}", opaquePointer); // } else { // invocation.AppendFormat("{0}", methodParameterEntity.Name); // } // } else { // invocation.AppendFormat(", {0}", methodParameterEntity.Name); // } // } // invocation.Append(");"); // this.Writer.WriteLineFormat (3, invocation.ToString()); // // if (functionEntity.ReturnOpaque) { // this.Writer.WriteLineFormat (3, "return new {0}(value);", typedEntity.Name); // } // // this.Writer.WriteLineFormat (2, "}}"); // // // Append static condition if needed // this.AppendEndCondition (functionEntity); // } /// <summary> /// Generates the specified entity. /// </summary> /// <param name = "typedEntity">The type entity.</param> /// <param name = "functionEntity">The function entity.</param> public void Generate(TypedEntity typedEntity, FunctionEntity functionEntity) { // Don't generate if required if (!functionEntity.Generate) { return; } if (functionEntity.MinAvailabilityAsVersion.IsGreaterThan(typedEntity.MinAvailabilityAsVersion)) { // Append static condition if needed this.AppendStartCondition(functionEntity); } // Append documentation this.AppendDocumentation (functionEntity); // Collect information bool needStorage = false; bool varargs = false; CollectInformations (functionEntity, ref needStorage, ref varargs); // Collect information on 32/64 bits invocations to check if they differ FunctionEntity functionEntity32 = DeriveFunctionEntity (functionEntity, false); FunctionEntity functionEntity64 = DeriveFunctionEntity (functionEntity, true); bool useMixedInvocation = !AreMethodTypesEqual (functionEntity32, functionEntity64); if (needStorage || useMixedInvocation) { if (useMixedInvocation) { this.GenerateWrapperFunction (typedEntity, functionEntity, functionEntity32, functionEntity64, needStorage); #if MIXED_MODE this.GenerateNativeFunction(typedEntity, functionEntity64, SUFFIX_64, false); #endif this.GenerateNativeFunction (typedEntity, functionEntity32, SUFFIX_32, false); } else { this.GenerateWrapperFunction (typedEntity, functionEntity, null, null, needStorage); this.GenerateNativeFunction (typedEntity, functionEntity, SUFFIX_INNER, false); } } else { this.GenerateNativeFunction (typedEntity, functionEntity, null, true); } if (functionEntity.MinAvailabilityAsVersion.IsGreaterThan(typedEntity.MinAvailabilityAsVersion)) { // Append static condition if needed this.AppendEndCondition(functionEntity); } // Update statistics this.Statistics.Functions++; }