Skip to content

Commit

Permalink
Better detection of typedefs in C++
Browse files Browse the repository at this point in the history
Still not really perfect and has some other issues still, so still draft for now
  • Loading branch information
oxisto committed Dec 12, 2024
1 parent f1cb0dc commit 075cc40
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -242,18 +242,18 @@ class DeclarationHandler(lang: CXXLanguageFrontend) :
*/
private val IASTSimpleDeclaration.isTypedef: Boolean
get() {
return if (this.rawSignature.contains("typedef")) {
if (this.declSpecifier is CPPASTCompositeTypeSpecifier) {
// we need to make a difference between structs that have typedefs and structs
// that are typedefs themselves
this.declSpecifier.toString() == "struct" &&
this.rawSignature.trim().startsWith("typedef")
return if (this.declSpecifier is IASTCompositeTypeSpecifier) {
// This is very stupid. For composite type specifiers, we need to check whether any
// of the sub-declarations contain a typedef
if (this.declSpecifier.rawSignature.contains("typedef")) {
(this.declSpecifier as IASTCompositeTypeSpecifier).getDeclarations(true).none {
it.rawSignature.contains("typedef")
}
} else {

true
false
}
} else {
false
this.declSpecifier.rawSignature.contains("typedef")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ internal class TypedefTest : BaseTest() {
fun testArbitraryTypedefLocation() {
val tu =
analyzeAndGetFirstTU(
listOf(topLevel.resolve("typedefs.cpp").toFile()),
listOf(topLevel.resolve("weird_typedefs.cpp").toFile()),
topLevel,
true
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1777,4 +1777,40 @@ internal class CXXLanguageFrontendTest : BaseTest() {

assertEquals(label, goto.targetLabel)
}

@Test
fun testTypedefStructCPP() {
val file = File("src/test/resources/cxx/typedef_struct.cpp")
val tu =
analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) {
it.registerLanguage<CPPLanguage>()
it.inferenceConfiguration(builder().enabled(false).build())
}
with(tu) {
val me = tu.memberExpressions
me.forEach { assertNotNull(it.refersTo) }

val test = tu.records.singleOrNull()
assertNotNull(test)
assertLocalName("test", test)
}
}

@Test
fun testTypedefStructC() {
val file = File("src/test/resources/c/typedef_struct.c")
val tu =
analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) {
it.registerLanguage<CLanguage>()
it.inferenceConfiguration(builder().enabled(false).build())
}
with(tu) {
val me = tu.memberExpressions
me.forEach { assertNotNull(it.refersTo) }

val test = tu.records.singleOrNull()
assertNotNull(test)
assertLocalName("test", test)
}
}
}
13 changes: 13 additions & 0 deletions cpg-language-cxx/src/test/resources/c/typedef_struct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
typedef struct test {
int a;
int b;
} S;

int structs() {
S s;
S t;
S* p=&s;
s.a=1;
s.b=2;
printf("%d %d\n", s.a, s.b);
}
15 changes: 15 additions & 0 deletions cpg-language-cxx/src/test/resources/cxx/typedef_struct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
typedef struct test {
int a;
int b;
} S;

int structs() {
S s;
S t;
S* p=&s;
s.a=1;
s.b=2;
printf("%d %d\n", s.a, s.b);
}

long typedef bla;
14 changes: 14 additions & 0 deletions cpg-language-cxx/src/test/resources/typedefs/weird_typedefs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// typedef can be used anywhere in the decl-specifier-seq
// more conventionally spelled "typedef unsigned long long int ullong;"
unsigned long typedef long int ullong;

// also possible with structs
struct bar {
int a;
int b;
} typedef baz;

// just some type that contains a typedef for more confusion
struct foo {
typedef const int a;
};

0 comments on commit 075cc40

Please sign in to comment.