Clang-format doesn't join function to return type if type is ALL_CAPS - clang-format

I'm noticing a strange behavior where clang-format will join a function name with its return type when the type is lower case, but not when the return type is all upper case.
Is there a way to get around this? Maybe this is being influenced by some other setting?
I've also tried BasedOnStyle: Microsoft). I have tried clang-format v12, v13, v14 and all seem to behave the same.
Desired format:
---
Language: Cpp
BasedOnStyle: LLVM
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
ColumnLimit: 120
PenaltyExcessCharacter: 10
PenaltyReturnTypeOnItsOwnLine: 100000000
...
Original File:
mytype
SomeFunctionLongName(
uint32_t param1, // aaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssssssss
uint32_t param2, // aaaaaaaaaaaaaaaaassssssssssssssssssssssssss
uint32_t param3 // aaaaaaaaaaaaaaaaa
);
MYTYPE
SomeFunctionLongNam2(
MYTYPE param1, // aaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssssssss
MYTYPE *param2, // aaaaaaaaaaaaaaaaassssssssssssssssssssssssss
MYTYPE **param3 // aaaaaaaaaaaaaaaaa
);
Run:
clang-format --style=file --verbose sample3.c
Result:
mytype SomeFunctionLongName(uint32_t param1, // aaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssssssss
uint32_t param2, // aaaaaaaaaaaaaaaaassssssssssssssssssssssssss
uint32_t param3 // aaaaaaaaaaaaaaaaa
);
MYTYPE
SomeFunctionLongNam2(MYTYPE param1, // aaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssssssss
MYTYPE *param2, // aaaaaaaaaaaaaaaaassssssssssssssssssssssssss
MYTYPE **param3 // aaaaaaaaaaaaaaaaa
);

Related

Why aren't constructor and static function tear-offs, with extending type parameters, identical when the base type is omitted or included?

Consider the following class:
class MyClass<T extends num> {
const MyClass();
void instanceFunction() {}
static void staticFunction<T extends num>() {}
}
The following expressions are all true:
identical(const MyClass(), const MyClass<num>());
identical(const MyClass.new(), const MyClass<num>.new());
identical(const MyClass().instanceFunction, const MyClass<num>().instanceFunction);
identical(MyClass.new, MyClass.new);
identical(MyClass<num>.new, MyClass<num>.new);
identical(MyClass.staticFunction, MyClass.staticFunction);
identical(MyClass.staticFunction<num>, MyClass.staticFunction<num>);
But when the base type, num, is included in one tear-off, such as in the expressions below, they are false:
identical(MyClass.new, MyClass<num>.new);
identical(MyClass.staticFunction, MyClass.staticFunction<num>);
Why is this the case?
The true cases:
identical(const MyClass(), const MyClass<num>());
You instantiate an MyClass object. Since MyClass is declared with MyClass<T extends num>, MyClass() with no explicit type specified is shorthand for MyClass<num>(). This expression therefore is the same as identical(const MyClass<num>, const MyClass<num>), which should obviously be true.
identical(const MyClass.new(), const MyClass<num>.new());
This is just a more roundabout version of the previous case.
identical(const MyClass().instanceFunction, const MyClass<num>().instanceFunction);
This is true for the same reason as the first case. const MyClass() is shorthand for const MyClass<num>(), const instances are canonicalized, so you're comparing .instanceFunction members of the exact same object.
identical(MyClass.new, MyClass.new);
Both arguments are the same and both are statically-known at compile-time, so there's no reason for this to be false.
identical(MyClass<num>.new, MyClass<num>.new);
This would be true for the same reason as the previous case.
identical(MyClass.staticFunction, MyClass.staticFunction);`
identical(MyClass.staticFunction<num>, MyClass.staticFunction<num>);
Both arguments to identical are the same, so that these evaluate to true shouldn't be surprising.
The false cases:
identical(MyClass.new, MyClass<num>.new);
identical(MyClass.staticFunction, MyClass.staticFunction<num>);
MyClass.new and MyClass.staticFunction are not shorthand for MyClass<num>.new and MyClass.staticFunction<num> respectively; they evaluate to generic functions:
var c1 = MyClass.new;
var c2 = MyClass<num>.new;
var f1 = MyClass.staticFunction;
var f2 = MyClass.staticFunction<num>;
then the type of c1 is MyClass<T> Function<T extends num>() and the type of c2 is MyClass<num> Function(). Similarly, the type of f1 is void Function<T extends num>() but the type of f2 is void Function(). c1 and f1 are still generic; you can do c1<num>() or f2<double>() later.
c2 and f2 have the type parameter statically bound already, so they have a different type and clearly should not be the same as c1 and f1 respectively.
A more interesting case is:
identical(f1<num>, MyClass.staticFunction<num>))
which evaluates to false. Why isn't this the same as the identical(MyClass.staticFunction<num>, MyClass.staticFunction<num>) case? I'm not sure exactly why, but I would presume that it's an implementation detail from the Dart compiler being able to trivially canonicalize MyClass.staticFunction<num> at compilation-time but not f1<num> due to f1 being potentially variable.

What am I missing. The compiler says that & needs an L value for this line:

I'm trying to merge two sorted linked lists into one linked list
start with the ListNode structure
struct ListNode
{
int val;
ListNode* next;
ListNode(): val(0), next(nullptr){}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
This is the code fragment that contains the problem line
int temp;
ListNoded* currR;
this is the offending line. The compiler says I need an 'L' value
currR->next = &ListNode();
//What am I missing?
Never mind. I figured it out. Those are constructors that run when I execute the "new" operator. I have to do something like ListNode* list1 = new struct ListNode();
That compiles and runs.

How can I match universal reference arguments to a member function using Clang AST matchers?

I'm trying to match arguments passed to a templated member function invocation using clang-query as a precursor to writing a clang-tidy check. Whilst I can get non-templated member functions to match, I'm unable to get templated member functions to. I'm using clang-14.0.0.
Consider:
#include <string>
class BaseTrace {
public:
template <typename... Args>
void Templated(const char *fmt, Args &&...args) {
}
void NotTemplated(const char *fmt, const char *s1, const char *s2) {
}
};
BaseTrace TRACE;
void trace1(const std::string &s1, const std::string &s2)
{
TRACE.Templated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
}
void trace2(const std::string &s1, const std::string &s2)
{
TRACE.NotTemplated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
}
Querying for normal member invocation function matches as expected:
clang-query> match match cxxMemberCallExpr(callee(functionDecl(hasName("NotTemplated"))), on(expr(hasType(cxxRecordDecl(hasName("::BaseTrace"))))), hasAnyArgument(cxxMemberCallExpr()))
Match #1:
/home/mac/git/llvm-project/build/../clang-tools-extra/test/clang-tidy/checkers/minimal-cstr.cpp:23:3: note: "root" binds here
TRACE.NotTemplated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 match.
But querying for a templated member function invocation does not:
clang-query> match match cxxMemberCallExpr(callee(functionDecl(hasName("Templated"), isTemplateInstantiation())), on(expr(hasType(cxxRecordDecl(hasName("::BaseTrace"))))), hasAnyArgument(cxxMemberCallExpr()))
0 matches.
The answer to this question implies that this ought to work. If I don't try to match the arguments then I am able to get a match:
clang-query> match cxxMemberCallExpr(callee(functionDecl(hasName("Templated"), isTemplateInstantiation())), on(anyOf(expr(hasType(cxxRecordDecl(hasName("::BaseTrace")))), expr(hasType(cxxRecordDecl(isDerivedFrom("::BaseTrace")))))))
Match #1:
/home/mac/git/llvm-project/build/../clang-tools-extra/test/clang-tidy/checkers/minimal-cstr.cpp:16:3: note: "root" binds here
TRACE.Templated("One:{} Two:{}\n", s1.c_str(), s2.c_str());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 match.
I don't seem to have the same problem when matching non-member functions.
Am I missing something, or is this potentially a clang limitation.
I'm not convinced that I've got to the bottom of this, but it appears that I can make the Templated method match by either using:
clang-query> set traversal IgnoreUnlessSpelledInSource
rather than the AsIs default with the match expression in the question, or by modifying the match expression to be:
clang-query> match cxxMemberCallExpr(callee(functionDecl(hasName("Templated"), isTemplateInstantiation())), on(expr(hasType(cxxRecordDecl(hasName("::BaseTrace"))))), hasAnyArgument(materializeTemporaryExpr(has(cxxMemberCallExpr()))))
to match the extra MaterializeTemporaryExpr node in the syntax tree.

TypeScript const assertions: how to use Array.prototype.includes?

I am trying to use an array of elements as union type, something that became easy with const assertions in TS 3.4, so I can do this:
const CAPITAL_LETTERS = ['A', 'B', 'C', ..., 'Z'] as const;
type CapitalLetter = typeof CAPITAL_LETTERS[string];
Now I want to test whether a string is a capital letter, but the following fails with "not assignable to parameter of type":
let str: string;
...
CAPITAL_LETTERS.includes(str);
Is there any better way to fix this rather than casting CAPITAL_LETTERS to unknown and then to Array<string>?
The standard library signature for Array<T>.includes(u) assumes that the value to be checked is of the same or narrower type than the array's elements T. But in your case you are doing the opposite, checking against a value which is of a wider type. In fact, the only time you would say that Array<T>.includes<U>(x: U) is a mistake and must be prohibited is if there is no overlap between T and U (i.e., when T & U is never).
Now, if you're not going to be doing this sort of "opposite" use of includes() very often, and you want zero runtime efects, you should just widen CAPITAL_LETTERS to ReadonlyArray<string> via type assertion:
(CAPITAL_LETTERS as ReadonlyArray<string>).includes(str); // okay
If, on the other hand, you feel seriously enough that this use of includes() should be accepted with no type assertions, and you want it to happen in all of your code, you could merge in a custom declaration:
// global augmentation needed if your code is in a module
// if your code is not in a module, get rid of "declare global":
declare global {
interface ReadonlyArray<T> {
includes<U>(x: U & ((T & U) extends never ? never : unknown)): boolean;
}
}
That will make it so that an array (well, a readonly array, but that's what you have in this example) will allow any parameter for .includes() as long as there is some overlap between the array element type and the parameter type. Since string & CapitalLetter is not never, it will allow the call. It will still forbid CAPITAL_LETTERS.includes(123), though.
Okay, hope that helps; good luck!
Another way to solve it is with a type guard
https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
const myConstArray = ["foo", "bar", "baz"] as const
function myFunc(x: string) {
//Argument of type 'string' is not assignable to parameter of type '"foo" | "bar" | "baz"'.
if (myConstArray.includes(x)) {
//Hey, a string could totally be one of those values! What gives, TS?
}
}
//get the string union type
type TMyConstArrayValue = typeof myConstArray[number]
//Make a type guard
//Here the "x is TMyConstArrayValue" tells TS that if this fn returns true then x is of that type
function isInMyConstArray(x: string): x is TMyConstArrayValue {
return myConstArray.includes(x as TMyConstArrayValue)
//Note the cast here, we're doing something TS things is unsafe but being explicit about it
//I like to this of type guards as saying to TS:
//"I promise that if this fn returns true then the variable is of the following type"
}
function myFunc2(x: string) {
if (isInMyConstArray(x)) {
//x is now "foo" | "bar" | "baz" as originally intended!
}
}
While you have to introduce another "unnecessary" function this ends up looking clean and working perfectly. In your case you would add
const CAPITAL_LETTERS = ['A', 'B', 'C', ..., 'Z'] as const;
type CapitalLetter = typeof CAPITAL_LETTERS[string];
function isCapitalLetter(x: string): x is CapitalLetter {
return CAPITAL_LETTERS.includes(x as CapitalLetter)
}
let str: string;
isCapitalLetter(str) //Now you have your comparison
//Not any more verbose than writing .includes inline
if(isCapitalLetter(str)){
//now str is of type CapitalLetter
}
Here's a solution that works well for strings & string literals using TypeScript 4.1 Template Literal Types that doesn't break anything else, and also narrows the type for convenience when used in conditions:
declare global {
interface ReadonlyArray<T> {
includes<S, R extends `${Extract<S, string>}`>(
this: ReadonlyArray<R>,
searchElement: S,
fromIndex?: number
): searchElement is R & S;
}
}
Originally posted by noppa in a TypeScript github issue related to this.
Adding to #imagio's answer, you can make the genetic type guard (thanks to #wprl for simplification)
function isIn<T>(values: readonly T[], x: any): x is T {
return values.includes(x);
}
And use it with any as const array:
const specialNumbers = [0, 1, 2, 3] as const;
function foo(n: number) {
if (isIn(specialNumbers, n)) {
//TypeScript will say that `s` has type `0 | 1 | 2 | 3` here
}
}
You can also create a curried version of Array.prototype.includes which works with tuples:
const PROPS = ['a', 'b', 'c'] as const;
const withTuple = <
List extends string[]
>(list: readonly [...List]) =>
(prop: string): prop is List[number] =>
list.includes(prop)
const includes = withTuple(PROPS);
const result = includes('d')
declare let str: string
if (includes(str)) {
str // "a" | "b" | "c"
}
Playground
Higher order function with list argument created for inference.
You can also check my article
Reassignment using a wider type annotation is potentially the simplest solution, if a little untidy due to adding an extraneous variable.
const CAPITAL_LETTERS = ['A', 'B', 'C', ..., 'Z'] as const;
const widenedCapitalLetters: string[] = CAPITAL_LETTERS
widenedCapitalLetters.includes("hello")
This allows you to keep the const assertion on the base array so you get the type narrowing you need.
using lodash
const CAPITAL_LETTERS = ['A', 'B', 'C', 'Z'] as const;
_.includes(CAPITAL_LETTERS, 'A');

meaning of const in `const ['foo', 'bar']` in dart

I know that const is compile-time constant in dart, but I don't understand mechanism behind const [F0, F1, F2] in the following code:
class Foo {
static const F0 = 'F0';
static const F1 = 'F1';
static const F2 = 'F2';
// const list of const values I guess...
static const CONST_LIST = const [F0, F1, F2]; // please explain this line
static final String FOO = CONST_LIST[0]; // ok
// compile error: 'const' varaibles must be constant value
// static const String BAR = CONST_LIST[1];
}
main() {
// is CONST_LIST const or not?
// below line it's ok for dartanalyzer but
// in runtime: Cannot change the content of an unmodifiable List
Foo.CONST_LIST[1] = 'new value';
}
I noticed that const is required by dart analyzer in const [F0, F1, F2]; but it does make list more like final (runtime immutable list) rather than compile time const.
UPDATE:
Another question is why CONST_LIST[1] is not "constant value". See commented declaration of Foo.BAR.
Günter has answered the second part of your question. Here is some more information about const.
Const means that the object's entire deep state can be determined entirely at compile time and that the object will be frozen and completely immutable.
More information in this article. Also see the following question.
Regarding the second part of your question, consider the following:
const int foo = 10 * 10;
The expression "10 * 10" can be evaluated at compile time, so it is a "constant expression". The types of things you can do in a constant expression need to be quite limited (otherwise you could run arbitrary Dart code in the compiler!). But some of these limitations are being relaxed as dart matures, as you can see in the bug which Günter linked to.
In contrast, consider the following:
final int bar = 10;
final int foo = bar * bar;
Since "bar * bar" is not a constant expression it is evaluated at runtime.
There is an open bug for this: see https://github.com/dart-lang/sdk/issues/3059

Resources