Skip to content

Commit

Permalink
[c#] refactor composeMethodFullName-alikes (#5267)
Browse files Browse the repository at this point in the history
xavierpinho authored Jan 28, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 21f2bc7 commit 6b9c87e
Showing 4 changed files with 36 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -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"

}

0 comments on commit 6b9c87e

Please sign in to comment.