⬆️ ⬇️

The theory of "broken" warnings

" The theory of" broken "warnings " is a fictitious theory that claims that the team connives with respect to minor warnings, such as "inconsistency with or without a sign", "operator before comma has no result", "non-standard extension used", etc. ., directly provokes developers to condone to similar or more serious warnings. The psychological mechanism of such provocation at the household level is illustrated by the phrase: “If others can, then why can't I?” - when the programmer sees that the warnings in the code of other developers are not repaired, he ceases to read the rules (and not only those whose violations he observed, but also any others) obligatory for myself. At the same time, the conditional average level of the “permissible warning” in the team is constantly decreasing, sooner or later leading to an increase in the number of already serious bugs.



Conversely, active work to prevent minor (even the most insignificant) warnings in the code and punish the authors of this code (the so-called zero tolerance) creates an atmosphere of intolerance for warnings in general, and the activity on suppressing minor warnings allows “simultaneously” to train and significantly limit in the possibilities of recidivists, usually neglecting the rules of the team.



The preliminary version of Visual Studio 2017 15.6 Preview 1 provides developers with tools to improve the quality of the code and cleanse it of warnings.



Description of the problem



Brushing jokes aside, it should be noted that not all warnings were created equal:

')



Alas, almost no warning has all five characteristics at once. Any diagnostics combines some of the features from this list, which gives rise to endless discussions about which problems you should notify the programmer, and which ones - no. Of course, different criteria are used in different development teams, and compiler developers are trying to create an extended classification of diagnostics in order to cater to all these criteria. Clang and GCC try to make a more subtle differentiation of warnings, combining them into families, and MSVC uses a coarser division into warning severity levels.



In our survey on diagnostics improvement ( Diagnostics Improvements Survey ), 15% of the 270 respondents stated that they collect code with the / Wall / WX keys, which indicates their zero tolerance for any warnings. Another 12% said they run the build with the / Wall option, which includes the / W4 level plus all disabled warnings. Another 30% collect code at the / W4 level. These three non-overlapping groups make up 57% of users who approach code quality more strictly than provided by the default settings of Visual Studio (level / W3 ) or the compiler itself (level / W1 ). The division of warnings into levels is to some extent arbitrary and in no way reflects our own approaches. For example, the MSVC library team diligently cleans up code at the / W4 level.



Despite the lack of consensus on what sets of warnings the developer should see, everyone agrees that, whatever set is adopted in a particular project, there should not be a single active warning at the end: they must all be either corrected or depressed. On the one hand, with this approach, every new warning serves as a threshold for distinguishing from the notorious Weber-Fechner law , and on the other hand, it is necessary in the cross-platform code, since the warnings issued to such code on one platform / compiler often turn into errors and more serious failures on the other, which has already been repeatedly reported . Zero tolerance for warnings is easy to graft with respect to the internal code, but it is almost impossible with the external code of third-party libraries whose authors can use a different set of issued / excluded warnings. The requirement that all libraries be cleared of all known warnings is impractical (due to false positives and the lack of a standard notation for suppressing them), and is unattainable (as many warnings are continuously expanded). The second is explained by the fact that ecosystems of compilers and libraries are developing together, and improvements in some cause the need for improvements - and therefore the need to keep a given pace - in others. As a result, developers have to deal with compilers that are lagging behind libraries, then with libraries that are lagging behind compilers, and neither of them is under their control. In such circumstances, programmers (assuming that they write in living and active languages ​​like C ++) want to determine for themselves what warnings they would like to see in the code that is not controlled by them.



Proposed Solution



We are introducing a new group of compilation options / external: * , which works with “external” header files. We have chosen the name " external header files " to the name " system header files " adopted in other compilers, since it better reflects the diversity of existing third-party libraries. In addition, the C ++ standard already appeals to external header files in the [lex.header] section, so our choice is quite natural. We have combined new keys into a group, instead of describing them separately, because it will be easier for users to master them : the full syntax of new keys can be foreseen by analogy with already known keys. At the moment, the group consists of 5 parameters, divided into two categories (see the relevant sections below):



Parameters defining a set of external header files





Parameters defining diagnostic behavior for external header files





The second group can be further expanded with parameters such as / external: w, / external: Wall, / external: Wv: <version>, / external: WX [-], / external: w <n> <warning>, / external: wd <warning>, / external: we <warning>, / external: wo <warning> , etc. They can be used as analogs of warning levels or any other standard keys for external (as opposed to user) header files. Note that, since this is an experimental function, you need to add the / experimental: external parameter to enable it, until we debug it to the end. Let's see what the new keys do.



External header files



Currently, library authors and users can specify the location of header files in four ways - they differ in the complexity of adding to build scripts, implementation, and degree of control.





Warning levels for external header files



The / external: W <n> option allows the user to set the default warning level for external header files. We include such inclusions in the analogue of the construction:



#pragma warning (push, n) //   n    #pragma warning (pop) 


Using this key in combination with the preferred way of specifying external header files, you can completely disable any warnings issued to these files.



Example:



External header file: some_lib_dir / some_hdr.hpp



 template <typename T> struct some_struct { static const T value = -7; // W4: warning C4245: 'initializing': // conversion from 'int' to // 'unsigned int', signed/unsigned // mismatch }; 


User code: my_prog.cpp



 #include "some_hdr.hpp" int main() { return some_struct<unsigned int>().value; } 


If you compile this code like this:



cl.exe / I some_lib_dir / W4 my_prog.cpp



The header file will display a Level 4 warning C4245, referred to in the comment. Compilation with parameters:



cl.exe / experimental: external / external: W0 / I some_lib_dir / W4 my_prog.cpp



will not have any effect, since we have not specified external header files. Compilation with parameters:



cl.exe / experimental: external / external: I some_lib_dir / W4 my_prog.cpp



also will not have any effect, since the level of warnings for external header files is not set and by default it corresponds to the level specified in the / W parameter (in our case 4). To suppress the warning in external header files, we must specify both the path to these files and the level of warnings for them:



cl.exe / experimental: external / external: I some_lib_dir / external: W0 / W4 my_prog.cpp



This command will get rid of all warnings on the file some_hdr.hpp, leaving only warnings on the file my_prog.cpp.



Warnings affecting both internal and external code



It would be great if you could just set the warning level for external header files, but this is how we risk weeding out some messages that are also relevant for internal, user files. If you use the pragma push / pop directives alone in conjunction with include, many useful warnings may disappear when instantiating patterns in custom code. Such warnings can indicate the presence of a problem on the user's side, and it manifests itself when only certain types are substituted into the template (for example, when they forgot to apply a type conversion from <type_traits> that removes const or &), and then this problem should be reported. Prior to this version, the level of warnings that was in effect at the time of issuing a message was determined solely on the basis of lexical analysis, while the problem area may be in a different scope. Apparently, it makes sense to compare alert levels at template instantiation points to determine which warnings should be issued and which should not.



In order not to accidentally silence warnings in templates that are defined in external header files, we allowed users to exclude templates from the simplified logic described above — this can be done by passing the / external: templates- option along with / external: W <n> . In doing so, we look not only at the current warning level at the point where the template definition is contained and the warning is issued, but also at the warning levels at all points in the template instantiation sequence. Our warning levels form a grid in relation to the entire set of messages at all levels (however, it is not perfect, because sometimes we issue warnings at several levels at once). A superset defining warnings that must be admitted at a given program point with respect to this grid would be the result of combining the messages allowed at each program point through a chain of instantiations. This is exactly what the / external: template- key serves for, allowing you to display warnings on templates stored in external header files and implemented in user (that is, internal) code.



cl.exe / experimental: external / external: I some_lib_dir / external: W0 / external: templates- / W4 my_prog.cpp



This command allows you to display a warning even though it is set to warning level 0 in the external header file.



Suppress and force warnings



The mechanism described above does not include and does not turn off warnings by itself - it only sets the default level for the specified set of files, and then the standard mechanisms for turning on, turning off and suppressing warnings come into play:





Also, by using / external: templates-, you can suppress a warning at the point of instantiation. In the example discussed earlier, the user can explicitly suppress a warning issued because of the / external key : templates- :



 int main() { #pragma warning( suppress : 4245) return some_struct<unsigned int>().value; } 


Library authors working on the other side can use these same mechanisms to force some or all warnings of a certain level to be turned on if they consider that these warnings are critical enough and should not be suppressed with the / external key : W <n> .



Example:



External header file: some_lib_dir / some_hdr.hpp



 #pragma warning( push, 4 ) #pragma warning( error : 4245 ) template <typename T> struct some_struct { static const T value = -7; // W4: warning C4245: 'initializing': // conversion from 'int' to // 'unsigned int', signed/unsigned // mismatch }; #pragma warning( pop ) 


By changing the library header file as shown above, the author of the library can be sure that this file will be checked with level 4, regardless of what level the user specified in the / external parameter : W <n> , the compiler will still issue all level 4 warnings and higher. Moreover, as shown there, it is possible to forcibly configure one or another warning so that it will always be considered an error, be turned off, suppressed, or be issued once for a given header file - and, again, the user will not be able to bypass this setting.



Restrictions



In the current version, it is possible to trigger warnings on external header files in cases when they are issued by the compiler optimizer (and not by the scanner). Such warnings are usually in the C47XX format, but not all C47XX messages are issued by the optimizer. As a rule, if a data flow or control analysis is required to detect some warning, then most likely it comes from the optimizer in our implementation and cannot yet be suppressed with the help of a new mechanism. We know about this problem, but the solution is unlikely to appear until the next major update of Visual Studio, since it involves major changes in the presentation of the intermediate code. However, such warnings can still be disabled in the standard way - using the / wd47XX switch.



In addition, this experimental functionality has not yet been integrated into / analyze warnings, since we want to first examine user feedback. Warnings / analyze is not divided into levels, so we are also looking for the best way to combine them with the current logic.



We cannot yet tell how this feature will work with SDL alerts, but we will keep in touch with the SDL team and let you know as soon as we know.



Conclusion



Returning to the analogy with the theory of broken windows, it should be noted that we ambiguously assess the impact of our innovation on the library ecosystem as a whole. On the one hand, it can harm them, since users will no longer consider errors in libraries as their problems, and therefore, they will be less likely to report them or correct them on their own. On the other hand, users will get more control over their own code and will be able to impose more stringent requirements on it. Previously, this was hampered by libraries that were not controlled by them, but now they can be pacified.



Although we recognize the possibility of this side effect, correcting errors in third-party code is still not the main task of a programmer, since he has his own code on which he should work and which should be cleaned of errors, while warnings to third-party libraries prevent this process, because it cannot enable the / wx option only for its files. But, more importantly, we are confident that the negative impact on libraries is compensated by another useful outcome.



By allowing developers to hide warnings to third-party libraries, we encourage them to pay more attention to their own code, improve it, or even completely clear warnings at the highest possible level for them. The authors of third-party libraries are the same developers, another link in this chain, and therefore, giving them the opportunity not to be distracted by dependencies in third-party code, we also encourage them to monitor the quality of their own code more carefully and to achieve compilability at the maximum possible warning level. . And so on. Why is it important? The fact is that with the current software development process, the number of warnings grows like an avalanche as you move along a chain of dependencies , and the further you are in this chain, the more difficult it becomes to cope with warnings; developers "break" under their weight and stop any attempts to correct the situation. When it is possible to separate your code from someone else’s, each developer in the chain has at his disposal the means to stop (blocking the consequences) this avalanche of warnings; he has an incentive to minimize its influence on his section, and thus on the whole chain as a whole . This, of course, is a speculative conclusion, but we believe that this effect is no less likely than a negative impact on libraries.



In conclusion, we invite you to experience the new functionality yourself and share your impressions with us. We kindly request: tell us not only about what you liked, but about what you did not like, otherwise the active minority will decide for you. The new mechanism is available in a preliminary version of Visual Studio 15.6 Preview 1 . As usual, you can contact us by leaving a comment below or by writing us an e-mail to visualcpp@microsoft.com ; You can send feedback using the Help -> Report A Problem in the product menu command or leave it in the developer community . Follow us on Twitter ( @VisualC ) and Facebook ( msftvisualcpp ).



PS Special thanks to Robert Schumacher - he pointed out the similarity of our theory with the theory of broken windows !



Translator's notes



  1. The article is published with the consent of the author. The original article was published in the Visual C ++ Team Blog in English: Broken Warnings Theory .
  2. Author's profile on GitHub: solodon4 .
  3. Discussion of the article on the Reddit website.

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



All Articles