From 6b9c87ef29cd88433bb1480dfd707d83367722f4 Mon Sep 17 00:00:00 2001 From: Xavier Pinho Date: Tue, 28 Jan 2025 20:55:07 +0000 Subject: [PATCH] [c#] refactor composeMethodFullName-alikes (#5267) --- .../AstForDeclarationsCreator.scala | 39 +++++++------------ .../AstForExpressionsCreator.scala | 2 +- .../datastructures/CSharpScope.scala | 9 +++++ .../io/joern/csharpsrc2cpg/utils/Utils.scala | 12 ++++++ 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForDeclarationsCreator.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForDeclarationsCreator.scala index 75c78819ced7..249d2d72ac01 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForDeclarationsCreator.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForDeclarationsCreator.scala @@ -6,7 +6,7 @@ import io.joern.csharpsrc2cpg.astcreation.BuiltinTypes.DotNetTypeMap import io.joern.csharpsrc2cpg.datastructures.* import io.joern.csharpsrc2cpg.parser.DotNetJsonAst.* import io.joern.csharpsrc2cpg.parser.{DotNetNodeInfo, ParserKeys} -import io.joern.csharpsrc2cpg.utils.Utils.{composeMethodFullName, composeMethodLikeSignature} +import io.joern.csharpsrc2cpg.utils.Utils.{composeGetterName, composeMethodFullName, composeMethodLikeSignature} import io.joern.x2cpg.utils.NodeBuilders.{newMethodReturnNode, newModifierNode} import io.joern.x2cpg.{Ast, Defines, ValidationMode} import io.shiftleft.codepropertygraph.generated.* @@ -93,7 +93,7 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) { if (shouldBuildCtor) { val methodReturn = newMethodReturnNode(BuiltinTypes.Void, None, None, None) - val signature = composeMethodLikeSignature(methodReturn.typeFullName, Seq.empty) + val signature = composeMethodLikeSignature(methodReturn.typeFullName) val modifiers = Seq(newModifierNode(ModifierTypes.CONSTRUCTOR), newModifierNode(ModifierTypes.INTERNAL)) val name = Defines.ConstructorMethodName val fullName = composeMethodFullName(typeDeclFullName, name, signature) @@ -135,7 +135,7 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) { if (shouldBuildCtor) { val methodReturn = newMethodReturnNode(BuiltinTypes.Void, None, None, None) - val signature = composeMethodLikeSignature(methodReturn.typeFullName, Nil) + val signature = composeMethodLikeSignature(methodReturn.typeFullName) val modifiers = Seq( newModifierNode(ModifierTypes.CONSTRUCTOR), newModifierNode(ModifierTypes.INTERNAL), @@ -355,11 +355,8 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) { .toSeq // TODO: Decide on proper return type for constructors. No `ReturnType` key in C# JSON for constructors so just // defaulted to void (same as java) for now - val methodReturn = newMethodReturnNode(BuiltinTypes.Void, None, None, None) - val signature = composeMethodLikeSignature( - BuiltinTypes.Void, - params.flatMap(_.nodes.collectFirst { case x: NewMethodParameterIn => x.typeFullName }) - ) + val methodReturn = newMethodReturnNode(BuiltinTypes.Void, None, None, None) + val signature = composeMethodLikeSignature(BuiltinTypes.Void, params) val typeDeclFullName = scope.surroundingTypeDeclFullName.getOrElse(Defines.UnresolvedNamespace); val modifiers = (modifiersForNode(constructorDecl) :+ newModifierNode(ModifierTypes.CONSTRUCTOR)) @@ -422,9 +419,8 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) { val methodReturnAstNode = createDotNetNodeInfo(methodDecl.json(ParserKeys.ReturnType)) val methodReturn = methodReturnNode(methodReturnAstNode, nodeTypeFullName(methodReturnAstNode)) - val signature = - methodSignature(methodReturn, params.flatMap(_.nodes.collectFirst { case x: NewMethodParameterIn => x })) - val fullName = s"${astFullName(methodDecl)}:$signature" + val signature = composeMethodLikeSignature(methodReturn.typeFullName, params) + val fullName = s"${astFullName(methodDecl)}:$signature" val methodNode_ = methodNode(methodDecl, name, code(methodDecl), fullName, Option(signature), relativeFileName) scope.pushNewScope(MethodScope(fullName)) @@ -441,10 +437,6 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) { Seq(methodAstWithAnnotations(methodNode_, thisNode +: params, body, methodReturn, modifiers, annotationAsts)) } - private def methodSignature(methodReturn: NewMethodReturn, params: Seq[NewMethodParameterIn]): String = { - composeMethodLikeSignature(methodReturn.typeFullName, params.map(_.typeFullName)) - } - private def astForParameter(paramNode: DotNetNodeInfo, idx: Int, paramTypeHint: Option[String] = None): Ast = { val name = nameFromNode(paramNode) val isVariadic = false // TODO @@ -561,16 +553,13 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) { } private def astForGetAccessorDeclaration(accessorDecl: DotNetNodeInfo, propertyDecl: DotNetNodeInfo): Seq[Ast] = { - val name = s"get_${nameFromNode(propertyDecl)}" - val modifiers = modifiersForNode(propertyDecl) - val returnType = nodeTypeFullName(propertyDecl) - val baseType = scope.surroundingTypeDeclFullName.getOrElse(Defines.UnresolvedNamespace) - val isStatic = modifiers.exists(_.modifierType == ModifierTypes.STATIC) - val parameters = if isStatic then Nil else astForThisParameter(propertyDecl) :: Nil - val signature = composeMethodLikeSignature( - returnType, - parameters.flatMap(_.nodes.collectFirst { case x: NewMethodParameterIn => x.typeFullName }) - ) + val name = composeGetterName(nameFromNode(propertyDecl)) + val modifiers = modifiersForNode(propertyDecl) + val returnType = nodeTypeFullName(propertyDecl) + val baseType = scope.surroundingTypeDeclFullName.getOrElse(Defines.UnresolvedNamespace) + val isStatic = modifiers.exists(_.modifierType == ModifierTypes.STATIC) + val parameters = if isStatic then Nil else astForThisParameter(propertyDecl) :: Nil + val signature = composeMethodLikeSignature(returnType, parameters) val fullName = composeMethodFullName(baseType, name, signature) val body = Ast(blockNode(accessorDecl)) val methodReturn = methodReturnNode(accessorDecl, returnType) diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala index 6f74abcbc694..fbde116281e4 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala @@ -378,7 +378,7 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) { lazy val byFieldAccess = scope.tryResolveFieldAccess(fieldIdentifierName, Some(baseTypeFullName)) // Getters look like fields, but are underneath `get_`-prefixed methods - lazy val byPropertyName = scope.tryResolveMethodInvocation(s"get_$fieldIdentifierName", Nil, Some(baseTypeFullName)) + lazy val byPropertyName = scope.tryResolveGetterInvocation(fieldIdentifierName, Some(baseTypeFullName)) // accessExpr might be a qualified name e.g. `System.Console`, in which case `System` (baseAst) is not a type // but a namespace. In this scenario, we look up the entire expression diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/datastructures/CSharpScope.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/datastructures/CSharpScope.scala index bd1045876901..9ec3b84db7c7 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/datastructures/CSharpScope.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/datastructures/CSharpScope.scala @@ -1,6 +1,7 @@ package io.joern.csharpsrc2cpg.datastructures import io.joern.csharpsrc2cpg.Constants +import io.joern.csharpsrc2cpg.utils.Utils import io.joern.x2cpg.Defines import io.joern.x2cpg.datastructures.{OverloadableScope, Scope, ScopeElement, TypedScope, TypedScopeElement} import io.joern.x2cpg.utils.ListUtils.singleOrNone @@ -165,4 +166,12 @@ class CSharpScope(summary: CSharpProgramSummary) ): Option[(CSharpMethod, String)] = { baseTypeFullName.flatMap(extensionsInScopeFor(_, callName, argTypes).headOption).map(x => (x.methods.head, x.name)) } + + def tryResolveGetterInvocation( + fieldIdentifierName: String, + baseTypeFullName: Option[String] + ): Option[CSharpMethod] = { + val getterMethodName = Utils.composeGetterName(fieldIdentifierName) + tryResolveMethodInvocation(getterMethodName, Nil, baseTypeFullName) + } } diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/utils/Utils.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/utils/Utils.scala index f2acc6347d4b..f3fc6bfd317a 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/utils/Utils.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/utils/Utils.scala @@ -1,12 +1,24 @@ package io.joern.csharpsrc2cpg.utils +import io.joern.x2cpg.Ast +import io.shiftleft.codepropertygraph.generated.nodes.NewMethodParameterIn + object Utils { def composeMethodLikeSignature(returnType: String, parameterTypes: collection.Seq[String]): String = { s"$returnType(${parameterTypes.mkString(",")})" } + def composeMethodLikeSignature(returnType: String, parameters: Seq[Ast] = Nil): String = { + composeMethodLikeSignature( + returnType, + parameters.flatMap(_.nodes.collectFirst { case x: NewMethodParameterIn => x.typeFullName }) + ) + } + def composeMethodFullName(typeDeclFullName: String, name: String, signature: String): String = { s"$typeDeclFullName.$name:$signature" } + def composeGetterName(fieldIdentifierName: String): String = s"get_$fieldIdentifierName" + }