mirror of https://github.com/mono/CppSharp.git
c-sharpdotnetmonobindingsbridgecclangcpluspluscppsharpglueinteropparserparsingpinvokeswigsyntax-treevisitorsxamarinxamarin-bindings
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
6.1 KiB
185 lines
6.1 KiB
using System; |
|
using System.Linq; |
|
using CppSharp.AST; |
|
using CppSharp.Generators.CLI; |
|
using CppSharp.Generators.CSharp; |
|
using System.Text; |
|
|
|
namespace CppSharp.Passes |
|
{ |
|
public class CleanInvalidDeclNamesPass : TranslationUnitPass |
|
{ |
|
private int uniqueName; |
|
|
|
string CheckName(string name) |
|
{ |
|
// Generate a new name if the decl still does not have a name |
|
if (string.IsNullOrWhiteSpace(name)) |
|
return string.Format("_{0}", uniqueName++); |
|
|
|
// Clean up the item name if the first digit is not a valid name. |
|
if (char.IsNumber(name[0])) |
|
return '_' + name; |
|
|
|
if (Driver.Options.IsCLIGenerator) |
|
return CLITextTemplate.SafeIdentifier(name); |
|
return Helpers.SafeIdentifier(name); |
|
} |
|
|
|
public override bool VisitDeclaration(Declaration decl) |
|
{ |
|
// Do not clean up namespace names since it can mess up with the |
|
// names of anonymous or the global namespace. |
|
if (decl is Namespace) |
|
return true; |
|
|
|
// types with empty names are assumed to be private |
|
if (decl is Class && string.IsNullOrWhiteSpace(decl.Name)) |
|
{ |
|
decl.Name = decl.Namespace.Name == "_" ? "__" : "_"; |
|
decl.ExplicitlyIgnore(); |
|
return false; |
|
} |
|
|
|
Function function = decl as Function; |
|
if (function == null || !function.IsOperator) |
|
decl.Name = CheckName(decl.Name); |
|
|
|
StringHelpers.CleanupText(ref decl.DebugText); |
|
return base.VisitDeclaration(decl); |
|
} |
|
|
|
public override bool VisitParameterDecl(Parameter parameter) |
|
{ |
|
return VisitDeclaration(parameter); |
|
} |
|
|
|
public override bool VisitClassDecl(Class @class) |
|
{ |
|
if (@class.IsDynamic) |
|
{ |
|
// HACK: entries in v-tables are not shared (as objects) with the virtual methods they represent; |
|
// this is why this pass fixes only the arg names used with real methods, |
|
// while the v-table entries could remain with empty names; |
|
// this should be fixed in the parser: it should reuse method objects |
|
foreach (var parameter in VTables.GatherVTableMethodEntries(@class).Where( |
|
entry => entry.Method != null).SelectMany(entry => entry.Method.Parameters)) |
|
{ |
|
parameter.Name = CheckName(parameter.Name); |
|
} |
|
} |
|
|
|
var currentUniqueName = this.uniqueName; |
|
this.uniqueName = 0; |
|
var ret = base.VisitClassDecl(@class); |
|
this.uniqueName = currentUniqueName; |
|
|
|
if (@class.Namespace.Classes.Any(d => d != @class && d.Name == @class.Name)) |
|
{ |
|
StringBuilder str = new StringBuilder(); |
|
str.Append(@class.Name); |
|
do |
|
{ |
|
str.Append('_'); |
|
} while (@class.Classes.Any(d => d != @class && d.Name == str.ToString())); |
|
@class.Name = str.ToString(); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
public override bool VisitFunctionDecl(Function function) |
|
{ |
|
var currentUniqueName = this.uniqueName; |
|
this.uniqueName = 0; |
|
var ret = base.VisitFunctionDecl(function); |
|
this.uniqueName = currentUniqueName; |
|
|
|
return ret; |
|
} |
|
|
|
public override bool VisitEvent(Event @event) |
|
{ |
|
var currentUniqueName = this.uniqueName; |
|
this.uniqueName = 0; |
|
var ret = base.VisitEvent(@event); |
|
this.uniqueName = currentUniqueName; |
|
|
|
return ret; |
|
} |
|
|
|
public override bool VisitFunctionType(FunctionType type, |
|
TypeQualifiers quals) |
|
{ |
|
var currentUniqueName = this.uniqueName; |
|
this.uniqueName = 0; |
|
var ret = base.VisitFunctionType(type, quals); |
|
this.uniqueName = currentUniqueName; |
|
|
|
return ret; |
|
} |
|
|
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
|
{ |
|
var @class = typedef.Namespace.FindClass(typedef.Name); |
|
|
|
// Clang will walk the typedef'd tag decl and the typedef decl, |
|
// so we ignore the class and process just the typedef. |
|
|
|
if (@class != null) |
|
typedef.ExplicitlyIgnore(); |
|
|
|
if (typedef.Type == null) |
|
typedef.ExplicitlyIgnore(); |
|
|
|
return base.VisitTypedefDecl(typedef); |
|
} |
|
|
|
private static void CheckEnumName(Enumeration @enum) |
|
{ |
|
// If we still do not have a valid name, then try to guess one |
|
// based on the enum value names. |
|
|
|
if (!String.IsNullOrWhiteSpace(@enum.Name)) |
|
return; |
|
|
|
var prefix = @enum.Items.Select(item => item.Name) |
|
.ToArray().CommonPrefix(); |
|
|
|
// Try a simple heuristic to make sure we end up with a valid name. |
|
if (prefix.Length < 3) |
|
return; |
|
|
|
prefix = prefix.Trim().Trim(new char[] { '_' }); |
|
@enum.Name = prefix; |
|
} |
|
|
|
public override bool VisitEnumDecl(Enumeration @enum) |
|
{ |
|
CheckEnumName(@enum); |
|
return base.VisitEnumDecl(@enum); |
|
} |
|
|
|
public override bool VisitEnumItem(Enumeration.Item item) |
|
{ |
|
item.Name = CheckName(item.Name); |
|
return base.VisitEnumItem(item); |
|
} |
|
|
|
public override bool VisitFieldDecl(Field field) |
|
{ |
|
if (field.Class.Fields.Count(c => c.Name.Equals(field.Name)) > 1) |
|
{ |
|
StringBuilder str = new StringBuilder(); |
|
str.Append(field.Name); |
|
do |
|
{ |
|
str.Append('_'); |
|
} while (field.Class.Fields.Any(c => c.Name.Equals(str.ToString()))); |
|
field.Name = str.ToString(); |
|
} |
|
return base.VisitFieldDecl(field); |
|
} |
|
} |
|
} |
|
|
|
|