diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index cfea4bcf..eb5eb556 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -37,42 +37,57 @@ namespace Cpp { using TInterp_t = void*; using TCppObject_t = void*; - enum BinaryOperator { - PtrMemD = 0, - PtrMemI, - Mul, - Div, - Rem, - Add, - Sub, - Shl, - Shr, - Cmp, - LT, - GT, - LE, - GE, - EQ, - NE, - And, - Xor, - Or, - LAnd, - LOr, - Assign, - MulAssign, - DivAssign, - RemAssign, - AddAssign, - SubAssign, - ShlAssign, - ShrAssign, - AndAssign, - XorAssign, - OrAssign, - Comma, + enum Operator { + OP_None, + OP_New, + OP_Delete, + OP_Array_New, + OP_Array_Delete, + OP_Plus, + OP_Minus, + OP_Star, + OP_Slash, + OP_Percent, + OP_Caret, + OP_Amp, + OP_Pipe, + OP_Tilde, + OP_Exclaim, + OP_Equal, + OP_Less, + OP_Greater, + OP_PlusEqual, + OP_MinusEqual, + OP_StarEqual, + OP_SlashEqual, + OP_PercentEqual, + OP_CaretEqual, + OP_AmpEqual, + OP_PipeEqual, + OP_LessLess, + OP_GreaterGreater, + OP_LessLessEqual, + OP_GreaterGreaterEqual, + OP_EqualEqual, + OP_ExclaimEqual, + OP_LessEqual, + OP_GreaterEqual, + OP_Spaceship, + OP_AmpAmp, + OP_PipePipe, + OP_PlusPlus, + OP_MinusMinus, + OP_Comma, + OP_ArrowStar, + OP_Arrow, + OP_Call, + OP_Subscript, + OP_Conditional, + OP_Coawait, }; + enum OperatorArity { kUnary = 1, kBinary, kBoth }; + /// A class modeling function calls for functions produced by the interpreter /// in compiled code. It provides an information if we are calling a standard /// function, constructor or destructor. @@ -513,9 +528,13 @@ namespace Cpp { CPPINTEROP_API std::string GetFunctionArgName(TCppFunction_t func, TCppIndex_t param_index); - ///\returns function that performs operation op on lc and rc - void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, - std::vector& operators); + ///\returns arity of the operator or kNone + OperatorArity GetOperatorArity(TCppFunction_t op); + + ///\returns list of operator overloads + void GetOperator(TCppScope_t scope, Operator op, + std::vector& operators, + OperatorArity kind = kBoth); /// Creates an instance of the interpreter we need for the various interop /// services. diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index e25ee9a2..eaef806b 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -3315,22 +3315,43 @@ namespace Cpp { return PI->getNameAsString(); } - void GetBinaryOperator(TCppScope_t scope, enum BinaryOperator op, - std::vector& operators) { - Decl* D = static_cast(scope); - auto* DC = llvm::dyn_cast(D); - Scope* S = getSema().getScopeForContext(DC); - if (!S) - return; - - clang::UnresolvedSet<8> lookup; + OperatorArity GetOperatorArity(TCppFunction_t op) { + Decl* D = static_cast(op); + if (auto* FD = llvm::dyn_cast(D)) { + if (FD->isOverloadedOperator()) { + switch (FD->getOverloadedOperator()) { +#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, \ + MemberOnly) \ + case OO_##Name: \ + if ((Unary) && (Binary)) \ + return kBoth; \ + if (Unary) \ + return kUnary; \ + if (Binary) \ + return kBinary; \ + break; +#include "clang/Basic/OperatorKinds.def" + default: + break; + } + } + } + return (OperatorArity)~0U; + } - getSema().LookupBinOp(S, SourceLocation(), (clang::BinaryOperatorKind)op, - lookup); + void GetOperator(TCppScope_t scope, Operator op, + std::vector& operators, OperatorArity kind) { + Decl* D = static_cast(scope); + if (auto* DC = llvm::dyn_cast_or_null(D)) { + ASTContext& C = getSema().getASTContext(); + DeclContextLookupResult Result = + DC->lookup(C.DeclarationNames.getCXXOperatorName( + (clang::OverloadedOperatorKind)op)); - for (NamedDecl* D : lookup) { - if (auto* FD = llvm::dyn_cast(D)) - operators.push_back(FD); + for (auto* i : Result) { + if (kind & GetOperatorArity(i)) + operators.push_back(i); + } } } diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 6de4a68e..88cd133f 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -967,7 +967,7 @@ TEST(ScopeReflectionTest, IncludeVector) { Interp->process(code); } -TEST(ScopeReflectionTest, GetBinaryOperator) { +TEST(ScopeReflectionTest, GetOperator) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -988,6 +988,8 @@ TEST(ScopeReflectionTest, GetBinaryOperator) { return MyClass(lhs.x + rhs.x); } + namespace extra_ops { + MyClass operator+(MyClass lhs, int rhs) { return MyClass(lhs.x + rhs); } @@ -995,20 +997,46 @@ TEST(ScopeReflectionTest, GetBinaryOperator) { MyClass operator+(int lhs, MyClass rhs) { return MyClass(lhs + rhs.x); } + + MyClass operator~(MyClass self) { + return MyClass(-self.x); + } + + } )"; Cpp::Declare(code.c_str()); std::vector ops; - Cpp::GetBinaryOperator(Cpp::GetGlobalScope(), Cpp::BinaryOperator::Add, ops); - EXPECT_EQ(ops.size(), 3); + Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Plus, ops); + EXPECT_EQ(ops.size(), 1); + ops.clear(); + + Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Minus, ops); + EXPECT_EQ(ops.size(), 1); + ops.clear(); + + Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Star, ops); + EXPECT_EQ(ops.size(), 0); + ops.clear(); + + // operators defined within a namespace + Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Plus, ops); + EXPECT_EQ(ops.size(), 2); + ops.clear(); + + // unary operator + Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops); + EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetBinaryOperator(Cpp::GetGlobalScope(), Cpp::BinaryOperator::Sub, ops); + Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops, + Cpp::OperatorArity::kUnary); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetBinaryOperator(Cpp::GetGlobalScope(), Cpp::BinaryOperator::Mul, ops); + Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops, + Cpp::OperatorArity::kBinary); EXPECT_EQ(ops.size(), 0); }