Tools and libraries to glue C/C++ APIs to high-level languages
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.
 
 
 
 
 

896 lines
32 KiB

using System;
using System.Linq;
using System.Text;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Types;
using Delegate = CppSharp.AST.Delegate;
using Type = CppSharp.AST.Type;
namespace CppSharp.Generators.CLI
{
public class CLIMarshalNativeToManagedPrinter : MarshalPrinter<MarshalContext>
{
public CLIMarshalNativeToManagedPrinter(MarshalContext marshalContext)
: base(marshalContext)
{
}
public override bool VisitType(Type type, TypeQualifiers quals)
{
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && typeMap.DoesMarshalling)
{
typeMap.CLIMarshalToManaged(Context);
return false;
}
return true;
}
public override bool VisitTagType(TagType tag, TypeQualifiers quals)
{
if (!VisitType(tag, quals))
return false;
var decl = tag.Declaration;
return decl.Visit(this);
}
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
switch (array.SizeType)
{
case ArrayType.ArraySize.Constant:
string value = Generator.GeneratedIdentifier("array") + Context.ParameterIndex;
Context.Before.WriteLine("cli::array<{0}>^ {1} = nullptr;", array.Type, value, array.Size);
Context.Before.WriteLine("if ({0} != 0)", Context.ReturnVarName);
Context.Before.WriteOpenBraceAndIndent();
Context.Before.WriteLine("{0} = gcnew cli::array<{1}>({2});", value, array.Type, array.Size);
Context.Before.WriteLine("for (int i = 0; i < {0}; i++)", array.Size);
if (array.Type.IsPointerToPrimitiveType(PrimitiveType.Void))
Context.Before.WriteLineIndent("{0}[i] = new ::System::IntPtr({1}[i]);",
value, Context.ReturnVarName);
else
Context.Before.WriteLineIndent("{0}[i] = {1}[i];", value, Context.ReturnVarName);
Context.Before.UnindentAndWriteCloseBrace();
Context.Return.Write(value);
break;
case ArrayType.ArraySize.Incomplete:
// const char* and const char[] are the same so we can use a string
if (array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) &&
array.QualifiedType.Qualifiers.IsConst)
return VisitPointerType(new PointerType
{
QualifiedPointee = array.QualifiedType
}, quals);
goto case ArrayType.ArraySize.Variable;
case ArrayType.ArraySize.Variable:
Context.Return.Write("nullptr");
break;
}
return true;
}
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var delegateType = function.ToString();
Context.Return.Write("safe_cast<{0}>(", delegateType + "^");
Context.Return.Write("System::Runtime::InteropServices::Marshal::");
Context.Return.Write("GetDelegateForFunctionPointer(");
Context.Return.Write("System::IntPtr({0}), {1}::typeid))", Context.ReturnVarName,
delegateType.TrimEnd('^'));
return true;
}
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
if (!VisitType(pointer, quals))
return false;
var pointee = pointer.Pointee.Desugar();
if (pointee.IsPrimitiveType(PrimitiveType.Void))
{
Context.Return.Write("::System::IntPtr({0})", Context.ReturnVarName);
return true;
}
if (pointer.IsConstCharString())
{
Context.Return.Write(MarshalStringToManaged(Context.ReturnVarName,
pointer.Pointee.Desugar() as BuiltinType));
return true;
}
PrimitiveType primitive;
var param = Context.Parameter;
if (param != null && (param.IsOut || param.IsInOut) &&
pointee.IsPrimitiveType(out primitive))
{
Context.Return.Write(Context.ReturnVarName);
return true;
}
if (pointee.IsPrimitiveType(out primitive))
{
var returnVarName = Context.ReturnVarName;
if (pointer.GetFinalQualifiedPointee().Qualifiers.IsConst !=
Context.ReturnType.Qualifiers.IsConst)
{
var nativeTypePrinter = new CppTypePrinter { PrintTypeQualifiers = false };
var returnType = Context.ReturnType.Type.Desugar();
var constlessPointer = new PointerType()
{
IsDependent = pointer.IsDependent,
Modifier = pointer.Modifier,
QualifiedPointee = new QualifiedType(returnType.GetPointee())
};
var nativeConstlessTypeName = constlessPointer.Visit(nativeTypePrinter, new TypeQualifiers());
returnVarName = string.Format("const_cast<{0}>({1})",
nativeConstlessTypeName, Context.ReturnVarName);
}
if (pointer.Pointee is TypedefType)
{
var desugaredPointer = new PointerType()
{
IsDependent = pointer.IsDependent,
Modifier = pointer.Modifier,
QualifiedPointee = new QualifiedType(pointee)
};
var nativeTypePrinter = new CppTypePrinter();
var nativeTypeName = desugaredPointer.Visit(nativeTypePrinter, quals);
Context.Return.Write("reinterpret_cast<{0}>({1})", nativeTypeName,
returnVarName);
}
else
Context.Return.Write(returnVarName);
return true;
}
TypeMap typeMap = null;
Context.Context.TypeMaps.FindTypeMap(pointee, out typeMap);
Class @class;
if (pointee.TryGetClass(out @class) && typeMap == null)
{
var instance = (pointer.IsReference) ? "&" + Context.ReturnVarName
: Context.ReturnVarName;
WriteClassInstance(@class, instance);
return true;
}
return pointer.QualifiedPointee.Visit(this);
}
private string MarshalStringToManaged(string varName, BuiltinType type)
{
var encoding = type.Type == PrimitiveType.Char ?
Encoding.ASCII : Encoding.Unicode;
if (Equals(encoding, Encoding.ASCII))
encoding = Context.Context.Options.Encoding;
string param;
if (Equals(encoding, Encoding.ASCII))
param = "E_UTF8";
else if (Equals(encoding, Encoding.Unicode) ||
Equals(encoding, Encoding.BigEndianUnicode))
param = "E_UTF16";
else
throw new NotSupportedException(string.Format("{0} is not supported yet.",
Context.Context.Options.Encoding.EncodingName));
return string.Format(
"({0} == 0 ? nullptr : clix::marshalString<clix::{1}>({0}))",
varName, param);
}
public override bool VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
return false;
}
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public bool VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Void:
return true;
case PrimitiveType.Bool:
case PrimitiveType.Char:
case PrimitiveType.Char16:
case PrimitiveType.WideChar:
case PrimitiveType.SChar:
case PrimitiveType.UChar:
case PrimitiveType.Short:
case PrimitiveType.UShort:
case PrimitiveType.Int:
case PrimitiveType.UInt:
case PrimitiveType.Long:
case PrimitiveType.ULong:
case PrimitiveType.LongLong:
case PrimitiveType.ULongLong:
case PrimitiveType.Float:
case PrimitiveType.Double:
case PrimitiveType.LongDouble:
case PrimitiveType.Null:
Context.Return.Write(Context.ReturnVarName);
return true;
}
throw new NotSupportedException();
}
public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(decl.Type, out typeMap) &&
typeMap.DoesMarshalling)
{
typeMap.Type = typedef;
typeMap.CLIMarshalToManaged(Context);
return typeMap.IsValueType;
}
FunctionType function;
if (decl.Type.IsPointerTo(out function))
{
Context.Return.Write($"{Context.ReturnVarName} == nullptr ? nullptr : safe_cast<{typedef}>(");
Context.Return.Write("System::Runtime::InteropServices::Marshal::");
Context.Return.Write("GetDelegateForFunctionPointer(");
Context.Return.Write("IntPtr({0}), {1}::typeid))",Context.ReturnVarName,
typedef.ToString().TrimEnd('^'));
return true;
}
return decl.Type.Visit(this);
}
public override bool VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(template, out typeMap) && typeMap.DoesMarshalling)
{
typeMap.Type = template;
typeMap.CLIMarshalToManaged(Context);
return true;
}
return template.Template.Visit(this);
}
public override bool VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public override bool VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public override bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public override bool VisitClassDecl(Class @class)
{
if (@class.CompleteDeclaration != null)
return VisitClassDecl(@class.CompleteDeclaration as Class);
var instance = string.Empty;
if (!Context.ReturnType.Type.IsPointer())
instance += "&";
instance += Context.ReturnVarName;
var needsCopy = Context.MarshalKind != MarshalKind.NativeField;
if (@class.IsRefType && needsCopy)
{
var name = Generator.GeneratedIdentifier(Context.ReturnVarName);
Context.Before.WriteLine("auto {0} = new ::{1}({2});", name,
@class.QualifiedOriginalName, Context.ReturnVarName);
instance = name;
}
WriteClassInstance(@class, instance);
return true;
}
public string QualifiedIdentifier(Declaration decl)
{
if (!string.IsNullOrEmpty(decl.TranslationUnit.Module.OutputNamespace))
return string.Format("{0}::{1}", decl.TranslationUnit.Module.OutputNamespace,
decl.QualifiedName);
return string.Format("{0}", decl.QualifiedName);
}
public void WriteClassInstance(Class @class, string instance)
{
if (@class.IsRefType)
Context.Return.Write("({0} == nullptr) ? nullptr : gcnew ",
instance);
Context.Return.Write("{0}(", QualifiedIdentifier(@class));
Context.Return.Write("(::{0}*)", @class.QualifiedOriginalName);
Context.Return.Write("{0})", instance);
}
public override bool VisitFieldDecl(Field field)
{
return field.Type.Visit(this);
}
public override bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public override bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public override bool VisitParameterDecl(Parameter parameter)
{
Context.Parameter = parameter;
var ret = parameter.Type.Visit(this, parameter.QualifiedType.Qualifiers);
Context.Parameter = null;
return ret;
}
public override bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public override bool VisitEnumDecl(Enumeration @enum)
{
Context.Return.Write("({0}){1}", ToCLITypeName(@enum),
Context.ReturnVarName);
return true;
}
public override bool VisitVariableDecl(Variable variable)
{
return variable.Type.Visit(this, variable.QualifiedType.Qualifiers);
}
private string ToCLITypeName(Declaration decl)
{
var typePrinter = new CLITypePrinter(Context.Context);
return typePrinter.VisitDeclaration(decl).ToString();
}
public override bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public override bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
return template.TemplatedFunction.Visit(this);
}
public override bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
public override bool VisitNamespace(Namespace @namespace)
{
throw new NotImplementedException();
}
public override bool VisitEvent(Event @event)
{
throw new NotImplementedException();
}
public bool VisitDelegate(Delegate @delegate)
{
throw new NotImplementedException();
}
}
public class CLIMarshalManagedToNativePrinter : MarshalPrinter<MarshalContext>
{
public readonly TextGenerator VarPrefix;
public readonly TextGenerator ArgumentPrefix;
public CLIMarshalManagedToNativePrinter(MarshalContext ctx)
: base(ctx)
{
VarPrefix = new TextGenerator();
ArgumentPrefix = new TextGenerator();
Context.MarshalToNative = this;
}
public override bool VisitType(Type type, TypeQualifiers quals)
{
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && typeMap.DoesMarshalling)
{
typeMap.CLIMarshalToNative(Context);
return false;
}
return true;
}
public override bool VisitTagType(TagType tag, TypeQualifiers quals)
{
if (!VisitType(tag, quals))
return false;
var decl = tag.Declaration;
return decl.Visit(this);
}
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
if (!VisitType(array, quals))
return false;
switch (array.SizeType)
{
case ArrayType.ArraySize.Constant:
if (string.IsNullOrEmpty(Context.ReturnVarName))
{
const string pinnedPtr = "__pinnedPtr";
Context.Before.WriteLine("cli::pin_ptr<{0}> {1} = &{2}[0];",
array.Type, pinnedPtr, Context.Parameter.Name);
const string arrayPtr = "__arrayPtr";
Context.Before.WriteLine("{0}* {1} = {2};", array.Type, arrayPtr, pinnedPtr);
Context.Return.Write("({0} (&)[{1}]) {2}", array.Type, array.Size, arrayPtr);
}
else
{
var supportBefore = Context.Before;
supportBefore.WriteLine("if ({0} != nullptr)", Context.ArgName);
supportBefore.WriteOpenBraceAndIndent();
supportBefore.WriteLine("for (int i = 0; i < {0}; i++)", array.Size);
supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};",
Context.ReturnVarName, Context.ArgName,
array.Type.IsPointerToPrimitiveType(PrimitiveType.Void) ? ".ToPointer()" : string.Empty);
supportBefore.UnindentAndWriteCloseBrace();
}
break;
default:
Context.Return.Write("null");
break;
}
return true;
}
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var returnType = function.ReturnType;
return returnType.Visit(this);
}
public bool VisitDelegateType(string type)
{
// We marshal function pointer types by calling
// GetFunctionPointerForDelegate to get a native function
// pointer ouf of the delegate. Then we can pass it in the
// native call. Since references are not tracked in the
// native side, we need to be careful and protect it with an
// explicit GCHandle if necessary.
var sb = new StringBuilder();
sb.AppendFormat("static_cast<{0}>(", type);
sb.Append("System::Runtime::InteropServices::Marshal::");
sb.Append("GetFunctionPointerForDelegate(");
sb.AppendFormat("{0}).ToPointer())", Context.Parameter.Name);
Context.Return.Write(sb.ToString());
return true;
}
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
if (!VisitType(pointer, quals))
return false;
var pointee = pointer.Pointee.Desugar();
if ((pointee.IsPrimitiveType(PrimitiveType.Char) ||
pointee.IsPrimitiveType(PrimitiveType.WideChar)) &&
pointer.QualifiedPointee.Qualifiers.IsConst)
{
Context.Before.WriteLine(
"auto _{0} = clix::marshalString<clix::E_UTF8>({1});",
Context.ArgName, Context.Parameter.Name);
Context.Return.Write("_{0}.c_str()", Context.ArgName);
return true;
}
if (pointee is FunctionType)
{
var cppTypePrinter = new CppTypePrinter();
var cppTypeName = pointer.Visit(cppTypePrinter, quals);
return VisitDelegateType(cppTypeName);
}
Enumeration @enum;
if (pointee.TryGetEnum(out @enum))
{
var isRef = Context.Parameter.Usage == ParameterUsage.Out ||
Context.Parameter.Usage == ParameterUsage.InOut;
ArgumentPrefix.Write("&");
Context.Return.Write("(::{0}){1}{2}", @enum.QualifiedOriginalName,
isRef ? string.Empty : "*", Context.Parameter.Name);
return true;
}
Class @class;
if (pointee.TryGetClass(out @class) && @class.IsValueType)
{
if (Context.Function == null)
Context.Return.Write("&");
return pointer.QualifiedPointee.Visit(this);
}
var finalPointee = pointer.GetFinalPointee();
if (finalPointee.IsPrimitiveType())
{
var cppTypePrinter = new CppTypePrinter();
var cppTypeName = pointer.Visit(cppTypePrinter, quals);
Context.Return.Write("({0})", cppTypeName);
Context.Return.Write(Context.Parameter.Name);
return true;
}
return pointer.QualifiedPointee.Visit(this);
}
public override bool VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
return false;
}
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public bool VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Void:
return true;
case PrimitiveType.Bool:
case PrimitiveType.Char:
case PrimitiveType.UChar:
case PrimitiveType.Short:
case PrimitiveType.UShort:
case PrimitiveType.Int:
case PrimitiveType.UInt:
case PrimitiveType.Long:
case PrimitiveType.ULong:
case PrimitiveType.LongLong:
case PrimitiveType.ULongLong:
case PrimitiveType.Float:
case PrimitiveType.Double:
Context.Return.Write(Context.Parameter.Name);
return true;
}
return false;
}
public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(decl.Type, out typeMap) &&
typeMap.DoesMarshalling)
{
typeMap.CLIMarshalToNative(Context);
return typeMap.IsValueType;
}
FunctionType func;
if (decl.Type.IsPointerTo(out func))
{
// Use the original typedef name if available, otherwise just use the function pointer type
string cppTypeName;
if (!decl.IsSynthetized)
cppTypeName = "::" + typedef.Declaration.QualifiedOriginalName;
else
{
var cppTypePrinter = new CppTypePrinter();
cppTypeName = decl.Type.Visit(cppTypePrinter, quals);
}
VisitDelegateType(cppTypeName);
return true;
}
PrimitiveType primitive;
if (decl.Type.IsPrimitiveType(out primitive))
{
Context.Return.Write("(::{0})", typedef.Declaration.QualifiedOriginalName);
}
return decl.Type.Visit(this);
}
public override bool VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(template, out typeMap) && typeMap.DoesMarshalling)
{
typeMap.Type = template;
typeMap.CLIMarshalToNative(Context);
return true;
}
return template.Template.Visit(this);
}
public override bool VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals)
{
Context.Return.Write(param.Parameter.Name);
return true;
}
public override bool VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public override bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public override bool VisitClassDecl(Class @class)
{
if (@class.CompleteDeclaration != null)
return VisitClassDecl(@class.CompleteDeclaration as Class);
if (@class.IsValueType)
{
MarshalValueClass(@class);
}
else
{
MarshalRefClass(@class);
}
return true;
}
private void MarshalRefClass(Class @class)
{
var type = Context.Parameter.Type.Desugar();
TypeMap typeMap;
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) &&
typeMap.DoesMarshalling)
{
typeMap.CLIMarshalToNative(Context);
return;
}
var method = Context.Function as Method;
if (type.IsReference() && (method == null ||
// redundant for comparison operators, they are handled in a special way
(method.OperatorKind != CXXOperatorKind.EqualEqual &&
method.OperatorKind != CXXOperatorKind.ExclaimEqual)))
{
Context.Before.WriteLine("if (ReferenceEquals({0}, nullptr))", Context.Parameter.Name);
Context.Before.WriteLineIndent(
"throw gcnew ::System::ArgumentNullException(\"{0}\", " +
"\"Cannot be null because it is a C++ reference (&).\");",
Context.Parameter.Name);
}
if (!type.SkipPointerRefs().IsPointer())
{
Context.Return.Write("*");
if (Context.Parameter.Type.IsReference())
VarPrefix.Write("&");
}
if (method != null
&& method.Conversion == MethodConversionKind.FunctionToInstanceMethod
&& Context.ParameterIndex == 0)
{
Context.Return.Write("(::{0}*)", @class.QualifiedOriginalName);
Context.Return.Write("NativePtr");
return;
}
Context.Return.Write("(::{0}*)", @class.QualifiedOriginalName);
Context.Return.Write("{0}->NativePtr", Context.Parameter.Name);
}
public void MarshalValueClass(Class @class)
{
var marshalVar = Context.MarshalVarPrefix + "_marshal" +
Context.ParameterIndex++;
Context.Before.WriteLine("auto {0} = ::{1}();", marshalVar,
@class.QualifiedOriginalName);
MarshalValueClassProperties(@class, marshalVar);
Context.Return.Write(marshalVar);
var param = Context.Parameter;
if (param.Kind == ParameterKind.OperatorParameter)
return;
if (param.Type.IsPointer())
ArgumentPrefix.Write("&");
}
public void MarshalValueClassProperties(Class @class, string marshalVar)
{
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared))
{
MarshalValueClassProperties(@base.Class, marshalVar);
}
foreach (var property in @class.Properties.Where( p => !ASTUtils.CheckIgnoreProperty(p)))
{
if (property.Field == null)
continue;
MarshalValueClassProperty(property, marshalVar);
}
}
private void MarshalValueClassProperty(Property property, string marshalVar)
{
var fieldRef = string.Format("{0}.{1}", Context.Parameter.Name,
property.Name);
var marshalCtx = new MarshalContext(Context.Context, Context.Indentation)
{
ArgName = fieldRef,
ParameterIndex = Context.ParameterIndex++,
MarshalVarPrefix = Context.MarshalVarPrefix
};
var marshal = new CLIMarshalManagedToNativePrinter(marshalCtx);
property.Visit(marshal);
Context.ParameterIndex = marshalCtx.ParameterIndex;
if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
Context.Before.Write(marshal.Context.Before);
Type type;
Class @class;
var isRef = property.Type.IsPointerTo(out type) &&
!(type.TryGetClass(out @class) && @class.IsValueType) &&
!type.IsPrimitiveType();
if (isRef)
{
Context.Before.WriteLine("if ({0} != nullptr)", fieldRef);
Context.Before.Indent();
}
Context.Before.WriteLine("{0}.{1} = {2};", marshalVar,
property.Field.OriginalName, marshal.Context.Return);
if (isRef)
Context.Before.Unindent();
}
public override bool VisitFieldDecl(Field field)
{
Context.Parameter = new Parameter
{
Name = Context.ArgName,
QualifiedType = field.QualifiedType
};
return field.Type.Visit(this);
}
public override bool VisitProperty(Property property)
{
Context.Parameter = new Parameter
{
Name = Context.ArgName,
QualifiedType = property.QualifiedType
};
return base.VisitProperty(property);
}
public override bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public override bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public override bool VisitParameterDecl(Parameter parameter)
{
return parameter.Type.Visit(this);
}
public override bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public override bool VisitEnumDecl(Enumeration @enum)
{
Context.Return.Write("(::{0}){1}", @enum.QualifiedOriginalName,
Context.Parameter.Name);
return true;
}
public override bool VisitVariableDecl(Variable variable)
{
throw new NotImplementedException();
}
public override bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public override bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
return template.TemplatedFunction.Visit(this);
}
public override bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
public override bool VisitNamespace(Namespace @namespace)
{
throw new NotImplementedException();
}
public override bool VisitEvent(Event @event)
{
throw new NotImplementedException();
}
public bool VisitDelegate(Delegate @delegate)
{
throw new NotImplementedException();
}
}
}