root/tests/usr.bin/indent/lsym_tag.c
/* $NetBSD: lsym_tag.c,v 1.10 2023/06/17 22:09:24 rillig Exp $ */

/*
 * Tests for the token lsym_tag, which represents one of the keywords
 * 'struct', 'union' or 'enum' that declare, define or use a tagged type.
 */

/* TODO: Add systematic tests for 'struct'. */
/* TODO: Add systematic tests for 'union'. */
/* TODO: Add systematic tests for 'enum'. */


//indent input
int
indent_enum_constants(void)
{
        enum color {
                red,
                green
        };
        enum color      colors[] = {
                red,
                red,
                red,
        };
        /*
         * Ensure that the token sequence 'enum type {' only matches if there
         * are no other tokens in between, to prevent statement continuations
         * from being indented like enum constant declarations.
         *
         * See https://gnats.netbsd.org/55453.
         */
        if (colors[0] == (enum color)1) {
                return 1
                  + 2
                  + 3;
        }
        return 0;
}
//indent end

//indent run-equals-input -ci2


//indent input
struct stat {
        mode_t          st_mode;
};

union variant {
        enum {
        }               tag;
        int             v_int;
        long            v_long;
        bool            v_bool;
        void           *v_pointer;
};
//indent end

//indent run-equals-input


/* See FreeBSD r303485. */
//indent input
int f(struct x *a);

void
t(void)
{
        static const struct {
                int     a;
                int     b;
        } c[] = {
                { D, E },
                { F, G }
        };
}

void u(struct x a) {
        int b;
        struct y c = (struct y *)&a;
}
//indent end

//indent run
int             f(struct x *a);

void
t(void)
{
        static const struct {
                int             a;
                int             b;
        }               c[] = {
                {D, E},
                {F, G}
        };
}

void
u(struct x a)
{
        int             b;
        struct y        c = (struct y *)&a;
}
//indent end


/* Comment between 'struct' and the tag name; doesn't occur in practice. */
//indent input
struct   /* comment */   tag var;
//indent end

//indent run -di0
struct /* comment */ tag var;
//indent end


/*
 * Ensure that the names of struct members are all indented the same.
 * Before 2023-05-15, the indentation depended on their type name.
 */
//indent input
struct outer {
        enum {
                untagged_constant,
        } untagged_member,
          second_untagged_member;
        enum tag_name {
                tagged_constant,
        } tagged_member,
          second_tagged_member;
};
//indent end

//indent run-equals-input -di0


/*
 * The initializer of an enum constant needs to be indented like any other
 * initializer, especially the continuation lines.
 */
//indent input
enum multi_line {
        ml1 = 1
            + 2
            + offsetof(struct s, member)
            + 3,
        ml2 = 1
            + 2
            + offsetof(struct s, member)
            + 3,
};
//indent end

//indent run-equals-input -ci4

//indent run-equals-input -ci4 -nlp


/*
 * When 'typedef' or a tag is followed by a name, that name marks a type and a
 * following '*' marks a pointer type.
 */
//indent input
{
        // $ Syntactically invalid but shows that '*' is not multiplication.
        a = struct x * y;
        a = (struct x * y)z;
}
//indent end

//indent run
{
        // $ Everything before the '*' is treated as a declaration.
        a = struct x   *y;
        a = (struct x *y)z;
}
//indent end