Skip to content

Commit

Permalink
resolving -> in a very hacky way
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Jun 29, 2024
1 parent 127be5f commit 8398eac
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ import org.neo4j.ogm.annotation.Relationship
* example would be a [CallExpression], which is resolved to a [FunctionDeclaration]. but if
* languages have the trait [HasOperatorOverloading], also operators, such as an [UnaryOperator]
*/
abstract class ResolvableExpression<T : FunctionDeclaration> : Expression(), HasType.TypeObserver {
abstract class ResolvableExpression<T : FunctionDeclaration> :
Expression(), HasBase, HasType.TypeObserver {
abstract val signature: List<Type>

abstract val arguments: List<Expression>?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,10 @@ open class CallExpression : ResolvableExpression<FunctionDeclaration>(), Argumen
// TODO: Not sure if we can add the template, templateParameters, templateInstantiation fields
// here
override fun hashCode() = Objects.hash(super.hashCode(), arguments)

override val base: Expression?
get() = null

override val operatorCode: String?
get() = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class UnaryOperator :
override val arguments: List<Expression>?
get() = null

override val base: Expression?
get() = this

private fun changeExpressionAccess() {
var access = AccessValues.READ
if (operatorCode == "++" || operatorCode == "--") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,56 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
return null
}
var member: ValueDeclaration? = null
val record = containingClass.recordDeclaration
var type = containingClass

// Check for a possible overloaded operator-> (C++ only?!)
if (
reference.language is HasOperatorOverloading &&
reference is MemberExpression &&
reference.operatorCode == "->" &&
reference.base.type !is PointerType
) {
var emptySignature =
object : ResolvableExpression<OperatorDeclaration>() {
override val signature: List<Type>
get() = listOf()

override val arguments: List<Expression>?
get() = null

override var language: Language<*>? = reference.language

override fun typeChanged(
newType: Type,
src: HasType,
) {}

override fun assignedTypeChanged(
assignedTypes: Set<Type>,
src: HasType,
) {}

override val base: Expression?
get() = reference.base

override val operatorCode: String?
get() = "->"
}
var op =
resolveCalleeByName("operator->", emptySignature)
.filterIsInstance<OperatorDeclaration>()
.singleOrNull()

// For now, we just re-direct the containing class, but we should actually model an
// implicit call to our operator in between
if (op != null) {
type = op.returnTypes.singleOrNull()?.root ?: unknownType()
// rather hacky
reference.name = type.root.name.fqn(reference.name.localName)
}
}

val record = type.recordDeclaration
if (record != null) {
member =
record.fields
Expand All @@ -418,7 +467,7 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
}
if (member == null) {
member =
containingClass.superTypes
type.superTypes
.flatMap { it.recordDeclaration?.fields ?: listOf() }
.filter { it.name.localName == reference.name.localName }
.map { it.definition }
Expand Down Expand Up @@ -894,21 +943,19 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
possibleTypes.add(base.type)
possibleTypes.addAll(base.assignedTypes)
}
} else if (call is UnaryOperator) {
bestGuess = call.type
possibleTypes.add(call.type)
possibleTypes.addAll(call.assignedTypes)
} else if (call is BinaryOperator) {
bestGuess = call.lhs.type
possibleTypes.add(call.lhs.type)
possibleTypes.addAll(call.lhs.assignedTypes)
} else {
} else if (call is CallExpression) {
// This could be a C++ member call with an implicit this (which we do not create), so
// let's add the current class to the possible list
scopeManager.currentRecord?.toType()?.let {
bestGuess = it
possibleTypes.add(it)
}
} else {
call.base?.let { base ->
bestGuess = base.type
possibleTypes.add(base.type)
possibleTypes.addAll(base.assignedTypes)
}
}

return Pair(possibleTypes, bestGuess)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,27 @@ class CXXDeclarationTest {
assertNotNull(binaryOp1)
assertInvokes(binaryOp1, plus.getOrNull(1))
}

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

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

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

var size = data.fields["size"]
assertNotNull(size)

var sizeRef = result.memberExpressions["size"]
assertNotNull(sizeRef)
assertRefersTo(sizeRef, size)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Data {
public:
int size;
};

class Proxy {
public:
Proxy() {
this->data = new Data();
}

Data* operator->() {
return data;
}

Data* data;
};

int main() {
Proxy p;
int size = p->size;
}

0 comments on commit 8398eac

Please sign in to comment.