From 4857c8fee32498f88ed8fd75ba051dd2e70d827a Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 11 Feb 2014 21:31:54 +0200 Subject: [PATCH] Improved the pass for generating properties. Signed-off-by: Dimitar Dobrev Conflicts: src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs --- .../GetterSetterToPropertyAdvancedPass.cs | 352 +++++++++--------- 1 file changed, 167 insertions(+), 185 deletions(-) diff --git a/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs b/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs index d121c9cb..99910bc0 100644 --- a/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs +++ b/src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs @@ -13,89 +13,39 @@ namespace CppSharp.Passes { public class GetterSetterToPropertyAdvancedPass : TranslationUnitPass { - // collect all types of methods first to be able to match pairs and detect virtuals and overrides; - // (a property needs to) be virtual or an override if either of its constituent methods are such) - private readonly List setters = new List(); - private readonly List setMethods = new List(); - private readonly List nonSetters = new List(); - private readonly HashSet getters = new HashSet(); - private static readonly HashSet verbs = new HashSet(); - - static GetterSetterToPropertyAdvancedPass() + private class PropertyGenerator { - LoadVerbs(); - } - - static Stream GetResourceStream (Assembly assembly) - { - var stream = assembly.GetManifestResourceStream("CppSharp.Generator.Passes.verbs.txt"); - if (stream != null) - return stream; - - stream = assembly.GetManifestResourceStream("verbs.txt"); - return stream; - } + private readonly List getters = new List(); + private readonly List setters = new List(); + private readonly List setMethods = new List(); + private readonly List nonSetters = new List(); - private static void LoadVerbs() - { - var assembly = Assembly.GetExecutingAssembly(); - using (var resourceStream = GetResourceStream(assembly)) + public PropertyGenerator(Class @class) { - using (var streamReader = new StreamReader(resourceStream)) - while (!streamReader.EndOfStream) - verbs.Add(streamReader.ReadLine()); + foreach (var method in @class.Methods.Where( + m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && !m.Ignore)) + DistributeMethod(method); } - } - public GetterSetterToPropertyAdvancedPass() - { - Options.VisitClassFields = false; - Options.VisitClassProperties = false; - Options.VisitNamespaceEnums = false; - Options.VisitNamespaceTemplates = false; - Options.VisitNamespaceTypedefs = false; - Options.VisitNamespaceEvents = false; - Options.VisitNamespaceVariables = false; - Options.VisitFunctionParameters = false; - Options.VisitTemplateArguments = false; - } - - public override bool VisitTranslationUnit(TranslationUnit unit) - { - bool result = base.VisitTranslationUnit(unit); - GenerateProperties(); - return result; - } - - public override bool VisitMethodDecl(Method method) - { - if (!method.IsConstructor && !method.IsDestructor && !method.IsOperator && - method.IsGenerated && !method.IsSynthetized) - DistributeMethod(method); - return base.VisitMethodDecl(method); - } - - public void GenerateProperties() - { - GenerateProperties(setters, false); - GenerateProperties(setMethods, true); - - foreach (Method getter in - from getter in getters - where getter.IsGenerated && - ((Class) getter.Namespace).Methods.All(m => m == getter || m.Name != getter.Name) - select getter) + public void GenerateProperties() { - // Make it a read-only property - GenerateProperty(getter.Namespace, getter); + GenerateProperties(setters, false); + GenerateProperties(setMethods, true); + + foreach (Method getter in + from getter in getters + where getter.IsGenerated && + ((Class) getter.Namespace).Methods.All(m => m == getter || m.Name != getter.Name) + select getter) + { + // Make it a read-only property + GenerateProperty(getter.Namespace, getter); + } } - } - private void GenerateProperties(IEnumerable settersToUse, bool readOnly) - { - foreach (var group in settersToUse.GroupBy(m => m.Namespace)) + private void GenerateProperties(IEnumerable settersToUse, bool readOnly) { - foreach (var setter in group) + foreach (var setter in settersToUse) { Class type = (Class) setter.Namespace; StringBuilder nameBuilder = new StringBuilder(setter.Name.Substring(3)); @@ -122,155 +72,187 @@ namespace CppSharp.Passes GenerateProperty(setter.Namespace, baseVirtualProperty.GetMethod, readOnly || isReadOnly ? null : setter); } - next: + next: ; } - } - foreach (Method nonSetter in nonSetters) - { - Class type = (Class) nonSetter.Namespace; - string name = GetPropertyName(nonSetter.Name); - Property baseVirtualProperty = type.GetRootBaseProperty(new Property { Name = name }); - if (!type.IsInterface && baseVirtualProperty != null) + foreach (Method nonSetter in nonSetters) { - bool isReadOnly = baseVirtualProperty.SetMethod == null; - if (readOnly == isReadOnly) + Class type = (Class) nonSetter.Namespace; + string name = GetPropertyName(nonSetter.Name); + Property baseVirtualProperty = type.GetRootBaseProperty(new Property { Name = name }); + if (!type.IsInterface && baseVirtualProperty != null) { - GenerateProperty(nonSetter.Namespace, nonSetter, - readOnly ? null : baseVirtualProperty.SetMethod); + bool isReadOnly = baseVirtualProperty.SetMethod == null; + if (readOnly == isReadOnly) + { + GenerateProperty(nonSetter.Namespace, nonSetter, + readOnly ? null : baseVirtualProperty.SetMethod); + } } } } - } - private static string GetReadWritePropertyName(INamedDecl getter, string afterSet) - { - string name = GetPropertyName(getter.Name); - if (name != afterSet && name.StartsWith("is")) + private static string GetReadWritePropertyName(INamedDecl getter, string afterSet) { - name = char.ToLowerInvariant(name[2]) + name.Substring(3); + string name = GetPropertyName(getter.Name); + if (name != afterSet && name.StartsWith("is")) + { + name = char.ToLowerInvariant(name[2]) + name.Substring(3); + } + return name; } - return name; - } - private static Type GetUnderlyingType(QualifiedType type) - { - TagType tagType = type.Type as TagType; - if (tagType != null) - return type.Type; - // TODO: we should normally check pointer types for const; - // however, there's some bug, probably in the parser, that returns IsConst = false for "const Type& arg" - // so skip the check for the time being - PointerType pointerType = type.Type as PointerType; - return pointerType != null ? pointerType.Pointee : type.Type; - } + private static Type GetUnderlyingType(QualifiedType type) + { + TagType tagType = type.Type as TagType; + if (tagType != null) + return type.Type; + // TODO: we should normally check pointer types for const; + // however, there's some bug, probably in the parser, that returns IsConst = false for "const Type& arg" + // so skip the check for the time being + PointerType pointerType = type.Type as PointerType; + return pointerType != null ? pointerType.Pointee : type.Type; + } - private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null) - { - Class type = (Class) context; - if (type.Properties.All(p => getter.Name != p.Name || - p.ExplicitInterfaceImpl != getter.ExplicitInterfaceImpl)) + private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null) { - Property property = new Property(); - property.Name = GetPropertyName(getter.Name); - property.Namespace = type; - property.QualifiedType = getter.OriginalReturnType; - if (getter.IsOverride || (setter != null && setter.IsOverride)) - { - Property baseVirtualProperty = type.GetRootBaseProperty(property); - if (baseVirtualProperty.SetMethod == null) - setter = null; - } - property.GetMethod = getter; - property.SetMethod = setter; - property.ExplicitInterfaceImpl = getter.ExplicitInterfaceImpl; - if (property.ExplicitInterfaceImpl == null && setter != null) + Class type = (Class) context; + if (type.Properties.All(p => getter.Name != p.Name || + p.ExplicitInterfaceImpl != getter.ExplicitInterfaceImpl)) { - property.ExplicitInterfaceImpl = setter.ExplicitInterfaceImpl; - } - if (getter.Comment != null) - { - var comment = new RawComment(); - comment.Kind = getter.Comment.Kind; - comment.BriefText = getter.Comment.BriefText; - comment.Text = getter.Comment.Text; - comment.FullComment = new FullComment(); - comment.FullComment.Blocks.AddRange(getter.Comment.FullComment.Blocks); - if (setter != null && setter.Comment != null) + Property property = new Property(); + property.Name = GetPropertyName(getter.Name); + property.Namespace = type; + property.QualifiedType = getter.OriginalReturnType; + if (getter.IsOverride || (setter != null && setter.IsOverride)) + { + Property baseVirtualProperty = type.GetRootBaseProperty(property); + if (baseVirtualProperty.SetMethod == null) + setter = null; + } + property.GetMethod = getter; + property.SetMethod = setter; + property.ExplicitInterfaceImpl = getter.ExplicitInterfaceImpl; + if (property.ExplicitInterfaceImpl == null && setter != null) + { + property.ExplicitInterfaceImpl = setter.ExplicitInterfaceImpl; + } + if (getter.Comment != null) { - comment.BriefText += Environment.NewLine + setter.Comment.BriefText; - comment.Text += Environment.NewLine + setter.Comment.Text; - comment.FullComment.Blocks.AddRange(setter.Comment.FullComment.Blocks); + var comment = new RawComment(); + comment.Kind = getter.Comment.Kind; + comment.BriefText = getter.Comment.BriefText; + comment.Text = getter.Comment.Text; + comment.FullComment = new FullComment(); + comment.FullComment.Blocks.AddRange(getter.Comment.FullComment.Blocks); + if (setter != null && setter.Comment != null) + { + comment.BriefText += Environment.NewLine + setter.Comment.BriefText; + comment.Text += Environment.NewLine + setter.Comment.Text; + comment.FullComment.Blocks.AddRange(setter.Comment.FullComment.Blocks); + } + property.Comment = comment; } - property.Comment = comment; + type.Properties.Add(property); + getter.GenerationKind = GenerationKind.None; + if (setter != null) + setter.GenerationKind = GenerationKind.None; } - type.Properties.Add(property); - getter.GenerationKind = GenerationKind.Internal; - if (setter != null) - setter.GenerationKind = GenerationKind.Internal; } - } - private static string GetPropertyName(string name) - { - if (GetFirstWord(name) == "get" && name != "get") + private static string GetPropertyName(string name) { - if (char.IsLower(name[0])) + if (GetFirstWord(name) == "get" && name != "get") { - if (name.Length == 4) + if (char.IsLower(name[0])) { + if (name.Length == 4) + { + return char.ToLowerInvariant( + name[3]).ToString(CultureInfo.InvariantCulture); + } return char.ToLowerInvariant( - name[3]).ToString(CultureInfo.InvariantCulture); + name[3]).ToString(CultureInfo.InvariantCulture) + + name.Substring(4); } - return char.ToLowerInvariant( - name[3]).ToString(CultureInfo.InvariantCulture) + - name.Substring(4); + return name.Substring(3); } - return name.Substring(3); + return name; } - return name; - } - private void DistributeMethod(Method method) - { - if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 && - method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) + private void DistributeMethod(Method method) { - if (method.Parameters.Count == 1) - setters.Add(method); + if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 && + method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) + { + if (method.Parameters.Count == 1) + setters.Add(method); + else + setMethods.Add(method); + } else - setMethods.Add(method); + { + if (IsGetter(method)) + getters.Add(method); + if (method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType)) + nonSetters.Add(method); + } + } + + private static bool IsGetter(Method method) + { + if (method.IsDestructor || + (method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) || + method.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType)) + return false; + var result = GetFirstWord(method.Name); + return (result.Length < method.Name.Length && + (result == "get" || result == "is" || result == "has")) || + (result != "to" && result != "new" && !verbs.Contains(result)); + } + + private static string GetFirstWord(string name) + { + List firstVerb = new List + { + char.ToLowerInvariant(name[0]) + }; + firstVerb.AddRange(name.Skip(1).TakeWhile( + c => char.IsLower(c) || !char.IsLetterOrDigit(c))); + return new string(firstVerb.ToArray()); } - else + } + + private static readonly HashSet verbs = new HashSet(); + + static GetterSetterToPropertyAdvancedPass() + { + LoadVerbs(); + } + + private static void LoadVerbs() + { + using (var resourceStream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream("CppSharp.Generator.Passes.verbs.txt")) { - if (IsGetter(method)) - getters.Add(method); - if (method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType)) - nonSetters.Add(method); + using (StreamReader streamReader = new StreamReader(resourceStream)) + while (!streamReader.EndOfStream) + verbs.Add(streamReader.ReadLine()); } } - private bool IsGetter(Method method) + public GetterSetterToPropertyAdvancedPass() { - if (method.IsDestructor || - (method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) || - method.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType)) - return false; - var result = GetFirstWord(method.Name); - return (result.Length < method.Name.Length && - (result == "get" || result == "is" || result == "has")) || - (result != "to" && result != "new" && !verbs.Contains(result)); + Options.VisitClassProperties = false; } - private static string GetFirstWord(string name) + public override bool VisitClassDecl(Class @class) { - List firstVerb = new List - { - char.ToLowerInvariant(name[0]) - }; - firstVerb.AddRange(name.Skip(1).TakeWhile( - c => char.IsLower(c) || !char.IsLetterOrDigit(c))); - return new string(firstVerb.ToArray()); + bool result = base.VisitClassDecl(@class); + + new PropertyGenerator(@class).GenerateProperties(); + + return result; } } }