Skip to content

Commit

Permalink
[c#] support for global using directives in CSharpProgramSummary (#…
Browse files Browse the repository at this point in the history
…5187)

* [c#] take into account global using directives

* update typesInScope instead of findGlobalTypes
  • Loading branch information
xavierpinho authored Dec 18, 2024
1 parent 5b77dea commit a2eba41
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ trait AstSummaryVisitor(implicit withSchemaValidation: ValidationMode) { this: A

def imports = cpg.imports.importedEntity.toSet

def globalImports = cpg.imports.filter(_.code.startsWith("global")).importedEntity.toSet

def toMethod(m: Method): CSharpMethod = {
CSharpMethod(
m.name,
Expand All @@ -78,7 +80,7 @@ trait AstSummaryVisitor(implicit withSchemaValidation: ValidationMode) { this: A
})
})
.asInstanceOf[NamespaceToTypeMap]
CSharpProgramSummary(mapping, imports)
CSharpProgramSummary(mapping, imports, globalImports)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import upickle.default.*

import java.io.{ByteArrayInputStream, InputStream}
import scala.annotation.targetName
import scala.collection.mutable.ListBuffer
import scala.io.Source
import scala.util.{Failure, Success, Try}
import java.net.JarURLConnection
Expand All @@ -27,14 +26,18 @@ type NamespaceToTypeMap = mutable.Map[String, mutable.Set[CSharpType]]
* @see
* [[CSharpProgramSummary.jsonToInitialMapping]] for generating initial mappings.
*/
case class CSharpProgramSummary(namespaceToType: NamespaceToTypeMap, imports: Set[String])
case class CSharpProgramSummary(namespaceToType: NamespaceToTypeMap, imports: Set[String], globalImports: Set[String])
extends ProgramSummary[CSharpType, CSharpMethod, CSharpField] {

def findGlobalTypes: Set[CSharpType] = namespaceToType.getOrElse(Constants.Global, Set.empty).toSet

@targetName("appendAll")
def ++=(other: CSharpProgramSummary): CSharpProgramSummary = {
new CSharpProgramSummary(ProgramSummary.merge(namespaceToType, other.namespaceToType), imports ++ other.imports)
new CSharpProgramSummary(
ProgramSummary.merge(namespaceToType, other.namespaceToType),
imports ++ other.imports,
globalImports ++ other.globalImports
)
}

}
Expand All @@ -47,9 +50,10 @@ object CSharpProgramSummary {

def apply(
namespaceToType: NamespaceToTypeMap = mutable.Map.empty,
imports: Set[String] = Set.empty
imports: Set[String] = Set.empty,
globalImports: Set[String] = Set.empty
): CSharpProgramSummary =
new CSharpProgramSummary(namespaceToType, imports)
new CSharpProgramSummary(namespaceToType, imports, globalImports)

def apply(summaries: Iterable[CSharpProgramSummary]): CSharpProgramSummary =
summaries.foldLeft(CSharpProgramSummary())(_ ++= _)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ class CSharpScope(summary: CSharpProgramSummary)
with TypedScope[CSharpMethod, CSharpField, CSharpType](summary)
with OverloadableScope[CSharpMethod] {

override val typesInScope: mutable.Set[CSharpType] = mutable.Set.empty[CSharpType].addAll(summary.findGlobalTypes)
override val typesInScope: mutable.Set[CSharpType] = mutable.Set
.empty[CSharpType]
.addAll(summary.findGlobalTypes)
.addAll(summary.globalImports.flatMap(summary.namespaceToType.getOrElse(_, Set.empty)))

/** @return
* the surrounding type declaration if one exists.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.joern.csharpsrc2cpg.querying.ast

import io.joern.csharpsrc2cpg.testfixtures.CSharpCode2CpgFixture
import io.shiftleft.semanticcpg.language.*

class UsingDirectiveTests extends CSharpCode2CpgFixture {

"`global using` directive in another file" should {
val cpg = code("""
|class Foo
|{
| static void Run()
| {
| Console.WriteLine("Hello");
| }
|}""".stripMargin)
.moreCode(
"""
|global using System;
|""".stripMargin,
"globals.cs"
)

"make the imported namespace available in the current file" in {
inside(cpg.call("WriteLine").l) {
case writeLine :: Nil =>
writeLine.methodFullName shouldBe "System.Console.WriteLine:System.Void(System.String)"
case xs =>
fail(s"Expected single WriteLine call, but found $xs")
}
}
}

"`using` directive in another file" should {
val cpg = code("""
|class Foo
|{
| static void Run()
| {
| Console.WriteLine("Hello");
| }
|}""".stripMargin)
.moreCode(
"""
|using System;
|""".stripMargin,
"dummy.cs"
)

"not affect the imported namespaces in the current file" in {
inside(cpg.call("WriteLine").l) {
case writeLine :: Nil =>
writeLine.methodFullName shouldBe "<unresolvedNamespace>.WriteLine:<unresolvedSignature>"
case xs =>
fail(s"Expected single WriteLine call, but found $xs")
}
}
}
}

0 comments on commit a2eba41

Please sign in to comment.