Browse Source

Improved the pass for generating properties.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>

Conflicts:
	src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs
pull/275/head
Dimitar Dobrev 12 years ago
parent
commit
4857c8fee3
  1. 352
      src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs

352
src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs

@ -13,89 +13,39 @@ namespace CppSharp.Passes
{ {
public class GetterSetterToPropertyAdvancedPass : TranslationUnitPass public class GetterSetterToPropertyAdvancedPass : TranslationUnitPass
{ {
// collect all types of methods first to be able to match pairs and detect virtuals and overrides; private class PropertyGenerator
// (a property needs to) be virtual or an override if either of its constituent methods are such)
private readonly List<Method> setters = new List<Method>();
private readonly List<Method> setMethods = new List<Method>();
private readonly List<Method> nonSetters = new List<Method>();
private readonly HashSet<Method> getters = new HashSet<Method>();
private static readonly HashSet<string> verbs = new HashSet<string>();
static GetterSetterToPropertyAdvancedPass()
{ {
LoadVerbs(); private readonly List<Method> getters = new List<Method>();
} private readonly List<Method> setters = new List<Method>();
private readonly List<Method> setMethods = new List<Method>();
static Stream GetResourceStream (Assembly assembly) private readonly List<Method> nonSetters = new List<Method>();
{
var stream = assembly.GetManifestResourceStream("CppSharp.Generator.Passes.verbs.txt");
if (stream != null)
return stream;
stream = assembly.GetManifestResourceStream("verbs.txt");
return stream;
}
private static void LoadVerbs() public PropertyGenerator(Class @class)
{
var assembly = Assembly.GetExecutingAssembly();
using (var resourceStream = GetResourceStream(assembly))
{ {
using (var streamReader = new StreamReader(resourceStream)) foreach (var method in @class.Methods.Where(
while (!streamReader.EndOfStream) m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && !m.Ignore))
verbs.Add(streamReader.ReadLine()); DistributeMethod(method);
} }
}
public GetterSetterToPropertyAdvancedPass() public void GenerateProperties()
{
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)
{ {
// Make it a read-only property GenerateProperties(setters, false);
GenerateProperty(getter.Namespace, getter); 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<Method> settersToUse, bool readOnly) private void GenerateProperties(IEnumerable<Method> settersToUse, bool readOnly)
{
foreach (var group in settersToUse.GroupBy(m => m.Namespace))
{ {
foreach (var setter in group) foreach (var setter in settersToUse)
{ {
Class type = (Class) setter.Namespace; Class type = (Class) setter.Namespace;
StringBuilder nameBuilder = new StringBuilder(setter.Name.Substring(3)); StringBuilder nameBuilder = new StringBuilder(setter.Name.Substring(3));
@ -122,155 +72,187 @@ namespace CppSharp.Passes
GenerateProperty(setter.Namespace, baseVirtualProperty.GetMethod, GenerateProperty(setter.Namespace, baseVirtualProperty.GetMethod,
readOnly || isReadOnly ? null : setter); readOnly || isReadOnly ? null : setter);
} }
next: next:
; ;
} }
} foreach (Method nonSetter in nonSetters)
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)
{ {
bool isReadOnly = baseVirtualProperty.SetMethod == null; Class type = (Class) nonSetter.Namespace;
if (readOnly == isReadOnly) string name = GetPropertyName(nonSetter.Name);
Property baseVirtualProperty = type.GetRootBaseProperty(new Property { Name = name });
if (!type.IsInterface && baseVirtualProperty != null)
{ {
GenerateProperty(nonSetter.Namespace, nonSetter, bool isReadOnly = baseVirtualProperty.SetMethod == null;
readOnly ? null : baseVirtualProperty.SetMethod); if (readOnly == isReadOnly)
{
GenerateProperty(nonSetter.Namespace, nonSetter,
readOnly ? null : baseVirtualProperty.SetMethod);
}
} }
} }
} }
}
private static string GetReadWritePropertyName(INamedDecl getter, string afterSet) private static string GetReadWritePropertyName(INamedDecl getter, string afterSet)
{
string name = GetPropertyName(getter.Name);
if (name != afterSet && name.StartsWith("is"))
{ {
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) private static Type GetUnderlyingType(QualifiedType type)
{ {
TagType tagType = type.Type as TagType; TagType tagType = type.Type as TagType;
if (tagType != null) if (tagType != null)
return type.Type; return type.Type;
// TODO: we should normally check pointer types for const; // 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" // 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 // so skip the check for the time being
PointerType pointerType = type.Type as PointerType; PointerType pointerType = type.Type as PointerType;
return pointerType != null ? pointerType.Pointee : type.Type; return pointerType != null ? pointerType.Pointee : type.Type;
} }
private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null) 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))
{ {
Property property = new Property(); Class type = (Class) context;
property.Name = GetPropertyName(getter.Name); if (type.Properties.All(p => getter.Name != p.Name ||
property.Namespace = type; p.ExplicitInterfaceImpl != getter.ExplicitInterfaceImpl))
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; Property property = new Property();
} property.Name = GetPropertyName(getter.Name);
if (getter.Comment != null) property.Namespace = type;
{ property.QualifiedType = getter.OriginalReturnType;
var comment = new RawComment(); if (getter.IsOverride || (setter != null && setter.IsOverride))
comment.Kind = getter.Comment.Kind; {
comment.BriefText = getter.Comment.BriefText; Property baseVirtualProperty = type.GetRootBaseProperty(property);
comment.Text = getter.Comment.Text; if (baseVirtualProperty.SetMethod == null)
comment.FullComment = new FullComment(); setter = null;
comment.FullComment.Blocks.AddRange(getter.Comment.FullComment.Blocks); }
if (setter != null && setter.Comment != 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; var comment = new RawComment();
comment.Text += Environment.NewLine + setter.Comment.Text; comment.Kind = getter.Comment.Kind;
comment.FullComment.Blocks.AddRange(setter.Comment.FullComment.Blocks); 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) private static string GetPropertyName(string name)
{
if (GetFirstWord(name) == "get" && name != "get")
{ {
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( return char.ToLowerInvariant(
name[3]).ToString(CultureInfo.InvariantCulture); name[3]).ToString(CultureInfo.InvariantCulture) +
name.Substring(4);
} }
return char.ToLowerInvariant( return name.Substring(3);
name[3]).ToString(CultureInfo.InvariantCulture) +
name.Substring(4);
} }
return name.Substring(3); return name;
} }
return name;
}
private void DistributeMethod(Method method) private void DistributeMethod(Method method)
{
if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 &&
method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void))
{ {
if (method.Parameters.Count == 1) if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 &&
setters.Add(method); method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void))
{
if (method.Parameters.Count == 1)
setters.Add(method);
else
setMethods.Add(method);
}
else 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<char> firstVerb = new List<char>
{
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<string> verbs = new HashSet<string>();
static GetterSetterToPropertyAdvancedPass()
{
LoadVerbs();
}
private static void LoadVerbs()
{
using (var resourceStream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("CppSharp.Generator.Passes.verbs.txt"))
{ {
if (IsGetter(method)) using (StreamReader streamReader = new StreamReader(resourceStream))
getters.Add(method); while (!streamReader.EndOfStream)
if (method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType)) verbs.Add(streamReader.ReadLine());
nonSetters.Add(method);
} }
} }
private bool IsGetter(Method method) public GetterSetterToPropertyAdvancedPass()
{ {
if (method.IsDestructor || Options.VisitClassProperties = false;
(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) public override bool VisitClassDecl(Class @class)
{ {
List<char> firstVerb = new List<char> bool result = base.VisitClassDecl(@class);
{
char.ToLowerInvariant(name[0]) new PropertyGenerator(@class).GenerateProperties();
};
firstVerb.AddRange(name.Skip(1).TakeWhile( return result;
c => char.IsLower(c) || !char.IsLetterOrDigit(c)));
return new string(firstVerb.ToArray());
} }
} }
} }

Loading…
Cancel
Save