Skip to content

Commit a23fa59

Browse files
fix - correct typeFullName for member with generic type, issue 105 (#2797)
* fix - correct typeFullName for member with generic type, issue 105 * PR comments for Issue no 105
1 parent c4aae96 commit a23fa59

File tree

3 files changed

+58
-5
lines changed

3 files changed

+58
-5
lines changed

joern-cli/frontends/javasrc2cpg/src/main/scala/io/joern/javasrc2cpg/passes/AstCreator.scala

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -726,11 +726,33 @@ class AstCreator(filename: String, javaParserAst: CompilationUnit, global: Globa
726726
private def astForFieldVariable(v: VariableDeclarator, fieldDeclaration: FieldDeclaration): Ast = {
727727
// TODO: Should be able to find expected type here
728728
val annotations = fieldDeclaration.getAnnotations
729-
val typeFullName =
730-
typeInfoCalc
731-
.fullName(v.getType)
732-
.orElse(scopeStack.lookupVariableType(v.getTypeAsString, wildcardFallback = true))
733-
.getOrElse(s"${Defines.UnresolvedNamespace}.${v.getTypeAsString}")
729+
730+
// variable can be declared with generic type, so we need to get rid of the <> part of it to get the package information
731+
// and append the <> when forming the typeFullName again
732+
// Ex - private Consumer<String, Integer> consumer;
733+
// From Consumer<String, Integer> we need to get to Consumer so splitting it by '<' and then combining with '<' to
734+
// form typeFullName as Consumer<String, Integer>
735+
736+
val typeFullNameWithoutGenericSplit = typeInfoCalc
737+
.fullName(v.getType)
738+
.orElse(scopeStack.lookupVariableType(v.getTypeAsString, wildcardFallback = true))
739+
.getOrElse(s"${Defines.UnresolvedNamespace}.${v.getTypeAsString}")
740+
val typeFullName = {
741+
// Check if the typeFullName is unresolved and if it has generic information to resolve the typeFullName
742+
if (
743+
typeFullNameWithoutGenericSplit
744+
.contains(Defines.UnresolvedNamespace) && v.getTypeAsString.contains(Defines.LeftAngularBracket)
745+
) {
746+
val splitByLeftAngular = v.getTypeAsString.split(Defines.LeftAngularBracket)
747+
scopeStack.lookupVariableType(splitByLeftAngular.head, wildcardFallback = true) match {
748+
case Some(fullName) =>
749+
fullName + splitByLeftAngular
750+
.slice(1, splitByLeftAngular.size)
751+
.mkString(Defines.LeftAngularBracket, Defines.LeftAngularBracket, "")
752+
case None => typeFullNameWithoutGenericSplit
753+
}
754+
} else typeFullNameWithoutGenericSplit
755+
}
734756
val name = v.getName.toString
735757
val node = memberNode(v, name, s"$typeFullName $name", typeFullName)
736758
val memberAst = Ast(node)

joern-cli/frontends/javasrc2cpg/src/test/scala/io/joern/javasrc2cpg/querying/MemberTests.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,35 @@ class NewMemberTests extends JavaSrcCode2CpgFixture {
2020
cpg.member.name("x").astChildren.size shouldBe 0
2121
}
2222

23+
"member with generic class" should {
24+
val cpg = code("""
25+
|import org.apache.kafka.clients.consumer.Consumer;
26+
|public class CountryPopulationConsumer {
27+
|
28+
| private Consumer<String, Integer> consumer;
29+
|
30+
| void foo() {
31+
| consumer.poll(1000);
32+
| }
33+
|}""".stripMargin)
34+
35+
"have a resolved typeFullName" in {
36+
cpg.member
37+
.name("consumer")
38+
.typeFullName
39+
.head shouldBe "org.apache.kafka.clients.consumer.Consumer<String,Integer>"
40+
}
41+
42+
"have a resolved package name in methodFullName" in {
43+
cpg
44+
.call("poll")
45+
.methodFullName
46+
.head
47+
.split(":")
48+
.head shouldBe "org.apache.kafka.clients.consumer.Consumer<String,Integer>.poll"
49+
}
50+
}
51+
2352
"enum entries with anonymous classes should not result in subtrees to the member node" in {
2453
val cpg = code("""
2554
|enum Foo {

joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/Defines.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ object Defines {
2525
// In some languages like Javascript dynamic calls do not provide any statically known
2626
// method/function interface information. In those cases please use this value.
2727
val DynamicCallUnknownFullName = "<unknownFullName>"
28+
29+
val LeftAngularBracket = "<"
2830
}

0 commit comments

Comments
 (0)