mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-11-18 00:18:21 +01:00
mkenums: Handle G_GNUC_FLAG_ENUM annotation
It can appear either after 'enum' or after the closing brace. Also handle __attribute__((flag_enum)) and, for C++ code, [[gnu::flag_enum]] and [[clang::flag_enum]] and various other spellings of those. If it is present, mark the enum as a flags enum, the same as if we detected left shifts in the values.
This commit is contained in:
@@ -207,9 +207,17 @@ def parse_entries(file, file_name):
|
||||
else:
|
||||
continue
|
||||
|
||||
m = re.match(r'\s*\}\s*(\w+)', line)
|
||||
m = re.match(r'''\s*\}\s*
|
||||
((?:
|
||||
G_GNUC_FLAG_ENUM|
|
||||
\[\[(?:.+,)*(?:gnu|clang)::flag_enum(?:,[^\]]+)*\]\]|
|
||||
__attribute__\(\((?:.+,)*(?:flag_enum|__flag_enum__)(?:,[^)]+)*\)\)
|
||||
)\s*)?
|
||||
(\w+)''', line, flags=re.X)
|
||||
if m:
|
||||
enumname = m.group(1)
|
||||
if m.group(1) is not None:
|
||||
flags = 1
|
||||
enumname = m.group(2)
|
||||
enumindex += 1
|
||||
return 1
|
||||
|
||||
@@ -519,7 +527,13 @@ def process_file(curfilename):
|
||||
if re.match(r'\s*typedef\s+enum.*;', line):
|
||||
continue
|
||||
|
||||
m = re.match(r'''\s*typedef\s+enum\s*[_A-Za-z]*[_A-Za-z0-9]*\s*
|
||||
m = re.match(r'''\s*typedef\s+enum\s*
|
||||
((?:
|
||||
G_GNUC_FLAG_ENUM|
|
||||
\[\[(?:.+,)*(?:gnu|clang)::flag_enum(?:,[^\]]+)*\]\]|
|
||||
__attribute__\(\((?:.+,)*(?:flag_enum|__flag_enum__)(?:,[^)]+)*\)\)
|
||||
)\s*)?
|
||||
[_A-Za-z]*[_A-Za-z0-9]*\s*
|
||||
({)?\s*
|
||||
(?:/\*<
|
||||
(([^*]|\*(?!/))*)
|
||||
@@ -527,8 +541,10 @@ def process_file(curfilename):
|
||||
\s*({)?''', line, flags=re.X)
|
||||
if m:
|
||||
groups = m.groups()
|
||||
if len(groups) >= 2 and groups[1] is not None:
|
||||
options = parse_trigraph(groups[1])
|
||||
if len(groups) >= 1 and groups[0] is not None:
|
||||
flags = 1
|
||||
if len(groups) >= 3 and groups[2] is not None:
|
||||
options = parse_trigraph(groups[2])
|
||||
if 'skip' in options:
|
||||
continue
|
||||
enum_prefix = options.get('prefix', None)
|
||||
@@ -556,7 +572,7 @@ def process_file(curfilename):
|
||||
print_warning("lowercase_name is deprecated, use underscore_name")
|
||||
|
||||
# Didn't have trailing '{' look on next lines
|
||||
if groups[0] is None and (len(groups) < 4 or groups[3] is None):
|
||||
if groups[1] is None and (len(groups) < 5 or groups[4] is None):
|
||||
while True:
|
||||
line = curfile.readline()
|
||||
if not line:
|
||||
|
||||
@@ -710,6 +710,101 @@ comment: {standard_bottom_comment}
|
||||
"4",
|
||||
)
|
||||
|
||||
def test_flag_enum_annotation(self):
|
||||
"""Test use of G_GNUC_FLAG_ENUM"""
|
||||
possible_spellings = [
|
||||
"G_GNUC_FLAG_ENUM",
|
||||
"__attribute__((flag_enum))",
|
||||
"__attribute__((__flag_enum__))",
|
||||
"__attribute__((flag_enum,deprecated))",
|
||||
"__attribute__((deprecated,__flag_enum__))",
|
||||
"[[gnu::flag_enum]]",
|
||||
"[[clang::flag_enum]]",
|
||||
"[[nodiscard,gnu::flag_enum]]",
|
||||
"[[clang::flag_enum,nodiscard]]",
|
||||
]
|
||||
for spelling in possible_spellings:
|
||||
# Test attribute after closing brace
|
||||
h_contents = (
|
||||
"""
|
||||
typedef enum {
|
||||
SOME_FLAGS_ONE = (1 << 1),
|
||||
} %s SomeFlags;
|
||||
"""
|
||||
% spelling
|
||||
)
|
||||
result = self.runMkenumsWithHeader(h_contents)
|
||||
self.assertEqual("", result.err)
|
||||
self.assertSingleEnum(
|
||||
result,
|
||||
"SomeFlags",
|
||||
"some_flags",
|
||||
"SOME_FLAGS",
|
||||
"FLAGS",
|
||||
"SOME",
|
||||
"",
|
||||
"flags",
|
||||
"Flags",
|
||||
"FLAGS",
|
||||
"SOME_FLAGS_ONE",
|
||||
"one",
|
||||
"2",
|
||||
)
|
||||
|
||||
# Test attribute after enum keyword, with anonymous enum
|
||||
h_contents = (
|
||||
"""
|
||||
typedef enum %s {
|
||||
SOME_FLAGS_TWO = (1 << 2),
|
||||
} SomeFlags;
|
||||
"""
|
||||
% spelling
|
||||
)
|
||||
result = self.runMkenumsWithHeader(h_contents)
|
||||
self.assertEqual("", result.err)
|
||||
self.assertSingleEnum(
|
||||
result,
|
||||
"SomeFlags",
|
||||
"some_flags",
|
||||
"SOME_FLAGS",
|
||||
"FLAGS",
|
||||
"SOME",
|
||||
"",
|
||||
"flags",
|
||||
"Flags",
|
||||
"FLAGS",
|
||||
"SOME_FLAGS_TWO",
|
||||
"two",
|
||||
"4",
|
||||
)
|
||||
|
||||
# Test attribute after enum keyword, with named enum
|
||||
h_contents = (
|
||||
"""
|
||||
typedef enum %s _SomeFlags {
|
||||
SOME_FLAGS_THREE = (1 << 3),
|
||||
} SomeFlags;
|
||||
"""
|
||||
% spelling
|
||||
)
|
||||
result = self.runMkenumsWithHeader(h_contents)
|
||||
self.assertEqual("", result.err)
|
||||
self.assertSingleEnum(
|
||||
result,
|
||||
"SomeFlags",
|
||||
"some_flags",
|
||||
"SOME_FLAGS",
|
||||
"FLAGS",
|
||||
"SOME",
|
||||
"",
|
||||
"flags",
|
||||
"Flags",
|
||||
"FLAGS",
|
||||
"SOME_FLAGS_THREE",
|
||||
"three",
|
||||
"8",
|
||||
)
|
||||
|
||||
def test_enum_symbolic_expression(self):
|
||||
"""Test use of symbol in value expression."""
|
||||
h_contents = """
|
||||
|
||||
Reference in New Issue
Block a user