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 9 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 @@ -127,28 +127,7 @@ namespace CppSharp.AST
IsPOD = false;
Type = ClassType.RefType;
Layout = new ClassLayout();
}
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;
specializations = new List<ClassTemplateSpecialization>();
}
public bool HasBase
@ -239,6 +218,22 @@ namespace CppSharp.AST @@ -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)
{
return Methods.Where(m => m.OperatorKind == kind);
@ -278,5 +273,7 @@ namespace CppSharp.AST @@ -278,5 +273,7 @@ namespace CppSharp.AST
{
return visitor.VisitClassDecl(this);
}
private List<ClassTemplateSpecialization> specializations;
}
}

12
src/CppParser/Parser.cpp

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

1
src/Generator/Driver.cs

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

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

@ -260,19 +260,6 @@ namespace CppSharp.Generators.CSharp @@ -260,19 +260,6 @@ namespace CppSharp.Generators.CSharp
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.
foreach (var @class in context.Classes.Where(c => !c.IsIncomplete))
{
@ -280,13 +267,14 @@ namespace CppSharp.Generators.CSharp @@ -280,13 +267,14 @@ namespace CppSharp.Generators.CSharp
GenerateInterface(@class);
else
{
var classTemplate = classTemplates.FirstOrDefault(t => t.TemplatedDecl == @class);
if (classTemplate != null)
if (@class.IsDependent)
{
GenerateClassTemplateSpecializationInternal(classTemplate);
classTemplates.Remove(classTemplate);
if (!(@class.Namespace is Class))
{
GenerateClassTemplateSpecializationInternal(@class);
}
}
else if (!@class.IsDependent)
else
{
GenerateClass(@class);
}
@ -343,18 +331,18 @@ namespace CppSharp.Generators.CSharp @@ -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;
if (classTemplate.TemplatedClass.Fields.Any(
if (classTemplate.Fields.Any(
f => f.Type.Desugar() is TemplateParameterType))
specializations = classTemplate.Specializations;
else
specializations = new[] { classTemplate.Specializations[0] };
if (classTemplate.TemplatedClass.Classes.Count == 0 && specializations.Count == 0)
return;
PushBlock(CSharpBlockKind.Namespace);
WriteLine("namespace {0}{1}",
classTemplate.OriginalNamespace is Class ?
@ -365,7 +353,7 @@ namespace CppSharp.Generators.CSharp @@ -365,7 +353,7 @@ namespace CppSharp.Generators.CSharp
foreach (var specialization in specializations)
GenerateClassInternals(specialization);
foreach (var nestedClass in classTemplate.TemplatedClass.Classes)
foreach (var nestedClass in classTemplate.Classes)
{
NewLine();
GenerateClassProlog(nestedClass);
@ -449,6 +437,9 @@ namespace CppSharp.Generators.CSharp @@ -449,6 +437,9 @@ namespace CppSharp.Generators.CSharp
if (@class.IsIncomplete)
return;
foreach (var nestedTemplate in @class.Classes.Where(c => !c.IsIncomplete && c.IsDependent))
GenerateClassTemplateSpecializationInternal(nestedTemplate);
System.Type typeMap = null;
if (Driver.TypeDatabase.TypeMaps.ContainsKey(@class.Name))
{

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

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

66
src/Generator/Passes/MoveNestedTemplateInternalsPass.cs

@ -1,66 +0,0 @@ @@ -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 @@ -20,20 +20,13 @@ namespace CppSharp.Passes
if (!base.VisitClassTemplateDecl(template))
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);
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;
}

18
src/Generator/Passes/TrimSpecializationsPass.cs

@ -6,29 +6,29 @@ namespace CppSharp.Passes @@ -6,29 +6,29 @@ namespace CppSharp.Passes
{
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;
template.Specializations.RemoveAll(
@class.Specializations.RemoveAll(
s => s.Fields.Any(f => f.Type.IsPrimitiveType(PrimitiveType.Void)));
if (template.Specializations.Count == 0)
if (@class.Specializations.Count == 0)
return false;
var groups = (from specialization in template.Specializations
var groups = (from specialization in @class.Specializations
group specialization by specialization.Arguments.All(
a => a.Type.Type != null && a.Type.Type.IsAddress()) into @group
select @group).ToList();
foreach (var group in groups.Where(g => g.Key))
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--)
if (template.Specializations[i] is ClassTemplatePartialSpecialization)
template.Specializations.RemoveAt(i);
for (int i = @class.Specializations.Count - 1; i >= 0; i--)
if (@class.Specializations[i] is ClassTemplatePartialSpecialization)
@class.Specializations.RemoveAt(i);
return true;
}

Loading…
Cancel
Save