diff options
author | Martin Liska <mliska@suse.cz> | 2022-11-13 21:59:29 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-11-14 09:35:06 +0100 |
commit | d77de738290156fafe079182888e5e03a2f835f1 (patch) | |
tree | 0fa1501804778de28e5323a1ecc0d39073b4045c /gcc/doc/ux.texi | |
parent | 40a39381063fdd83c4cbf5eacebfc50a2201308b (diff) | |
download | gcc-d77de738290156fafe079182888e5e03a2f835f1.zip gcc-d77de738290156fafe079182888e5e03a2f835f1.tar.gz gcc-d77de738290156fafe079182888e5e03a2f835f1.tar.bz2 |
Revert "sphinx: remove texinfo files"
This reverts commit 54ca4eef58661a7d7a511e2bbbe309bde1732abf.
Diffstat (limited to 'gcc/doc/ux.texi')
-rw-r--r-- | gcc/doc/ux.texi | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/gcc/doc/ux.texi b/gcc/doc/ux.texi new file mode 100644 index 0000000..1e27b2b --- /dev/null +++ b/gcc/doc/ux.texi @@ -0,0 +1,661 @@ +@c Copyright (C) 2018-2022 Free Software Foundation, Inc. +@c Free Software Foundation, Inc. +@c This is part of the GCC manual. +@c For copying conditions, see the file gcc.texi. + +@node User Experience Guidelines +@chapter User Experience Guidelines +@cindex user experience guidelines +@cindex guidelines, user experience + +To borrow a slogan from +@uref{https://elm-lang.org/news/compilers-as-assistants, Elm}, + +@quotation +@strong{Compilers should be assistants, not adversaries.} A compiler should +not just detect bugs, it should then help you understand why there is a bug. +It should not berate you in a robot voice, it should give you specific hints +that help you write better code. Ultimately, a compiler should make +programming faster and more fun! +@author Evan Czaplicki +@end quotation + +This chapter provides guidelines on how to implement diagnostics and +command-line options in ways that we hope achieve the above ideal. + +@menu +* Guidelines for Diagnostics:: How to implement diagnostics. +* Guidelines for Options:: Guidelines for command-line options. +@end menu + + +@node Guidelines for Diagnostics +@section Guidelines for Diagnostics +@cindex guidelines for diagnostics +@cindex diagnostics, guidelines for + +@subsection Talk in terms of the user's code + +Diagnostics should be worded in terms of the user's source code, and the +source language, rather than GCC's own implementation details. + +@subsection Diagnostics are actionable +@cindex diagnostics, actionable + +A good diagnostic is @dfn{actionable}: it should assist the user in +taking action. + +Consider what an end user will want to do when encountering a diagnostic. + +Given an error, an end user will think: ``How do I fix this?'' + +Given a warning, an end user will think: + +@itemize @bullet +@item +``Is this a real problem?'' +@item +``Do I care?'' +@item +if they decide it's genuine: ``How do I fix this?'' +@end itemize + +A good diagnostic provides pertinent information to allow the user to +easily answer the above questions. + +@subsection The user's attention is important + +A perfect compiler would issue a warning on every aspect of the user's +source code that ought to be fixed, and issue no other warnings. +Naturally, this ideal is impossible to achieve. + +@cindex signal-to-noise ratio (metaphorical usage for diagnostics) +@cindex diagnostics, false positive +@cindex diagnostics, true positive +@cindex false positive +@cindex true positive + +Warnings should have a good @dfn{signal-to-noise ratio}: we should have few +@dfn{false positives} (falsely issuing a warning when no warning is +warranted) and few @dfn{false negatives} (failing to issue a warning when +one @emph{is} justified). + +Note that a false positive can mean, in practice, a warning that the +user doesn't agree with. Ideally a diagnostic should contain enough +information to allow the user to make an informed choice about whether +they should care (and how to fix it), but a balance must be drawn against +overloading the user with irrelevant data. + +@subsection Sometimes the user didn't write the code + +GCC is typically used in two different ways: + +@itemize @bullet +@item +Semi-interactive usage: GCC is used as a development tool when the user +is writing code, as the ``compile'' part of the ``edit-compile-debug'' +cycle. The user is actively hacking on the code themself (perhaps a +project they wrote, or someone else's), where they just made a change +to the code and want to see what happens, and to be warned about +mistakes. + +@item +Batch rebuilds: where the user is recompiling one or more existing +packages, and GCC is a detail that's being invoked by various build +scripts. Examples include a user trying to bring up an operating system +consisting of hundreds of packages on a new CPU architecture, where the +packages were written by many different people, or simply rebuilding +packages after a dependency changed, where the user is hoping +``nothing breaks'', since they are unfamiliar with the code. +@end itemize + +Keep both of these styles of usage in mind when implementing diagnostics. + +@subsection Precision of Wording + +Provide the user with details that allow them to identify what the +problem is. For example, the vaguely-worded message: + +@smallexample +demo.c:1:1: warning: 'noinline' attribute ignored [-Wattributes] + 1 | int foo __attribute__((noinline)); + | ^~~ +@end smallexample + +@noindent +doesn't tell the user why the attribute was ignored, or what kind of +entity the compiler thought the attribute was being applied to (the +source location for the diagnostic is also poor; +@pxref{input_location_example,,discussion of @code{input_location}}). +A better message would be: + +@smallexample +demo.c:1:24: warning: attribute 'noinline' on variable 'foo' was + ignored [-Wattributes] + 1 | int foo __attribute__((noinline)); + | ~~~ ~~~~~~~~~~~~~~~^~~~~~~~~ +demo.c:1:24: note: attribute 'noinline' is only applicable to functions +@end smallexample + +@noindent +which spells out the missing information (and fixes the location +information, as discussed below). + +The above example uses a note to avoid a combinatorial explosion of possible +messages. + +@subsection Try the diagnostic on real-world code + +It's worth testing a new warning on many instances of real-world code, +written by different people, and seeing what it complains about, and +what it doesn't complain about. + +This may suggest heuristics that silence common false positives. + +It may also suggest ways to improve the precision of the message. + +@subsection Make mismatches clear + +Many diagnostics relate to a mismatch between two different places in the +user's source code. Examples include: +@itemize @bullet + @item + a type mismatch, where the type at a usage site does not match the type + at a declaration + + @item + the argument count at a call site does not match the parameter count + at the declaration + + @item + something is erroneously duplicated (e.g.@: an error, due to breaking a + uniqueness requirement, or a warning, if it's suggestive of a bug) + + @item + an ``opened'' syntactic construct (such as an open-parenthesis) is not + closed + + @c TODO: more examples? +@end itemize + +In each case, the diagnostic should indicate @strong{both} pertinent +locations (so that the user can easily see the problem and how to fix it). + +The standard way to do this is with a note (via @code{inform}). For +example: + +@smallexample + auto_diagnostic_group d; + if (warning_at (loc, OPT_Wduplicated_cond, + "duplicated %<if%> condition")) + inform (EXPR_LOCATION (t), "previously used here"); +@end smallexample + +@noindent +which leads to: + +@smallexample +demo.c: In function 'test': +demo.c:5:17: warning: duplicated 'if' condition [-Wduplicated-cond] + 5 | else if (flag > 3) + | ~~~~~^~~ +demo.c:3:12: note: previously used here + 3 | if (flag > 3) + | ~~~~~^~~ +@end smallexample + +@noindent +The @code{inform} call should be guarded by the return value from the +@code{warning_at} call so that the note isn't emitted when the warning +is suppressed. + +For cases involving punctuation where the locations might be near +each other, they can be conditionally consolidated via +@code{gcc_rich_location::add_location_if_nearby}: + +@smallexample + auto_diagnostic_group d; + gcc_rich_location richloc (primary_loc); + bool added secondary = richloc.add_location_if_nearby (secondary_loc); + error_at (&richloc, "main message"); + if (!added secondary) + inform (secondary_loc, "message for secondary"); +@end smallexample + +@noindent +This will emit either one diagnostic with two locations: +@smallexample + demo.c:42:10: error: main message + (foo) + ~ ^ +@end smallexample + +@noindent +or two diagnostics: + +@smallexample + demo.c:42:4: error: main message + foo) + ^ + demo.c:40:2: note: message for secondary + ( + ^ +@end smallexample + +@subsection Location Information +@cindex diagnostics, locations +@cindex location information +@cindex source code, location information +@cindex caret + +GCC's @code{location_t} type can support both ordinary locations, +and locations relating to a macro expansion. + +As of GCC 6, ordinary locations changed from supporting just a +point in the user's source code to supporting three points: the +@dfn{caret} location, plus a start and a finish: + +@smallexample + a = foo && bar; + ~~~~^~~~~~ + | | | + | | finish + | caret + start +@end smallexample + +Tokens coming out of libcpp have locations of the form @code{caret == start}, +such as for @code{foo} here: + +@smallexample + a = foo && bar; + ^~~ + | | + | finish + caret == start +@end smallexample + +Compound expressions should be reported using the location of the +expression as a whole, rather than just of one token within it. + +For example, in @code{-Wformat}, rather than underlining just the first +token of a bad argument: + +@smallexample + printf("hello %i %s", (long)0, "world"); + ~^ ~ + %li +@end smallexample + +@noindent +the whole of the expression should be underlined, so that the user can +easily identify what is being referred to: + +@smallexample + printf("hello %i %s", (long)0, "world"); + ~^ ~~~~~~~ + %li +@end smallexample + +@c this was r251239 + +Avoid using the @code{input_location} global, and the diagnostic functions +that implicitly use it---use @code{error_at} and @code{warning_at} rather +than @code{error} and @code{warning}, and provide the most appropriate +@code{location_t} value available at that phase of the compilation. It's +possible to supply secondary @code{location_t} values via +@code{rich_location}. + +@noindent +@anchor{input_location_example} +For example, in the example of imprecise wording above, generating the +diagnostic using @code{warning}: + +@smallexample + // BAD: implicitly uses @code{input_location} + warning (OPT_Wattributes, "%qE attribute ignored", name); +@end smallexample + +@noindent +leads to: + +@smallexample +// BAD: uses @code{input_location} +demo.c:1:1: warning: 'noinline' attribute ignored [-Wattributes] + 1 | int foo __attribute__((noinline)); + | ^~~ +@end smallexample + +@noindent +which thus happened to use the location of the @code{int} token, rather +than that of the attribute. Using @code{warning_at} with the location of +the attribute, providing the location of the declaration in question +as a secondary location, and adding a note: + +@smallexample + auto_diagnostic_group d; + gcc_rich_location richloc (attrib_loc); + richloc.add_range (decl_loc); + if (warning_at (OPT_Wattributes, &richloc, + "attribute %qE on variable %qE was ignored", name)) + inform (attrib_loc, "attribute %qE is only applicable to functions"); +@end smallexample + +@noindent +would lead to: + +@smallexample +// OK: use location of attribute, with a secondary location +demo.c:1:24: warning: attribute 'noinline' on variable 'foo' was + ignored [-Wattributes] + 1 | int foo __attribute__((noinline)); + | ~~~ ~~~~~~~~~~~~~~~^~~~~~~~~ +demo.c:1:24: note: attribute 'noinline' is only applicable to functions +@end smallexample + +@c TODO labelling of ranges + +@subsection Coding Conventions + +See the @uref{https://gcc.gnu.org/codingconventions.html#Diagnostics, +diagnostics section} of the GCC coding conventions. + +In the C++ front end, when comparing two types in a message, use @samp{%H} +and @samp{%I} rather than @samp{%T}, as this allows the diagnostics +subsystem to highlight differences between template-based types. +For example, rather than using @samp{%qT}: + +@smallexample + // BAD: a pair of %qT used in C++ front end for type comparison + error_at (loc, "could not convert %qE from %qT to %qT", expr, + TREE_TYPE (expr), type); +@end smallexample + +@noindent +which could lead to: + +@smallexample +error: could not convert 'map<int, double>()' from 'map<int,double>' + to 'map<int,int>' +@end smallexample + +@noindent +using @samp{%H} and @samp{%I} (via @samp{%qH} and @samp{%qI}): + +@smallexample + // OK: compare types in C++ front end via %qH and %qI + error_at (loc, "could not convert %qE from %qH to %qI", expr, + TREE_TYPE (expr), type); +@end smallexample + +@noindent +allows the above output to be simplified to: + +@smallexample +error: could not convert 'map<int, double>()' from 'map<[...],double>' + to 'map<[...],int>' +@end smallexample + +@noindent +where the @code{double} and @code{int} are colorized to highlight them. + +@c %H and %I were added in r248698. + +@subsection Group logically-related diagnostics + +Use @code{auto_diagnostic_group} when issuing multiple related +diagnostics (seen in various examples on this page). This informs the +diagnostic subsystem that all diagnostics issued within the lifetime +of the @code{auto_diagnostic_group} are related. For example, +@option{-fdiagnostics-format=json} will treat the first diagnostic +emitted within the group as a top-level diagnostic, and all subsequent +diagnostics within the group as its children. + +@subsection Quoting +Text should be quoted by either using the @samp{q} modifier in a directive +such as @samp{%qE}, or by enclosing the quoted text in a pair of @samp{%<} +and @samp{%>} directives, and never by using explicit quote characters. +The directives handle the appropriate quote characters for each language +and apply the correct color or highlighting. + +The following elements should be quoted in GCC diagnostics: + +@itemize @bullet +@item +Language keywords. +@item +Tokens. +@item +Boolean, numerical, character, and string constants that appear in the +source code. +@item +Identifiers, including function, macro, type, and variable names. +@end itemize + +Other elements such as numbers that do not refer to numeric constants that +appear in the source code should not be quoted. For example, in the message: + +@smallexample +argument %d of %qE must be a pointer type +@end smallexample + +@noindent +since the argument number does not refer to a numerical constant in the +source code it should not be quoted. + +@subsection Spelling and Terminology + +See the @uref{https://gcc.gnu.org/codingconventions.html#Spelling +Spelling, terminology and markup} section of the GCC coding conventions. + +@subsection Fix-it hints +@cindex fix-it hints +@cindex diagnostics guidelines, fix-it hints + +GCC's diagnostic subsystem can emit @dfn{fix-it hints}: small suggested +edits to the user's source code. + +They are printed by default underneath the code in question. They +can also be viewed via @option{-fdiagnostics-generate-patch} and +@option{-fdiagnostics-parseable-fixits}. With the latter, an IDE +ought to be able to offer to automatically apply the suggested fix. + +Fix-it hints contain code fragments, and thus they should not be marked +for translation. + +Fix-it hints can be added to a diagnostic by using a @code{rich_location} +rather than a @code{location_t} - the fix-it hints are added to the +@code{rich_location} using one of the various @code{add_fixit} member +functions of @code{rich_location}. They are documented with +@code{rich_location} in @file{libcpp/line-map.h}. +It's easiest to use the @code{gcc_rich_location} subclass of +@code{rich_location} found in @file{gcc-rich-location.h}, as this +implicitly supplies the @code{line_table} variable. + +For example: + +@smallexample + if (const char *suggestion = hint.suggestion ()) + @{ + gcc_rich_location richloc (location); + richloc.add_fixit_replace (suggestion); + error_at (&richloc, + "%qE does not name a type; did you mean %qs?", + id, suggestion); + @} +@end smallexample + +@noindent +which can lead to: + +@smallexample +spellcheck-typenames.C:73:1: error: 'singed' does not name a type; did + you mean 'signed'? + 73 | singed char ch; + | ^~~~~~ + | signed +@end smallexample + +Non-trivial edits can be built up by adding multiple fix-it hints to one +@code{rich_location}. It's best to express the edits in terms of the +locations of individual tokens. Various handy functions for adding +fix-it hints for idiomatic C and C++ can be seen in +@file{gcc-rich-location.h}. + +@subsubsection Fix-it hints should work + +When implementing a fix-it hint, please verify that the suggested edit +leads to fixed, compilable code. (Unfortunately, this currently must be +done by hand using @option{-fdiagnostics-generate-patch}. It would be +good to have an automated way of verifying that fix-it hints actually fix +the code). + +For example, a ``gotcha'' here is to forget to add a space when adding a +missing reserved word. Consider a C++ fix-it hint that adds +@code{typename} in front of a template declaration. A naive way to +implement this might be: + +@smallexample +gcc_rich_location richloc (loc); +// BAD: insertion is missing a trailing space +richloc.add_fixit_insert_before ("typename"); +error_at (&richloc, "need %<typename%> before %<%T::%E%> because " + "%qT is a dependent scope", + parser->scope, id, parser->scope); +@end smallexample + +@noindent +When applied to the code, this might lead to: + +@smallexample +T::type x; +@end smallexample + +@noindent +being ``corrected'' to: + +@smallexample +typenameT::type x; +@end smallexample + +@noindent +In this case, the correct thing to do is to add a trailing space after +@code{typename}: + +@smallexample +gcc_rich_location richloc (loc); +// OK: note that here we have a trailing space +richloc.add_fixit_insert_before ("typename "); +error_at (&richloc, "need %<typename%> before %<%T::%E%> because " + "%qT is a dependent scope", + parser->scope, id, parser->scope); +@end smallexample + +@noindent +leading to this corrected code: + +@smallexample +typename T::type x; +@end smallexample + +@subsubsection Express deletion in terms of deletion, not replacement + +It's best to express deletion suggestions in terms of deletion fix-it +hints, rather than replacement fix-it hints. For example, consider this: + +@smallexample + auto_diagnostic_group d; + gcc_rich_location richloc (location_of (retval)); + tree name = DECL_NAME (arg); + richloc.add_fixit_replace (IDENTIFIER_POINTER (name)); + warning_at (&richloc, OPT_Wredundant_move, + "redundant move in return statement"); +@end smallexample + +@noindent +which is intended to e.g.@: replace a @code{std::move} with the underlying +value: + +@smallexample + return std::move (retval); + ~~~~~~~~~~^~~~~~~~ + retval +@end smallexample + +@noindent +where the change has been expressed as replacement, replacing +with the name of the declaration. +This works for simple cases, but consider this case: + +@smallexample +#ifdef SOME_CONFIG_FLAG +# define CONFIGURY_GLOBAL global_a +#else +# define CONFIGURY_GLOBAL global_b +#endif + +int fn () +@{ + return std::move (CONFIGURY_GLOBAL /* some comment */); +@} +@end smallexample + +@noindent +The above implementation erroneously strips out the macro and the +comment in the fix-it hint: + +@smallexample + return std::move (CONFIGURY_GLOBAL /* some comment */); + ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + global_a +@end smallexample + +@noindent +and thus this resulting code: + +@smallexample + return global_a; +@end smallexample + +@noindent +It's better to do deletions in terms of deletions; deleting the +@code{std::move (} and the trailing close-paren, leading to +this: + +@smallexample + return std::move (CONFIGURY_GLOBAL /* some comment */); + ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CONFIGURY_GLOBAL /* some comment */ +@end smallexample + +@noindent +and thus this result: + +@smallexample + return CONFIGURY_GLOBAL /* some comment */; +@end smallexample + +@noindent +Unfortunately, the pertinent @code{location_t} values are not always +available. + +@c the above was https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01474.html + +@subsubsection Multiple suggestions + +In the rare cases where you need to suggest more than one mutually +exclusive solution to a problem, this can be done by emitting +multiple notes and calling +@code{rich_location::fixits_cannot_be_auto_applied} on each note's +@code{rich_location}. If this is called, then the fix-it hints in +the @code{rich_location} will be printed, but will not be added to +generated patches. + + +@node Guidelines for Options +@section Guidelines for Options +@cindex command-line options, guidelines for +@cindex options, guidelines for +@cindex guidelines for options + +@c TODO |