mirror of https://github.com/mono/CppSharp.git
19 changed files with 433 additions and 432 deletions
@ -0,0 +1,178 @@
@@ -0,0 +1,178 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using CppSharp.AST; |
||||
using Type = CppSharp.AST.Type; |
||||
|
||||
namespace CppSharp.Generators.AST |
||||
{ |
||||
public class ASTRecord |
||||
{ |
||||
public ASTRecord Parent; |
||||
public object Object; |
||||
|
||||
public bool GetParent<T>(out T @out) |
||||
{ |
||||
@out = default(T); |
||||
|
||||
if (Parent == null) |
||||
return false; |
||||
|
||||
var v = Parent.Object; |
||||
if (!(v is T)) |
||||
return false; |
||||
|
||||
@out = (T) v; |
||||
return true; |
||||
} |
||||
|
||||
// Pushes ancestors into the stack until it is found one of type T.
|
||||
public bool GetAncestors<T>(ref Stack<object> ancestors) |
||||
{ |
||||
ancestors.Push(this); |
||||
|
||||
T value; |
||||
if (GetParent(out value)) |
||||
{ |
||||
ancestors.Push(value); |
||||
return true; |
||||
} |
||||
|
||||
return Parent != null |
||||
&& Parent.GetAncestors<T>(ref ancestors); |
||||
} |
||||
} |
||||
|
||||
public class ASTRecord<T> : ASTRecord |
||||
{ |
||||
public T Value |
||||
{ |
||||
get { return (T) Object; } |
||||
} |
||||
} |
||||
|
||||
public class ASTRecordStack |
||||
{ |
||||
private readonly Stack<ASTRecord> recordStack; |
||||
|
||||
public ASTRecordStack() |
||||
{ |
||||
recordStack = new Stack<ASTRecord>(); |
||||
} |
||||
|
||||
public ASTRecord<T> Push<T>(T value) |
||||
{ |
||||
ASTRecord parent = null; |
||||
|
||||
if (recordStack.Count > 0) |
||||
parent = recordStack.Peek(); |
||||
|
||||
var record = new ASTRecord<T>() |
||||
{ |
||||
Parent = parent, |
||||
Object = value |
||||
}; |
||||
recordStack.Push(record); |
||||
return record; |
||||
} |
||||
|
||||
public void Pop() |
||||
{ |
||||
recordStack.Pop(); |
||||
} |
||||
} |
||||
|
||||
static class ASTRecordExtensions |
||||
{ |
||||
public static bool IsBaseClass(this ASTRecord record) |
||||
{ |
||||
Class decl; |
||||
return record.GetParent(out decl) && decl.BaseClass == record.Object; |
||||
} |
||||
|
||||
public static bool IsFieldValueType(this ASTRecord record) |
||||
{ |
||||
var ancestors = new Stack<object>(); |
||||
if(!record.GetAncestors<Field>(ref ancestors)) |
||||
return false; |
||||
|
||||
var field = (Field)ancestors.Pop(); |
||||
|
||||
Class decl; |
||||
if (!field.Type.Desugar().IsTagDecl(out decl)) |
||||
return false; |
||||
|
||||
return decl.IsValueType; |
||||
} |
||||
} |
||||
|
||||
public class RecordCollector : AstVisitor |
||||
{ |
||||
public readonly ISet<ASTRecord<Declaration>> Declarations; |
||||
private readonly ASTRecordStack recordStack; |
||||
|
||||
public TranslationUnit translationUnit; |
||||
|
||||
public ISet<object> Visited2 { get; private set; } |
||||
public bool AlreadyVisited2(object o) |
||||
{ |
||||
return !Visited2.Add(o); |
||||
} |
||||
|
||||
public RecordCollector(TranslationUnit translationUnit) |
||||
{ |
||||
this.translationUnit = translationUnit; |
||||
Declarations = new HashSet<ASTRecord<Declaration>>(); |
||||
recordStack = new ASTRecordStack(); |
||||
Visited2 = new HashSet<object>(); |
||||
} |
||||
|
||||
public override bool VisitDeclaration(Declaration decl) |
||||
{ |
||||
if(translationUnit.FileName.Contains("Font")) |
||||
Console.Write(""); |
||||
|
||||
if (decl.IsIncomplete && decl.CompleteDeclaration != null) |
||||
decl = decl.CompleteDeclaration; |
||||
|
||||
if(AlreadyVisited2(decl)) |
||||
return ShouldVisitChilds(decl); |
||||
Visited.Remove(decl); // So Class can be revisited
|
||||
|
||||
Declarations.Add(recordStack.Push(decl)); |
||||
decl.Visit(this); |
||||
recordStack.Pop(); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public override bool VisitType(Type type, TypeQualifiers quals) |
||||
{ |
||||
type = type.Desugar(); |
||||
|
||||
if(AlreadyVisited2(type)) |
||||
return true; |
||||
|
||||
recordStack.Push(type); |
||||
type.Visit(this); |
||||
recordStack.Pop(); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public bool ShouldVisitChilds(Declaration decl) |
||||
{ |
||||
if(decl == translationUnit) |
||||
return true; |
||||
|
||||
if (decl is TranslationUnit) |
||||
return false; |
||||
|
||||
if (decl.Namespace == null) |
||||
return true; |
||||
|
||||
// No need to continue visiting after a declaration of
|
||||
// another translation unit is encountered.
|
||||
return decl.Namespace.TranslationUnit == translationUnit; |
||||
} |
||||
} |
||||
} |
||||
@ -1,207 +0,0 @@
@@ -1,207 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using CppSharp.AST; |
||||
|
||||
namespace CppSharp.Generators.CLI |
||||
{ |
||||
public struct CLIForwardReference |
||||
{ |
||||
public Declaration Declaration; |
||||
public Namespace Namespace; |
||||
public string Text; |
||||
} |
||||
|
||||
public class CLIForwardReferencePrinter : IDeclVisitor<bool> |
||||
{ |
||||
public readonly IList<string> Includes; |
||||
public readonly IList<CLIForwardReference> Refs; |
||||
private readonly TypeRefsVisitor TypeRefs; |
||||
private TypeReference currentTypeReference; |
||||
|
||||
public CLIForwardReferencePrinter(TypeRefsVisitor typeRefs) |
||||
{ |
||||
Includes = new List<string>(); |
||||
Refs = new List<CLIForwardReference>(); |
||||
TypeRefs = typeRefs; |
||||
} |
||||
|
||||
public void Process() |
||||
{ |
||||
foreach (var typeRef in TypeRefs.References) |
||||
{ |
||||
currentTypeReference = typeRef; |
||||
typeRef.Declaration.Visit(this); |
||||
} |
||||
|
||||
foreach (var baseClass in TypeRefs.Bases) |
||||
VisitBaseClass(baseClass); |
||||
} |
||||
|
||||
public void VisitBaseClass(Class @class) |
||||
{ |
||||
if (@class.IsIncomplete) |
||||
@class = @class.CompleteDeclaration as Class; |
||||
|
||||
if (@class == null) |
||||
return; |
||||
|
||||
Includes.Add(GetHeaderFromDecl(@class)); |
||||
} |
||||
|
||||
public bool VisitDeclaration(Declaration decl) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitClassDecl(Class @class) |
||||
{ |
||||
var completeDecl = @class.CompleteDeclaration as Class; |
||||
if (@class.IsIncomplete && completeDecl != null) |
||||
return VisitClassDecl(completeDecl); |
||||
|
||||
if (@class.IsValueType) |
||||
{ |
||||
Refs.Add(new CLIForwardReference() |
||||
{ |
||||
Declaration = @class, |
||||
Namespace = currentTypeReference.Namespace, |
||||
Text = string.Format("value struct {0};", @class.Name) |
||||
}); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
Refs.Add(new CLIForwardReference() |
||||
{ |
||||
Declaration = @class, |
||||
Namespace = currentTypeReference.Namespace, |
||||
Text = string.Format("ref class {0};", @class.Name) |
||||
}); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public bool VisitFieldDecl(Field field) |
||||
{ |
||||
Class @class; |
||||
if (field.Type.IsTagDecl(out @class)) |
||||
{ |
||||
if (@class.IsValueType) |
||||
Includes.Add(GetHeaderFromDecl(@class)); |
||||
else |
||||
VisitClassDecl(@class); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
Enumeration @enum; |
||||
if (field.Type.IsTagDecl(out @enum)) |
||||
return VisitEnumDecl(@enum); |
||||
|
||||
Includes.Add(GetHeaderFromDecl(field)); |
||||
return true; |
||||
} |
||||
|
||||
public bool VisitFunctionDecl(Function function) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitMethodDecl(Method method) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitParameterDecl(Parameter parameter) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public string GetHeaderFromDecl(Declaration decl) |
||||
{ |
||||
var @namespace = decl.Namespace; |
||||
var unit = @namespace.TranslationUnit; |
||||
|
||||
if (unit.Ignore) |
||||
return string.Empty; |
||||
|
||||
if (unit.IsSystemHeader) |
||||
return string.Empty; |
||||
|
||||
return Path.GetFileNameWithoutExtension(unit.FileName); |
||||
} |
||||
|
||||
public bool VisitTypedefDecl(TypedefDecl typedef) |
||||
{ |
||||
FunctionType function; |
||||
if (typedef.Type.IsPointerTo<FunctionType>(out function)) |
||||
{ |
||||
Includes.Add(GetHeaderFromDecl(typedef)); |
||||
return true; |
||||
} |
||||
|
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitEnumDecl(Enumeration @enum) |
||||
{ |
||||
Includes.Add(GetHeaderFromDecl(@enum)); |
||||
|
||||
if (@enum.Type.IsPrimitiveType(PrimitiveType.Int32)) |
||||
{ |
||||
Refs.Add(new CLIForwardReference() |
||||
{ |
||||
Declaration = @enum, |
||||
Namespace = currentTypeReference.Namespace, |
||||
Text = string.Format("enum struct {0};", @enum.Name) |
||||
}); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
Refs.Add(new CLIForwardReference() |
||||
{ |
||||
Declaration = @enum, |
||||
Namespace = currentTypeReference.Namespace, |
||||
Text = string.Format("enum struct {0} : {1};", @enum.Name, @enum.Type) |
||||
}); |
||||
return true; |
||||
} |
||||
|
||||
public bool VisitVariableDecl(Variable variable) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitClassTemplateDecl(ClassTemplate template) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitFunctionTemplateDecl(FunctionTemplate template) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitMacroDefinition(MacroDefinition macro) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitNamespace(Namespace @namespace) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitEvent(Event @event) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public bool VisitProperty(Property property) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,162 @@
@@ -0,0 +1,162 @@
|
||||
using System.Collections.Generic; |
||||
using CppSharp.AST; |
||||
using CppSharp.Generators.AST; |
||||
using CppSharp.Types; |
||||
|
||||
namespace CppSharp.Generators.CLI |
||||
{ |
||||
public class CLITypeReference |
||||
{ |
||||
public Include Include; |
||||
public string FowardReference; |
||||
} |
||||
|
||||
public class CLITypeReferenceCollector : AstVisitor |
||||
{ |
||||
private Dictionary<Declaration, CLITypeReference> typeReferences; |
||||
private readonly ITypeMapDatabase TypeMapDatabase; |
||||
private TranslationUnit TranslationUnit; |
||||
|
||||
public IEnumerable<CLITypeReference> TypeReferences |
||||
{ |
||||
get { return typeReferences.Values; } |
||||
} |
||||
|
||||
public CLITypeReferenceCollector(ITypeMapDatabase typeMapDatabase) |
||||
{ |
||||
TypeMapDatabase = typeMapDatabase; |
||||
typeReferences = new Dictionary<Declaration,CLITypeReference>(); |
||||
} |
||||
|
||||
public CLITypeReference GetTypeReference(Declaration decl) |
||||
{ |
||||
if(typeReferences.ContainsKey(decl)) |
||||
return typeReferences[decl]; |
||||
|
||||
var @ref = new CLITypeReference(); |
||||
typeReferences.Add(decl, @ref); |
||||
return @ref; |
||||
} |
||||
|
||||
public void Process(Namespace @namespace) |
||||
{ |
||||
var collector = new RecordCollector(@namespace.TranslationUnit); |
||||
@namespace.Visit(collector); |
||||
|
||||
TranslationUnit = @namespace.TranslationUnit; |
||||
|
||||
foreach (var record in collector.Declarations) |
||||
{ |
||||
record.Value.Visit(this); |
||||
GenerateInclude(record); |
||||
ProcessTypeMap(record); |
||||
} |
||||
} |
||||
|
||||
private void ProcessTypeMap(ASTRecord<Declaration> record) |
||||
{ |
||||
TypeMap typeMap; |
||||
if (!TypeMapDatabase.FindTypeMap(record.Value, out typeMap)) return; |
||||
|
||||
// Typemap must explicitly set the include file when one is required.
|
||||
GetTypeReference(record.Value).Include.File = ""; |
||||
|
||||
typeMap.Declaration = record.Value; |
||||
typeMap.CLITypeReference(this, record); |
||||
} |
||||
|
||||
private void GenerateInclude(ASTRecord<Declaration> record) |
||||
{ |
||||
var decl = record.Value; |
||||
if(decl.Namespace == null) |
||||
return; |
||||
|
||||
var declFile = decl.Namespace.TranslationUnit.FileName; |
||||
|
||||
if(decl.Namespace.TranslationUnit.IsSystemHeader) |
||||
return; |
||||
|
||||
if(decl.Ignore) |
||||
return; |
||||
|
||||
if(IsBuiltinTypedef(decl)) |
||||
return; |
||||
|
||||
if (declFile.Contains("String")) |
||||
return; |
||||
|
||||
GetTypeReference(decl).Include = new Include() |
||||
{ |
||||
File = declFile, |
||||
Kind = Include.IncludeKind.Quoted, |
||||
InHeader = IsIncludeInHeader(record) |
||||
}; |
||||
} |
||||
|
||||
private bool IsBuiltinTypedef(Declaration decl) |
||||
{ |
||||
var typedefDecl = decl as TypedefDecl; |
||||
if(typedefDecl == null) return false; |
||||
if(typedefDecl.Type is BuiltinType) return true; |
||||
|
||||
var typedefType = typedefDecl.Type as TypedefType; |
||||
if(typedefType == null) return false; |
||||
if(typedefType.Declaration == null) return false; |
||||
|
||||
return typedefType.Declaration.Type is BuiltinType; |
||||
} |
||||
|
||||
private bool IsIncludeInHeader(ASTRecord<Declaration> record) |
||||
{ |
||||
return record.IsBaseClass() || record.IsFieldValueType(); |
||||
} |
||||
|
||||
public override bool VisitDeclaration(Declaration decl) |
||||
{ |
||||
return ShouldVisitDecl(decl); |
||||
} |
||||
|
||||
public override bool VisitClassDecl(Class @class) |
||||
{ |
||||
if(!ShouldVisitDecl(@class)) |
||||
return false; |
||||
|
||||
if (@class.IsIncomplete && @class.CompleteDeclaration != null) |
||||
@class = (Class) @class.CompleteDeclaration; |
||||
|
||||
var keywords = @class.IsValueType? "value struct" : "ref class"; |
||||
var @ref = string.Format("{0} {1};", keywords, @class.Name); |
||||
|
||||
GetTypeReference(@class).FowardReference = @ref; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public override bool VisitEnumDecl(Enumeration @enum) |
||||
{ |
||||
if(!ShouldVisitDecl(@enum)) |
||||
return false; |
||||
|
||||
var @base = ""; |
||||
if(!@enum.Type.IsPrimitiveType(PrimitiveType.Int32)) |
||||
@base = string.Format(" : {0}", @enum.Type); |
||||
|
||||
var @ref = string.Format("enum struct {0}{1};", @enum.Name, @base); |
||||
|
||||
GetTypeReference(@enum).FowardReference = @ref; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
private bool ShouldVisitDecl(Declaration decl) |
||||
{ |
||||
if(decl.Namespace != null && decl.Namespace.TranslationUnit.IsSystemHeader) |
||||
return false; |
||||
|
||||
if (decl.Ignore) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
@ -1,30 +0,0 @@
@@ -1,30 +0,0 @@
|
||||
using CppSharp.AST; |
||||
|
||||
namespace CppSharp.Passes |
||||
{ |
||||
public class CheckTypeReferencesPass : TranslationUnitPass |
||||
{ |
||||
TypeRefsVisitor typeRefs; |
||||
|
||||
public override bool VisitTranslationUnit(TranslationUnit unit) |
||||
{ |
||||
if (unit.Ignore) |
||||
return false; |
||||
|
||||
if (unit.IsSystemHeader) |
||||
return false; |
||||
|
||||
typeRefs = new TypeRefsVisitor(); |
||||
return typeRefs.VisitTranslationUnit(unit); |
||||
} |
||||
} |
||||
|
||||
public static class CheckTypeReferencesExtensions |
||||
{ |
||||
public static void CheckTypeReferences(this PassBuilder builder) |
||||
{ |
||||
var pass = new CheckTypeReferencesPass(); |
||||
builder.AddPass(pass); |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue