📜 ⬆️ ⬇️

Support for Visual Studio 2017 and Roslyn 2.0 in PVS-Studio: sometimes using ready-made solutions is not so easy

In this article I want to tell you about the problems that the PVS-Studio developers faced with the support of the new version of Visual Studio. In addition, I will try to answer the question: why is the support of our C # analyzer based on a “ready-made solution” (in this case, Roslyn) turned out to be more costly in some situations than our “self-written” C ++ analyzer.

With the release of the new version of Visual Studio - 2017, Microsoft introduces a large number of innovations for its "flagship" IDE. These include:


The PVS-Studio 6.14 version, which supports Visual Studio 2017, was released only 10 days after the release of this IDE. We began work on supporting the new VS much earlier - at the end of last year. Of course, far from all the innovations in Visual Studio hurt the work of PVS-Studio, however, the latest release of this IDE turned out to be especially difficult for us in terms of supporting it in all components of our product. The most heavily affected was not our “traditional” C ++ analyzer (support for the new version of Visual C ++ was quite fast), but the components responsible for interaction with the MSBuild build system and the Roslyn platform (on which our C # analyzer is based).

Also, the new version of Visual Studio was the first since the C # analyzer appeared in PVS-Studio (which we released in parallel with the first Roslyn release in Visual Studio 2015), and the C ++ analyzer on Windows was more closely integrated with the MSBuild build system. Therefore, due to the difficulties encountered in updating these components, support for the new VS has become the most costly for us in the entire history of our product.
')

What solutions from Microsoft are used by PVS-Studio?


Most likely, you know, PVS-Studio is a static analyzer for C / C ++ / C # languages, running on Windows and Linux. What does PVS-Studio consist of? First of all, this is, of course, a cross-platform C ++ analyzer and a set of (mostly) cross-platform utilities for its integration into various building systems.

However, on the Windows platform, most of our users use a technology stack for developing software from Microsoft, i.e. Visual C ++ / C #, Visual Studio, MSBuild, etc. For them, we have the tools to work with the analyzer from the Visual Studio environment (IDE plugin), and the command line utility for testing C ++ / C # MSBuild projects. The same utility “under the hood” is also used by our VS plugin. This utility for analyzing the structure of projects directly uses the API provided by MSBuild itself. Our C # analyzer is based on the .NET Compiler Platform (Roslyn), and is currently only available for Windows users.

So, we see that on the Windows platform, PVS-Studio uses Microsoft’s “native” tools for integration into Visual Studio, analysis of the build system and analysis of C # code. With the release of the new version of Visual Studio, all these components have also been updated.

What has changed for us with the release of Visual Studio 2017


In addition to updating versions of MSBuild and Roslyn, Visual Studio 2017 also contains a number of innovations that have touched our product. Coincidentally, a number of our components ceased to work, which were used without any changes by us during several previous releases of Visual Studio, and some of them have been working since the days of Visual Studio 2005 (which we no longer support). Let us consider in more detail these changes.

New order of installation of Visual Studio 2017


The new modular installation system , which allows the user to select only the components he needs to work, has been completely “untied” from using the Windows system registry. Theoretically, this made the development environment more “portable”, and allowed to install several different editions of Visual Studio on the same system. All this, however, significantly influenced the developers of extensions, as all the code that previously allowed to determine the presence of the installed environment itself or its individual components ceased to work.

Figure 1 - New Visual Studio Installer


Figure 1 - New Visual Studio Installer

To obtain information about the instances of Visual Studio installed on the system, developers are now encouraged to use COM interfaces, in particular, ISetupConfiguration . I think many will agree that the usability of COM interfaces is inferior to reading from the registry. And if, for example, for the C # code at least the wrappers of these interfaces already exist, we had to work a lot to adapt our installer based on InnoSetup. In fact, here Microsoft changed one Windows-specific technology to another. In my opinion, the gain from such a transition is rather doubtful, especially since VS has so far failed to completely abandon the use of the registry. At least in this version.

A more significant consequence of this transition, in addition to the rather subjective ease of use, for us was the fact that it indirectly affected the work of the MSBuild 15 libraries used by us, and their backward compatibility with previous versions of MSBuild. The reason for this is that the new version of MSBuild also stopped using the registry. We had to update all the MSBuild components we use, because Roslyn directly depends on them. I will tell you more about the consequences of these changes later.

Changes in the C ++ MSBuild framework


By MSBuild infrastructure for C ++, I first of all mean the interlayer that is responsible for directly calling the compiler when building Visual C ++ projects. This layer has the name PlatformToolset in MSBuild and is responsible for preparing the environment in which the C ++ compiler runs. PlatformToolset also provides backward compatibility with previous versions of Visual C ++ compilers. It allows you to work with the latest version of MSBuild to build projects that use previous versions of the Visual C ++ compiler.

For example, you can build a project that uses the C ++ compiler from Visual Studio 2015 in MSBuild 15 / Visual Studio 2017, if this version of the compiler is installed on the system. This can be useful, because allows you to start using the new version of the IDE on the project right away, without first porting the project to the new version of the compiler (which is not always easy).

PVS-Studio fully supports PlatformToolsets and uses the native MSBuild API to prepare the C ++ analyzer environment, thereby allowing the analyzer to check the source code as close as possible to how it is compiled.

Such close integration with MSBuild made it possible for us earlier to fairly easily maintain the new versions of the C ++ compiler from Microsoft. More precisely, to support his assembly environment, because directly supporting compiler features (for example, syntax and header files using this syntax) is not included in the issues covered in this article. We simply added a new PlatformToolset to the list of supported.

In the new version of Visual C ++, the order of setting the compiler environment has undergone noticeable changes, again “breaking” our code that worked for all versions earlier, starting with Visual Studio 2010. And although PlatformToolsets from previous versions of the compiler still work, to support the new toolset I had to write a separate branch of code. By a strange coincidence (and perhaps not a coincidence), MSBuild developers also changed the naming pattern of the C ++ toolset: v100, v110, v120, v140 in previous versions, and v141 in the latest version (while Visual Studio 2017 still has version 15.0).

In the new version, the structure of vcvars scripts was completely changed, to which the deployment of the compiler environment is tied. These scripts set the environment variables required for the compiler, complement PATH with paths to binary directories and system C ++ libraries, etc. The analyzer also needs an identical environment for work, in particular, for preprocessing source files before starting the analysis itself.

It can be said that the new version of the deployment scripts, in a sense, is made “neater”, and, most likely, it is easier to maintain and expand (it is possible that the update of these scripts was caused by the inclusion of clang support in the new version of Visual C ++ compiler), but from the point of view of the developers of the C ++ analyzer, this added to our work.

C # PVS-Studio analyzer


Together with Visual Studio 2017, Roslyn 2.0 and MSBuild 15 were released. It may seem that to support these new versions in PVS-Studio C # it will be enough just to update the packages used by Nuget in your projects. After that, our analyzer will immediately have access to all the “goodies” of new versions, such as support for C # 7.0, new types of .NET Core projects, etc.

Indeed, updating the packages we use and rebuilding the C # analyzer was quite simple. However, the very first launch of such a new version on our tests showed that “everything broke”. Further experiments showed that the C # analyzer works correctly only on the system where Visual Studio 2017 \ MSBuild 15 is installed. Just the fact that our distribution contains the correct versions of the Roslyn \ MSBuild libraries we use was not enough. The release of the new version of C # analyzer "as is" would entail a deterioration in the analysis results of all our users working with previous versions of C # compilers.

When we created the first version of the C # analyzer that used Roslyn 1.0, we tried to make our analyzer as “independent” solution as possible, not requiring the user to have any third-party installed components in the system. In this case, the main requirement for the user system is the collection of the checked project - if the project is collected, then it can be checked by the analyzer. Obviously, on Windows, building Visual C # projects (csproj) requires at least an MSBuild and C # compiler.

We immediately abandoned the idea of ​​requiring our users to install the latest versions of MSBuild and Visual C # along with a C # analyzer. If a user normally builds a project, for example, in Visual Studio 2013 (which in turn uses MSBuild 12), the requirement to install MSBuild 15 will look redundant. We, on the contrary, try to lower the “threshold” to start using our analyzer.

Microsoft's Web installers proved to be very demanding of the size of the downloads they need - while our distribution has a size of about 50 megabytes, the installer, for example, for Visual C ++ 2017 (which is also needed for the C ++ analyzer) estimated the amount of data to download at 3 gigabytes. As a result, as we found out later, the presence of these components would still not be enough for the C # analyzer to work correctly.

How PVS-Studio interacts with Roslyn


When we first started developing our C # analyzer, we had 2 ways to interact with the Roslyn platform.

The first option was to use the Diagnostics API analyzers specially created for the development of .NET. This API provides the ability, inheriting from the abstract class DiagnosticAnalyzer , to implement its "diagnostics". Using the CodeFixProvider class , users could implement automatic fixes for such warnings.

The undoubted advantage of this approach is the full power of the existing infrastructure of Roslyn. Diagnostic rules are immediately available in the Visual Studio code editor, they can be automatically applied both when editing code in the IDE editor and when starting a project reassembly. This approach does not require the analyzer developer to open the project files and source files on his own - everything will be done as part of the work of the native Roslyn compiler. If we would go this way initially, then we most likely would not have problems with switching to the new Roslyn, at least in this form, as now.

The second option was to implement a fully autonomous analyzer, by analogy with how PVS-Studio C ++ works. We stopped at it, because decided to make the C # parser infrastructure as close as possible to the existing C / C ++ tool. In the future, this made it possible to quickly adapt both the current C ++ diagnostics (of course, not all, but that part of them that was relevant for C #), and more “advanced” analysis techniques .

Roslyn provides opportunities for the implementation of this approach: we open the Visual C # project files on our own, build syntax trees from the source code and implement our own mechanism for traversing them. All this is done using the MSBuild and Roslyn APIs. Thus, we got full control over all stages of the analysis, and do not depend on the work of the compiler or IDE.

No matter how attractive the “free” integration with the Visual Studio code editor seemed to be, we chose to use our own IDE interface, as it presents much more features than the standard Error List (where such warnings will be issued). Using the Diagnostics API would also limit us to compiler versions based on Roslyn, i.e. coming together with Visual Studio 2015 and 2017, while the independent analyzer allowed us to support all previous versions.

During the creation of the C # analyzer, we were faced with the fact that Roslyn was very tightly tied to MSBuild. Of course, here I am talking about the Windows version of Roslyn, with the Linux version we, unfortunately, have not yet had to work, so I can not say how things are there.

I will say right away that the Roslyn API for working with MSBuild projects, in my opinion, remains quite raw even in version 2.0. When creating a C # analyzer, we had to write many different “crutches”, since Roslyn incorrectly did some things (incorrectly = “not the way MSBuild would have done when building the same projects”), which eventually led to false positives and analysis errors when checking source files.

Roslyn’s MSBuild obsession is what led to the problems we encountered when upgrading to Visual Studio 2017.

Roslyn and MSBuild


For the analyzer to work, we, for the most part, need to get two entities from Roslyn: the syntactic tree of the code being tested and the semantic model of this tree, i.e. the value of syntactic constructions representing its nodes — types of class fields, return values ​​and method signatures, etc. And if to obtain a syntactic tree using Roslyn, it is enough to have a file with the source code, then to generate a semantic model of this file, it is necessary to compile the project that includes it.

Updating Roslyn to version 2.0 resulted in errors in the semantic model on our tests (as indicated by the V051 messages of the analyzer). Such errors usually manifest themselves in the results of the analyzer as falsely negative / false positives, i.e. some good messages disappear and bad messages appear.

For the semantic model Roslyn provides the so-called. Workspace API, which can open. NET MSBuild projects (in our case it is csproj and vbproj) and get the “compilation” of such projects. In this context, we are talking about the Compilation service class object in Roslyn, which abstracts in itself the preparation and call of the C # compiler. From such a “compilation” we can get directly the semantic model. Errors in compilation ultimately lead to errors in the semantic model.

Now let's look at how Roslyn interacts with MSBuild to get a “compilation” of the project. The following is a diagram illustrating this interaction in a simplified form:

Figure 2 - Roslyn and MSBuild interaction diagram


Figure 2 - Roslyn and MSBuild interaction diagram

The diagram is divided into 2 segments - PVS-Studio and Build Tools. The PVS-Studio segment contains components that come with our analyzer in the distribution kit - MSBuild and Roslyn libraries that implement the APIs we use. The Build Tools segment includes an assembly system infrastructure that must be present in the system for the API data to work correctly.

After the analyzer has requested a compilation object from the Workspace API (to obtain a semantic model), Roslyn launches the project build, or, in MSBuild terminology, execution of the csc assembly task. After starting the assembly, control passes to MSBuild, which performs all the preparatory steps in accordance with its build scripts.

It should be noted that this is not a “normal” build (it will not lead to the generation of binary files), but the so-called design mode. The ultimate goal of this step is to get Roslyn all the information that would have been provided to the compiler during the "real" build. If the assembly is tied up with some pre-assembly steps (for example, running scripts to auto-generate part of the source files), all such actions will also be performed by MSBuild, as if it were a normal assembly.

Having obtained the management, MSBuild, or rather, the library that comes with PVS-Studio, will start searching the system for the installed build tools (toolsets). Having found a suitable toolset, it will attempt to instantiate the steps described in the build script. Toolsets correspond to MSBuild instances installed on the system. For example, MSBuild 14 (Visual Studio 2015) installs the toolset 14.0, MSBuild 12 - 12.0, etc.

The toolset contains all typical build scripts for MSBuild projects. (, csproj) (, ). Toolset , : , . , MSBuild, , (.. MSBuild , PVS-Studio) .

Build Tools. csc. MSBuild , , tasks toolset'. Tasks — xml , , task'. , csc. ( command line csc.exe). , «» , , , . Roslyn — ( , ), , \ ..

, - - « », Roslyn , , .. MSBuild Execution API. ( MSBuild Evaluation API). . — .NET Core , — , . «» csproj (define') , .

Something went wrong


, , , , «» PVS-Studio C# , , Roslyn MSBuild. , Build Tools PVS-Studio « » , , . , MSBuild , , . , Visual C#, 2010 Visual Studio. Roslyn C# Visual Studio — 2015.

, , , MSBuild 15. Visual Studio 2015 (MSBuild 14). «» Roslyn — MSBuild toolset. toolset , MSBuild toolset — MSBuild . And since Roslyn 2.0 MSBuild 15, toolset' .

, toolset , MSBuild toolset — «» , toolset 4- . 4-? toolset 4- MSBuild , .NET Framework 4 ( MSBuild framework'). targets , csc task' , , .

Roslyn? -, , Visual Studio 2015, .. ( Roslyn 1.0) MSBuild .

-, MSBuild, , , , , toolset'. MSBuild toolset' , MSBuild 15 config MSBuild.exe. MSBuild « » — c:\Program Files (x86)\MSBuild\%VersionNumber% , Visual Studio ( ).

«» toolset — . , toolset , — app.config MSBuild.exe, , MSBuild.exe, PVS-Studio_Cmd.exe. MSBuild . COM , ISetupConfiguration , MSBuild toolset Visual Studio. , standalone MSBuild, , COM — Visual Studio.

, , -, , , , , . , , Visual Studio 2015 \ MSBuild 14. , , .

Roslyn , toolset. , toolset «»? , MSBuild API C++ C++ . Since , . , Roslyn , toolset , ( , .. Nuget ). . , . ?

, , , — PVS-Studio_Cmd.exe. , toolset' dll . Roslyn 2.0, , , Microsoft.CodeAnalysis.dll, 2.0. PVS-Studio_Cmd.exe ( C# ). , 2015 Visual Studio, toolset 14.0. , MSBuild tasks . Since C# toolset' (, Visual Studio 2015) Roslyn 1.3, , , MSBuild Microsoft.CodeAnalysis.dll 1.3. , .. .

? AppDomain'? Roslyn (.. , ), \ , .. , workspace', .

C# backend C++ C# solution , 2 backend' — Roslyn 1.0 2.0 . :


. Visual Studio 2015 3 , Roslyn — 1.0 1.3. , , 2.1 , backend', , , Visual Studio.

, toolset', Roslyn, , 12.0 (Visual Studio 2013). , , .. , .

C#


, «» toolset 15.0 . Roslyn Visual Studio ( C#). , «» MSBuild 15:


, , Roslyn , , Roslyn MSBuild (, Roslyn «» , csc.exe ). , toolset' props targets , toolset . xml MSBuild , — .

, , «» MSBuild «» toolset . MSBuild : Running without any defined toolsets. Most functionality limited. Likely will not be able to build or evaluate a project. (eg reference to Microsoft.*.dll without a toolset definition or Visual Studio instance installed) . , MSBuild , - , MSBuild.exe. , , « ».

MSBuild 15 toolset? , toolset app.config MSBuild.exe. , (PVS-Studio_Cmd.exe) MSBUILD_EXE_PATH . ! MSBuild Release Candidate 4. , master MSBuild GitHub'. , master' toolset' — appconfig' toolset , MSBuild.exe. 0 MSBuild.exe, MSBUILD_EXE_PATH PVS-Studio_Cmd.exe.

MSBuild . , toolset' , MSBuild — . , WebApplication, Portable, .NET Core . Visual Studio, MSBuild. «» MSBuild , , . « » toolset. ( MSBuildExtensionsPath) toolset' , PVS-Studio_Cmd.exe . , WebApplication Visual Studio 2015, , , , , extension' toolset' 14.0, . MSBuild props\targets , .

C# Visual Studio, - MSBuild. - MSBuild, toolset', PVS-Studio.

PVS-Studio , Lightweight Solution Load


Visual Studio 2017, , , — «lightweight solution load».

3 - lightweight solution load


3 — lightweight solution load

IDE , . «lightweight solution load» ( ) Visual Studio. ( ) : ( ), . .

:


, , . , , Visual Studio 2017 «lightweight solution load», .

« », RC Visual Studio « » Microsoft , , . — , , PVS-Studio.

? , , Visual Studio 2 — Visual Studio, 2- — Visual Studio SDK ( Visual Studio ). - Visual Studio SDK RC Visual Studio 2017. .. SDK ( , – ), . , PVS-Studio, . , , .

Conclusion


Visual Studio 2017 «» PVS-Studio . — MSBuild\Visual Studio, C# PVS-Studio ( ).

C#, , Roslyn . — 4 . , , C++ , C#. . , «», Roslyn / Visual Studio. C#, Roslyn, - ( MSBuild Visual Studio), . Roslyn MSBuild standalone .

, «» C++ - , , Clang. , C++ . , , , « », .



, : Paul Eremeev. Support of Visual Studio 2017 and Roslyn 2.0 in PVS-Studio: sometimes it's not that easy to use ready-made solutions as it may seem

Read the article and have a question?
Often our articles are asked the same questions. We collected answers to them here: Answers to questions from readers of articles about PVS-Studio, version 2015 . Please review the list.

Source: https://habr.com/ru/post/327874/


All Articles