mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-11-18 08:28:22 +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:
|
else:
|
||||||
continue
|
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:
|
if m:
|
||||||
enumname = m.group(1)
|
if m.group(1) is not None:
|
||||||
|
flags = 1
|
||||||
|
enumname = m.group(2)
|
||||||
enumindex += 1
|
enumindex += 1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -519,7 +527,13 @@ def process_file(curfilename):
|
|||||||
if re.match(r'\s*typedef\s+enum.*;', line):
|
if re.match(r'\s*typedef\s+enum.*;', line):
|
||||||
continue
|
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*
|
({)?\s*
|
||||||
(?:/\*<
|
(?:/\*<
|
||||||
(([^*]|\*(?!/))*)
|
(([^*]|\*(?!/))*)
|
||||||
@@ -527,8 +541,10 @@ def process_file(curfilename):
|
|||||||
\s*({)?''', line, flags=re.X)
|
\s*({)?''', line, flags=re.X)
|
||||||
if m:
|
if m:
|
||||||
groups = m.groups()
|
groups = m.groups()
|
||||||
if len(groups) >= 2 and groups[1] is not None:
|
if len(groups) >= 1 and groups[0] is not None:
|
||||||
options = parse_trigraph(groups[1])
|
flags = 1
|
||||||
|
if len(groups) >= 3 and groups[2] is not None:
|
||||||
|
options = parse_trigraph(groups[2])
|
||||||
if 'skip' in options:
|
if 'skip' in options:
|
||||||
continue
|
continue
|
||||||
enum_prefix = options.get('prefix', None)
|
enum_prefix = options.get('prefix', None)
|
||||||
@@ -556,7 +572,7 @@ def process_file(curfilename):
|
|||||||
print_warning("lowercase_name is deprecated, use underscore_name")
|
print_warning("lowercase_name is deprecated, use underscore_name")
|
||||||
|
|
||||||
# Didn't have trailing '{' look on next lines
|
# 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:
|
while True:
|
||||||
line = curfile.readline()
|
line = curfile.readline()
|
||||||
if not line:
|
if not line:
|
||||||
|
|||||||
@@ -710,6 +710,101 @@ comment: {standard_bottom_comment}
|
|||||||
"4",
|
"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):
|
def test_enum_symbolic_expression(self):
|
||||||
"""Test use of symbol in value expression."""
|
"""Test use of symbol in value expression."""
|
||||||
h_contents = """
|
h_contents = """
|
||||||
|
|||||||
Reference in New Issue
Block a user