diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs index c0ee2604..bda4a545 100644 --- a/src/Generator/AST/Utils.cs +++ b/src/Generator/AST/Utils.cs @@ -1,6 +1,8 @@ - -using System; +using System; +using System.Collections.Generic; using System.Linq; +using CppSharp.AST.Extensions; +using CppSharp.Types; namespace CppSharp.AST { @@ -20,6 +22,9 @@ namespace CppSharp.AST { if (!method.IsGenerated) return true; + if (method.IsDependent && UsesAdditionalTypeParam(method)) + return true; + var isEmptyCtor = method.IsConstructor && method.Parameters.Count == 0; var @class = method.Namespace as Class; @@ -48,9 +53,10 @@ namespace CppSharp.AST if (!baseClass.IsInterface) { var copyConstructor = baseClass.Methods.FirstOrDefault(m => m.IsCopyConstructor); - if (copyConstructor == null - || copyConstructor.Access == AccessSpecifier.Private - || !copyConstructor.IsDeclared) + if (copyConstructor == null || + copyConstructor.Access == AccessSpecifier.Private || + (!copyConstructor.IsDeclared && + !copyConstructor.TranslationUnit.IsSystemHeader)) return true; } } @@ -61,7 +67,7 @@ namespace CppSharp.AST public static bool CheckIgnoreField(Field field, bool useInternals = false) { - if (field.Access == AccessSpecifier.Private && !useInternals) + if (field.Access == AccessSpecifier.Private && !useInternals) return true; if (field.Class.IsValueType && field.IsDeclared) @@ -80,6 +86,99 @@ namespace CppSharp.AST return !prop.IsGenerated; } + + public static void CheckTypeForSpecialization(Type type, Declaration container, + Action addSpecialization, + ITypeMapDatabase typeMaps, bool internalOnly = false) + { + type = type.Desugar(); + type = type.GetFinalPointee() ?? type; + ClassTemplateSpecialization specialization; + if (!type.TryGetDeclaration(out specialization) || + specialization.IsExplicitlyGenerated) + return; + + TypeMap typeMap; + typeMaps.FindTypeMap(specialization, out typeMap); + + if ((!internalOnly && (((specialization.Ignore || + specialization.TemplatedDecl.TemplatedClass.Ignore) && typeMap == null) || + specialization.Arguments.Any(a => UnsupportedTemplateArgument( + specialization, a, typeMaps)))) || + specialization.IsIncomplete || + specialization.TemplatedDecl.TemplatedClass.IsIncomplete || + specialization is ClassTemplatePartialSpecialization || + container.Namespace == specialization) + return; + + while (container.Namespace != null) + { + if (container.Namespace == specialization) + return; + container = container.Namespace; + } + + if (!internalOnly && typeMaps.FindTypeMap(specialization, out typeMap)) + { + var typePrinterContext = new TypePrinterContext { Type = type }; + var mappedTo = typeMap.CSharpSignatureType(typePrinterContext); + mappedTo = mappedTo.Desugar(); + mappedTo = (mappedTo.GetFinalPointee() ?? mappedTo); + if (mappedTo.IsPrimitiveType() || mappedTo.IsPointerToPrimitiveType() || mappedTo.IsEnum()) + return; + } + + addSpecialization(specialization); + } + + public static bool IsTypeExternal(Module module, Type type) + { + Declaration declaration; + if (!(type.GetFinalPointee() ?? type).TryGetDeclaration(out declaration)) + return false; + + declaration = declaration.CompleteDeclaration ?? declaration; + if (declaration.Namespace == null || declaration.TranslationUnit.Module == null) + return false; + + return declaration.TranslationUnit.Module.Dependencies.Contains(module); + } + + private static bool UsesAdditionalTypeParam(Method method) + { + var specialization = method.Namespace as ClassTemplateSpecialization; + Class template; + if (specialization != null) + template = specialization.TemplatedDecl.TemplatedClass; + else + { + template = (Class) method.Namespace; + if (!template.IsDependent) + return false; + } + var typeParams = template.TemplateParameters.Select(t => t.Name).ToList(); + return method.Parameters.Any(p => + { + if (!p.IsDependent) + return false; + var desugared = p.Type.Desugar(); + var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar() + as TemplateParameterType; + return finalType != null && !typeParams.Contains(finalType.Parameter.Name); + }); + } + + private static bool UnsupportedTemplateArgument( + ClassTemplateSpecialization specialization, TemplateArgument a, ITypeMapDatabase typeMaps) + { + if (a.Type.Type == null || + IsTypeExternal(specialization.TranslationUnit.Module, a.Type.Type)) + return true; + + var typeIgnoreChecker = new TypeIgnoreChecker(typeMaps); + a.Type.Type.Visit(typeIgnoreChecker); + return typeIgnoreChecker.IsIgnored; + } } public static class Operators diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index fcb6e0ce..4beb7438 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -368,7 +368,7 @@ namespace CppSharp.Passes } if (Options.DoAllModulesHaveLibraries() && - module != Options.SystemModule && IsTypeExternal(module, type)) + module != Options.SystemModule && ASTUtils.IsTypeExternal(module, type)) { msg = "external"; return true; @@ -433,19 +433,6 @@ namespace CppSharp.Passes return !decl.IsIncomplete || decl.CompleteDeclaration != null; } - public static bool IsTypeExternal(Module module, Type type) - { - Declaration declaration; - if (!(type.GetFinalPointee() ?? type).TryGetDeclaration(out declaration)) - return false; - - declaration = declaration.CompleteDeclaration ?? declaration; - if (declaration.Namespace == null || declaration.TranslationUnit.Module == null) - return false; - - return declaration.TranslationUnit.Module.Dependencies.Contains(module); - } - private bool IsTypeIgnored(Type type) { var checker = new TypeIgnoreChecker(TypeMaps); diff --git a/src/Generator/Passes/GenerateSymbolsPass.cs b/src/Generator/Passes/GenerateSymbolsPass.cs index 2f93ed0a..b90f62c5 100644 --- a/src/Generator/Passes/GenerateSymbolsPass.cs +++ b/src/Generator/Passes/GenerateSymbolsPass.cs @@ -83,9 +83,21 @@ namespace CppSharp.Passes if (function.IsGenerated) { - CheckTypeForSpecialization(function.OriginalReturnType.Type); + Action add = + s => + { + ICollection specs; + if (specializations.ContainsKey(s.TranslationUnit.Module)) + specs = specializations[s.TranslationUnit.Module]; + else specs = specializations[s.TranslationUnit.Module] = + new HashSet(); + specs.Add(s); + }; + ASTUtils.CheckTypeForSpecialization(function.OriginalReturnType.Type, + function, add, Context.TypeMaps); foreach (var parameter in function.Parameters) - CheckTypeForSpecialization(parameter.Type); + ASTUtils.CheckTypeForSpecialization(parameter.Type, function, + add, Context.TypeMaps); } if (!NeedsSymbol(function)) @@ -95,54 +107,6 @@ namespace CppSharp.Passes return function.Visit(symbolsCodeGenerator); } - private void CheckTypeForSpecialization(AST.Type type) - { - type = type.Desugar(); - ClassTemplateSpecialization specialization; - type = type.GetFinalPointee() ?? type; - if (!type.TryGetDeclaration(out specialization)) - return; - - if (specialization.Ignore || - specialization.TemplatedDecl.TemplatedClass.Ignore || - specialization.IsIncomplete || - specialization.TemplatedDecl.TemplatedClass.IsIncomplete || - specialization is ClassTemplatePartialSpecialization || - specialization.Arguments.Any(a => UnsupportedTemplateArgument(specialization, a))) - return; - - TypeMap typeMap; - if (Context.TypeMaps.FindTypeMap(specialization, out typeMap)) - { - var typePrinterContext = new TypePrinterContext { Type = type }; - var mappedTo = typeMap.CSharpSignatureType(typePrinterContext); - mappedTo = mappedTo.Desugar(); - mappedTo = (mappedTo.GetFinalPointee() ?? mappedTo); - if (mappedTo.IsPrimitiveType() || mappedTo.IsPointerToPrimitiveType() || mappedTo.IsEnum()) - return; - } - - HashSet list; - if (specializations.ContainsKey(specialization.TranslationUnit.Module)) - list = specializations[specialization.TranslationUnit.Module]; - else - specializations[specialization.TranslationUnit.Module] = - list = new HashSet(); - list.Add(specialization); - } - - private bool UnsupportedTemplateArgument(ClassTemplateSpecialization specialization, TemplateArgument a) - { - if (a.Type.Type == null || - CheckIgnoredDeclsPass.IsTypeExternal( - specialization.TranslationUnit.Module, a.Type.Type)) - return true; - - var typeIgnoreChecker = new TypeIgnoreChecker(Context.TypeMaps); - a.Type.Type.Visit(typeIgnoreChecker); - return typeIgnoreChecker.IsIgnored; - } - public class SymbolsCodeEventArgs : EventArgs { public SymbolsCodeEventArgs(Module module) diff --git a/src/Generator/Passes/TrimSpecializationsPass.cs b/src/Generator/Passes/TrimSpecializationsPass.cs index 6332dbba..08f6d33f 100644 --- a/src/Generator/Passes/TrimSpecializationsPass.cs +++ b/src/Generator/Passes/TrimSpecializationsPass.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using CppSharp.AST; using CppSharp.AST.Extensions; @@ -7,38 +8,124 @@ namespace CppSharp.Passes { public class TrimSpecializationsPass : TranslationUnitPass { + public override bool VisitASTContext(ASTContext context) + { + var result = base.VisitASTContext(context); + foreach (var template in templates) + CleanSpecializations(template); + return result; + } + public override bool VisitClassDecl(Class @class) { - if (!base.VisitClassDecl(@class) || @class.IsIncomplete || !@class.IsDependent) + if (!base.VisitClassDecl(@class)) return false; - @class.Specializations.RemoveAll( - s => s.Fields.Any(f => f.Type.IsPrimitiveType(PrimitiveType.Void))); + if (@class.IsDependent) + templates.Add(@class); + else + foreach (var @base in @class.Bases.Where(b => b.IsClass)) + { + var specialization = @base.Class as ClassTemplateSpecialization; + if (specialization != null) + specializations.Add(specialization); + } - foreach (var specialization in @class.Specializations.Where(s => s.Arguments.Any( - a => a.Type.Type != null && - CheckIgnoredDeclsPass.IsTypeExternal(@class.TranslationUnit.Module, a.Type.Type)) || - @class is ClassTemplatePartialSpecialization)) - specialization.ExplicitlyIgnore(); + return true; + } - if (@class.Specializations.Count == 0) + public override bool VisitFunctionDecl(Function function) + { + if (!base.VisitFunctionDecl(function)) return false; - Func allPointers = a => a.Type.Type != null && a.Type.Type.IsAddress(); - var groups = (from specialization in @class.Specializations - group specialization by specialization.Arguments.All(allPointers) into @group + if (function.IsGenerated) + { + Action add = + s => + { + if (internalSpecializations.Contains(s)) + internalSpecializations.Remove(s); + specializations.Add(s); + }; + ASTUtils.CheckTypeForSpecialization(function.OriginalReturnType.Type, + function, add, Context.TypeMaps); + foreach (var parameter in function.Parameters) + ASTUtils.CheckTypeForSpecialization(parameter.Type, function, + add, Context.TypeMaps); + } + + return true; + } + + public override bool VisitFieldDecl(Field field) + { + if (!base.VisitDeclaration(field)) + return false; + + ASTUtils.CheckTypeForSpecialization(field.Type, field, + s => + { + if (!specializations.Contains(s)) + internalSpecializations.Add(s); + }, Context.TypeMaps, true); + return true; + } + + private void CleanSpecializations(Class template) + { + template.Specializations.RemoveAll(s => !s.IsExplicitlyGenerated && + !specializations.Contains(s) && !internalSpecializations.Contains(s)); + + foreach (var specialization in template.Specializations.Where( + s => !s.IsExplicitlyGenerated && + (s.Arguments.Any(a => + { + if (a.Kind != TemplateArgument.ArgumentKind.Declaration && + a.Kind != TemplateArgument.ArgumentKind.Template && + a.Kind != TemplateArgument.ArgumentKind.Type) + return true; + + var type = a.Type.Type.Desugar(); + if (ASTUtils.IsTypeExternal(template.TranslationUnit.Module, type) || + type.IsPrimitiveType(PrimitiveType.Void)) + return true; + + var typeIgnoreChecker = new TypeIgnoreChecker(TypeMaps); + type.Visit(typeIgnoreChecker); + return typeIgnoreChecker.IsIgnored; + }) || + s.SpecializationKind == TemplateSpecializationKind.ExplicitSpecialization || + s is ClassTemplatePartialSpecialization || + internalSpecializations.Contains(s)))) + specialization.ExplicitlyIgnore(); + + Func allPointers = + a => a.Type.Type != null && a.Type.Type.IsAddress(); + var groups = (from specialization in template.Specializations + group specialization by specialization.Arguments.All(allPointers) + into @group select @group).ToList(); foreach (var group in groups.Where(g => g.Key)) foreach (var specialization in group.Skip(1)) - @class.Specializations.Remove(specialization); + template.Specializations.Remove(specialization); - for (int i = @class.Specializations.Count - 1; i >= 0; i--) - if (@class.Specializations[i] is ClassTemplatePartialSpecialization && - !@class.Specializations[i].Arguments.All(allPointers)) - @class.Specializations.RemoveAt(i); + for (int i = template.Specializations.Count - 1; i >= 0; i--) + { + var specialization = template.Specializations[i]; + if (specialization is ClassTemplatePartialSpecialization && + !specialization.Arguments.All(allPointers)) + template.Specializations.RemoveAt(i); + } - return true; + if (!template.IsExplicitlyGenerated && + template.Specializations.All(s => s.Ignore)) + template.ExplicitlyIgnore(); } + + private HashSet specializations = new HashSet(); + private HashSet internalSpecializations = new HashSet(); + private HashSet templates = new HashSet(); } }