Browse Source

Stored specializations in the templated class itself because ClassTemplate is not a complete declaration.

ClassTemplate in Clang does not actually represent a complete declaration. For example, let's see the implementation of clang::ClassTemplateDecl::isThisDeclarationADefinition:

    bool isThisDeclarationADefinition() const {
      return getTemplatedDecl()->isThisDeclarationADefinition();
    }

(http://clang.llvm.org/doxygen/DeclTemplate_8h_source.html#l01995 at the time of this commit)

The above shows that class templates do not have definitions, instead, their "definitions" are those of the real templates classes.
In addition let's see ClassTemplateDecl::getCanonicalDecl():

    const ClassTemplateDecl *getCanonicalDecl() const {
      return cast<ClassTemplateDecl>(
               RedeclarableTemplateDecl::getCanonicalDecl());
    }

(http://clang.llvm.org/doxygen/DeclTemplate_8h_source.html#l02023 at the time of this commit)

In turn RedeclarableTemplateDecl::getCanonicalDecl() is defined as:

   RedeclarableTemplateDecl *getCanonicalDecl() override {
     return getFirstDecl();
   }

where getFirstDecl() returns just that - the first encountered declaration which might as well be a forward one.
This means that the only complete declaration ClassTemplateDecl can point to is the template class itself,
and the latter is therefore our only choice if we want to have a full list of all specializations of that template class.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/678/head
Dimitar Dobrev 10 years ago
parent
commit
06410eddbc
  1. 41
      src/AST/Class.cs
  2. 12
      src/CppParser/Parser.cpp
  3. 1
      src/Generator/Driver.cs
  4. 39
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  5. 2
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  6. 66
      src/Generator/Passes/MoveNestedTemplateInternalsPass.cs
  7. 15
      src/Generator/Passes/ResolveIncompleteDeclsPass.cs
  8. 18
      src/Generator/Passes/TrimSpecializationsPass.cs

41
src/AST/Class.cs

@ -127,28 +127,7 @@ namespace CppSharp.AST
IsPOD = false; IsPOD = false;
Type = ClassType.RefType; Type = ClassType.RefType;
Layout = new ClassLayout(); Layout = new ClassLayout();
} specializations = new List<ClassTemplateSpecialization>();
public Class(Class @class)
: base(@class)
{
Bases = new List<BaseClassSpecifier>(@class.Bases);
Fields = new List<Field>(@class.Fields);
Properties = new List<Property>(@class.Properties);
Methods = new List<Method>(@class.Methods);
Specifiers = new List<AccessSpecifierDecl>(@class.Specifiers);
IsPOD = @class.IsPOD;
Type = @class.Type;
Layout = new ClassLayout(@class.Layout);
IsAbstract = @class.IsAbstract;
IsUnion = @class.IsUnion;
IsOpaque = @class.IsOpaque;
IsDynamic = @class.IsDynamic;
IsPolymorphic = @class.IsPolymorphic;
HasNonTrivialDefaultConstructor = @class.HasNonTrivialDefaultConstructor;
HasNonTrivialCopyConstructor = @class.HasNonTrivialCopyConstructor;
HasNonTrivialDestructor = @class.HasNonTrivialDestructor;
IsStatic = @class.IsStatic;
} }
public bool HasBase public bool HasBase
@ -239,6 +218,22 @@ namespace CppSharp.AST
} }
} }
/// <summary>
/// If this class is a template, this list contains all of its specializations.
/// <see cref="ClassTemplate"/> cannot be relied upon to contain all of them because
/// ClassTemplateDecl in Clang is not a complete declaration, it only serves to forward template classes.
/// </summary>
public List<ClassTemplateSpecialization> Specializations
{
get
{
if (!IsDependent)
throw new InvalidOperationException(
"Only dependent classes have specializations.");
return specializations;
}
}
public override IEnumerable<Function> FindOperator(CXXOperatorKind kind) public override IEnumerable<Function> FindOperator(CXXOperatorKind kind)
{ {
return Methods.Where(m => m.OperatorKind == kind); return Methods.Where(m => m.OperatorKind == kind);
@ -278,5 +273,7 @@ namespace CppSharp.AST
{ {
return visitor.VisitClassDecl(this); return visitor.VisitClassDecl(this);
} }
private List<ClassTemplateSpecialization> specializations;
} }
} }

12
src/CppParser/Parser.cpp

@ -1148,12 +1148,6 @@ ClassTemplate* Parser::WalkClassTemplate(const clang::ClassTemplateDecl* TD)
return CT; return CT;
CT = new ClassTemplate(); CT = new ClassTemplate();
if (!TD->isThisDeclarationADefinition())
{
CT->IsIncomplete = true;
if (TD->getCanonicalDecl()->isThisDeclarationADefinition())
CT->CompleteDeclaration = WalkClassTemplate(TD->getCanonicalDecl());
}
HandleDeclaration(TD, CT); HandleDeclaration(TD, CT);
CT->Name = GetDeclName(TD); CT->Name = GetDeclName(TD);
@ -1374,12 +1368,6 @@ FunctionTemplate* Parser::WalkFunctionTemplate(const clang::FunctionTemplateDecl
/*AddToNamespace=*/false); /*AddToNamespace=*/false);
FT = new FunctionTemplate(); FT = new FunctionTemplate();
if (!TD->isThisDeclarationADefinition())
{
FT->IsIncomplete = true;
if (TD->getCanonicalDecl()->isThisDeclarationADefinition())
FT->CompleteDeclaration = WalkFunctionTemplate(TD->getCanonicalDecl());
}
HandleDeclaration(TD, FT); HandleDeclaration(TD, FT);
FT->Name = GetDeclName(TD); FT->Name = GetDeclName(TD);

1
src/Generator/Driver.cs

@ -307,7 +307,6 @@ namespace CppSharp
if (Options.GenerateInlines) if (Options.GenerateInlines)
TranslationUnitPasses.AddPass(new GenerateInlinesCodePass()); TranslationUnitPasses.AddPass(new GenerateInlinesCodePass());
TranslationUnitPasses.AddPass(new TrimSpecializationsPass()); TranslationUnitPasses.AddPass(new TrimSpecializationsPass());
TranslationUnitPasses.AddPass(new MoveNestedTemplateInternalsPass());
TranslationUnitPasses.AddPass(new GenerateTemplatesCodePass()); TranslationUnitPasses.AddPass(new GenerateTemplatesCodePass());
} }

39
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -260,19 +260,6 @@ namespace CppSharp.Generators.CSharp
GenerateTypedef(typedef); GenerateTypedef(typedef);
} }
var templateGroups = (from template in context.Templates.OfType<ClassTemplate>()
where !template.IsIncomplete && !template.TemplatedDecl.IsIncomplete &&
template.Specializations.Count > 0
group template by context.Classes.Contains(template.TemplatedClass)
into @group
select @group).ToList();
if (templateGroups.Count > 0 && !templateGroups[0].Key)
foreach (var classTemplate in templateGroups[0])
GenerateClassTemplateSpecializationInternal(classTemplate);
var classTemplates = templateGroups.Where(g => g.Key).SelectMany(g => g).ToList();
// Generate all the struct/class declarations. // Generate all the struct/class declarations.
foreach (var @class in context.Classes.Where(c => !c.IsIncomplete)) foreach (var @class in context.Classes.Where(c => !c.IsIncomplete))
{ {
@ -280,13 +267,14 @@ namespace CppSharp.Generators.CSharp
GenerateInterface(@class); GenerateInterface(@class);
else else
{ {
var classTemplate = classTemplates.FirstOrDefault(t => t.TemplatedDecl == @class); if (@class.IsDependent)
if (classTemplate != null)
{ {
GenerateClassTemplateSpecializationInternal(classTemplate); if (!(@class.Namespace is Class))
classTemplates.Remove(classTemplate); {
GenerateClassTemplateSpecializationInternal(@class);
}
} }
else if (!@class.IsDependent) else
{ {
GenerateClass(@class); GenerateClass(@class);
} }
@ -343,18 +331,18 @@ namespace CppSharp.Generators.CSharp
} }
} }
private void GenerateClassTemplateSpecializationInternal(ClassTemplate classTemplate) private void GenerateClassTemplateSpecializationInternal(Class classTemplate)
{ {
if (classTemplate.Specializations.Count == 0)
return;
IList<ClassTemplateSpecialization> specializations; IList<ClassTemplateSpecialization> specializations;
if (classTemplate.TemplatedClass.Fields.Any( if (classTemplate.Fields.Any(
f => f.Type.Desugar() is TemplateParameterType)) f => f.Type.Desugar() is TemplateParameterType))
specializations = classTemplate.Specializations; specializations = classTemplate.Specializations;
else else
specializations = new[] { classTemplate.Specializations[0] }; specializations = new[] { classTemplate.Specializations[0] };
if (classTemplate.TemplatedClass.Classes.Count == 0 && specializations.Count == 0)
return;
PushBlock(CSharpBlockKind.Namespace); PushBlock(CSharpBlockKind.Namespace);
WriteLine("namespace {0}{1}", WriteLine("namespace {0}{1}",
classTemplate.OriginalNamespace is Class ? classTemplate.OriginalNamespace is Class ?
@ -365,7 +353,7 @@ namespace CppSharp.Generators.CSharp
foreach (var specialization in specializations) foreach (var specialization in specializations)
GenerateClassInternals(specialization); GenerateClassInternals(specialization);
foreach (var nestedClass in classTemplate.TemplatedClass.Classes) foreach (var nestedClass in classTemplate.Classes)
{ {
NewLine(); NewLine();
GenerateClassProlog(nestedClass); GenerateClassProlog(nestedClass);
@ -449,6 +437,9 @@ namespace CppSharp.Generators.CSharp
if (@class.IsIncomplete) if (@class.IsIncomplete)
return; return;
foreach (var nestedTemplate in @class.Classes.Where(c => !c.IsIncomplete && c.IsDependent))
GenerateClassTemplateSpecializationInternal(nestedTemplate);
System.Type typeMap = null; System.Type typeMap = null;
if (Driver.TypeDatabase.TypeMaps.ContainsKey(@class.Name)) if (Driver.TypeDatabase.TypeMaps.ContainsKey(@class.Name))
{ {

2
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -642,7 +642,7 @@ namespace CppSharp.Generators.CSharp
var specialization = decl as ClassTemplateSpecialization; var specialization = decl as ClassTemplateSpecialization;
if (specialization != null) if (specialization != null)
{ {
ctx = specialization.TemplatedDecl.Namespace; ctx = specialization.TemplatedDecl.TemplatedClass.Namespace;
if (specialization.OriginalNamespace is Class) if (specialization.OriginalNamespace is Class)
{ {
names.Add(string.Format("{0}_{1}", decl.OriginalNamespace.Name, decl.Name)); names.Add(string.Format("{0}_{1}", decl.OriginalNamespace.Name, decl.Name));

66
src/Generator/Passes/MoveNestedTemplateInternalsPass.cs

@ -1,66 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
namespace CppSharp.Passes
{
public class MoveNestedTemplateInternalsPass : TranslationUnitPass
{
public MoveNestedTemplateInternalsPass()
{
Options.VisitClassBases = false;
Options.VisitClassFields = false;
Options.VisitClassMethods = false;
Options.VisitClassProperties = false;
Options.VisitFunctionParameters = false;
Options.VisitFunctionReturnType = false;
Options.VisitNamespaceEnums = false;
Options.VisitNamespaceEvents = false;
Options.VisitNamespaceTypedefs = false;
Options.VisitNamespaceVariables = false;
Options.VisitTemplateArguments = false;
}
public override bool VisitLibrary(ASTContext context)
{
var result = base.VisitLibrary(context);
foreach (var entry in movedClassTemplates)
{
foreach (var template in entry.Value)
{
foreach (var decl in new[] { template, template.TemplatedDecl })
{
int index = entry.Key.Declarations.IndexOf(decl.Namespace);
decl.Namespace.Declarations.Remove(decl);
decl.Namespace = entry.Key;
entry.Key.Declarations.Insert(index, decl);
}
}
}
return result;
}
public override bool VisitClassTemplateDecl(ClassTemplate template)
{
if (!base.VisitClassTemplateDecl(template) ||
template.Specializations.Count == 0 ||
template.Specializations.All(s => s is ClassTemplatePartialSpecialization))
return false;
var @class = template.TemplatedDecl.Namespace as Class;
if (@class == null || @class is ClassTemplateSpecialization ||
@class.Namespace is Class)
return false;
if (movedClassTemplates.ContainsKey(@class.Namespace))
movedClassTemplates[@class.Namespace].Add(template);
else
movedClassTemplates.Add(@class.Namespace, new List<ClassTemplate> { template });
return true;
}
private Dictionary<DeclarationContext, IList<ClassTemplate>> movedClassTemplates =
new Dictionary<DeclarationContext, IList<ClassTemplate>>();
}
}

15
src/Generator/Passes/ResolveIncompleteDeclsPass.cs

@ -20,20 +20,13 @@ namespace CppSharp.Passes
if (!base.VisitClassTemplateDecl(template)) if (!base.VisitClassTemplateDecl(template))
return false; return false;
if (template.IsIncomplete && template.CompleteDeclaration != null)
{
var completeDeclaration = (ClassTemplate) template.CompleteDeclaration;
foreach (var specialization in template.Specializations.Where(
spec => completeDeclaration.Specializations.All(s => s.USR != spec.USR)))
{
specialization.TemplatedDecl = completeDeclaration;
completeDeclaration.Specializations.Add(specialization);
}
}
EnsureCompleteDeclaration(template.TemplatedDecl); EnsureCompleteDeclaration(template.TemplatedDecl);
template.TemplatedDecl = template.TemplatedDecl.CompleteDeclaration ?? template.TemplatedDecl; template.TemplatedDecl = template.TemplatedDecl.CompleteDeclaration ?? template.TemplatedDecl;
// store all spesializations in the real template class because ClassTemplateDecl only forwards
foreach (var specialization in template.Specializations.Where(
s => !template.TemplatedClass.Specializations.Contains(s)))
template.TemplatedClass.Specializations.Add(specialization);
return true; return true;
} }

18
src/Generator/Passes/TrimSpecializationsPass.cs

@ -6,29 +6,29 @@ namespace CppSharp.Passes
{ {
public class TrimSpecializationsPass : TranslationUnitPass public class TrimSpecializationsPass : TranslationUnitPass
{ {
public override bool VisitClassTemplateDecl(ClassTemplate template) public override bool VisitClassDecl(Class @class)
{ {
if (!base.VisitClassTemplateDecl(template) || template.IsIncomplete) if (!base.VisitClassDecl(@class) || @class.IsIncomplete || !@class.IsDependent)
return false; return false;
template.Specializations.RemoveAll( @class.Specializations.RemoveAll(
s => s.Fields.Any(f => f.Type.IsPrimitiveType(PrimitiveType.Void))); s => s.Fields.Any(f => f.Type.IsPrimitiveType(PrimitiveType.Void)));
if (template.Specializations.Count == 0) if (@class.Specializations.Count == 0)
return false; return false;
var groups = (from specialization in template.Specializations var groups = (from specialization in @class.Specializations
group specialization by specialization.Arguments.All( group specialization by specialization.Arguments.All(
a => a.Type.Type != null && a.Type.Type.IsAddress()) into @group a => a.Type.Type != null && a.Type.Type.IsAddress()) into @group
select @group).ToList(); select @group).ToList();
foreach (var group in groups.Where(g => g.Key)) foreach (var group in groups.Where(g => g.Key))
foreach (var specialization in group.Skip(1)) foreach (var specialization in group.Skip(1))
template.Specializations.Remove(specialization); @class.Specializations.Remove(specialization);
for (int i = template.Specializations.Count - 1; i >= 0; i--) for (int i = @class.Specializations.Count - 1; i >= 0; i--)
if (template.Specializations[i] is ClassTemplatePartialSpecialization) if (@class.Specializations[i] is ClassTemplatePartialSpecialization)
template.Specializations.RemoveAt(i); @class.Specializations.RemoveAt(i);
return true; return true;
} }

Loading…
Cancel
Save