From 0875ea1284c410d9f15708ace9f939991af10832 Mon Sep 17 00:00:00 2001 From: estevenson Date: Thu, 13 Apr 2017 19:40:13 -0700 Subject: [PATCH] Android: convert kEnumName to ENUM_NAME in java_cpp_enum.py. Since the Blink rename, enum entry names now use the kCamelCase naming convention instead of SHOUTY_CASE. This doesn't match well with Java naming conventions and Java constants created by java_cpp_enum.py look out of place with the rest of the Java codebase. This CL modifies java_cpp_enum.py so that C++ enum naming conventions don't leak into the Java side, specifically translating kCamelCase and CamelCase enum entries to SHOUTY_CASE. BUG=710335 Review-Url: https://codereview.chromium.org/2815103004 Cr-Original-Commit-Position: refs/heads/master@{#464661} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 23b8f65ce75fc2ff04a28cb5a940861c134e0797 --- android/gyp/java_cpp_enum.py | 43 ++++++++- android/gyp/java_cpp_enum_tests.py | 138 ++++++++++++++++++++++++++++- 2 files changed, 177 insertions(+), 4 deletions(-) diff --git a/android/gyp/java_cpp_enum.py b/android/gyp/java_cpp_enum.py index 3cb70ce8c..f66f6cb11 100755 --- a/android/gyp/java_cpp_enum.py +++ b/android/gyp/java_cpp_enum.py @@ -54,6 +54,7 @@ class EnumDefinition(object): self._Validate() self._AssignEntryIndices() self._StripPrefix() + self._NormalizeNames() def _Validate(self): assert self.class_name @@ -92,10 +93,10 @@ class EnumDefinition(object): def StripEntries(entries): ret = collections.OrderedDict() - for (k, v) in entries.iteritems(): + for k, v in entries.iteritems(): stripped_key = k.replace(prefix_to_strip, '', 1) if isinstance(v, basestring): - stripped_value = v.replace(prefix_to_strip, '', 1) + stripped_value = v.replace(prefix_to_strip, '') else: stripped_value = v ret[stripped_key] = stripped_value @@ -105,6 +106,44 @@ class EnumDefinition(object): self.entries = StripEntries(self.entries) self.comments = StripEntries(self.comments) + def _NormalizeNames(self): + self.entries = _TransformKeys(self.entries, _KCamelToShouty) + self.comments = _TransformKeys(self.comments, _KCamelToShouty) + + +def _TransformKeys(d, func): + """Normalize keys in |d| and update references to old keys in |d| values.""" + normal_keys = {k: func(k) for k in d} + ret = collections.OrderedDict() + for k, v in d.iteritems(): + # Need to transform values as well when the entry value was explicitly set + # (since it could contain references to other enum entry values). + if isinstance(v, basestring): + for normal_key in normal_keys: + v = v.replace(normal_key, normal_keys[normal_key]) + ret[normal_keys[k]] = v + return ret + + +def _KCamelToShouty(s): + """Convert |s| from kCamelCase or CamelCase to SHOUTY_CASE. + + kFooBar -> FOO_BAR + FooBar -> FOO_BAR + FooBAR9 -> FOO_BAR9 + FooBARBaz -> FOO_BAR_BAZ + """ + if not re.match(r'^k?([A-Z][^A-Z]+|[A-Z0-9]+)+$', s): + return s + # Strip the leading k. + s = re.sub(r'^k', '', s) + # Add _ between title words and anything else. + s = re.sub(r'([^_])([A-Z][^A-Z_0-9]+)', r'\1_\2', s) + # Add _ between lower -> upper transitions. + s = re.sub(r'([^A-Z_0-9])([A-Z])', r'\1_\2', s) + return s.upper() + + class DirectiveSet(object): class_name_override_key = 'CLASS_NAME_OVERRIDE' enum_package_key = 'ENUM_PACKAGE' diff --git a/android/gyp/java_cpp_enum_tests.py b/android/gyp/java_cpp_enum_tests.py index 8d9e60de6..cd6e1ee18 100755 --- a/android/gyp/java_cpp_enum_tests.py +++ b/android/gyp/java_cpp_enum_tests.py @@ -97,9 +97,16 @@ public @interface ClassName { VALUE_ZERO = 1 << 0, VALUE_ONE = 1 << 1, }; + + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + enum EnumName { + ENUM_NAME_ZERO = 1 << 0, + ENUM_NAME_ONE = 1 << 1, + ENUM_NAME_TWO = ENUM_NAME_ZERO | ENUM_NAME_ONE, + }; """.split('\n') definitions = HeaderParser(test_data).ParseDefinitions() - self.assertEqual(1, len(definitions)) + self.assertEqual(2, len(definitions)) definition = definitions[0] self.assertEqual('EnumName', definition.class_name) self.assertEqual('test.namespace', definition.enum_package) @@ -107,6 +114,13 @@ public @interface ClassName { ('VALUE_ONE', '1 << 1')]), definition.entries) + definition = definitions[1] + expected_entries = collections.OrderedDict([ + ('ZERO', '1 << 0'), + ('ONE', '1 << 1'), + ('TWO', 'ZERO | ONE')]) + self.assertEqual(expected_entries, definition.entries) + def testParseMultilineEnumEntry(self): test_data = """ // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace @@ -289,6 +303,26 @@ public @interface ClassName { ('B', 1)]), definition.entries) + def testParseWithStrippingAndRelativeReferences(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: other.package + // GENERATED_JAVA_PREFIX_TO_STRIP: P_ + enum EnumTwo { + P_A = 1, + // P_A is old-don't use P_A. + P_B = P_A, + }; + """.split('\n') + definitions = HeaderParser(test_data).ParseDefinitions() + definition = definitions[0] + self.assertEqual('EnumTwo', definition.class_name) + self.assertEqual('other.package', definition.enum_package) + self.assertEqual(collections.OrderedDict([('A', '1'), + ('B', 'A')]), + definition.entries) + self.assertEqual(collections.OrderedDict([('B', 'A is old-don\'t use A.')]), + definition.comments) + def testParseSingleLineAndRegularEnum(self): test_data = """ // GENERATED_JAVA_ENUM_PACKAGE: test.namespace @@ -311,7 +345,7 @@ public @interface ClassName { definition = definitions[0] self.assertEqual( collections.OrderedDict([('A', '1'), ('B', 'A')]), definition.entries) - self.assertEqual(collections.OrderedDict([('ENUM_ONE_B', 'Comment there')]), + self.assertEqual(collections.OrderedDict([('B', 'Comment there')]), definition.comments) self.assertEqual(3, len(definitions)) @@ -322,6 +356,106 @@ public @interface ClassName { definition = definitions[2] self.assertEqual(collections.OrderedDict([('FOO', 0)]), definition.entries) + def testParseWithCamelCaseNames(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + enum EnumTest { + EnumTestA = 1, + // comment for EnumTestB. + EnumTestB = 2, + }; + + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + // GENERATED_JAVA_PREFIX_TO_STRIP: Test + enum AnEnum { + TestHTTPOption, + TestHTTPSOption, + }; + + """.split('\n') + definitions = HeaderParser(test_data).ParseDefinitions() + definition = definitions[0] + self.assertEqual( + collections.OrderedDict([('ENUM_TEST_A', '1'), ('ENUM_TEST_B', '2')]), + definition.entries) + self.assertEqual( + collections.OrderedDict([('ENUM_TEST_B', 'comment for ENUM_TEST_B.')]), + definition.comments) + + definition = definitions[1] + self.assertEqual( + collections.OrderedDict([('HTTP_OPTION', 0), ('HTTPS_OPTION', 1)]), + definition.entries) + + def testParseWithKCamelCaseNames(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + enum EnumOne { + kEnumOne = 1, + // comment for kEnumTwo. + kEnumTwo = 2, + }; + + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName + // GENERATED_JAVA_PREFIX_TO_STRIP: kEnumName + enum EnumName { + kEnumNameFoo, + kEnumNameBar + }; + + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + enum EnumName { + kEnumNameFoo, + kEnumBar, + }; + + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + enum Keys { + kSymbolKey = 1 << 0, + kAltKey = 1 << 1, + kUpKey = 1 << 2, + kKeyModifiers = kSymbolKey | kAltKey | kUpKey | kKeyModifiers, + }; + + // GENERATED_JAVA_ENUM_PACKAGE: test.namespace + enum Mixed { + kTestVal, + kCodecMPEG2 + }; + """.split('\n') + definitions = HeaderParser(test_data).ParseDefinitions() + definition = definitions[0] + self.assertEqual( + collections.OrderedDict([('ENUM_ONE', '1'), ('ENUM_TWO', '2')]), + definition.entries) + self.assertEqual( + collections.OrderedDict([('ENUM_TWO', 'comment for ENUM_TWO.')]), + definition.comments) + + definition = definitions[1] + self.assertEqual( + collections.OrderedDict([('FOO', 0), ('BAR', 1)]), + definition.entries) + + definition = definitions[2] + self.assertEqual( + collections.OrderedDict([('ENUM_NAME_FOO', 0), ('ENUM_BAR', 1)]), + definition.entries) + + definition = definitions[3] + expected_entries = collections.OrderedDict([ + ('SYMBOL_KEY', '1 << 0'), + ('ALT_KEY', '1 << 1'), + ('UP_KEY', '1 << 2'), + ('KEY_MODIFIERS', 'SYMBOL_KEY | ALT_KEY | UP_KEY | KEY_MODIFIERS')]) + self.assertEqual(expected_entries, definition.entries) + + definition = definitions[4] + self.assertEqual( + collections.OrderedDict([('TEST_VAL', 0), ('CODEC_MPEG2', 1)]), + definition.entries) + def testParseThrowsOnUnknownDirective(self): test_data = """ // GENERATED_JAVA_UNKNOWN: Value