Skip to content

Commit

Permalink
C-style ranged designators
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Nov 29, 2023
1 parent 5185b4b commit b1f3c8d
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -569,39 +569,33 @@ class ExpressionHandler(lang: CXXLanguageFrontend) :
return newProblemExpression("no designator found")
}

// We need to start with our target (which we need to find in a hacky way) as
// first ref
val baseName =
(((ctx.parent as? IASTInitializerList)?.parent as? IASTInitializer)?.parent
as? IASTDeclarator)
?.name
.toString()
var ref = newReference(baseName)

val lhs =
when (des) {
is CPPASTArrayDesignator -> {
handle(des.subscriptExpression)
val sub = newSubscriptExpression()
sub.arrayExpression = ref
handle(des.subscriptExpression)?.let { sub.subscriptExpression = it }
sub
}
is CPPASTFieldDesignator -> {
// We need to start with our target (which we need to find in a hacky way) as
// first ref
val baseName =
(((ctx.parent as? IASTInitializerList)?.parent as? IASTInitializer)?.parent
as? IASTDeclarator)
?.name
.toString()
var ref = newReference(baseName)
// Then we loop through all designators and chain them. Only field designators
// can be chained in this way
for (field in
ctx.designators.toList().filterIsInstance<CPPASTFieldDesignator>()) {
// the old ref is our new base
ref = newMemberExpression(field.name.toString(), ref, rawNode = des)
ref = newMemberExpression(field.name.toString(), ref, rawNode = field)
}
ref
}
is CPPASTArrayRangeDesignator -> {
val range =
newRangeExpression(
handle(des.rangeFloor),
handle(des.rangeCeiling),
rawNode = des
)
range.operatorCode = "..."
range
}
else -> {
Util.errorWithFileLocation(
frontend,
Expand All @@ -621,47 +615,71 @@ class ExpressionHandler(lang: CXXLanguageFrontend) :
)
}

private fun handleCDesignatedInitializer(ctx: CASTDesignatedInitializer): AssignExpression {
private fun handleCDesignatedInitializer(ctx: CASTDesignatedInitializer): Expression {
val rhs = handle(ctx.operand)
val lhs = ArrayList<Expression>()
if (ctx.designators.isEmpty()) {

// We need to check the first designator first
val des = ctx.designators.firstOrNull()
if (des == null) {
Util.errorWithFileLocation(frontend, ctx, log, "no designator found")
} else {
for (des in ctx.designators) {
var oneLhs: Expression? = null
when (des) {
is CASTArrayDesignator -> {
oneLhs = handle(des.subscriptExpression)
}
is CASTFieldDesignator -> {
oneLhs = newReference(des.name.toString(), unknownType(), rawNode = des)
}
is CASTArrayRangeDesignator -> {
oneLhs =
newRangeExpression(
handle(des.rangeFloor),
handle(des.rangeCeiling),
rawNode = des
)
oneLhs.operatorCode = "..."
}
else -> {
Util.errorWithFileLocation(
frontend,
ctx,
log,
"Unknown designated lhs {}",
des.javaClass.toGenericString()
)
return newProblemExpression("no designator found")
}

// We need to start with our target (which we need to find in a hacky way) as
// first ref
val baseName =
(((ctx.parent as? IASTInitializerList)?.parent as? IASTInitializer)?.parent
as? IASTDeclarator)
?.name
.toString()
var ref = newReference(baseName)

val lhs =
when (des) {
is CASTArrayDesignator -> {
val sub = newSubscriptExpression(rawNode = des)
sub.arrayExpression = ref
handle(des.subscriptExpression)?.let { sub.subscriptExpression = it }
sub
}
is CASTArrayRangeDesignator -> {
val sub = newSubscriptExpression(rawNode = des)
sub.arrayExpression = ref

val range = newRangeExpression(rawNode = des)
des.rangeFloor?.let { range.floor = handle(it) }
des.rangeCeiling?.let { range.ceiling = handle(it) }
range.operatorCode = "..."
sub.subscriptExpression = range
sub
}
is CASTFieldDesignator -> {
// Then we loop through all designators and chain them. Only field designators
// can be chained in this way
for (field in
ctx.designators.toList().filterIsInstance<CPPASTFieldDesignator>()) {
// the old ref is our new base
ref = newMemberExpression(field.name.toString(), ref, rawNode = field)
}
ref
}
if (oneLhs != null) {
lhs.add(oneLhs)
else -> {
Util.errorWithFileLocation(
frontend,
ctx,
log,
"Unknown designated lhs {}",
des.javaClass.toGenericString()
)
null
}
}
}

return newAssignExpression(lhs = lhs, rhs = listOfNotNull(rhs), rawNode = ctx)
return newAssignExpression(
lhs = listOfNotNull(lhs),
rhs = listOfNotNull(rhs),
rawNode = ctx
)
}

private fun handleIntegerLiteral(ctx: IASTLiteralExpression): Expression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,19 @@ internal class CXXLanguageFrontendTest : BaseTest() {
assertTrue(expected.isEmpty(), java.lang.String.join(", ", expected.keys))
}

@Test
@Throws(Exception::class)
fun testCDesignatedInitializer() {
val file = File("src/test/resources/c/designated.c")
val tu =
analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) {
it.registerLanguage<CLanguage>()
}

val foo3 = tu.variables["foo3"]
assertNotNull(foo3)
}

@Test
@Throws(Exception::class)
fun testDesignatedInitializerAsAssignment() {
Expand Down
23 changes: 23 additions & 0 deletions cpg-language-cxx/src/test/resources/c/designated.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
struct Point
{
int x, y, z;
};

struct Outer {
struct Point p;
};

int main()
{
// Examples of initialization using
// designated initialization
struct Point p1 = {.y = 0, .z = 1, .x = 2};
struct Point p2 = {.x = 20};
struct Outer o = {.p.x = 10};
int foo2[10] = { [3] = 1, [5] = 2 };

// This only works in C (!!)
int foo3[10] = { [0 ... 9] = 2 };

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
#include <time.h>
#include <inttypes.h>

struct Outer {
struct Point p;
};

struct Point
{
int x, y, z;
};

struct Outer {
struct Point p;
};

int main()
{
// Examples of initialization using
Expand All @@ -22,8 +22,6 @@ int main()
struct Point p2 = {.x = 20};
struct Outer o = {.p.x = 10};
int foo2[10] = { [3] = 1, [5] = 2 };
// this one is a gcc extension
int foo2[10] = { [0...9] = 2 };

return 0;
}

0 comments on commit b1f3c8d

Please sign in to comment.