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.
327 lines
11 KiB
327 lines
11 KiB
using System.Collections.Generic; |
|
using System.Globalization; |
|
using System.Linq; |
|
using CppSharp.AST; |
|
using CppSharp.AST.Extensions; |
|
using CppSharp.Generators; |
|
using CppSharp.Generators.C; |
|
using CppSharp.Generators.CLI; |
|
using CppSharp.Generators.CSharp; |
|
using CppSharp.Types; |
|
|
|
namespace CppSharp.Passes |
|
{ |
|
class DeclarationName |
|
{ |
|
private readonly Dictionary<Function, int> functions; |
|
private int Count; |
|
|
|
public DeclarationName() |
|
{ |
|
functions = new Dictionary<Function, int>(); |
|
} |
|
|
|
public bool UpdateName(Declaration decl) |
|
{ |
|
var function = decl as Function; |
|
if (function != null) |
|
{ |
|
return UpdateName(function); |
|
} |
|
|
|
var property = decl as Property; |
|
var isIndexer = property != null && property.Parameters.Count > 0; |
|
if (isIndexer) |
|
{ |
|
return false; |
|
} |
|
|
|
var count = Count++; |
|
if (count == 0) |
|
return false; |
|
|
|
decl.Name += count.ToString(CultureInfo.InvariantCulture); |
|
return true; |
|
} |
|
|
|
private bool UpdateName(Function function) |
|
{ |
|
if (Count == 0) |
|
Count++; |
|
|
|
var duplicate = functions.Keys.FirstOrDefault(f => |
|
function.SynthKind != FunctionSynthKind.DefaultValueOverload && |
|
f.Parameters.Where(p => p.Kind == ParameterKind.Regular || |
|
p.Kind == ParameterKind.Extension).SequenceEqual( |
|
function.Parameters.Where(p => p.Kind == ParameterKind.Regular || |
|
p.Kind == ParameterKind.Extension), |
|
ParameterTypeComparer.Instance)); |
|
|
|
if (duplicate == null) |
|
{ |
|
functions.Add(function, 0); |
|
return false; |
|
} |
|
|
|
var methodCount = ++functions[duplicate]; |
|
|
|
if (Count < methodCount + 1) |
|
Count = methodCount + 1; |
|
|
|
var method = function as Method; |
|
if (function.IsOperator) |
|
{ |
|
// TODO: turn into a method; append the original type (say, "signed long") |
|
// of the last parameter to the type so that the user knows which overload is called |
|
function.ExplicitlyIgnore(); |
|
} |
|
else if (method != null && method.IsConstructor) |
|
{ |
|
function.ExplicitlyIgnore(); |
|
} |
|
else |
|
function.Name += methodCount.ToString(CultureInfo.InvariantCulture); |
|
return true; |
|
} |
|
|
|
public static string FixSignatureForConversions(Function function, string signature) |
|
{ |
|
switch (function.OperatorKind) |
|
{ |
|
// C# does not allow an explicit and an implicit operator from the same type |
|
case CXXOperatorKind.Conversion: |
|
signature = signature.Replace("implicit ", "conversion "); |
|
break; |
|
case CXXOperatorKind.ExplicitConversion: |
|
signature = signature.Replace("explicit ", "conversion "); |
|
break; |
|
} |
|
return signature; |
|
} |
|
|
|
public class ParameterTypeComparer : IEqualityComparer<Parameter> |
|
{ |
|
public static readonly ParameterTypeComparer Instance = |
|
new ParameterTypeComparer(); |
|
|
|
public static TypeMapDatabase TypeMaps { get; set; } |
|
public static GeneratorKind GeneratorKind { get; set; } |
|
|
|
public bool Equals(Parameter x, Parameter y) |
|
{ |
|
Type left = x.Type.Desugar(resolveTemplateSubstitution: false); |
|
Type right = y.Type.Desugar(resolveTemplateSubstitution: false); |
|
if (left.Equals(right)) |
|
return true; |
|
|
|
if (CheckForSpecializations(left, right)) |
|
return true; |
|
|
|
// TODO: some target languages might make a difference between values and pointers |
|
Type leftPointee = left.GetPointee(); |
|
Type rightPointee = right.GetPointee(); |
|
|
|
if (CheckForSpecializations(leftPointee, rightPointee)) |
|
return true; |
|
|
|
return leftPointee != null && rightPointee != null && |
|
leftPointee.GetMappedType(TypeMaps, GeneratorKind).Equals( |
|
rightPointee.GetMappedType(TypeMaps, GeneratorKind)); |
|
} |
|
|
|
private static bool CheckForSpecializations(Type leftPointee, Type rightPointee) |
|
{ |
|
Class leftClass; |
|
Class rightClass; |
|
if (!leftPointee.TryGetDeclaration(out leftClass) || |
|
!rightPointee.TryGetDeclaration(out rightClass)) |
|
return false; |
|
|
|
var leftSpecialization = leftClass as ClassTemplateSpecialization ?? |
|
leftClass.Namespace as ClassTemplateSpecialization; |
|
var rightSpecialization = rightClass as ClassTemplateSpecialization ?? |
|
rightClass.Namespace as ClassTemplateSpecialization; |
|
|
|
return leftSpecialization != null && rightSpecialization != null && |
|
leftSpecialization.TemplatedDecl.TemplatedDecl.Equals( |
|
rightSpecialization.TemplatedDecl.TemplatedDecl) && |
|
leftSpecialization.Arguments.SequenceEqual( |
|
rightSpecialization.Arguments, TemplateArgumentComparer.Instance) && |
|
leftClass.OriginalName == rightClass.OriginalName; |
|
} |
|
|
|
public int GetHashCode(Parameter obj) |
|
{ |
|
return obj.Type.GetHashCode(); |
|
} |
|
|
|
public static TypePrinter TypePrinter { get; set; } |
|
} |
|
|
|
public class TemplateArgumentComparer : IEqualityComparer<TemplateArgument> |
|
{ |
|
public static readonly TemplateArgumentComparer Instance = |
|
new TemplateArgumentComparer(); |
|
|
|
public bool Equals(TemplateArgument x, TemplateArgument y) |
|
{ |
|
if (x.Kind != TemplateArgument.ArgumentKind.Type || |
|
y.Kind != TemplateArgument.ArgumentKind.Type) |
|
return x.Equals(y); |
|
Type left = x.Type.Type.GetMappedType(ParameterTypeComparer.TypeMaps, |
|
ParameterTypeComparer.GeneratorKind); |
|
Type right = y.Type.Type.GetMappedType(ParameterTypeComparer.TypeMaps, |
|
ParameterTypeComparer.GeneratorKind); |
|
// consider Type and const Type the same |
|
if (left.IsReference() && !left.IsPointerToPrimitiveType()) |
|
left = left.GetPointee(); |
|
if (right.IsReference() && !right.IsPointerToPrimitiveType()) |
|
right = right.GetPointee(); |
|
return left.Equals(right); |
|
} |
|
|
|
public int GetHashCode(TemplateArgument obj) |
|
{ |
|
return obj.GetHashCode(); |
|
} |
|
} |
|
} |
|
|
|
public class CheckDuplicatedNamesPass : TranslationUnitPass |
|
{ |
|
private readonly IDictionary<string, DeclarationName> names; |
|
|
|
public CheckDuplicatedNamesPass() |
|
{ |
|
ClearVisitedDeclarations = false; |
|
names = new Dictionary<string, DeclarationName>(); |
|
} |
|
|
|
public override bool VisitASTContext(ASTContext context) |
|
{ |
|
TypePrinter typePrinter = null; |
|
switch (Options.GeneratorKind) |
|
{ |
|
case GeneratorKind.C: |
|
typePrinter = new CppTypePrinter(Context) |
|
{ |
|
PrintFlavorKind = CppTypePrintFlavorKind.C |
|
}; |
|
break; |
|
case GeneratorKind.CPlusPlus: |
|
case GeneratorKind.NAPI: |
|
case GeneratorKind.QuickJS: |
|
typePrinter = new CppTypePrinter(Context); |
|
break; |
|
case GeneratorKind.CLI: |
|
typePrinter = new CLITypePrinter(Context); |
|
break; |
|
case GeneratorKind.CSharp: |
|
typePrinter = new CSharpTypePrinter(Context); |
|
break; |
|
default: |
|
throw new System.NotImplementedException(); |
|
} |
|
DeclarationName.ParameterTypeComparer.TypePrinter = typePrinter; |
|
DeclarationName.ParameterTypeComparer.TypeMaps = Context.TypeMaps; |
|
DeclarationName.ParameterTypeComparer.GeneratorKind = Options.GeneratorKind; |
|
return base.VisitASTContext(context); |
|
} |
|
|
|
public override bool VisitProperty(Property decl) |
|
{ |
|
if (!VisitDeclaration(decl)) |
|
return false; |
|
|
|
if (decl.ExplicitInterfaceImpl == null) |
|
CheckDuplicate(decl); |
|
|
|
return false; |
|
} |
|
|
|
public override bool VisitFunctionDecl(Function decl) |
|
{ |
|
if (!VisitDeclaration(decl)) |
|
return false; |
|
|
|
if (ASTUtils.CheckIgnoreFunction(decl)) |
|
return false; |
|
|
|
CheckDuplicate(decl); |
|
return false; |
|
} |
|
|
|
public override bool VisitMethodDecl(Method decl) |
|
{ |
|
if (!VisitDeclaration(decl)) |
|
return false; |
|
|
|
if (ASTUtils.CheckIgnoreMethod(decl)) |
|
return false; |
|
|
|
if (decl.ExplicitInterfaceImpl == null) |
|
CheckDuplicate(decl); |
|
|
|
return false; |
|
} |
|
|
|
public override bool VisitClassDecl(Class @class) |
|
{ |
|
if (!base.VisitClassDecl(@class)) |
|
return false; |
|
|
|
if (@class.IsIncomplete) |
|
return false; |
|
|
|
// DeclarationName should always process methods first, |
|
// so we visit methods first. |
|
foreach (var method in @class.Methods) |
|
VisitMethodDecl(method); |
|
|
|
foreach (var function in @class.Functions) |
|
VisitFunctionDecl(function); |
|
|
|
if (!@class.IsDependent) |
|
{ |
|
foreach (var fields in @class.Layout.Fields.GroupBy( |
|
f => f.Name).Select(g => g.ToList())) |
|
{ |
|
for (var i = 1; i < fields.Count; i++) |
|
{ |
|
var name = fields[i].Name; |
|
fields[i].Name = (string.IsNullOrEmpty(name) ? "__" : name) + i; |
|
} |
|
} |
|
} |
|
|
|
foreach (var property in @class.Properties) |
|
VisitProperty(property); |
|
|
|
return false; |
|
} |
|
|
|
private void CheckDuplicate(Declaration decl) |
|
{ |
|
if (decl.IsDependent || !decl.IsGenerated) |
|
return; |
|
|
|
if (string.IsNullOrWhiteSpace(decl.Name)) |
|
return; |
|
|
|
var fullName = decl.QualifiedName; |
|
var function = decl as Function; |
|
if (function != null) |
|
fullName = DeclarationName.FixSignatureForConversions(function, fullName); |
|
|
|
// If the name is not yet on the map, then add it. |
|
if (!names.ContainsKey(fullName)) |
|
names.Add(fullName, new DeclarationName()); |
|
|
|
if (names[fullName].UpdateName(decl)) |
|
{ |
|
Diagnostics.Debug("Duplicate name {0}, renamed to {1}", |
|
fullName, decl.Name); |
|
} |
|
} |
|
} |
|
}
|
|
|