NetBSD/tests/usr.bin/indent/fmt_decl.c

987 lines
18 KiB
C

/* $NetBSD: fmt_decl.c,v 1.46 2023/05/23 16:53:57 rillig Exp $ */
/*
* Tests for declarations of global variables, external functions, and local
* variables.
*
* See also:
* opt_di.c
*/
/* See FreeBSD r303570 */
/*
* A type definition usually declares a single type, so there is no need to
* align the newly declared type name with the other variables.
*/
//indent input
typedef void ( * function_ptr ) ( int * ) ;
//indent end
//indent run
typedef void (*function_ptr)(int *);
//indent end
/*
* In variable declarations, the names of the first declarators are indented
* by the amount given in '-di', which defaults to 16.
*/
//indent input
extern void ( * function_pointer ) ( int * ) ;
extern void * pointer;
//indent end
//indent run
/* $ XXX: Why is the token 'function_pointer' not aligned with 'pointer'? */
extern void (*function_pointer)(int *);
extern void *pointer;
//indent end
//indent input
static const struct
{
double x;
double y, z;
} n[m + 1] =
{
{
.0,
.9,
5
}
};
//indent end
//indent run
static const struct
{
double x;
double y, z;
} n[m + 1] =
{
{
.0,
.9,
5
}
};
//indent end
//indent input
typedef struct Complex
{
double x;
double y;
} Complex;
//indent end
//indent run
typedef struct Complex
{
double x;
double y;
} Complex;
//indent end
/*
* Ensure that function definitions are reasonably indented. Before
* 2023-05-11, tokens were repeatedly read, and the line numbers were wrong.
*/
//indent input
void
t1 (char *a, int b,
void (*fn)(void))
{}
//indent end
//indent run
void
t1(char *a, int b,
void (*fn)(void))
{
}
//indent end
/* See opt_bc.c. */
//indent input
void t2 (char *x, int y)
{
int a,
b,
c;
int
*d,
*e,
*f;
int (*g)(),
(*h)(),
(*i)();
int j,
k,
l;
int m
,n
,o
;
int chars[ /* push the comma beyond column 74 ...... */ ], x;
}
//indent end
//indent run
void
t2(char *x, int y)
{
int a, b, c;
int
*d, *e, *f;
int (*g)(), (*h)(), (*i)();
int j, k, l;
int m
,n
,o
;
int chars[/* push the comma beyond column 74 ...... */],
x;
}
//indent end
//indent input
const int int_minimum_size =
MAXALIGN(offsetof(int, test)) + MAXIMUM_ALIGNOF;
//indent end
//indent run-equals-input
/*
* Ensure that the usual GCC-style function attributes are formatted in a
* sensible way.
*/
//indent input
void single_param(int) __attribute__((__noreturn__)) ;
void function(const char *, ...) __attribute__((format(printf, 1, 2))) ;
//indent end
//indent run -di0
void single_param(int) __attribute__((__noreturn__));
void function(const char *, ...) __attribute__((format(printf, 1, 2)));
//indent end
//indent run
void single_param(int) __attribute__((__noreturn__));
void function(const char *, ...) __attribute__((format(printf, 1, 2)));
//indent end
//indent input
static
_attribute_printf(1, 2)
void
print_error(const char *fmt,...)
{
}
//indent end
//indent run
static
_attribute_printf(1, 2)
void
print_error(const char *fmt, ...)
{
}
//indent end
//indent input
static _attribute_printf(1, 2)
void
print_error(const char *fmt,...)
{
}
//indent end
//indent run
static _attribute_printf(1, 2)
void
print_error(const char *fmt, ...)
{
}
//indent end
//indent input
static void _attribute_printf(1, 2)
print_error(const char *fmt,...)
{
}
//indent end
//indent run
static void
_attribute_printf(1, 2)
print_error(const char *fmt, ...)
{
}
//indent end
/* See FreeBSD r309380 */
//indent input
static LIST_HEAD(, alq) ald_active;
static int ald_shutting_down = 0;
struct thread *ald_thread;
//indent end
//indent run
static LIST_HEAD(, alq) ald_active;
static int ald_shutting_down = 0;
struct thread *ald_thread;
//indent end
//indent input
static int
old_style_definition(a, b, c)
struct thread *a;
int b;
double ***c;
{
}
//indent end
//indent run
static int
old_style_definition(a, b, c)
struct thread *a;
int b;
double ***c;
{
}
//indent end
/*
* Demonstrate how variable declarations are broken into several lines when
* the line length limit is set quite low.
*/
//indent input
struct s a,b;
struct s0 a,b;
struct s01 a,b;
struct s012 a,b;
struct s0123 a,b;
struct s01234 a,b;
struct s012345 a,b;
struct s0123456 a,b;
struct s01234567 a,b;
struct s012345678 a,b;
struct s0123456789 a,b;
struct s01234567890 a,b;
struct s012345678901 a,b;
struct s0123456789012 a,b;
struct s01234567890123 a,b;
//indent end
//indent run -l20 -di0
struct s a, b;
/* $ XXX: See process_comma, varname_len for why this line is broken. */
struct s0 a,
b;
/* $ XXX: The indentation of the second line is wrong. The variable names */
/* $ XXX: 'a' and 'b' should be in the same column; the word 'struct' is */
/* $ XXX: missing in the calculation for the indentation. */
struct s01 a,
b;
struct s012 a,
b;
struct s0123 a,
b;
struct s01234 a,
b;
struct s012345 a,
b;
struct s0123456 a,
b;
struct s01234567 a,
b;
struct s012345678 a,
b;
struct s0123456789 a,
b;
struct s01234567890 a,
b;
struct s012345678901 a,
b;
struct s0123456789012 a,
b;
struct s01234567890123 a,
b;
//indent end
//indent input
char * x(void)
{
type identifier;
type *pointer;
unused * value;
(void)unused * value;
dmax = (double)3 * 10.0;
dmin = (double)dmax * 10.0;
davg = (double)dmax * dmin;
return NULL;
}
//indent end
//indent run
char *
x(void)
{
type identifier;
type *pointer;
unused *value;
(void)unused * value;
dmax = (double)3 * 10.0;
dmin = (double)dmax * 10.0;
davg = (double)dmax * dmin;
return NULL;
}
//indent end
//indent input
int *
y(void) {
}
int
z(void) {
}
//indent end
//indent run
int *
y(void)
{
}
int
z(void)
{
}
//indent end
//indent input
int x;
int *y;
int * * * * z;
//indent end
//indent run
int x;
int *y;
int ****z;
//indent end
//indent input
int main(void) {
char (*f1)() = NULL;
char *(*f1)() = NULL;
char *(*f2)();
}
//indent end
/*
* Before NetBSD io.c 1.103 from 2021-10-27, indent wrongly placed the second
* and third variable declaration in column 1. This bug has been introduced
* to NetBSD when FreeBSD indent was imported in 2019.
*/
//indent run -ldi0
int
main(void)
{
char (*f1)() = NULL;
char *(*f1)() = NULL;
char *(*f2)();
}
//indent end
//indent run
int
main(void)
{
/* $ XXX: Not really pretty, the name 'f1' should be aligned, if at all. */
char (*f1)() = NULL;
/* $ XXX: Not really pretty, the name 'f1' should be aligned, if at all. */
char *(* f1)() = NULL;
/* $ XXX: Not really pretty, the name 'f2' should be aligned, if at all. */
char *(* f2)();
}
//indent end
/*
* In some ancient time long before ISO C90, variable declarations with
* initializer could be written without '='. The C Programming Language from
* 1978 doesn't mention this form anymore.
*
* Before NetBSD lexi.c 1.123 from 2021-10-31, indent treated the '-' as a
* unary operator.
*/
//indent input
int a - 1;
{
int a - 1;
}
//indent end
//indent run -di0
int a - 1;
{
int a - 1;
}
//indent end
/*
* Between 2019-04-04 and before lexi.c 1.146 from 2021-11-19, the indentation
* of the '*' depended on the function name, which did not make sense. For
* function names that matched [A-Za-z]+, the '*' was placed correctly, for
* all other function names (containing [$0-9_]) the '*' was right-aligned on
* the declaration indentation, which defaults to 16.
*/
//indent input
int *
f2(void)
{
}
int *
yy(void)
{
}
int *
int_create(void)
{
}
//indent end
//indent run-equals-input
/*
* Since 2019-04-04, the space between the '){' is missing.
*/
//indent input
int *
function_name_____20________30________40________50
(void)
{}
//indent end
/*
* Before 2023-05-11, indent moved the '{' right after the '(void)', without
* any space in between.
*/
//indent run
int *function_name_____20________30________40________50
(void)
{
}
//indent end
/*
* Since 2019-04-04 and before lexi.c 1.144 from 2021-11-19, some function
* names were preserved while others were silently discarded.
*/
//indent input
int *
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
(void)
{}
//indent end
/*
* Before 2023-05-11, indent moved the '{' right after the '(void)', without
* any space in between.
*/
//indent run
int *aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
(void)
{
}
//indent end
/*
* Before 1990, when C90 standardized function prototypes, a function
* declaration or definition did not contain a '*' that may have looked
* similar to the binary operator '*' because it was surrounded by two
* identifiers.
*
* As of 2021-11-21, indent interpreted the '*' in the function declaration in
* line 1 as a binary operator, even though the '*' was followed by a ','
* directly. This was not visible in the output though since indent never
* outputs a space before a comma.
*
* In the function declaration in line 2 and the function definition in line
* 5, indent interpreted the '*' as a binary operator as well and accordingly
* placed spaces around the '*'. On a very low syntactical analysis level,
* this may have made sense since the '*' was surrounded by words, but still
* the '*' is part of a declaration, where a binary operator does not make
* sense.
*
* Essentially, as of 2021, indent had missed the last 31 years of advances in
* the C programming language, in particular the invention of function
* prototypes. Instead, the workaround had been to require all type names to
* be specified via the options '-ta' and '-T'. This put the burden on the
* user instead of the implementer.
*
* Fixed in lexi.c 1.156 from 2021-11-25.
*/
//indent input
void buffer_add(buffer *, char);
void buffer_add(buffer *buf, char ch);
void
buffer_add(buffer *buf, char ch)
{
*buf->e++ = ch;
}
//indent end
/* Before lexi.c 1.156 from 2021-11-25, indent generated 'buffer * buf'. */
//indent run
void buffer_add(buffer *, char);
/* $ FIXME: space after '*' */
void buffer_add(buffer * buf, char ch);
void
buffer_add(buffer *buf, char ch)
{
*buf->e++ = ch;
}
//indent end
/*
* Before lexi.c 1.153 from 2021-11-25, indent did not recognize 'Token' as a
* type name and then messed up the positioning of the '{'.
*/
//indent input
static Token
ToToken(bool cond)
{
}
//indent end
//indent run-equals-input -TToken
/* Since lexi.c 1.153 from 2021-11-25. */
//indent run-equals-input
/*
* Before indent.c 1.309 from 2023-05-23, indent easily got confused by unknown
* type names in struct declarations, as a ';' did not finish a declaration.
*/
//indent input
typedef struct OpenDirs {
CachedDirList list;
HashTable /* of CachedDirListNode */ table;
} OpenDirs;
//indent end
//indent run-equals-input -THashTable
//indent run-equals-input
/*
* Before lexi.c 1.153 from 2021-11-25, indent easily got confused by unknown
* type names, even in declarations that are syntactically unambiguous.
*/
//indent input
static CachedDir *dot = NULL;
//indent end
//indent run-equals-input -TCachedDir
//indent run-equals-input
/*
* Before lexi.c 1.153 from 2021-11-25, indent easily got confused by unknown
* type names in declarations.
*/
//indent input
static CachedDir *
CachedDir_New(const char *name)
{
}
//indent end
//indent run-equals-input
/*
* Before lexi.c 1.156 from 2021-11-25, indent easily got confused by unknown
* type names in declarations and generated 'CachedDir * dir' with an extra
* space.
*/
//indent input
static CachedDir *
CachedDir_Ref(CachedDir *dir)
{
}
//indent end
//indent run-equals-input
/*
* Before lexi.c 1.156 from 2021-11-25, indent easily got confused by unknown
* type names in declarations and generated 'HashEntry * he' with an extra
* space.
*
* Before lexi.c 1.153 from 2021-11-25, indent also placed the '{' at the end
* of the line.
*/
//indent input
static bool
HashEntry_KeyEquals(const HashEntry *he, Substring key)
{
}
//indent end
//indent run-equals-input
/*
* Before lexi.c 1.156 from 2021-11-25, indent didn't notice that the two '*'
* are in a declaration, instead it interpreted the first '*' as a binary
* operator, therefore generating 'CachedDir * *var' with an extra space.
*/
//indent input
static void
CachedDir_Assign(CachedDir **var, CachedDir *dir)
{
}
//indent end
//indent run-equals-input -TCachedDir
//indent run-equals-input
/*
* Before lexi.c 1.153 from 2021-11-25, all initializer expressions after the
* first one were indented as if they were statement continuations. This was
* caused by the token 'Shell' being identified as a word, not as a type name.
*/
//indent input
static Shell shells[] = {
{
first,
second,
},
};
//indent end
//indent run-equals-input
/*
* Before lexi.c 1.158 from 2021-11-25, indent easily got confused by function
* attribute macros that followed the function declaration. Its primitive
* heuristic between deciding between a function declaration and a function
* definition only looked for ')' immediately followed by ',' or ';'. This was
* sufficient for well-formatted code before 1990. With the addition of
* function prototypes and GCC attributes, the situation became more
* complicated, and it took indent 31 years to adapt to this new reality.
*/
//indent input
static void JobInterrupt(bool, int) MAKE_ATTR_DEAD;
static void JobRestartJobs(void);
//indent end
//indent run
static void JobInterrupt(bool, int) MAKE_ATTR_DEAD;
static void JobRestartJobs(void);
//indent end
/*
* Before lexi.c 1.158 from 2021-11-25, indent easily got confused by the
* tokens ')' and ';' in the function body. It wrongly regarded them as
* finishing a function declaration.
*/
//indent input
MAKE_INLINE const char *
GNode_VarTarget(GNode *gn) { return GNode_ValueDirect(gn, TARGET); }
//indent end
/*
* Before lexi.c 1.156 from 2021-11-25, indent generated 'GNode * gn' with an
* extra space.
*
* Before lexi.c 1.158 from 2021-11-25, indent wrongly placed the function
* name in line 1, together with the '{'.
*/
//indent run
MAKE_INLINE const char *
GNode_VarTarget(GNode *gn)
{
return GNode_ValueDirect(gn, TARGET);
}
//indent end
//indent run-equals-prev-output -TGNode
/*
* Ensure that '*' in declarations is interpreted (or at least formatted) as
* a 'pointer to' type derivation, not as a binary or unary operator.
*/
//indent input
number *var = a * b;
void
function(void)
{
number *var = a * b;
}
//indent end
//indent run-equals-input -di0
/*
* In declarations, most occurrences of '*' are pointer type derivations.
* There are a few exceptions though. Some of these are hard to detect
* without knowing which identifiers are type names.
*/
//indent input
char str[expr * expr];
char str[expr**ptr];
char str[*ptr**ptr];
char str[sizeof(expr * expr)];
char str[sizeof(int) * expr];
char str[sizeof(*ptr)];
char str[sizeof(type**)];
char str[sizeof(**ptr)];
//indent end
//indent run -di0
char str[expr * expr];
char str[expr * *ptr];
char str[*ptr * *ptr];
char str[sizeof(expr * expr)];
char str[sizeof(int) * expr];
char str[sizeof(*ptr)];
/* $ FIXME: should be 'type **' */
char str[sizeof(type * *)];
char str[sizeof(**ptr)];
//indent end
/*
* Since lexi.c 1.158 from 2021-11-25, whether the function 'a' was considered
* a declaration or a definition depended on the preceding struct, in
* particular the length of the 'pn' line. This didn't make sense at all and
* was due to an out-of-bounds memory access.
*
* Seen amongst others in args.c 1.72, function add_typedefs_from_file.
* Fixed in lexi.c 1.165 from 2021-11-27.
*/
//indent input
struct {
} v = {
pn("ta"),
};
static void
a(char *fe)
{
}
struct {
} v = {
pn("t"),
};
static void
a(char *fe)
{
}
//indent end
//indent run -di0
struct {
} v = {
pn("ta"),
};
static void
a(char *fe)
{
}
struct {
} v = {
pn("t"),
};
static void
a(char *fe)
{
}
//indent end
/*
* Before NetBSD indent.c 1.178 from 2021-10-29, indent removed the blank
* before the '=', in the second and third of these function pointer
* declarations. This was because indent interpreted the prototype parameters
* 'int' and 'int, int' as type casts, which doesn't make sense at all. Fixing
* this properly requires large style changes since indent is based on simple
* heuristics all over. This didn't change in indent.c 1.178; instead, the
* rule for inserting a blank before a binary operator was changed to always
* insert a blank, except at the beginning of a line.
*/
//indent input
char *(*fn)() = NULL;
char *(*fn)(int) = NULL;
char *(*fn)(int, int) = NULL;
//indent end
/* XXX: The parameter '(int)' is wrongly interpreted as a type cast. */
/* XXX: The parameter '(int, int)' is wrongly interpreted as a type cast. */
//indent run-equals-input -di0
/*
* Depending on whether there was a line break in the function header, the
* spaces around the '||' operator were erroneously removed.
*/
//indent input
bool is_identifier_start(char ch)
{
return ch_isalpha(ch) || ch == '_';
}
bool
is_identifier_start(char ch)
{
return ch_isalpha(ch) || ch == '_';
}
//indent end
//indent run
bool
is_identifier_start(char ch)
{
return ch_isalpha(ch) || ch == '_';
}
bool
is_identifier_start(char ch)
{
return ch_isalpha(ch) || ch == '_';
}
//indent end
//indent input
void buf_add_chars(struct buffer *, const char *, size_t);
static inline bool
ch_isalnum(char ch)
{
return isalnum((unsigned char)ch) != 0;
}
static inline bool
ch_isalpha(char ch)
{
return isalpha((unsigned char)ch) != 0;
}
//indent end
//indent run -i4 -di0
// $ FIXME: 'buffer' is classified as 'word'.
// $
// $ XXX: 'char' is classified as 'type_in_parentheses'; check whether this
// $ XXX: lexer symbol should only be used for types in cast expressions.
// $
// $ FIXME: 'size_t' is classified as 'word'.
void buf_add_chars(struct buffer *, const char *, size_t);
static inline bool
ch_isalnum(char ch)
{
return isalnum((unsigned char)ch) != 0;
}
static inline bool
ch_isalpha(char ch)
{
return isalpha((unsigned char)ch) != 0;
}
//indent end
//indent run-equals-input -i4 -di0
//indent input
void __printflike(1, 2)
debug_printf(const char *fmt, ...)
{
}
//indent end
//indent run
void
// $ FIXME: No line break here.
__printflike(1, 2)
debug_printf(const char *fmt, ...)
{
}
//indent end
//indent input
void
(error_at)(int msgid, const pos_t *pos, ...)
{
}
//indent end
//indent run -ci4 -di0 -ndj -nlp
void
// $ FIXME: Wrong indentation, should be 0 instead.
(error_at)(int msgid, const pos_t *pos, ...)
{
}
//indent end