Skip to content

Commit 03c8d12

Browse files
authored
[c#] support for <Using Include=XXX> in csproj files (#5240)
1 parent a498a15 commit 03c8d12

File tree

2 files changed

+110
-11
lines changed

2 files changed

+110
-11
lines changed

joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/utils/ImplicitUsingsCollector.scala

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,40 @@ object ImplicitUsingsCollector {
7676
.collect { case x if x.label == "ImplicitUsings" => x.text }
7777
.exists(x => x == "true" || x == "enable")
7878

79-
val exclusions = rootElem.child
79+
val usingsFromProjectType = if (projectType.isDefined && implicitUsingsEnabled) {
80+
projectTypeMapping.getOrElse(projectType.get, Nil)
81+
} else {
82+
Nil
83+
}
84+
85+
// Once we gather the initial set of implicit usings (if any) based on the project type, we
86+
// process ItemGroup.Using tags. The order in which we process these matters, e.g.
87+
// <Using Include="System"/>
88+
// <Using Remove="System"/>
89+
// removes "System", whereas
90+
// <Using Remove="System"/>
91+
// <Using Include="System"/>
92+
// adds "System".
93+
94+
rootElem.child
8095
.collect { case x if x.label == "ItemGroup" => x.child }
8196
.flatten
82-
.collect {
83-
case x if x.label == "Using" && x.attribute("Remove").isDefined =>
84-
x.attribute("Remove").flatMap(_.headOption.map(_.text))
85-
}
97+
.collect { case x if x.label == "Using" => x }
8698
.flatten
99+
.foldLeft(usingsFromProjectType.toSet) { case (acc, node) =>
100+
if (node.attribute("Remove").isDefined) {
101+
node.attribute("Remove").flatMap(_.headOption.map(_.text)) match
102+
case None => acc
103+
case Some(toRemove) => acc.excl(toRemove)
104+
} else if (node.attribute("Include").isDefined) {
105+
node.attribute("Include").flatMap(_.headOption.map(_.text)) match
106+
case None => acc
107+
case Some(toInclude) => acc + toInclude
108+
} else {
109+
acc
110+
}
111+
}
87112
.toList
88-
89-
if (projectType.isDefined && implicitUsingsEnabled) {
90-
projectTypeMapping.getOrElse(projectType.get, Nil).diff(exclusions)
91-
} else {
92-
Nil
93-
}
94113
}
95114

96115
}

joern-cli/frontends/csharpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/querying/ast/ImplicitUsingsTests.scala

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,86 @@ class ImplicitUsingsTests extends CSharpCode2CpgFixture {
147147
)
148148
}
149149
}
150+
151+
"accompanied by a NET.Sdk csproj with ImplicitUsings disabled but including `System`" should {
152+
val cpg = code("""
153+
|Console.WriteLine("Foo");
154+
|""".stripMargin)
155+
.moreCode(
156+
"""
157+
|<Project Sdk="Microsoft.NET.Sdk">
158+
| <PropertyGroup>
159+
| <OutputType>Exe</OutputType>
160+
| <ImplicitUsings>false</ImplicitUsings>
161+
| </PropertyGroup>
162+
| <ItemGroup>
163+
| <Using Include="System" />
164+
| </ItemGroup>
165+
|</Project>
166+
|""".stripMargin,
167+
fileName = "App.csproj"
168+
)
169+
170+
"resolve WriteLine call" in {
171+
cpg.call.nameExact("WriteLine").methodFullName.l shouldBe List(
172+
"System.Console.WriteLine:System.Void(System.String)"
173+
)
174+
}
175+
}
176+
177+
"accompanied by a NET.Sdk csproj with ImplicitUsings enabled but including and excluding `System`" should {
178+
val cpg = code("""
179+
|Console.WriteLine("Foo");
180+
|""".stripMargin)
181+
.moreCode(
182+
"""
183+
|<Project Sdk="Microsoft.NET.Sdk">
184+
| <PropertyGroup>
185+
| <OutputType>Exe</OutputType>
186+
| <ImplicitUsings>true</ImplicitUsings>
187+
| </PropertyGroup>
188+
| <ItemGroup>
189+
| <Using Include="System" />
190+
| <Using Remove="System" />
191+
| </ItemGroup>
192+
|</Project>
193+
|""".stripMargin,
194+
fileName = "App.csproj"
195+
)
196+
197+
"not resolve WriteLine call" in {
198+
cpg.call.nameExact("WriteLine").methodFullName.l shouldBe List(
199+
"<unresolvedNamespace>.WriteLine:<unresolvedSignature>"
200+
)
201+
}
202+
}
203+
204+
"accompanied by a NET.Sdk csproj with ImplicitUsings enabled but excluding and including `System`" should {
205+
val cpg = code("""
206+
|Console.WriteLine("Foo");
207+
|""".stripMargin)
208+
.moreCode(
209+
"""
210+
|<Project Sdk="Microsoft.NET.Sdk">
211+
| <PropertyGroup>
212+
| <OutputType>Exe</OutputType>
213+
| <ImplicitUsings>true</ImplicitUsings>
214+
| </PropertyGroup>
215+
| <ItemGroup>
216+
| <Using Remove="System" />
217+
| <Using Include="System" />
218+
| </ItemGroup>
219+
|</Project>
220+
|""".stripMargin,
221+
fileName = "App.csproj"
222+
)
223+
224+
"resolve WriteLine call" in {
225+
cpg.call.nameExact("WriteLine").methodFullName.l shouldBe List(
226+
"System.Console.WriteLine:System.Void(System.String)"
227+
)
228+
}
229+
}
150230
}
151231

152232
}

0 commit comments

Comments
 (0)