diff --git a/src/AST/Function.cs b/src/AST/Function.cs index ae6d1838..a0f45e08 100644 --- a/src/AST/Function.cs +++ b/src/AST/Function.cs @@ -74,6 +74,16 @@ namespace CppSharp.AST { return visitor.VisitParameterDecl(this); } + + /// + /// HACK: in many cases QualifiedType.Qualifiers.IsConst does not work. + /// It's false in Clang to begin with. I tried fixing it to no avail. + /// I don't have any more time at the moment. + /// + public bool IsConst + { + get { return DebugText.StartsWith("const ", System.StringComparison.Ordinal); } + } } public class ParameterTypeComparer : IEqualityComparer diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index adc2aa42..f1bf97b2 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -568,7 +568,7 @@ std::string Parser::GetTypeName(const clang::Type* Type) return TypeName; } -static TypeQualifiers GetTypeQualifiers(clang::QualType Type) +static TypeQualifiers GetTypeQualifiers(const clang::QualType& Type) { TypeQualifiers quals; quals.IsConst = Type.isLocalConstQualified(); @@ -577,7 +577,7 @@ static TypeQualifiers GetTypeQualifiers(clang::QualType Type) return quals; } -QualifiedType Parser::GetQualifiedType(clang::QualType qual, clang::TypeLoc* TL) +QualifiedType Parser::GetQualifiedType(const clang::QualType& qual, clang::TypeLoc* TL) { QualifiedType qualType; qualType.Type = WalkType(qual, TL); @@ -2276,7 +2276,7 @@ Type* Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL, auto PTL = PVD->getTypeSourceInfo()->getTypeLoc(); FA->Name = PVD->getNameAsString(); - FA->QualifiedType = GetQualifiedType(PVD->getType(), &PTL); + FA->QualifiedType = GetQualifiedType(PVD->getOriginalType(), &PTL); } else { @@ -2807,7 +2807,7 @@ void Parser::WalkFunction(const clang::FunctionDecl* FD, Function* F, HandlePreprocessedEntities(P, paramRange, MacroLocation::FunctionParameters); - P->QualifiedType = GetQualifiedType(VD->getType(), &PTL); + P->QualifiedType = GetQualifiedType(VD->getOriginalType(), &PTL); P->HasDefaultValue = VD->hasDefaultArg(); P->_Namespace = NS; P->Index = VD->getFunctionScopeIndex(); diff --git a/src/CppParser/Parser.h b/src/CppParser/Parser.h index 6f78b913..ba6816d2 100644 --- a/src/CppParser/Parser.h +++ b/src/CppParser/Parser.h @@ -103,7 +103,7 @@ private: std::vector WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, clang::TemplateSpecializationTypeLoc* TSTL); std::vector WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, const clang::ASTTemplateArgumentListInfo* TSTL); void WalkVTable(const clang::CXXRecordDecl* RD, Class* C); - QualifiedType GetQualifiedType(clang::QualType qual, clang::TypeLoc* TL = 0); + QualifiedType GetQualifiedType(const clang::QualType& qual, clang::TypeLoc* TL = 0); void ReadClassLayout(Class* Class, const clang::RecordDecl* RD, clang::CharUnits Offset, bool IncludeVirtualBases); LayoutField WalkVTablePointer(Class* Class, const clang::CharUnits& Offset, const std::string& prefix); VTableLayout WalkVTableLayout(const clang::VTableLayout& VTLayout); diff --git a/src/Generator.Tests/AST/TestAST.cs b/src/Generator.Tests/AST/TestAST.cs index 0a2e4018..d2a19b51 100644 --- a/src/Generator.Tests/AST/TestAST.cs +++ b/src/Generator.Tests/AST/TestAST.cs @@ -19,11 +19,6 @@ namespace CppSharp.Generator.Tests.AST PrimitiveType primitiveType; return type.IsPrimitiveType(out primitiveType) ? primitiveType.ToString() : string.Empty; }; - } - - [SetUp] - public void Setup() - { ParseLibrary("AST.h", "ASTExtensions.h"); } diff --git a/src/Generator/Passes/CheckAmbiguousFunctions.cs b/src/Generator/Passes/CheckAmbiguousFunctions.cs index 6ae4d594..4ce5cb4c 100644 --- a/src/Generator/Passes/CheckAmbiguousFunctions.cs +++ b/src/Generator/Passes/CheckAmbiguousFunctions.cs @@ -1,22 +1,36 @@ using System; using System.Linq; using CppSharp.AST; +using CppSharp.AST.Extensions; namespace CppSharp.Passes { /// /// Checks for ambiguous functions/method declarations. + /// /// Example: - /// + /// /// struct S + /// /// { + /// /// void Foo(int a, int b = 0); + /// /// void Foo(int a); - /// + /// /// void Bar(); + /// /// void Bar() const; - /// }; /// + /// + /// void Qux(int& i); + /// + /// void Qux(int&& i); + /// + /// void Qux(const int& i); + /// + /// }; + /// /// When we call Foo(0) the compiler will not know which call we want and /// will error out so we need to detect this and either ignore the methods /// or flag them such that the generator can explicitly disambiguate when @@ -46,7 +60,8 @@ namespace CppSharp.Passes if (!overload.IsGenerated) continue; if (CheckConstnessForAmbiguity(function, overload) || - CheckDefaultParametersForAmbiguity(function, overload)) + CheckDefaultParametersForAmbiguity(function, overload) || + CheckSingleParameterPointerConstnessForAmbiguity(function, overload)) { function.IsAmbiguous = true; overload.IsAmbiguous = true; @@ -120,5 +135,62 @@ namespace CppSharp.Passes return false; } + + private static bool CheckSingleParameterPointerConstnessForAmbiguity( + Function function, Function overload) + { + var functionParams = function.Parameters.Where( + p => p.Kind == ParameterKind.Regular && p.Type.IsAddress()).ToList(); + // It's difficult to handle this case for more than one parameter + // For example, if we have: + // void f(float&, const int&); + // void f(const float&, int&); + // what should we do? Generate both? Generate the first one encountered? + // Generate the one with the least amount of "complex" parameters? + // So let's just start with the simplest case for the time being + if (functionParams.Count != 1) + return false; + var overloadParams = overload.Parameters.Where( + p => p.Kind == ParameterKind.Regular && p.Type.IsAddress()).ToList(); + if (overloadParams.Count != 1) + return false; + + var parameterFunction = functionParams[0]; + var parameterOverload = overloadParams[0]; + + if (!parameterFunction.Type.GetPointee().Equals(parameterOverload.Type.GetPointee())) + return false; + + if (parameterFunction.IsConst && !parameterOverload.IsConst) + { + function.ExplicitlyIgnore(); + return true; + } + + if (parameterOverload.IsConst && !parameterFunction.IsConst) + { + overload.ExplicitlyIgnore(); + return true; + } + + var pointerParamFunction = (PointerType) parameterFunction.Type; + var pointerParamOverload = (PointerType) parameterOverload.Type; + + if (pointerParamFunction.Modifier == PointerType.TypeModifier.RVReference && + pointerParamOverload.Modifier != PointerType.TypeModifier.RVReference) + { + function.ExplicitlyIgnore(); + return true; + } + + if (pointerParamFunction.Modifier != PointerType.TypeModifier.RVReference && + pointerParamOverload.Modifier == PointerType.TypeModifier.RVReference) + { + overload.ExplicitlyIgnore(); + return true; + } + + return false; + } } } diff --git a/tests/Common/Common.cpp b/tests/Common/Common.cpp index 3b570b07..1df2be3f 100644 --- a/tests/Common/Common.cpp +++ b/tests/Common/Common.cpp @@ -626,4 +626,24 @@ void FuncWithTypeAlias(custom_int_t i) void FuncWithTemplateTypeAlias(TypeAliasTemplate i) { -} \ No newline at end of file +} + +HasOverloadsWithDifferentPointerKindsToSameType::HasOverloadsWithDifferentPointerKindsToSameType() +{ +} + +HasOverloadsWithDifferentPointerKindsToSameType::~HasOverloadsWithDifferentPointerKindsToSameType() +{ +} + +void HasOverloadsWithDifferentPointerKindsToSameType::overload(int& i) +{ +} + +void HasOverloadsWithDifferentPointerKindsToSameType::overload(int&& i) +{ +} + +void HasOverloadsWithDifferentPointerKindsToSameType::overload(const int& i) +{ +} diff --git a/tests/Common/Common.cs b/tests/Common/Common.cs index cb08754e..a4eb0f7d 100644 --- a/tests/Common/Common.cs +++ b/tests/Common/Common.cs @@ -56,6 +56,7 @@ namespace CppSharp.Tests base.Setup(driver); driver.Options.OutputNamespace = "CommonTest"; + driver.Options.UnityBuild = true; } public override void SetupPasses(Driver driver) diff --git a/tests/Common/Common.h b/tests/Common/Common.h index 6633e8c4..6c8f7968 100644 --- a/tests/Common/Common.h +++ b/tests/Common/Common.h @@ -1202,3 +1202,12 @@ enum EmptyEnumsWithSameMemberPrefixAndUnderscore_4 }; +class DLL_API HasOverloadsWithDifferentPointerKindsToSameType +{ +public: + HasOverloadsWithDifferentPointerKindsToSameType(); + ~HasOverloadsWithDifferentPointerKindsToSameType(); + void overload(int& i); + void overload(int&& i); + void overload(const int& i); +};