Commit df7de693 authored by mpcomplete@google.com's avatar mpcomplete@google.com

Fix a bug with mojom imports where 2 imports with the same namespace would

cause a variable name collision in JS.

BUG=325500
R=darin@chromium.org

Review URL: https://codereview.chromium.org/159983003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251105 0039d316-1c4b-4281-b951-d872f2087c98
parent d42a9d5c
......@@ -117,7 +117,12 @@ define([
expect(full.point.y).toBe(15);
expect(full.shape_masks.length).toBe(1);
expect(full.shape_masks[0]).toBe(1 << imported.SHAPE_RECTANGLE);
// TODO(mpcomplete): This is broken.
// http://crbug.com/320082
// expect(full.shape_masks[0]).toBe(1 << imported.Shape.SHAPE_RECTANGLE);
//expect(full.thing.shape).toBe(imported.Shape.SHAPE_RECTANGLE);
//expect(full.thing.color).toBe(imported.Color.COLOR_RED);
}
function ServiceImpl() {
......
......@@ -211,6 +211,7 @@
'sources': [
'public/bindings/tests/sample_service.mojom',
'public/bindings/tests/sample_import.mojom',
'public/bindings/tests/sample_import2.mojom',
],
'includes': [ 'public/bindings/mojom_bindings_generator.gypi' ],
'export_dependent_settings': [
......
......@@ -10,7 +10,7 @@ define([
{%- endfor %}
], function(core, codec
{%- for import in imports -%}
, {{import.namespace}}
, {{import.unique_name}}
{%- endfor -%}
) {
......
......@@ -35,7 +35,7 @@ tmp{{depth}}.{{subfield.name}} = {{result}};
}
{#--- POD types ---#}
{%- else -%}
{{caller(value)}}
{{caller(value|substitute_namespace(imports))}}
{%- endif %}
{%- endmacro %}
......
......@@ -131,8 +131,7 @@ class Generator(mojom_generator.Generator):
"verify_token_type": mojom_generator.VerifyTokenType,
}
@UseJinja("cpp_templates/module.h.tmpl", filters=cpp_filters)
def GenerateModuleHeader(self):
def GetJinjaExports(self):
return {
"module_name": self.module.name,
"namespace": self.module.namespace,
......@@ -144,31 +143,17 @@ class Generator(mojom_generator.Generator):
"include_prefix": self.GetIncludePrefix(),
}
@UseJinja("cpp_templates/module.h.tmpl", filters=cpp_filters)
def GenerateModuleHeader(self):
return self.GetJinjaExports()
@UseJinja("cpp_templates/module_internal.h.tmpl", filters=cpp_filters)
def GenerateModuleInternalHeader(self):
return {
"module_name": self.module.name,
"namespace": self.module.namespace,
"imports": self.module.imports,
"kinds": self.module.kinds,
"enums": self.module.enums,
"structs": self.GetStructs(),
"interfaces": self.module.interfaces,
"include_prefix": self.GetIncludePrefix(),
}
return self.GetJinjaExports()
@UseJinja("cpp_templates/module.cc.tmpl", filters=cpp_filters)
def GenerateModuleSource(self):
return {
"module_name": self.module.name,
"namespace": self.module.namespace,
"imports": self.module.imports,
"kinds": self.module.kinds,
"enums": self.module.enums,
"structs": self.GetStructs(),
"interfaces": self.module.interfaces,
"include_prefix": self.GetIncludePrefix(),
}
return self.GetJinjaExports()
def GenerateFiles(self):
self.Write(self.GenerateModuleHeader(), "%s.h" % self.module.name)
......
......@@ -148,6 +148,19 @@ def JavaScriptEncodeSnippet(kind):
return JavaScriptEncodeSnippet(mojom.MSGPIPE)
def SubstituteNamespace(value, imports):
for import_item in imports:
value = value.replace(import_item["namespace"] + ".",
import_item["unique_name"] + ".")
return value
def JavascriptType(kind):
if kind.imported_from:
return kind.imported_from["unique_name"] + "." + kind.name
return kind.name
class Generator(mojom_generator.Generator):
js_filters = {
......@@ -159,15 +172,16 @@ class Generator(mojom_generator.Generator):
"is_object_kind": mojom_generator.IsObjectKind,
"is_string_kind": mojom_generator.IsStringKind,
"is_array_kind": lambda kind: isinstance(kind, mojom.Array),
"js_type": lambda kind: kind.GetFullName("."),
"js_type": JavascriptType,
"stylize_method": mojom_generator.StudlyCapsToCamel,
"substitute_namespace": SubstituteNamespace,
"verify_token_type": mojom_generator.VerifyTokenType,
}
@UseJinja("js_templates/module.js.tmpl", filters=js_filters)
def GenerateJsModule(self):
return {
"imports": self.module.imports,
"imports": self.GetImports(),
"kinds": self.module.kinds,
"enums": self.module.enums,
"structs": self.GetStructs() + self.GetStructsFromMethods(),
......@@ -176,3 +190,12 @@ class Generator(mojom_generator.Generator):
def GenerateFiles(self):
self.Write(self.GenerateJsModule(), "%s.js" % self.module.name)
def GetImports(self):
# Since each import is assigned a variable in JS, they need to have unique
# names.
counter = 1
for each in self.module.imports:
each["unique_name"] = "import" + str(counter)
counter += 1
return self.module.imports
......@@ -46,7 +46,11 @@ def LoadGenerators(generators_string):
def ProcessFile(args, generator_modules, filename, processed_files):
# Ensure we only visit each file once.
processed_files.append(filename)
if filename in processed_files:
if processed_files[filename] is None:
raise Exception("Circular dependency: " + filename)
return processed_files[filename]
processed_files[filename] = None
dirname, name = os.path.split(filename)
name = os.path.splitext(name)[0]
......@@ -61,9 +65,8 @@ def ProcessFile(args, generator_modules, filename, processed_files):
# We use these to generate proper type info.
for import_data in mojom['imports']:
import_filename = os.path.join(dirname, import_data['filename'])
if import_filename not in processed_files:
import_data['module'] = ProcessFile(
args, generator_modules, import_filename, processed_files)
import_data['module'] = ProcessFile(
args, generator_modules, import_filename, processed_files)
module = mojom_data.OrderedModuleFromData(mojom)
for generator_module in generator_modules:
......@@ -71,6 +74,7 @@ def ProcessFile(args, generator_modules, filename, processed_files):
args.output_dir)
generator.GenerateFiles()
processed_files[filename] = module
return module
def Main():
......@@ -95,7 +99,7 @@ def Main():
os.makedirs(args.output_dir)
for filename in args.filename:
ProcessFile(args, generator_modules, filename, [])
ProcessFile(args, generator_modules, filename, {})
return 0
......
......@@ -69,7 +69,7 @@ class Field(object):
class Struct(Kind):
def __init__(self, name = None):
self.name = name
self.imported_from_namespace = None
self.imported_from = None
if name != None:
spec = 'x:' + name
else:
......@@ -78,11 +78,11 @@ class Struct(Kind):
self.fields = []
@classmethod
def CreateFromImport(cls, kind, import_namespace):
def CreateFromImport(cls, kind, imported_from):
"""Used with 'import module' - clones the kind imported from the
given module's namespace."""
kind = copy.deepcopy(kind)
kind.imported_from_namespace = import_namespace
kind.imported_from = imported_from
return kind
def AddField(self, name, kind, ordinal = None, default = None):
......@@ -92,16 +92,16 @@ class Struct(Kind):
def GetFullName(self, separator):
"""Returns the fully qualified type name, including namespace prefix."""
if self.imported_from_namespace:
return separator.join([self.imported_from_namespace, self.name])
if self.imported_from:
return separator.join([self.imported_from["namespace"], self.name])
return self.name
def GetFullNameInternal(self, separator):
"""Returns the fully qualified type name for an internal data structure,
including namespace prefix."""
if self.imported_from_namespace:
if self.imported_from:
return separator.join(
[self.imported_from_namespace, "internal", self.name])
[self.imported_from["namespace"], "internal", self.name])
return self.name
......
......@@ -54,12 +54,19 @@ def KindFromData(kinds, data):
kinds[data] = kind
return kind
def ImportFromData(data):
def ImportFromData(module, data):
import_module = data['module']
import_item = {}
import_item['module_name'] = import_module.name
import_item['namespace'] = import_module.namespace
# Copy the struct kinds from our imports into the current module.
for kind in import_module.kinds.itervalues():
# TODO(mpcomplete): Handle enums
if isinstance(kind, mojom.Struct) and kind.imported_from is None:
kind = mojom.Struct.CreateFromImport(kind, import_item)
module.kinds[kind.spec] = kind
return import_item
def StructToData(struct):
......@@ -182,25 +189,19 @@ def ModuleFromData(data):
module.kinds = {}
for kind in mojom.PRIMITIVES:
module.kinds[kind.spec] = kind
# Copy the struct kinds from our imports into the current module.
for import_data in data['imports']:
import_module = import_data['module']
for kind in import_module.kinds.itervalues():
# TODO(mpcomplete): Handle enums
if isinstance(kind, mojom.Struct):
kind = mojom.Struct.CreateFromImport(
kind, import_module.namespace)
module.kinds[kind.spec] = kind
module.name = data['name']
module.namespace = data['namespace']
# Imports must come first, because they add to module.kinds which is used
# by by the others.
module.imports = map(
lambda import_data: ImportFromData(import_data), data['imports'])
lambda import_data: ImportFromData(module, import_data),
data['imports'])
module.structs = map(
lambda struct: StructFromData(module, struct), data['structs'])
module.interfaces = map(
lambda interface:
InterfaceFromData(module, interface), data['interfaces'])
lambda interface: InterfaceFromData(module, interface),
data['interfaces'])
if data.has_key('enums'):
module.enums = map(
lambda enum: EnumFromData(module.kinds, enum), data['enums'])
......
......@@ -8,7 +8,7 @@ module imported {
// sample_service.mojom, to show how import works.
enum Shape {
SHAPE_RECTANGLE,
SHAPE_RECTANGLE = 1,
SHAPE_CIRCLE,
SHAPE_TRIANGLE,
};
......
// Copyright 2014 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.
import "sample_import.mojom"
module imported {
// This sample adds more types and constants to the "imported" namespace,
// to test a bug with importing multiple modules with the same namespace.
enum Color {
COLOR_RED,
COLOR_BLACK,
};
struct Size {
int32 width;
int32 height;
};
struct Thing {
int32 shape;
int32 color;
Point location = {0, 0};
Size size;
};
} // module imported
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import "sample_import.mojom"
import "sample_import2.mojom"
module sample {
......@@ -47,6 +48,7 @@ struct DefaultsTest {
uint8[] data = [1, 2, 3] @2;
imported.Point point = {7, 15} @3;
int32[] shape_masks = [1 << imported.SHAPE_RECTANGLE] @4;
imported.Thing thing = {imported.SHAPE_RECTANGLE, imported.COLOR_RED};
};
interface Port {
......
......@@ -342,6 +342,9 @@ TEST(BindingsSampleTest, DefaultValues) {
EXPECT_EQ(1u, full.shape_masks().size());
EXPECT_EQ(1 << imported::SHAPE_RECTANGLE, full.shape_masks()[0]);
EXPECT_EQ(imported::SHAPE_RECTANGLE, full.thing().shape());
EXPECT_EQ(imported::COLOR_RED, full.thing().color());
}
} // namespace sample
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment