diff options
author | rdevlin.cronin <rdevlin.cronin@chromium.org> | 2016-03-22 15:11:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-22 22:13:13 +0000 |
commit | 63ef43c0af90ca5f23d0606e2394b0e5f25fc0b5 (patch) | |
tree | 14ff1d1b8c8f9aae47fe4456d2bce99ad8f55b60 /tools | |
parent | 3a1e77f21225b290585e1e9432f3cdecbf63866d (diff) | |
download | chromium_src-63ef43c0af90ca5f23d0606e2394b0e5f25fc0b5.zip chromium_src-63ef43c0af90ca5f23d0606e2394b0e5f25fc0b5.tar.gz chromium_src-63ef43c0af90ca5f23d0606e2394b0e5f25fc0b5.tar.bz2 |
[Extensions] Update generated code to support move operations
Generated extensions code currently uses linked_ptrs for non-copyable types
stored in containers. Instead, these types should just be movable. Update the
code generator to support move operations for flagged idl files and apply it
to the developerPrivate API as a first step/POC.
BUG=595949
Review URL: https://codereview.chromium.org/1811413002
Cr-Commit-Position: refs/heads/master@{#382704}
Diffstat (limited to 'tools')
-rw-r--r-- | tools/json_schema_compiler/cc_generator.py | 79 | ||||
-rw-r--r-- | tools/json_schema_compiler/cpp_type_generator.py | 7 | ||||
-rwxr-xr-x | tools/json_schema_compiler/cpp_type_generator_test.py | 13 | ||||
-rw-r--r-- | tools/json_schema_compiler/h_generator.py | 4 | ||||
-rwxr-xr-x | tools/json_schema_compiler/idl_schema.py | 2 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/BUILD.gn | 1 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/json_schema_compiler_tests.gyp | 1 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/objects_movable.idl | 23 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/objects_unittest.cc | 40 | ||||
-rw-r--r-- | tools/json_schema_compiler/util.h | 25 |
10 files changed, 188 insertions, 7 deletions
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py index ac1679b..499671f 100644 --- a/tools/json_schema_compiler/cc_generator.py +++ b/tools/json_schema_compiler/cc_generator.py @@ -126,8 +126,17 @@ class _Generator(object): (c.Append('%s::%s()' % (classname_in_namespace, classname)) .Cblock(self._GenerateInitializersAndBody(type_)) .Append('%s::~%s() {}' % (classname_in_namespace, classname)) - .Append() ) + if 'use_movable_types' in type_.namespace.compiler_options: + # Note: we use 'rhs' because some API objects have a member 'other'. + (c.Append('%s::%s(%s&& rhs)' % + (classname_in_namespace, classname, classname)) + .Cblock(self._GenerateMoveCtor(type_)) + .Append('%s& %s::operator=(%s&& rhs)' % + (classname_in_namespace, classname_in_namespace, + classname)) + .Cblock(self._GenerateMoveAssignOperator(type_)) + ) if type_.origin.from_json: c.Cblock(self._GenerateTypePopulate(classname_in_namespace, type_)) if cpp_namespace is None: # only generate for top-level types @@ -178,12 +187,78 @@ class _Generator(object): raise TypeError(t) if items: - s = ': %s' % (', '.join(items)) + s = ': %s' % (',\n'.join(items)) else: s = '' s = s + ' {}' return Code().Append(s) + def _GetMoveProps(self, type_, copy_str, move_str): + """Returns a tuple of (props, dicts) for the type. + + |props| is a list of all the copyable or movable properties generated using + the copy_str and move_str, and |dicts| is a list of all the dictionary + properties by name. + + Properties: + - |type_| the Type to get the properties from + - |copy_str| the string to use when copying a value; should have two + placeholders to take the property name. + - |move_str| the string to use when moving a value; should have two + placeholders to take the property name. + """ + props = [] + dicts = [] + for prop in type_.properties.values(): + t = prop.type_ + + real_t = self._type_helper.FollowRef(t) + if (prop.optional or + t.property_type == PropertyType.ANY or + t.property_type == PropertyType.ARRAY or + t.property_type == PropertyType.BINARY or + t.property_type == PropertyType.CHOICES or + t.property_type == PropertyType.OBJECT or + t.property_type == PropertyType.REF or + t.property_type == PropertyType.STRING): + props.append(move_str % (prop.unix_name, prop.unix_name)) + elif t.property_type == PropertyType.FUNCTION: + dicts.append(prop.unix_name) + elif (real_t.property_type == PropertyType.ENUM or + t.property_type == PropertyType.INTEGER or + t.property_type == PropertyType.DOUBLE or + t.property_type == PropertyType.BOOLEAN): + props.append(copy_str % (prop.unix_name, prop.unix_name)) + else: + raise TypeError(t) + + return (props, dicts) + + def _GenerateMoveCtor(self, type_): + props, dicts = self._GetMoveProps(type_, '%s(rhs.%s)', + '%s(std::move(rhs.%s))') + s = '' + if props: + s = s + ': %s' % (',\n'.join(props)) + s = s + '{' + for item in dicts: + s = s + ('\n%s.Swap(&rhs.%s);' % (item, item)) + s = s + '\n}' + + return Code().Append(s) + + def _GenerateMoveAssignOperator(self, type_): + props, dicts = self._GetMoveProps(type_, '%s = rhs.%s;', + '%s = std::move(rhs.%s);') + s = '{\n' + if props: + s = s + '\n'.join(props) + for item in dicts: + s = s + ('\n%s.Swap(&rhs.%s);' % (item, item)) + s = s + '\nreturn *this;\n}' + + return Code().Append(s) + def _GenerateTypePopulate(self, cpp_namespace, type_): """Generates the function for populating a type given a pointer to it. diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py index 3d307a9..24cbf61 100644 --- a/tools/json_schema_compiler/cpp_type_generator.py +++ b/tools/json_schema_compiler/cpp_type_generator.py @@ -121,7 +121,12 @@ class CppTypeGenerator(object): # TODO(kalman): change this - but it's an exceedingly far-reaching change. if not self.FollowRef(type_).property_type == PropertyType.ENUM: if is_in_container and (is_ptr or not self.IsCopyable(type_)): - cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type) + # Only wrap the object in a linked_ptr if this API isn't using movable + # types. Since base::Values aren't yet movable, wrap them too. + # TODO(devlin): Eventually, movable types should be the default. + if (not 'use_movable_types' in type_.namespace.compiler_options or + cpp_type == 'base::Value' or cpp_type == 'base::DictionaryValue'): + cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type) elif is_ptr: cpp_type = 'scoped_ptr<%s>' % cpp_util.PadForGenerics(cpp_type) diff --git a/tools/json_schema_compiler/cpp_type_generator_test.py b/tools/json_schema_compiler/cpp_type_generator_test.py index 51fcfe9..69d80dc 100755 --- a/tools/json_schema_compiler/cpp_type_generator_test.py +++ b/tools/json_schema_compiler/cpp_type_generator_test.py @@ -6,6 +6,7 @@ from cpp_namespace_environment import CppNamespaceEnvironment from cpp_type_generator import CppTypeGenerator from json_schema import CachedLoad +import idl_schema import model import unittest @@ -49,6 +50,10 @@ class CppTypeGeneratorTest(unittest.TestCase): self.content_settings_json = CachedLoad('test/content_settings.json') self.content_settings = self.models['content_settings'].AddNamespace( self.content_settings_json[0], 'path/to/content_settings.json') + self.objects_movable_idl = idl_schema.Load('test/objects_movable.idl') + self.objects_movable = self.models['objects_movable'].AddNamespace( + self.objects_movable_idl[0], 'path/to/objects_movable.idl', + include_compiler_options=True) def testGenerateIncludesAndForwardDeclarations(self): m = model.Model() @@ -153,6 +158,14 @@ class CppTypeGeneratorTest(unittest.TestCase): manager.GetCppType( self.permissions.types['Permissions'].properties['origins'].type_)) + manager = CppTypeGenerator(self.models.get('objects_movable'), + _FakeSchemaLoader(None)) + self.assertEquals( + 'std::vector<MovablePod>', + manager.GetCppType( + self.objects_movable.types['MovableParent']. + properties['pods'].type_)) + def testGetCppTypeLocalRef(self): manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None)) self.assertEquals( diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py index 173e549..5452885 100644 --- a/tools/json_schema_compiler/h_generator.py +++ b/tools/json_schema_compiler/h_generator.py @@ -228,6 +228,10 @@ class _Generator(object): .Append('%(classname)s();') .Append('~%(classname)s();') ) + if 'use_movable_types' in type_.namespace.compiler_options: + (c.Append('%(classname)s(%(classname)s&& rhs);') + .Append('%(classname)s& operator=(%(classname)s&& rhs);') + ) if type_.origin.from_json: (c.Append() .Comment('Populates a %s object from a base::Value. Returns' diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py index 58efe28..5fda70e 100755 --- a/tools/json_schema_compiler/idl_schema.py +++ b/tools/json_schema_compiler/idl_schema.py @@ -500,6 +500,8 @@ class IDLSchema(object): compiler_options['implemented_in'] = node.value elif node.name == 'camel_case_enum_to_string': compiler_options['camel_case_enum_to_string'] = node.value + elif node.name == 'use_movable_types': + compiler_options['use_movable_types'] = node.value elif node.name == 'deprecated': deprecated = str(node.value) elif node.name == 'documentation_title': diff --git a/tools/json_schema_compiler/test/BUILD.gn b/tools/json_schema_compiler/test/BUILD.gn index 33e6219..e12493f 100644 --- a/tools/json_schema_compiler/test/BUILD.gn +++ b/tools/json_schema_compiler/test/BUILD.gn @@ -23,6 +23,7 @@ json_schema_api("api") { "idl_other_namespace.idl", "idl_other_namespace_sub_namespace.idl", "objects.json", + "objects_movable.idl", "simple_api.json", ] diff --git a/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp b/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp index 404e9b0..a0203dc 100644 --- a/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp +++ b/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp @@ -25,6 +25,7 @@ 'idl_other_namespace_sub_namespace.idl', 'idl_object_types.idl', 'objects.json', + 'objects_movable.idl', 'simple_api.json', 'error_generation.json' ], diff --git a/tools/json_schema_compiler/test/objects_movable.idl b/tools/json_schema_compiler/test/objects_movable.idl new file mode 100644 index 0000000..b09f1a8 --- /dev/null +++ b/tools/json_schema_compiler/test/objects_movable.idl @@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Movable Objects. +[use_movable_types=true] namespace objectsMovable { + enum Foo { + BAR, + BAZ + }; + + dictionary MovablePod { + Foo foo; + DOMString str; + long num; + boolean b; + }; + + dictionary MovableParent { + MovablePod[] pods; + DOMString[] strs; + }; +}; diff --git a/tools/json_schema_compiler/test/objects_unittest.cc b/tools/json_schema_compiler/test/objects_unittest.cc index 5e28386..2cb6fc6 100644 --- a/tools/json_schema_compiler/test/objects_unittest.cc +++ b/tools/json_schema_compiler/test/objects_unittest.cc @@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "tools/json_schema_compiler/test/objects.h" - #include <stddef.h> #include "base/json/json_writer.h" #include "testing/gtest/include/gtest/gtest.h" +#include "tools/json_schema_compiler/test/objects.h" +#include "tools/json_schema_compiler/test/objects_movable.h" using namespace test::api::objects; +using namespace test::api::objects_movable; TEST(JsonSchemaCompilerObjectsTest, ObjectParamParamsCreate) { { @@ -71,3 +72,38 @@ TEST(JsonSchemaCompilerObjectsTest, OnObjectFiredCreate) { ASSERT_TRUE(results->GetDictionary(0, &result)); ASSERT_TRUE(result->Equals(&expected)); } +TEST(JsonSchemaCompilerMovableObjectsTest, MovableObjectsTest) { + std::vector<MovablePod> pods; + { + MovablePod pod; + pod.foo = FOO_BAR; + pod.str = "str1"; + pod.num = 42; + pod.b = true; + pods.push_back(std::move(pod)); + } + { + MovablePod pod; + pod.foo = FOO_BAZ; + pod.str = "str2"; + pod.num = 45; + pod.b = false; + pods.push_back(std::move(pod)); + } + MovableParent parent; + parent.pods = std::move(pods); + parent.strs.push_back("pstr"); + + MovableParent parent2(std::move(parent)); + ASSERT_EQ(2u, parent2.pods.size()); + EXPECT_EQ(FOO_BAR, parent2.pods[0].foo); + EXPECT_EQ("str1", parent2.pods[0].str); + EXPECT_EQ(42, parent2.pods[0].num); + EXPECT_TRUE(parent2.pods[0].b); + EXPECT_EQ(FOO_BAZ, parent2.pods[1].foo); + EXPECT_EQ("str2", parent2.pods[1].str); + EXPECT_EQ(45, parent2.pods[1].num); + EXPECT_FALSE(parent2.pods[1].b); + ASSERT_EQ(1u, parent2.strs.size()); + EXPECT_EQ("pstr", parent2.strs[0]); +} diff --git a/tools/json_schema_compiler/util.h b/tools/json_schema_compiler/util.h index 59d65d0..945f061 100644 --- a/tools/json_schema_compiler/util.h +++ b/tools/json_schema_compiler/util.h @@ -57,6 +57,19 @@ bool PopulateItem(const base::Value& from, linked_ptr<T>* out) { return true; } +// This template is used for types generated by tools/json_schema_compiler. +template <class T> +bool PopulateItem(const base::Value& from, T* out) { + const base::DictionaryValue* dict = nullptr; + if (!from.GetAsDictionary(&dict)) + return false; + T obj; + if (!T::Populate(*dict, &obj)) + return false; + *out = std::move(obj); + return true; +} + // This template is used for types generated by tools/json_schema_compiler with // error generation enabled. template <class T> @@ -82,7 +95,9 @@ bool PopulateArrayFromList(const base::ListValue& list, std::vector<T>* out) { for (const base::Value* value : list) { if (!PopulateItem(*value, &item)) return false; - out->push_back(item); + // T might not be movable, but in that case it should be copyable, and this + // will still work. + out->push_back(std::move(item)); } return true; @@ -148,12 +163,18 @@ void AddItemToList(const linked_ptr<T>& from, base::ListValue* out) { out->Append(from->ToValue().release()); } +// This template is used for types generated by tools/json_schema_compiler. +template <class T> +void AddItemToList(const T& from, base::ListValue* out) { + out->Append(from.ToValue()); +} + // Set |out| to the the contents of |from|. Requires PopulateItem to be // implemented for |T|. template <class T> void PopulateListFromArray(const std::vector<T>& from, base::ListValue* out) { out->Clear(); - for (const auto& item : from) + for (const T& item : from) AddItemToList(item, out); } |