From e03402c1c7890f13e52def96d154598b9da9682a Mon Sep 17 00:00:00 2001
From: Georgii Borovinskikh
<117642191+georgii-borovinskikh-sonarsource@users.noreply.github.com>
Date: Mon, 16 Dec 2024 14:40:47 +0100
Subject: [PATCH] SLVS-1673 Include environment variables in generated
compilation db (#5892)
[SLVS-1673](https://sonarsource.atlassian.net/browse/SLVS-1673)
[SLVS-1673]:
https://sonarsource.atlassian.net/browse/SLVS-1673?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
---
.../CompilationDatabaseEntry.cs | 29 ++--
.../EnvironmentVariableProviderTests.cs | 20 +++
src/Core/EnvironmentVariableProvider.cs | 26 +++-
.../VCXCompilationDatabaseProviderTests.cs | 132 +++++++++++++++---
.../VCXCompilationDatabaseStorageTests.cs | 47 +++----
...egration.Vsix_Baseline_WithStrongNames.txt | 5 +-
...ation.Vsix_Baseline_WithoutStrongNames.txt | 5 +-
.../IVCXCompilationDatabaseStorage.cs | 38 +++--
.../VCXCompilationDatabaseProvider.cs | 41 +++++-
9 files changed, 260 insertions(+), 83 deletions(-)
rename src/CFamily/{CMake => CompilationDatabase}/CompilationDatabaseEntry.cs (62%)
diff --git a/src/CFamily/CMake/CompilationDatabaseEntry.cs b/src/CFamily/CompilationDatabase/CompilationDatabaseEntry.cs
similarity index 62%
rename from src/CFamily/CMake/CompilationDatabaseEntry.cs
rename to src/CFamily/CompilationDatabase/CompilationDatabaseEntry.cs
index 12273db1a8..1332634f64 100644
--- a/src/CFamily/CMake/CompilationDatabaseEntry.cs
+++ b/src/CFamily/CompilationDatabase/CompilationDatabaseEntry.cs
@@ -20,23 +20,22 @@
using Newtonsoft.Json;
-namespace SonarLint.VisualStudio.CFamily.CMake
+namespace SonarLint.VisualStudio.CFamily.CompilationDatabase;
+
+///
+/// Schema based on https://clang.llvm.org/docs/JSONCompilationDatabase.html
+///
+public class CompilationDatabaseEntry
{
- ///
- /// Schema based on https://clang.llvm.org/docs/JSONCompilationDatabase.html
- ///
- public class CompilationDatabaseEntry
- {
- [JsonProperty("directory")]
- public string Directory { get; set; }
+ [JsonProperty("directory")]
+ public string Directory { get; set; }
- [JsonProperty("command")]
- public string Command { get; set; }
+ [JsonProperty("command")]
+ public string Command { get; set; }
- [JsonProperty("file")]
- public string File { get; set; }
+ [JsonProperty("file")]
+ public string File { get; set; }
- [JsonProperty("arguments")]
- public string Arguments { get; set; }
- }
+ [JsonProperty("environment")]
+ public IEnumerable Environment { get; set; }
}
diff --git a/src/Core.UnitTests/EnvironmentVariableProviderTests.cs b/src/Core.UnitTests/EnvironmentVariableProviderTests.cs
index d3abc138c3..748ce830e7 100644
--- a/src/Core.UnitTests/EnvironmentVariableProviderTests.cs
+++ b/src/Core.UnitTests/EnvironmentVariableProviderTests.cs
@@ -28,6 +28,26 @@ namespace SonarLint.VisualStudio.Core.UnitTests
[TestClass]
public class EnvironmentVariableProviderTests
{
+ [TestMethod]
+ public void MefCtor_CheckIsExported() => MefTestHelpers.CheckTypeCanBeImported();
+
+ [TestMethod]
+ public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent();
+
+ [TestMethod]
+ public void GetAll_ReturnsExpectedValues()
+ {
+ var testSubject = EnvironmentVariableProvider.Instance;
+ using var environmentVariableScope = new EnvironmentVariableScope();
+ environmentVariableScope.SetVariable("VAR1", "VAL1");
+ environmentVariableScope.SetVariable("VAR2", "VAL2");
+
+ var variables = testSubject.GetAll();
+
+ variables.Should().HaveCountGreaterThan(2);
+ variables.Should().Contain([("VAR1", "VAL1"), ("VAR2", "VAL2")]);
+ }
+
[TestMethod]
[DataRow(null)]
[DataRow("")]
diff --git a/src/Core/EnvironmentVariableProvider.cs b/src/Core/EnvironmentVariableProvider.cs
index 098412c9d3..573d8f62d6 100644
--- a/src/Core/EnvironmentVariableProvider.cs
+++ b/src/Core/EnvironmentVariableProvider.cs
@@ -19,8 +19,11 @@
*/
using System;
+using System.Collections;
+using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
+using SonarLint.VisualStudio.Core;
namespace SonarLint.VisualStudio.Core
{
@@ -38,12 +41,20 @@ public interface IEnvironmentVariableProvider
/// Gets the path to the system special folder that is identified by the specified enumeration.
///
string GetFolderPath(Environment.SpecialFolder folder);
+
+ ///
+ /// Gets the current process environment variables
+ ///
+ List<(string name, string value)> GetAll();
}
+ [Export(typeof(IEnvironmentVariableProvider))]
+ [PartCreationPolicy(CreationPolicy.Shared)]
public class EnvironmentVariableProvider : IEnvironmentVariableProvider
{
- public static EnvironmentVariableProvider Instance { get; } = new EnvironmentVariableProvider();
+ public static EnvironmentVariableProvider Instance { get; } = new();
+ [ImportingConstructor]
private EnvironmentVariableProvider()
{
// no-op
@@ -60,6 +71,19 @@ public string TryGet(string variableName)
}
public string GetFolderPath(Environment.SpecialFolder folder) => Environment.GetFolderPath(folder);
+
+ public List<(string name, string value)> GetAll()
+ {
+ var variables = new List<(string name, string value)>();
+ foreach (DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables())
+ {
+ if (environmentVariable is { Key: string variableName, Value: string variableValue })
+ {
+ variables.Add((variableName, variableValue));
+ }
+ }
+ return variables;
+ }
}
///
diff --git a/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseProviderTests.cs b/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseProviderTests.cs
index 6a8c4100be..13e95e69b2 100644
--- a/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseProviderTests.cs
+++ b/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseProviderTests.cs
@@ -20,6 +20,7 @@
using NSubstitute.ReturnsExtensions;
using SonarLint.VisualStudio.CFamily;
+using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.CFamily;
using SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject;
@@ -28,60 +29,155 @@ namespace SonarLint.VisualStudio.Integration.UnitTests.CFamily.VcxProject;
[TestClass]
public class VCXCompilationDatabaseProviderTests
{
+ private const string CDFile = "cdfilevalue";
+ private const string CDDirectory = "cddirectoryvalue";
+ private const string CDCommand = "cdcommandvalue";
+ private const string EnvInclude = "envincludevalue";
private const string SourceFilePath = "some path";
private IVCXCompilationDatabaseStorage storage;
private IFileConfigProvider fileConfigProvider;
- private VCXCompilationDatabaseProvider testSubject;
+ private IEnvironmentVariableProvider envVarProvider;
+
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ storage = Substitute.For();
+ fileConfigProvider = Substitute.For();
+ envVarProvider = Substitute.For();
+ envVarProvider.GetAll().Returns([]);
+ }
[TestMethod]
- public void MefCtor_CheckIsExported() =>
+ public void MefCtor_CheckIsExported()
+ {
+ envVarProvider.GetAll().Returns([]);
MefTestHelpers.CheckTypeCanBeImported(
MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport(envVarProvider),
MefTestHelpers.CreateExport());
+ }
[TestMethod]
public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent();
- [TestInitialize]
- public void TestInitialize()
- {
- storage = Substitute.For();
- fileConfigProvider = Substitute.For();
- testSubject = new VCXCompilationDatabaseProvider(
- storage,
- fileConfigProvider);
- }
-
[TestMethod]
public void CreateOrNull_NoFileConfig_ReturnsNull()
{
fileConfigProvider.Get(SourceFilePath, default).ReturnsNull();
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
testSubject.CreateOrNull(SourceFilePath).Should().BeNull();
- storage.DidNotReceiveWithAnyArgs().CreateDatabase(default);
+ storage.DidNotReceiveWithAnyArgs().CreateDatabase(default, default, default, default);
}
[TestMethod]
public void CreateOrNull_FileConfig_CantStore_ReturnsNull()
{
- var fileConfig = Substitute.For();
+ var fileConfig = GetFileConfig();
fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
- storage.CreateDatabase(fileConfig).ReturnsNull();
+ storage.CreateDatabase(default, default, default, default).ReturnsNullForAnyArgs();
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
testSubject.CreateOrNull(SourceFilePath).Should().BeNull();
- storage.Received().CreateDatabase(fileConfig);
+ storage.Received().CreateDatabase(CDFile, CDDirectory, CDCommand, Arg.Any>());
}
[TestMethod]
public void CreateOrNull_FileConfig_StoresAndReturnsHandle()
{
- var fileConfig = Substitute.For();
+ var fileConfig = GetFileConfig();
fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
var compilationDatabaseHandle = Substitute.For();
- storage.CreateDatabase(fileConfig).Returns(compilationDatabaseHandle);
+ storage.CreateDatabase(CDFile, CDDirectory, CDCommand, Arg.Any>()).Returns(compilationDatabaseHandle);
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
testSubject.CreateOrNull(SourceFilePath).Should().Be(compilationDatabaseHandle);
}
+
+ [TestMethod]
+ public void CreateOrNull_NoEnvIncludeInFileConfig_UsesStatic()
+ {
+ var fileConfig = GetFileConfig(null);
+ fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
+ envVarProvider.GetAll().Returns([("Var1", "Value1"), ("INCLUDE", "static"), ("Var2", "Value2")]);
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
+
+ testSubject.CreateOrNull(SourceFilePath);
+
+ storage.Received(1).CreateDatabase(CDFile, CDDirectory, CDCommand, Arg.Is>(x => x.SequenceEqual(new [] { "Var1=Value1", "INCLUDE=static", "Var2=Value2" })));
+ }
+
+ [TestMethod]
+ public void CreateOrNull_FileConfigHasEnvInclude_UsesDynamic()
+ {
+ var fileConfig = GetFileConfig(EnvInclude);
+ fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
+ envVarProvider.GetAll().Returns([("Var1", "Value1"), ("INCLUDE", "static"), ("Var2", "Value2")]);
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
+
+ testSubject.CreateOrNull(SourceFilePath);
+
+ storage.Received(1).CreateDatabase(CDFile, CDDirectory, CDCommand, Arg.Is>(x => x.SequenceEqual(new [] { "Var1=Value1", "Var2=Value2", $"INCLUDE={EnvInclude}"})));
+ }
+
+ [TestMethod]
+ public void CreateOrNull_NoStaticInclude_UsesDynamic()
+ {
+ var fileConfig = GetFileConfig(EnvInclude);
+ fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
+ envVarProvider.GetAll().Returns([("Var1", "Value1"), ("Var2", "Value2")]);
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
+
+ testSubject.CreateOrNull(SourceFilePath);
+
+ storage.Received(1).CreateDatabase(CDFile, CDDirectory, CDCommand, Arg.Is>(x => x.SequenceEqual(new [] { "Var1=Value1", "Var2=Value2", $"INCLUDE={EnvInclude}"})));
+ }
+
+ [TestMethod]
+ public void CreateOrNull_StaticEnvVarsAreCached()
+ {
+ var fileConfig = GetFileConfig();
+ fileConfigProvider.Get(SourceFilePath, default).Returns(fileConfig);
+ envVarProvider.GetAll().Returns([("Var1", "Value1"), ("Var2", "Value2")]);
+ var testSubject = new VCXCompilationDatabaseProvider(
+ storage,
+ envVarProvider,
+ fileConfigProvider);
+
+ testSubject.CreateOrNull(SourceFilePath);
+ testSubject.CreateOrNull(SourceFilePath);
+ testSubject.CreateOrNull(SourceFilePath);
+
+ envVarProvider.Received(1).GetAll();
+ }
+
+ private IFileConfig GetFileConfig(string envInclude = EnvInclude)
+ {
+ var fileConfig = Substitute.For();
+ fileConfig.CDFile.Returns(CDFile);
+ fileConfig.CDDirectory.Returns(CDDirectory);
+ fileConfig.CDCommand.Returns(CDCommand);
+ fileConfig.EnvInclude.Returns(envInclude);
+ return fileConfig;
+ }
}
diff --git a/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseStorageTests.cs b/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseStorageTests.cs
index 07a739e6b0..5c9886d678 100644
--- a/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseStorageTests.cs
+++ b/src/Integration.Vsix.UnitTests/CFamily/VcxProject/VCXCompilationDatabaseStorageTests.cs
@@ -21,7 +21,7 @@
using System.IO;
using Newtonsoft.Json;
using NSubstitute.ExceptionExtensions;
-using SonarLint.VisualStudio.CFamily.CMake;
+using SonarLint.VisualStudio.CFamily.CompilationDatabase;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Helpers;
using SonarLint.VisualStudio.Core.SystemAbstractions;
@@ -35,12 +35,22 @@ public class VCXCompilationDatabaseStorageTests
private const string CompileCommand = "compile";
private const string SourceDirectory = @"C:\a\b\c";
private const string SourceFileName = "source.cpp";
+ private static readonly IEnumerable EnvValue = ["envincludevalue"];
private static readonly string SourceFilePath = Path.Combine(SourceDirectory, SourceFileName);
private IFileSystemService fileSystemService;
private IThreadHandling threadHandling;
private IVCXCompilationDatabaseStorage testSubject;
private TestLogger testLogger;
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ fileSystemService = Substitute.For();
+ threadHandling = Substitute.For();
+ testLogger = new TestLogger();
+ testSubject = new VCXCompilationDatabaseStorage(fileSystemService, threadHandling, testLogger);
+ }
+
[TestMethod]
public void MefCtor_CheckIsExported() =>
MefTestHelpers.CheckTypeCanBeImported(
@@ -51,21 +61,12 @@ public void MefCtor_CheckIsExported() =>
[TestMethod]
public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent();
- [TestInitialize]
- public void TestInitialize()
- {
- fileSystemService = Substitute.For();
- threadHandling = Substitute.For();
- testLogger = new TestLogger();
- testSubject = new VCXCompilationDatabaseStorage(fileSystemService, threadHandling, testLogger);
- }
-
[TestMethod]
public void CreateDatabase_NonCriticalException_ReturnsNull()
{
fileSystemService.Directory.CreateDirectory(default).ThrowsForAnyArgs();
- var database = testSubject.CreateDatabase(Substitute.For());
+ var database = testSubject.CreateDatabase(default, default, default, default);
database.Should().BeNull();
testLogger.AssertPartialOutputStrings(nameof(NotImplementedException));
@@ -76,7 +77,7 @@ public void CreateDatabase_CriticalException_Throws()
{
fileSystemService.Directory.CreateDirectory(default).ThrowsForAnyArgs();
- var act = () => testSubject.CreateDatabase(Substitute.For());
+ var act = () => testSubject.CreateDatabase(default, default, default, default);
act.Should().Throw();
}
@@ -85,9 +86,8 @@ public void CreateDatabase_CriticalException_Throws()
public void CreateDatabase_FileWritten_ReturnsPathToDatabaseWithCorrectContent()
{
var expectedDirectory = Path.Combine(Path.GetTempPath(), "SLVS", "VCXCD", PathHelper.PerVsInstanceFolderName.ToString());
- var fileConfig = SetUpFileConfig();
- var databaseHandle = testSubject.CreateDatabase(fileConfig);
+ var databaseHandle = testSubject.CreateDatabase(SourceFilePath, SourceDirectory, CompileCommand, EnvValue);
var temporaryCompilationDatabaseHandle = databaseHandle.Should().BeOfType().Subject;
Directory.GetParent(temporaryCompilationDatabaseHandle.FilePath).FullName.Should().BeEquivalentTo(expectedDirectory);
@@ -102,10 +102,9 @@ public void CreateDatabase_FileWritten_ReturnsPathToDatabaseWithCorrectContent()
public void CreateDatabase_CreatesDifferentHandlesForSameFile()
{
var expectedDirectory = Path.Combine(Path.GetTempPath(), "SLVS", "VCXCD", PathHelper.PerVsInstanceFolderName.ToString());
- var fileConfig = SetUpFileConfig();
- var databaseHandle1 = testSubject.CreateDatabase(fileConfig);
- var databaseHandle2 = testSubject.CreateDatabase(fileConfig);
+ var databaseHandle1 = testSubject.CreateDatabase(SourceFilePath, SourceDirectory, CompileCommand, EnvValue);
+ var databaseHandle2 = testSubject.CreateDatabase(SourceFilePath, SourceDirectory, CompileCommand, EnvValue);
Directory.GetParent(databaseHandle1.FilePath).FullName.Should().BeEquivalentTo(expectedDirectory);
Directory.GetParent(databaseHandle2.FilePath).FullName.Should().BeEquivalentTo(expectedDirectory);
@@ -117,7 +116,7 @@ public void CreateDatabase_Disposed_Throws()
{
testSubject.Dispose();
- var act = () => testSubject.CreateDatabase(Substitute.For());
+ var act = () => testSubject.CreateDatabase(default, default, default, default);
act.Should().Throw();
}
@@ -157,19 +156,11 @@ public void Dispose_CatchesAndLogsException()
testLogger.AssertPartialOutputStringExists(exception.ToString());
}
- private static IFileConfig SetUpFileConfig()
- {
- var fileConfig = Substitute.For();
- fileConfig.CDFile.Returns(SourceFilePath);
- fileConfig.CDDirectory.Returns(SourceDirectory);
- fileConfig.CDCommand.Returns(CompileCommand);
- return fileConfig;
- }
-
private void VerifyDatabaseContents()
{
var serializedCompilationDatabase = fileSystemService.File.ReceivedCalls().Single().GetArguments()[1] as string;
var compilationDatabaseEntries = JsonConvert.DeserializeObject(serializedCompilationDatabase);
- compilationDatabaseEntries.Should().BeEquivalentTo(new CompilationDatabaseEntry { Directory = SourceDirectory, File = SourceFilePath, Command = CompileCommand, Arguments = null });
+ var compilationDatabaseEntry = compilationDatabaseEntries.Single();
+ compilationDatabaseEntry.Should().BeEquivalentTo(new CompilationDatabaseEntry { Directory = SourceDirectory, File = SourceFilePath, Command = CompileCommand, Environment = EnvValue});
}
}
diff --git a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt
index ebf7b6c0c2..850e3e1294 100644
--- a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt
+++ b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt
@@ -1,7 +1,7 @@
---
################################
# Assembly references report
-# Report date/time: 2024-12-16T11:53:41.3325180Z
+# Report date/time: 2024-12-16T13:22:38.0076364Z
################################
#
# Generated by Devtility CheckAsmRefs v0.11.0.223
@@ -56,12 +56,13 @@ Referenced assemblies:
- 'SonarLint.VisualStudio.SLCore, Version=8.9.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
- 'SonarQube.Client, Version=8.9.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
- 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
+- 'System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.IO.Abstractions, Version=9.0.0.0, Culture=neutral, PublicKeyToken=96bf224d23c43e59'
- 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
-# Number of references: 31
+# Number of references: 32
---
Assembly: 'SonarLint.VisualStudio.CFamily, Version=8.9.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
diff --git a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt
index f4d516f9da..4972915101 100644
--- a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt
+++ b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt
@@ -1,7 +1,7 @@
---
################################
# Assembly references report
-# Report date/time: 2024-12-16T11:53:41.3325180Z
+# Report date/time: 2024-12-16T13:22:38.0076364Z
################################
#
# Generated by Devtility CheckAsmRefs v0.11.0.223
@@ -56,12 +56,13 @@ Referenced assemblies:
- 'SonarLint.VisualStudio.SLCore, Version=8.9.0.0, Culture=neutral, PublicKeyToken=null'
- 'SonarQube.Client, Version=8.9.0.0, Culture=neutral, PublicKeyToken=null'
- 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
+- 'System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.IO.Abstractions, Version=9.0.0.0, Culture=neutral, PublicKeyToken=96bf224d23c43e59'
- 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
-# Number of references: 31
+# Number of references: 32
---
Assembly: 'SonarLint.VisualStudio.CFamily, Version=8.9.0.0, Culture=neutral, PublicKeyToken=null'
diff --git a/src/Integration.Vsix/CFamily/VcxProject/IVCXCompilationDatabaseStorage.cs b/src/Integration.Vsix/CFamily/VcxProject/IVCXCompilationDatabaseStorage.cs
index df2c92c6c5..8a68220e98 100644
--- a/src/Integration.Vsix/CFamily/VcxProject/IVCXCompilationDatabaseStorage.cs
+++ b/src/Integration.Vsix/CFamily/VcxProject/IVCXCompilationDatabaseStorage.cs
@@ -21,7 +21,7 @@
using System.ComponentModel.Composition;
using System.IO;
using Newtonsoft.Json;
-using SonarLint.VisualStudio.CFamily.CMake;
+using SonarLint.VisualStudio.CFamily.CompilationDatabase;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.CFamily;
using SonarLint.VisualStudio.Core.Helpers;
@@ -31,28 +31,46 @@ namespace SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject;
internal interface IVCXCompilationDatabaseStorage : IDisposable
{
- ICompilationDatabaseHandle CreateDatabase(IFileConfig fileConfig);
+ ICompilationDatabaseHandle CreateDatabase(
+ string file,
+ string directory,
+ string command,
+ IEnumerable environment);
}
[Export(typeof(IVCXCompilationDatabaseStorage))]
[PartCreationPolicy(CreationPolicy.Shared)]
-[method: ImportingConstructor]
-internal sealed class VCXCompilationDatabaseStorage(IFileSystemService fileSystemService, IThreadHandling threadHandling, ILogger logger)
- : IVCXCompilationDatabaseStorage
+internal sealed class VCXCompilationDatabaseStorage : IVCXCompilationDatabaseStorage
{
- private bool disposed;
private readonly string compilationDatabaseDirectoryPath = PathHelper.GetTempDirForTask(true, "VCXCD");
+ private readonly IFileSystemService fileSystemService;
+ private readonly IThreadHandling threadHandling;
+ private readonly ILogger logger;
+ private bool disposed;
+
+ [ImportingConstructor]
+ public VCXCompilationDatabaseStorage(IFileSystemService fileSystemService, IThreadHandling threadHandling, ILogger logger)
+ {
+ this.fileSystemService = fileSystemService;
+ this.threadHandling = threadHandling;
+ this.logger = logger;
+ }
- public ICompilationDatabaseHandle CreateDatabase(IFileConfig fileConfig)
+ public ICompilationDatabaseHandle CreateDatabase(
+ string file,
+ string directory,
+ string command,
+ IEnumerable environment)
{
ThrowIfDisposed();
threadHandling.ThrowIfOnUIThread();
var compilationDatabaseEntry = new CompilationDatabaseEntry
{
- Directory = fileConfig.CDDirectory,
- Command = fileConfig.CDCommand,
- File = fileConfig.CDFile
+ Directory = directory,
+ Command = command,
+ File = file,
+ Environment = environment
};
var compilationDatabase = new[] { compilationDatabaseEntry };
diff --git a/src/Integration.Vsix/CFamily/VcxProject/VCXCompilationDatabaseProvider.cs b/src/Integration.Vsix/CFamily/VcxProject/VCXCompilationDatabaseProvider.cs
index c8e5b7c46d..8d287fe8c7 100644
--- a/src/Integration.Vsix/CFamily/VcxProject/VCXCompilationDatabaseProvider.cs
+++ b/src/Integration.Vsix/CFamily/VcxProject/VCXCompilationDatabaseProvider.cs
@@ -18,22 +18,49 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+using System.Collections.Immutable;
using System.ComponentModel.Composition;
using SonarLint.VisualStudio.CFamily;
+using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.CFamily;
namespace SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject;
[Export(typeof(IVCXCompilationDatabaseProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
-[method: ImportingConstructor]
-internal class VCXCompilationDatabaseProvider(
- IVCXCompilationDatabaseStorage storage,
- IFileConfigProvider fileConfigProvider)
- : IVCXCompilationDatabaseProvider
+internal class VCXCompilationDatabaseProvider : IVCXCompilationDatabaseProvider
{
+ private const string IncludeEntryName = "INCLUDE";
+ private readonly ImmutableList staticEnvironmentVariableEntries;
+ private readonly IVCXCompilationDatabaseStorage storage;
+ private readonly IFileConfigProvider fileConfigProvider;
+
+ [method: ImportingConstructor]
+ public VCXCompilationDatabaseProvider(
+ IVCXCompilationDatabaseStorage storage,
+ IEnvironmentVariableProvider environmentVariableProvider,
+ IFileConfigProvider fileConfigProvider)
+ {
+ this.storage = storage;
+ this.fileConfigProvider = fileConfigProvider;
+ staticEnvironmentVariableEntries = ImmutableList.CreateRange(environmentVariableProvider.GetAll().Select(x => new EnvironmentEntry(x.name, x.value)));
+ }
+
public ICompilationDatabaseHandle CreateOrNull(string filePath) =>
- fileConfigProvider.Get(filePath, null) is {} fileConfig
- ? storage.CreateDatabase(fileConfig)
+ fileConfigProvider.Get(filePath, null) is { } fileConfig
+ ? storage.CreateDatabase(fileConfig.CDFile, fileConfig.CDDirectory, fileConfig.CDCommand, GetEnvironmentEntries(fileConfig.EnvInclude).Select(x => x.FormattedEntry))
: null;
+
+ private ImmutableList GetEnvironmentEntries(string fileConfigEnvInclude) =>
+ string.IsNullOrEmpty(fileConfigEnvInclude)
+ ? staticEnvironmentVariableEntries
+ : staticEnvironmentVariableEntries
+ .RemoveAll(x => x.Name == IncludeEntryName)
+ .Add(new EnvironmentEntry(IncludeEntryName, fileConfigEnvInclude));
+
+ private readonly struct EnvironmentEntry(string name, string value)
+ {
+ public string Name { get; } = name;
+ public string FormattedEntry { get; } = $"{name}={value}";
+ }
}