Skip to content

Commit

Permalink
javasrc2cpg - workaround for failing to resolve a method's external r…
Browse files Browse the repository at this point in the history
…eturn type when it contains type arguments (#4044)
  • Loading branch information
xavierpinho authored Jan 13, 2024
1 parent 21558c7 commit f14eea0
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import io.shiftleft.codepropertygraph.generated.Operators
import io.shiftleft.codepropertygraph.generated.DispatchTypes
import io.shiftleft.codepropertygraph.generated.EdgeTypes
import com.github.javaparser.ast.Node
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserParameterDeclaration
import io.joern.javasrc2cpg.astcreation.declarations.AstForMethodsCreator.PartialConstructorDeclaration

private[declarations] trait AstForMethodsCreator { this: AstCreator =>
Expand All @@ -54,6 +55,9 @@ private[declarations] trait AstForMethodsCreator { this: AstCreator =>
val returnTypeFullName = expectedReturnType
.flatMap(typeInfoCalc.fullName)
.orElse(scope.lookupType(simpleMethodReturnType))
.orElse(
Try(methodDeclaration.getType.asClassOrInterfaceType).toOption.flatMap(t => scope.lookupType(t.getNameAsString))
)
.orElse(typeParameters.find(_.name == simpleMethodReturnType).map(_.typeFullName))

scope.pushMethodScope(
Expand Down Expand Up @@ -260,6 +264,14 @@ private[declarations] trait AstForMethodsCreator { this: AstCreator =>
.map { param =>
Try(param.getType).toOption
.flatMap(paramType => typeInfoCalc.fullName(paramType, typeParamValues))
// In a scenario where we have an import of an external type e.g. `import foo.bar.Baz` and
// this parameter's type is e.g. `Baz<String>`, the lookup will fail. However, if we lookup
// for `Baz` instead (i.e. without type arguments), then the lookup will succeed.
.orElse(
Try(
param.asInstanceOf[JavaParserParameterDeclaration].getWrappedNode.getType.asClassOrInterfaceType
).toOption.flatMap(t => scope.lookupType(t.getNameAsString))
)
}

toOptionList(parameterTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,75 @@ class MethodTests3 extends JavaSrcCode2CpgFixture {
cpg.method("virtualMethod").isVirtual.fullName.head shouldBe "Foo.virtualMethod:void(java.lang.Integer)"
}
}

class MethodTests4 extends JavaSrcCode2CpgFixture {

"List<String> in the method return type" should {
val cpg = code("""
|import java.util.*;
|class Foo {
| List<String> run() {
| return null;
| }
|}
|""".stripMargin)

"have correct signature and full name" in {
val List(method) = cpg.method("run").l
method.signature shouldBe "java.util.List()"
method.fullName shouldBe "Foo.run:java.util.List()"
}
}

"Baz<String> in the method return type" should {
val cpg = code("""
|import foo.bar.Baz;
|class Foo {
| Baz<String> run() {
| return null;
| }
|}
|""".stripMargin)

"have correct signature and full name" in {
val List(method) = cpg.method("run").l
method.signature shouldBe "foo.bar.Baz()"
method.fullName shouldBe "Foo.run:foo.bar.Baz()"
}
}

"Identity method for Baz<String>" should {
val cpg = code("""
|import foo.bar.Baz;
|class Foo {
| Baz<String> run(Baz<String> x) {
| return x;
| }
|}
|""".stripMargin)

"have correct signature and full name" in {
val List(method) = cpg.method("run").l
method.signature shouldBe "foo.bar.Baz(foo.bar.Baz)"
method.fullName shouldBe "Foo.run:foo.bar.Baz(foo.bar.Baz)"
}
}

"Generic identity method for Baz<T>" should {
val cpg = code("""
|import foo.bar.Baz;
|class Foo {
| <T> Baz<T> run(Baz<T> x) {
| return x;
| }
|}
|""".stripMargin)

"have correct signature and full name" in {
val List(method) = cpg.method("run").l
method.signature shouldBe "foo.bar.Baz(foo.bar.Baz)"
method.fullName shouldBe "Foo.run:foo.bar.Baz(foo.bar.Baz)"
}
}

}

0 comments on commit f14eea0

Please sign in to comment.