Code Action
clice offers code actions on a selection: refactorings that generate or reshape code from what the compiler knows about it, and quick fixes for names no header declares. Every action is computed to completion when it is offered, so applying one never waits on a second request; edits carry the document version they were computed for, and an editor refuses them once the buffer moved on. The same actions run headless through clice inspect code_action.
An action anchors on the innermost construct the selection covers — a method declaration, a class name, a switch, an auto — so the list stays short: a click on a method name offers what applies to that method, a click on the class name what applies to the class.
Defining Functions
Define a declared method
A method declaration offers an inline body and an out-of-line definition after its class
The out-of-line definition repeats the declaration with S:: before the name and drops what belongs to the declaration alone, such as default arguments.
Declaration-only specifiers dropped
virtual, static, explicit, override and final do not appear on the definition
Specifiers that must stay, such as constexpr and noexcept, are kept.
Definition-scope return type
A return type naming a nested type or another namespace is spelled so it resolves at the definition
Parameter types are looked up in the class scope like the declaration's and stay as written.
Class template member
The definition of a class template's member carries the template head and the template arguments in its qualifier
Default template arguments are not repeated on the head.
Member function template
A member template keeps its own template head, minus its default arguments, after the class's
Constrained templates keep their requires-clauses, which a definition must repeat.
Constructors, destructors and operators
Special member functions are defined under the class name they are spelled with
Conversion functions and operators keep their full spelling.
Free function declaration
A declared free function is defined right after its declaration, in the same namespace
The name needs no qualifier inside the namespace; the return type is spelled for that scope.
Placement after existing definitions
When the class already has out-of-line definitions in the file, the new one goes after the last of them
The qualifier follows the scope of that definition, not the class's.
Define all missing members
On the class name, every member function without a definition is defined at once, in declaration order
Members that already have a definition, pure virtuals and defaulted members are left alone.
Missing members from a definition
Inside an out-of-line definition, the class's remaining undefined members are offered too
This is how a source file completes a class declared elsewhere: the definitions join the ones already there.
Define in the host source
In a header, a member can also be defined in the source file the header is compiled with
The definition is fully qualified and joins the class's other definitions in that file; members already defined in some source file are not offered again. Templates, inline functions and functions other files cannot see stay in the header; any other function defined there out of the class is marked inline.
Nested class member
A nested class's member is defined after the outermost enclosing class, qualified through every level
Dependent return type
A return type naming the class template or one of its member types is qualified through the template's parameters
Declarations under a linkage specification
Functions declared with C linkage are defined like any other, inside the linkage block or after a single-declaration form
Implementing Interfaces
Implement pure virtual methods
A class deriving from an abstract base receives an override declaration for each unimplemented pure virtual method
The declarations go at the end of the class body.
Pure virtuals through a chain
Only the methods no class in the chain implemented are declared, and a class gets a public: label for them
Types for the derived class
Parameter and return types written in the base's scope are qualified so they resolve in the derived class
Reference qualifiers and constness are carried over.
Conversion functions and pointer parameters
A conversion function has no return type to print, and a parameter whose type wraps its name keeps that shape
Bases sharing a signature
One declaration overrides the pure virtual methods of every base with that signature, noexcept when any of them is
Specifiers of the override
A C variadic parameter, consteval and whether the base's method is noexcept carry over to the override
A method whose exception specification depends on the arguments of a base class template gets no declaration.
Switch Cases
Missing enum cases
A switch over an enum receives the enumerators it does not handle, followed by a break
Enumerators sharing a handled value are considered covered.
Cases before the default
With a default present, the missing cases go right before it and fall through into it, keeping the behavior
The action is offered from anywhere inside the switch.
Unscoped enum in a namespace
Enumerators of an unscoped enum are qualified with the enum's namespace when the switch lies outside it
Complete switch offers nothing
A switch handling every enumerator, or one over a non-enum value, offers no action
Selection covering the switch
A selection spanning the whole statement offers the same action as a cursor inside it
Labels depending on templates
A switch with a label depending on template parameters offers no action, since only an instantiation knows which enumerators it covers
A switch in a template whose labels do not depend on its parameters is completed as anywhere else.
Sections declaring variables
Without a default, a switch declaring a variable at its own scope receives the missing cases before its first label, since a label after the declaration would jump past it
No section falls through into cases placed there.
Deduced Types
Expand auto in declarations
auto in a variable declaration is replaced by the type it deduced, leaving qualifiers and declarators in place
Deduced return type
A function's deduced auto return type expands to the deduced type, spelled for the function's scope
Expand decltype
A decltype specifier expands to the type it denotes
Unnameable types stay auto
Lambdas, dependent types and types the declaration cannot name are not expanded
A type cannot be named where it is local to another function, a member type the declaration has no access to, or the type of sizeof with no standard name for it declared yet (MSVC compatibility declares size_t implicitly).
Forwarding references and declarator types
auto&& bound to an lvalue takes the deduced reference in place of both tokens, and a type that wraps the name is left alone
Names spelled for the scope
A name drops the enclosing namespaces only as far as the shorter name still finds the same type
A name hidden by a declaration closer to the expansion keeps its qualifier, and one hidden even when fully qualified starts from the global scope.
Standard names of builtin types
The types of sizeof, a pointer difference and nullptr expand to their standard names where those are declared
Without a declaration of std::nullptr_t in sight, the type of nullptr is written decltype(nullptr).
Constant deduced pointers
A const written before an auto that deduced a pointer moves behind the *, keeping the pointer itself constant
When other specifiers stand between the const and the auto, the declaration is left as written.
Macros
Expand a macro invocation
A macro invocation is replaced by the tokens it expands to
Arguments are substituted; the action is offered from the macro name or anywhere inside its arguments.
Nested macros expand fully
A macro whose body invokes other macros expands to the final tokens
Directive references and empty macros
A macro named in a preprocessor condition, on any of its lines, is not an expansion to replace, while a macro expanding to nothing is deleted
Macros running pragmas
A macro whose expansion executes a _Pragma operator offers no expansion, since the pragma leaves no tokens behind to write in its place
Tokens stay apart
The expansion is spaced so its tokens merge neither with each other nor with the text written flush against the invocation
Missing Includes
Standard library include
An unresolved standard library name offers the header declaring it, from the standard library mapping
The directive goes after the includes at the top of the file. An unqualified name also tries the std namespace.
Include for a project symbol
A name declared in a project header the file does not include offers that header, spelled relative to the file
The candidates come from the project index: lib.h is known because another source file includes it.
First include of a file
A file without includes receives the directive at its start, after a #pragma once when there is one
Includes under conditionals
An include nested in a feature condition is not where a directive that must always apply goes: it follows the last one at the file's own level, or the include guard
Embedded and trailing includes
An include inside extern "C" or a type body, or one following the code, is no place for a new directive: it joins the includes at the top of the file
Reordering Definitions
Reorder definitions by declaration
The out-of-line definitions of a class's members are reordered to follow the declaration order in the class
Each definition moves with the comment block directly above it.
Namespace blocks reorder separately
Definitions written in different namespace blocks are reordered within each block, never across
Free functions by declaration order
From a free function's definition, the definitions of the functions declared alongside it are reordered as declared
Trailing comments stay in place
A comment ending a definition's line moves with that definition, never with the one below it
Definitions using what lies between
A definition stays where it is when moving it would put it before something it uses, such as a variable or macro defined between the definitions; the others are reordered around it
Constructors
Memberwise constructor
A class receives a constructor taking every field in order, scalars by value and copyable classes by const reference
Existing constructor not duplicated
No constructor is generated when the class already declares one taking as many arguments as it has fields
Single field is explicit
A one-field class gets an explicit constructor, placed under a public: label when the class ends in another section
Declarator-shaped field types
A field whose type wraps the name, such as a function pointer, keeps that shape in the parameter
Base without a default constructor
No constructor is generated when a base class needs its own initializer, since the memberwise one initializes fields alone
Deleted base default constructor
A base whose default constructor is deleted explicitly, or implicitly by a reference member or a const member nothing initializes, blocks the memberwise constructor too
A const member of a class that initializes all its own fields leaves the base default-constructible.
Move-only fields
A field whose class moves but does not copy is taken by value and moved from, and an rvalue reference field binds its argument through std::move
The file gains #include <utility> when nothing declares std::move before the class. A class that neither copies nor moves gets no constructor.
Formatting
Generated text is formatted with the project's clang-format style when one applies to the file, so a definition or a block of case labels lands in the surrounding code's layout. Without a style, or with DisableFormat, the text keeps the layout shown in the examples above.
Known Limitations
- A definition placed in the host source goes after the last definition of the class's members the index knows in that file, or at the end of the file when it holds none. Which source file hosts a header follows the header's compilation context.
- Members already defined in another source file are left out of a "define missing members" action only when the project index knows that definition; with indexing disabled every undefined member is offered.
- A return type naming a member of a dependent base class is copied as written into an out-of-line definition, where it may need
typenameand the base's qualifier. - Missing-include candidates come from the standard library mapping and from headers the project index has seen; a header no indexed source file includes is not suggested.
Not Implemented
Quick fixes from compiler and clang-tidy fix-it hints, extract function and variable, inline function and variable, moving a definition between header and source, converting an unscoped enum to a scoped one, and changing a function's signature across its callers.
