/*      $NetBSD: fmt_decl.c,v 1.60 2023/06/25 19:19:42 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 =
// $ FIXME: Missing indentation.
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;
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

//indent run
void            buffer_add(buffer *, char);
// $ FIXME: There should be no space after the '*'.
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)];
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'.
// $
// $ 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


/*
* When a name is defined both as a function and as a macro, the name in the
* function definition must be enclosed in parentheses, to prevent the macro
* from being expanded. It is also possible to undefine the macro, but that is
* often not done in practice.
*/
//indent input
void
(error_at)(int msgid, const pos_t *pos, ...)
{
}
//indent end

//indent run-equals-input


//indent input
struct a {
       struct b {
               struct c {
                       struct d1 {
                               int e;
                       } d1;
                       struct d2 {
                               int e;
                       } d2;
               } c;
       } b;
};
//indent end

//indent run-equals-input -di0


//indent input
static FILE *ArchFindMember(const char *, const char *,
                           struct ar_hdr *, const char *);

bool
Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
{
}

static void MAKE_ATTR_PRINTFLIKE(5, 0)
ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn,
                   ParseErrorLevel level, const char *fmt, va_list ap)
{
}

typedef struct {
       const char *m_name;
} mod_t;
//indent end

//indent run -fbs -di0 -psl
// $ Must be detected as a function declaration, not a definition.
static FILE *ArchFindMember(const char *, const char *,
                           struct ar_hdr *, const char *);

bool
Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
{
}

static void
MAKE_ATTR_PRINTFLIKE(5, 0)
ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn,
                   ParseErrorLevel level, const char *fmt, va_list ap)
{
}

typedef struct {
       const char *m_name;
} mod_t;
//indent end


//indent input
int a[] = {1, 2},
b[] = {1, 2};
{
int a[] = {1, 2},
b[] = {1, 2};
}
//indent end

//indent run -di0
int a[] = {1, 2},
// $ FIXME: Missing indentation.
b[] = {1, 2};
{
       int a[] = {1, 2},
       // $ FIXME: Missing indentation.
       b[] = {1, 2};
}
//indent end


/*
* When a type occurs at the top level, it forces a line break before.
*/
//indent input
__attribute__((__dead__)) void die(void) {}
//indent end

//indent run
__attribute__((__dead__))
void
die(void)
{
}
//indent end


/*
* In very rare cases, the type of a declarator might include literal tab
* characters. This tab might affect the indentation of the declarator, but
* only if it occurs before the declarator, and that is hard to achieve.
*/
//indent input
int             arr[sizeof "    "];
//indent end

//indent run-equals-input


/*
* The '}' of an initializer is not supposed to end the statement, it only ends
* the brace level of the initializer expression.
*/
//indent input
int multi_line[1][1][1] = {
{
{
1
},
},
};
int single_line[2][1][1] = {{{1},},{{2}}};
//indent end

//indent run -di0
int multi_line[1][1][1] = {
       {
               {
                       1
               },
       },
};
int single_line[2][1][1] = {{{1},}, {{2}}};
//indent end


/*
* The '}' of an initializer is not supposed to end the statement, it only ends
* the brace level of the initializer expression.
*/
//indent input
{
int multi_line = {
{
{
b
},
},
};
int single_line = {{{b},},{}};
}
//indent end

//indent run -di0
{
       int multi_line = {
               {
                       {
                               b
                       },
               },
       };
       int single_line = {{{b},}, {}};
}
//indent end


/*
* In initializers, multi-line expressions don't have their second line
* indented, even though they should.
*/
//indent input
{
multi_line = (int[]){
{1
+1},
{1
+1},
{1
+1},
};
}
//indent end

//indent run
{
       multi_line = (int[]){
               {1
               + 1},
               {1
               + 1},
               {1
               + 1},
       };
}
//indent end


/*
*
*/
//indent input
int
old_style(a)
       struct {
               int             member;
       }               a;
{
       stmt;
}
//indent end

//indent run-equals-input