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.
 
 
 
 
 

343 lines
13 KiB

using System;
using System.Linq;
using CppSharp.AST.Extensions;
using CppSharp.Types;
namespace CppSharp.AST
{
public static class ASTUtils
{
public static bool CheckIgnoreFunction(Function function)
{
if (!function.IsGenerated) return true;
if (function is Method method)
return CheckIgnoreMethod(method);
return false;
}
public static bool CheckIgnoreMethod(Method method)
{
var originalClass = method.OriginalNamespace as Class;
if (!method.IsGenerated &&
(originalClass == null || method.IsInternal || !originalClass.IsInterface))
return true;
if (method.IsDependent && UsesAdditionalTypeParam(method))
return true;
var isEmptyCtor = method.IsConstructor && method.Parameters.Count == 0;
var @class = method.Namespace as Class;
if (@class != null && @class.IsValueType && isEmptyCtor)
return true;
if (method.IsDestructor)
return true;
if (method.OperatorKind == CXXOperatorKind.Equal)
return true;
if (method.Access == AccessSpecifier.Private && !method.IsOverride && !method.IsExplicitlyGenerated)
return true;
// Ignore copy constructor if a base class don't has or has a private copy constructor
if (method.IsCopyConstructor)
{
var baseClass = @class;
while (baseClass != null && baseClass.HasBaseClass)
{
baseClass = baseClass.BaseClass;
if (!baseClass.IsInterface)
{
var copyConstructor = baseClass.Methods.FirstOrDefault(m => m.IsCopyConstructor);
if (copyConstructor == null ||
copyConstructor.Access == AccessSpecifier.Private ||
(!copyConstructor.IsDeclared &&
!copyConstructor.TranslationUnit.IsSystemHeader))
return true;
}
}
}
return false;
}
public static bool CheckIgnoreField(Field field, bool useInternals = false)
{
if (field.Access == AccessSpecifier.Private && !useInternals)
return true;
if (field.Class.IsValueType && field.IsDeclared)
return false;
return !field.IsGenerated && (!useInternals || !field.IsInternal);
}
public static bool CheckIgnoreProperty(Property prop)
{
if (prop.Access == AccessSpecifier.Private)
return true;
if (prop.Field != null && prop.Field.Class.IsValueType && prop.IsDeclared)
return false;
return !prop.IsGenerated;
}
public static bool CheckTypeForSpecialization(Type type, Declaration container,
Action<ClassTemplateSpecialization> addSpecialization,
ITypeMapDatabase typeMaps, bool internalOnly = false)
{
type = type.Desugar();
type = (type.GetFinalPointee() ?? type).Desugar();
ClassTemplateSpecialization specialization = GetParentSpecialization(type);
if (specialization == null)
return true;
if (IsSpecializationNeeded(container, typeMaps, internalOnly,
type, specialization))
return false;
if (!internalOnly)
{
if (IsSpecializationSelfContained(specialization, container))
return true;
if (IsMappedToPrimitive(typeMaps, type))
return true;
}
if (specialization.Arguments.Select(
a => a.Type.Type).Any(t => t != null &&
!CheckTypeForSpecialization(t, specialization, addSpecialization,
typeMaps, internalOnly)))
return false;
addSpecialization(specialization);
return true;
}
public static bool IsTypeExternal(Module module, Type type)
{
var typeModule = type.GetModule();
return typeModule != null && typeModule.Dependencies.Contains(module);
}
private static bool UsesAdditionalTypeParam(Method method)
{
Class template;
if (method.Namespace is ClassTemplateSpecialization specialization)
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);
});
}
public static bool UnsupportedTemplateArgument(this ClassTemplateSpecialization specialization,
TemplateArgument a, ITypeMapDatabase typeMaps)
{
if (a.Type.Type == null ||
IsTypeExternal(
specialization.TemplatedDecl.TemplatedDecl.TranslationUnit.Module, a.Type.Type))
return true;
var typeIgnoreChecker = new TypeIgnoreChecker(typeMaps);
a.Type.Type.Visit(typeIgnoreChecker);
return typeIgnoreChecker.IsIgnored;
}
private static bool IsSpecializationNeeded(Declaration container,
ITypeMapDatabase typeMaps, bool internalOnly, Type type,
ClassTemplateSpecialization specialization)
{
typeMaps.FindTypeMap(type, out var typeMap);
return (!internalOnly && (((specialization.Ignore ||
specialization.TemplatedDecl.TemplatedClass.Ignore) && typeMap == null) ||
specialization.Arguments.Any(a => specialization.UnsupportedTemplateArgument(a, typeMaps)) ||
container.Namespace == specialization)) ||
(!internalOnly && specialization.TemplatedDecl.TemplatedClass.IsIncomplete) ||
specialization is ClassTemplatePartialSpecialization;
}
private static ClassTemplateSpecialization GetParentSpecialization(Type type)
{
if (type.TryGetDeclaration(out Declaration declaration))
{
ClassTemplateSpecialization specialization;
do
{
specialization = declaration as ClassTemplateSpecialization;
declaration = declaration.Namespace;
} while (declaration != null && specialization == null);
return specialization;
}
return null;
}
private static bool IsSpecializationSelfContained(
ClassTemplateSpecialization specialization, Declaration container)
{
while (container.Namespace != null)
{
if (container.Namespace == specialization)
return true;
container = container.Namespace;
}
return false;
}
public static bool IsMappedToPrimitive(ITypeMapDatabase typeMaps, Type type)
{
if (!typeMaps.FindTypeMap(type, out var typeMap))
return false;
var typePrinterContext = new TypePrinterContext { Type = type };
var mappedTo = typeMap.CSharpSignatureType(typePrinterContext);
mappedTo = mappedTo.Desugar();
mappedTo = (mappedTo.GetFinalPointee() ?? mappedTo).Desugar();
return (mappedTo.IsPrimitiveType() ||
mappedTo.IsPointerToPrimitiveType() || mappedTo.IsEnum());
}
}
public static class Operators
{
public static CXXOperatorArity ClassifyOperator(Function function)
{
switch (function.Parameters.Count)
{
case 0: return CXXOperatorArity.Zero;
case 1: return CXXOperatorArity.Unary;
default: return CXXOperatorArity.Binary;
}
}
public static string GetOperatorOverloadPair(CXXOperatorKind kind)
{
switch (kind)
{
case CXXOperatorKind.EqualEqual:
return "!=";
case CXXOperatorKind.ExclaimEqual:
return "==";
case CXXOperatorKind.Less:
return ">";
case CXXOperatorKind.Greater:
return "<";
case CXXOperatorKind.LessEqual:
return ">=";
case CXXOperatorKind.GreaterEqual:
return "<=";
default:
throw new NotSupportedException();
}
}
public static bool IsBuiltinOperator(CXXOperatorKind kind)
{
GetOperatorIdentifier(kind, out var isBuiltin);
return isBuiltin;
}
public static string GetOperatorIdentifier(CXXOperatorKind kind)
{
return GetOperatorIdentifier(kind, out _);
}
public static string GetOperatorIdentifier(CXXOperatorKind kind,
out bool isBuiltin)
{
isBuiltin = true;
// These follow the order described in MSDN (Overloadable Operators).
switch (kind)
{
// These unary operators can be overloaded
case CXXOperatorKind.Plus: return "operator +";
case CXXOperatorKind.Minus: return "operator -";
case CXXOperatorKind.Exclaim: return "operator !";
case CXXOperatorKind.Tilde: return "operator ~";
case CXXOperatorKind.PlusPlus: return "operator ++";
case CXXOperatorKind.MinusMinus: return "operator --";
// These binary operators can be overloaded
case CXXOperatorKind.Star: return "operator *";
case CXXOperatorKind.Slash: return "operator /";
case CXXOperatorKind.Percent: return "operator %";
case CXXOperatorKind.Amp: return "operator &";
case CXXOperatorKind.Pipe: return "operator |";
case CXXOperatorKind.Caret: return "operator ^";
case CXXOperatorKind.LessLess: return "operator <<";
case CXXOperatorKind.GreaterGreater: return "operator >>";
// The comparison operators can be overloaded
case CXXOperatorKind.EqualEqual: return "operator ==";
case CXXOperatorKind.ExclaimEqual: return "operator !=";
case CXXOperatorKind.Less: return "operator <";
case CXXOperatorKind.Greater: return "operator >";
case CXXOperatorKind.LessEqual: return "operator <=";
case CXXOperatorKind.GreaterEqual: return "operator >=";
// Assignment operators cannot be overloaded
case CXXOperatorKind.PlusEqual:
case CXXOperatorKind.MinusEqual:
case CXXOperatorKind.StarEqual:
case CXXOperatorKind.SlashEqual:
case CXXOperatorKind.PercentEqual:
case CXXOperatorKind.AmpEqual:
case CXXOperatorKind.PipeEqual:
case CXXOperatorKind.CaretEqual:
case CXXOperatorKind.LessLessEqual:
case CXXOperatorKind.GreaterGreaterEqual:
// The array indexing operator cannot be overloaded
case CXXOperatorKind.Subscript:
// The conditional logical operators cannot be overloaded
case CXXOperatorKind.AmpAmp:
case CXXOperatorKind.PipePipe:
// These operators cannot be overloaded.
case CXXOperatorKind.Equal:
case CXXOperatorKind.Comma:
case CXXOperatorKind.ArrowStar:
case CXXOperatorKind.Arrow:
case CXXOperatorKind.Call:
case CXXOperatorKind.Conditional:
case CXXOperatorKind.Coawait:
case CXXOperatorKind.New:
case CXXOperatorKind.Delete:
case CXXOperatorKind.Array_New:
case CXXOperatorKind.Array_Delete:
isBuiltin = false;
return "Operator" + kind.ToString();
case CXXOperatorKind.Conversion:
return "implicit operator";
case CXXOperatorKind.ExplicitConversion:
return "explicit operator";
}
throw new NotSupportedException();
}
}
}