Reading C++ Code with Ease
Programmers often spend more time reading code than writing it. Your own program logic is difficult to figure out at times, not to mention trying to understand someone else’s code!
Modern C++ makes this even more complicated. Try to guess the types in this code. When you’re ready, click the GIF to see the answer:
This is why we believe reading assistance features are as important as those that help you write new code.
We first introduced various inlay hints in ReSharper C++ 2018.3. We’ve been iterating and improving them, and in the 2019.3 release we are ready to give you Type Name Hints.
Let’s take a look at what kinds of hints are available now and how they can help you:
- Parameter name hints
- Aggregate initialization hints
- Namespace name hints
- Preprocessor directive hints
- Type name hints
Parameter name hints
Parameter name hints were the first editor adornments introduced in ReSharper C++. They help you find your way through long lists of parameters, by showing parameter names next to the corresponding arguments in function calls. In the example below, parameter name hints help you immediately spot the fact that the height and width arguments are mixed up:
In the next example, you only need a quick glance to get the version details for this function:
Parameter name hints are also available for macro calls. To show them, go to ReSharper | Options | Environment | Editor | Inlay Hints and clear the checkbox Hide parameter name hints in macro calls.
Remember that you can Ctrl+Click on a hint to navigate to the corresponding parameter. This navigation shortcut works with all kinds of inlay hints.
Aggregate initialization hints
Inlay hints are also available when an object of an aggregate type is initialized with a brace-enclosed initializer list or with a parenthesized list of values (since C++20). They allow you to see the names of the members you are initializing and spot if they are out of order.
These hints also work for arrays and can help with multidimensional initialization:
When using aggregate initialization, the braces around the nested initializer lists may be elided. To make code more readable in this case, you can use the
missing-braces Clang diagnostic and add braces around the initialization of subobjects with Alt+Enter.
Namespace name hints
Namespaces can be used to create independent code sections and prevent any naming conflicts by working in different scopes. A large project can have any number of namespaces, which sometimes are nested or even do not have a name. In such cases, some code style guides, such as Google and LLVM, recommend adding comments indicating what namespace is being closed by the current brace. But if you read the code without these comments, the namespace hints will guide you through.
Note the use of the inline keyword in the nested namespace definition, supported since C++20. If you want to read more about new C++20 features and their support, follow the C++20 and ReSharper C++ series of blog posts.
You can also enable a Clang-Tidy inspection (llvm-namespace-comment in ReSharper | Options | Code Inspection | Inspection Severity) and use a quick-fix to generate namespace comments.
Preprocessor directive hints
Long and nested conditional preprocessor sections can be confusing, so preprocessor directive hints are ready to indicate the corresponding condition for each closing directive. Here’s a sample of the new
__has_include operand, which helps you determine whether or not a specific library header is available for inclusion:
Type name hints
Type name hints help you when a C++ type is deduced automatically by the compiler from the surrounding code. ReSharper C++ provides type name hints for auto variables, function and lambda return types, in structured bindings, dependent code, and after function calls.
auto is sometimes used for hard-to-spell long types, and it would be nice to see what the type deduces to when it’s not clear from the initializer of the variable. In this example, the inlay hint reveals that the actual type of the iterator variable is a standard container iterator:
However, the most common case is when you omit the type because there is nothing new to say to the compiler, so you can make the code cleaner and more flexible. But what if you see the code for the first time, and only the compiler knows all the types? Then, type hints can make it clear what’s going on:
Function and lambda return types
The return types of functions and lambdas can be automatically deduced from the return statement when they are omitted in the code. If this is the case, ReSharper C++ shows you a hint with the deduced type:
Structured binding declarations introduced in C++17 allow you to decompose an object into its constituent elements. You can create structured bindings to non-static data members of a class, or to elements of structured types like an array, a pair, or a tuple. Here you can see type hints in action when binding to the elements of a tuple object:
Type hints also work for dependent code, but they are turned off by default to not affect the performance (we are working on it, so please stay tuned!). Inside the definition of a template, the meaning of some constructs may differ from one instantiation to another. But we still can provide some additional useful information for types and expressions:
With the default settings, this kind of type hint is shown only after multiline chained function calls. Function chaining is a typical pattern where the state of the same object is modified by successively calling several member functions. Here both parameter name and function call hints help you disentangle a complex chain of calls:
All hint options can be configured to meet your requirements: you can hide some excessive hints, or show even obvious ones if they help you see the big picture. Right-click on a hint to open the context menu or go to ReSharper | Options | Environment | Editor | Inlay Hints.
There is always an option to hover over any entity and see a tooltip with all the required information, but with inlay hints you can just focus on reading the code. We are currently working on new context actions that will improve readability even for non-ReSharper C++ users, so you can share your benefits with others! The actions will convert hints into comments or, for example, into designators for a C++20 designated initialization.
What do you think about our plans? What else can we do to make code easier to read for you? Please leave your feedback and suggestions in the comments below.
Download ReSharper C++ 2019.3 from our site and see if you can read code more easily with these hints.
Subscribe to Blog updates
C++20 Modules Come to ReSharper C++
We've implemented support for both of the main ways to introduce modules into your codebase: named modules and header units.
Blueprint Support Comes to ReSharper C++
With the new hints, you will be aware of derived Blueprint classes, UFunction implementations, and default values of UProperties set in the Blueprint files.
Take your C++ Coding to the Next Level with ReSharper C++
Check out the series of super-short video tips that you can watch one-by-one, while you’re having your morning coffee or tea or waiting for a build to finish.
ReSharper C++ Quick Tips: Text Search
A new episode in the ReSharper C++ Quick Tips video series is now available! If you missed the previous ones, here are the links: Overload Resolution Code Completion Converting Enum to String Macro Substitution C++20's Comparisons Includes Analyzer Postfix Completion Modernizing Quick-Fixes Inlay H…