Skip to content

Commit

Permalink
Fix overload operator-> for CallExpression (#1842)
Browse files Browse the repository at this point in the history
* Handle overloaded operator-> for CallExpression

* Add test case for handle overloaded operator-> for CallExpression
  • Loading branch information
peckto authored Nov 20, 2024
1 parent 66aa2da commit 90a1534
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,35 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
}
}

/**
* This function resolves a possible overloaded -> (arrow) operator, for languages which support
* operator overloading. The implicit call to the overloaded operator function is inserted as
* base for the MemberExpression. This can be the case for a [MemberExpression] or
* [MemberCallExpression]
*/
private fun resolveOverloadedArrowOperator(ex: Expression): Type? {
var type: Type? = null
if (
ex.language is HasOperatorOverloading &&
ex is MemberExpression &&
ex.operatorCode == "->" &&
ex.base.type !is PointerType
) {
val result = resolveOperator(ex)
val op = result?.bestViable?.singleOrNull()
if (result?.success == SUCCESSFUL && op is OperatorDeclaration) {
type = op.returnTypes.singleOrNull()?.root ?: unknownType()

// We need to insert a new operator call expression in between
val call = operatorCallFromDeclaration(op, ex)

// Make the call our new base
ex.base = call
}
}
return type
}

protected fun resolveMember(
containingClass: ObjectType,
reference: Reference
Expand All @@ -334,25 +363,8 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
var member: ValueDeclaration? = null
var type: Type = containingClass

// Check for a possible overloaded operator->
if (
reference.language is HasOperatorOverloading &&
reference is MemberExpression &&
reference.operatorCode == "->" &&
reference.base.type !is PointerType
) {
val result = resolveOperator(reference)
val op = result?.bestViable?.singleOrNull()
if (result?.success == SUCCESSFUL && op is OperatorDeclaration) {
type = op.returnTypes.singleOrNull()?.root ?: unknownType()

// We need to insert a new operator call expression in between
val call = operatorCallFromDeclaration(op, reference)

// Make the call our new base
reference.base = call
}
}
// Handle a possible overloaded operator->
type = resolveOverloadedArrowOperator(reference) ?: type

val record = type.recordDeclaration
if (record != null) {
Expand Down Expand Up @@ -398,6 +410,9 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
val callee = call.callee
val language = call.language

// Handle a possible overloaded operator->
resolveOverloadedArrowOperator(callee)

// Dynamic function invokes (such as function pointers) are handled by extra pass, so we are
// not resolving them here.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,4 +306,48 @@ class CXXDeclarationTest {
assertEquals(p, opCall.base)
assertInvokes(opCall, op)
}

@Test
fun testCallExpressionOperator() {
val file = File("src/test/resources/cxx/operators/call_expression.cpp")
val result =
analyze(listOf(file), file.parentFile.toPath(), true) {
it.registerLanguage<CPPLanguage>()
}
assertNotNull(result)

var proxy = result.records["Proxy"]
assertNotNull(proxy)

var funcBar = proxy.functions["bar"]
assertNotNull(funcBar)

var op = proxy.operators["operator->"]
assertNotNull(op)

var data = result.records["Data"]
assertNotNull(data)

var funcFoo = data.functions["foo"]
assertNotNull(funcFoo)

val p = result.refs["p"]
assertNotNull(p)
assertEquals(proxy.toType(), p.type)

var funcFooRef = result.memberExpressions["foo"]
assertNotNull(funcFooRef)
assertRefersTo(funcFooRef, funcFoo)

var funcBarRef = result.memberExpressions["bar"]
assertNotNull(funcBarRef)
assertRefersTo(funcBarRef, funcBar)

// we should now have an implicit call to our operator in-between "p" and "foo"
val opCall = funcFooRef.base
assertNotNull(opCall)
assertIs<OperatorCallExpression>(opCall)
assertEquals(p, opCall.base)
assertInvokes(opCall, op)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
struct Data {
int foo() {
return 1;
}
};

struct Proxy {
Data *data;
Proxy() {
data = new Data;
}
Data* operator->() {
return data;
}
int bar() {
return 1;
}
};

int main() {
Proxy p;

int i = p->foo();
int j = p.bar();
return 1;
}

0 comments on commit 90a1534

Please sign in to comment.