Problem with using common .editorconfig file (imported in csproj) in Visual Studio 2019 Preview 4 - roslyn

I want to streamling code analysis and the respetive rules accross multiple projects and teams.
We used to do that by having a NuGet package that imported analyzers to projects (Microsoft.CodeAnalysis.FxCopAnalyzers and StyleCop.Analyzers) and defined a ruleset to define how each rule was handled by VS (error, warning, etc.).
I have been trying to setup this using a common .editorconfig file instead of the ruleset. The problem is that settings like the following just seem to be ignored when the .editorconfig file is imported from a shared folder.
dotnet_diagnostic.CA1062.severity = error
For the purpose of testing this, I have a very simple scenario that illustrates the problem.
The .editorconfig file is as follows:
[*.cs]
dotnet_diagnostic.CA1062.severity = error
#dotnet_code_quality.null_check_validation_methods = NotNull
Now this file is imported in a csproj like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Import Project="..\..\_Shared\Build.props" />
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
Build.props is like this:
<Project>
<PropertyGroup>
<SkipDefaultEditorConfigAsAdditionalFile>true</SkipDefaultEditorConfigAsAdditionalFile>
</PropertyGroup>
<ItemGroup Condition="Exists('$(MSBuildThisFileDirectory)\.editorconfig')" >
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\.editorconfig" />
</ItemGroup>
</Project>
The following code is supposed to trigger an error on CA1062:
public int Calculate(InputData input)
{
SmartGuard.NotNull(nameof(input), input);
if (this.Multiply)
{
return input.Value * 2;
}
else
{
return input.Value + 2;
}
}
But the result is a warning:
Now, if I change .editorconfig and uncomment the second line:
[*.cs]
dotnet_diagnostic.CA1062.severity = error
dotnet_code_quality.null_check_validation_methods = NotNull
The error goes way which means that null_check_validation_methods is being considered.
Why is that dotnet_diagnostic.CA1062.severity = error is being ignored?

This and other issues with the .editorconfig mechanics were reported in the following issues:
https://github.com/dotnet/roslyn/issues/38782
https://github.com/dotnet/roslyn/issues/43080
These have been solved and the original question is answered by implementing the recommendations referenced in those issues.

The problem you have comes from the fact, that the ".editorconfig" file mechanics (which is not defined by Visual Studio or Microsoft - it's pre-existing standard) is based on where the files are located in the folder structure. It has nothing to do with the mechanics of the Visual Studio projects.
See here on Microsoft's mention of this:
When you add an .editorconfig file to a folder in your file hierarchy, its settings apply to all applicable files at that level and below. You can also override EditorConfig settings for a particular project, codebase, or part of a codebase, such that it uses different conventions than other parts of the codebase. This can be useful when you incorporate code from somewhere else, and don’t want to change its conventions.
To override some or all of the EditorConfig settings, add an .editorconfig file at the level of the file hierarchy you want those overridden settings to apply. The new EditorConfig file settings apply to files at the same level and any subdirectories.
[ hierarchy image here ]
If you want to override some but not all of the settings, specify just those settings in the .editorconfig file. Only those properties that you explicitly list in the lower-level file are overridden. Other settings from higher-level .editorconfig files continue to apply. If you want to ensure that no settings from any higher-level .editorconfig files are applied to this part of the codebase, add the root=true property to the lower-level .editorconfig file:
# top-most EditorConfig file
root = true
EditorConfig files are read top to bottom. If there are multiple properties with the same name, the most recently found property with that name takes precedence.
Or here for the EditorConfig project.
Or here for the EditorConfig specification:
File Processing
When a filename is given to EditorConfig a search is performed in the directory of the given file and all parent directories for an EditorConfig file (named “.editorconfig” by default). Non-existing directories are treated as if they exist and are empty. All found EditorConfig files are searched for sections with section names matching the given filename. The search shall stop if an EditorConfig file is found with the root key set to true in the preamble or when reaching the root filesystem directory.
Files are read top to bottom and the most recent rules found take precedence. If multiple EditorConfig files have matching sections, the rules from the closer EditorConfig file are read last, so pairs in closer files take precedence.

I use Visual Studio version 16.11.2 and my experience is that the problem you describe appears, as a bug, when editing a project file in Visual Studio AFTER you have added a link to it to a it as a solution item. After such an action StyleCop does not any longer listen to the .editorconfig-file of the project.
To re-trigger StyleCop errors as build errors I then have to:
Remove the link to the .editorconfig for the project.
Add a copy of .editorconfig to the project.
Remove the copy of the .editorconfig to the project.
Re-add the link to the .editorconfig.
Quite akward yes, but the above DOES trigger the errors to appear as build errors again.
Moreover, in the version of Visual Studio above, I need to have the line below in the .csproj-file:
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
For previous versions of Visual Studio I had to have the lines below instead:
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors></WarningsAsErrors>
</PropertyGroup>

Related

Where exactly is macro $(VCTargetsPath) defined?

We had a discussion before.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e04e7791-c0c4-4598-b900-310878f5af45/how-can-i-locate-and-change-the-vctargetspath-variable?forum=msbuild
After hours searching .props files, all the $(VCTargetsPath) in .prop and .targets are deleted, but Visual Studio can still recognize this macro/variable correctly.
By modifing Microsoft.Cpp.ToolsetLocation.props, $(VCTargetsPath) can be modified and in consequence VS can no longer create new project.
So, where exactly this macro defined?
I believed that this macro is not and shouldn't be hardcoded.
Where exactly is macro $(VCTargetsPath) defined?
Actually, VCTargetsPath property is defined in the MSBuild system props or targets files under MSBuild folder(C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild). And the files are nested and related to each other. Therefore, the values of various properties are referred to each other in the level-by-level files, and the value of VCTargetsPath is no exception.
==========================================================================
MSBuild is actually equivalent to soft coding. Once MSBuild is installed, it exists as a bunch of dlls and various established props and targets files. You can modify its properties or extend its functions in various ways in the props or targets file. The MSBuild itself is an open source build tool. It is not as unchangeable as you think.
==========================================================================
The VCTargetsPath is actually defined in the msbuild props file called Microsoft.Cpp.ToolsetLocation.props as you said.
It's just that the various targets and props files in MSBuild are nested and interrelated. VCTargetsPath is set as the value of _VCTargetsPathForToolset property while _VCTargetsPathForToolset is defined in another associated targets or props file.
In general, use <import projects="xxxx\xxx.props or targets" /> to embed another file in the current targets or props file.
And there are so many files in MSBuild that if you want to search layer by layer until you find the final specific value, it might seem a little complicated.
Besides, VCTargetsPath is the path of some tools used by MSBuild to compile c++ projects.
The default value in VS2019 is C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160.
You can write a custom target in the xxx.vcxproj file to output its value.
1) write this in xxx.vcxproj file:
<Target Name="test123" AfterTargets="Build">
<Message Importance="high" Text="$(VCTargetsPath)"></Message>
</Target>
2) Then rebuild your project and you can see this:
It is the MSBuild system defined path. If you change it easily, it will cause the project to fail to compile, unless you have a set of self-defined system similar to MSBuild to build C++ projects, and then put it in new path, let the new path overwrite VCTargetsPath property.
In addition, I am curious why you want to find the lowest VCTargetPath value. If you want to know the principle of it, the above answer explains it.
And if you want to overwrite its value, you can just create an environment system variable called VCTargetsPath directly, and then set its value to a new one.
Restart VS to enable such new value. It is much easier than modifying the targets file.

Set debug/run environment variable in Visual Studio 2017 C++ project?

I'm trying to set automatically run/debug environmental variables for my project in Visual Studio.
I mean, is there any CMake or C++ code line to do this not needing to do it manually?
Here are the instructions how to do it manually (what I want to avoid).
Here there is an still unsolved question about how to do it with Cmake (seems not to be possible).
I also tried with setenv() and putenv() in different ways but it didn't work, because the main function doesn't even run until that line of code, before an error message shows up: "Some.dll was not found" and the program stops.
If your dll is one you are intending to use, this answer details how to quickly ensure it is found at runtime (putting the DLL alongside the executable)
If by 'automatic' you mean in code, you can set environment variables in code using _putenv as described in this answer similar to what you seem to be describing.
ostringstream classSize;
classSize << "classSize=" << howManyInClass;
_putenv(classSize.str().c_str());
The solution I found is base on this answer.
Steps for the solution:
Create a UserTemplate.vcxproj.user file next to the CMakeLists.txt file, with the next content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH=..\Your\Path\to\Binaries;%PATH%".</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
Where ..\Your\Path\to\Binaries is the relative path to your binary
files (the two points at the beginning .. are optional, if you
want to go up in the relative directory path, you may want to use
them).
Add the next lines of code in the CMakeLists.txt file.
# Configure the template file
SET(USER_FILE main.vcxproj.user)
SET(OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${USER_FILE})
CONFIGURE_FILE(UserTemplate.vcxproj.user ${USER_FILE} #ONLY)
Where ProjectName is the name of the VS project where you want to define your PATH variable.

ResolveAssemblyReference cannot find dll and I cannot force it to look where it is

I have solution with n csharp projects and cpp project on top, this cpp provides interfaces and headers so those csharp ones can be used in other cpp solutions.
The build machine is configured to build csharp project with anyCPU architecture so it provides single assembly per build in Solution\bin\Release. For cpp the anyCpu is not available so I build project twice and store assemblies in Solution\bin\Release\x86 and x64 folders.
This is all to get it packaged in nuget as a single package with .targets file to ease consumption in other cpp projects.
Issue is that cpp project is looking for csharp asseblies using ResolveAssemblyReference and cannot find it, giving missleading message:
ResolveAssemblyReferences:
Primary reference "Implementation".
Could not find dependent files. Expected file "C:\Jenkins\Workspace\Solution\bin\Release\x86\Implementation.dll" does not exist.
Could not find dependent files. Expected file "C:\Jenkins\Workspace\Solution\bin\Release\x86\Implementation.dll" does not exist.
Resolved file path is "C:\Jenkins\Workspace\Solution\bin\Release\x86\Implementation.dll".
Reference found at search path location "".
I tried to alternate ResolveAssemblyReferences behaviour using command line properties, custom targets/properties, but without any luck. The parameters described in https://learn.microsoft.com/en-us/visualstudio/msbuild/resolveassemblyreference-task?view=vs-2017 seem to be computed during the build process and I cannot inject any value, which should be in this case something like $(OutDir)..
The one feasable solution seems to be copy c# dlls into each cpp folder, but I dont think it is the way to solve it properly.
Closes I got is by using /p:ReferencePath like below:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MsBuild\15.0\bin\MsBuild.exe" /p:BuildProjectReferences=false /p:Configuration=Release /p:DebugType=full /p:DebugSymbols=true /p:PlatformToolset=v120 /p:WindowsTargetPlatformVersion=8.1 /p:ForceImportBeforeCppTargets="C:\Jenkins\Workspace\Solution\Cpp.props" /p:OutDir="C:\Jenkins\Workspace\Solution\bin\Release\x86\" /p:Platform=Win32 /t:Build Interface\Interface.vcxproj /p:ReferencePath="C:\jenkins\workspace\Solution\bin\Release"
My custom Cpp.props does:
<Target Name="Output" BeforeTargets="ResolveAssemblyReferences">
<Message Text="AssemblySearchPaths: $(AssemblySearchPaths)" />
</Target>
and by adding /p:ReferencePath it got added to AssemblySearchPaths as second record, after {CandidateAssemblyFiles}; but it is still not finding those dlls

C++ Windows Driver MSB3030 could not copy the file '' because it was not found

VS2017, SDK/WDK, C++ project
we have a c++ solution (driver) that is shared across developers via Team Foundation Services - visualstudio.com (now called azure devops?).
When I perform a get latest source code, and want to rebuild the solution I get two MSB3030 errors:
"Could not copy the file "C:\path of my colleague his file" because it was not found."
I found it strange that I saw on one of the two errors a path of my colleague his pc. He works on C:\ I'm working on E:\
Unloading the project, I saw he path being set here:
<ItemGroup>
<FilesToPackage Include="C:\path of my colleague\foo.xml" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PackageRelativeDirectory>
</PackageRelativeDirectory>
</FilesToPackage>
We cannot get this solution to build because of the MSB3030. First we have to clean the specific projects individually, rebuild it, then build another project etc.. a few steps to perform manually in the correct order , trial and error, drinking coffee, throwing bananas to the pc and praying that a monkey outputs the code correctly.
Has anyone seen somehting similar regarding MSB3030 errors?
On my pc I see the path of my colleague, but he doesn't see my path (strange!).
C:\Program Files (x86)\Windows
Kits\10\build\WindowsDriver.common.targets(1699,5): error MSB3030:
Could not copy the file 'C:...' because it was not found.
I've set the Any CPU to x64 because it doesn't make any sense for c++.
C++ Windows Driver MSB3030 could not copy the file '' because it was not found
The reason for this issue is that the path of the ItemGroup is an absolute path in the project file:
<ItemGroup>
<FilesToPackage Include="C:\path of my colleague\foo.xml" ...>
...
</FilesToPackage>
</ItemGroup>
Regardless of whether your colleague has added this file to source control, when you pull the code from the TFS server to your local and put the code in a different local folder, the absolute path will bring you a lot of trouble, you need to manually check the code on the TFS server for this file and you need to modify the absolute path of this file in your project. But this problem will reappear after your colleague updates after you submit your code. Because an absolute path cannot be assigned to two different paths C:\ and E:\.
To resolve this issue, you need to change the absolute path to a relative path in the source code. Generally, we prefer to add this file to the Solution/Project folder, then use the MSBuild Macros $(SolutionDir)/$(ProjectDir) to specify it.
Check Common macros for build commands and properties for some more details.
Hope this helps.

Why is '.editorconfig' not doing anything in Visual Studio 2017?

I have the following version of Visual Studio:
Microsoft Visual Studio Community 2017 Version 15.1 (26403.7) Release
VisualStudio.15.Release/15.1.0+26403.7
I created a new project and added a .editorconfig file at my solution base folder.
Its content is the following:
root = true
[*.cs]
indent_style = space:warning
indent_size = 12:warning
# C# and Visual Basic code style settings:
[{*.cs,*.vb}]
dotnet_style_qualification_for_field = false:warning
The file location should be right:
.editorconfig <-- Here it is
ApplicationInsights.config
App_Data
App_Start
bin
Content
Controllers
favicon.ico
fonts
Global.asax
Global.asax.cs
Models
obj
packages.config
Properties
Scripts
Startup.cs
Views
Web.config
Web.config.backup.1
Web.Debug.config
Web.Release.config
WebApplication8.csproj
WebApplication8.csproj.user
But whenever I edit a .cs file, nothing special happen (despite indentation not following the rule), I expect a warning (after a build, for instance) to show up, but no.
Is there something wrong with my configuration, or is there something which could hinder the configuration from being applied?
I had this same problem. The solution was adding the .editorconfig file to the solution in my case. You can choose to either add it to the solution or the project, depending on whether you want it applied everywhere or just the individual project.
Solution Explorer → right-click your solution or project → Add → Existing Item... (if you have the .editorconfig file in position at the root of the solution or project) or New Item... (then search for editorconfig in the Add New Item wizard and choose the appropriate type for your work).
I solved a similar issue by placing the .editorconfig file at the root folder of the project, i.e., the same folder as your .sln file.
Try to put the .editorconfig file into the same folder as your source file. If it helps, try to move it up (into one of the parent directories) until you get it high enough to affect all the files you need.
If you have any EditorConfig extensions installed, try to uninstall them. There were some related bugs reported.
I had a similar problem and this is how I solved it:
My solution folder had a parent folder named between square brackets [], like [ParentFolderName], so I removed the square brackets and everything worked as expected.
For a reason or another, the editorconfig file does not do anything when the solution folder has a parent folder named between square brackets. The IDE (in my case Visual Studio 2017) uses its settings.