DevTools: generate class-per domain for remote debugging protocol.

BUG=580337
NOTRY=true

Review-Url: https://codereview.chromium.org/2025953002
Cr-Original-Commit-Position: refs/heads/master@{#397326}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 556210b7bb7f75aa8f305d7175d1b3271bb21d5e
diff --git a/CodeGenerator.py b/CodeGenerator.py
index 4027fd5..e00e0d3 100644
--- a/CodeGenerator.py
+++ b/CodeGenerator.py
@@ -33,22 +33,39 @@
 import jinja2
 
 cmdline_parser = optparse.OptionParser()
+cmdline_parser.add_option("--domains")
 cmdline_parser.add_option("--output_dir")
-cmdline_parser.add_option("--generate_dispatcher")
+cmdline_parser.add_option("--output_package")
+cmdline_parser.add_option("--string_type")
+cmdline_parser.add_option("--export_macro")
+
+generate_domains = set()
 
 try:
     arg_options, arg_values = cmdline_parser.parse_args()
     if (len(arg_values) == 0):
         raise Exception("At least one plain argument expected (found %s)" % len(arg_values))
     output_dirname = arg_options.output_dir
-    generate_dispatcher = arg_options.generate_dispatcher
     if not output_dirname:
         raise Exception("Output directory must be specified")
+    output_package = arg_options.output_package
+    if not output_package:
+        raise Exception("Output package must be specified")
+    string_type = arg_options.string_type
+    if not string_type:
+        raise Exception("String type must be specified")
+    export_macro = arg_options.export_macro
+    if not export_macro:
+        raise Exception("Export macro must be specified")
+    output_domains = arg_options.domains
+    if output_domains and len(output_domains):
+        for domain in output_domains.split(","):
+            generate_domains.add(domain)
 except Exception:
     # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
     exc = sys.exc_info()[1]
     sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
-    sys.stderr.write("Usage: <script> --output_dir <output_dir> blink_protocol.json v8_protocol.json ...\n")
+    sys.stderr.write("Usage: <script> --output_dir <output_dir> protocol.json ...\n")
     exit(1)
 
 json_api = {"domains": []}
@@ -88,30 +105,6 @@
     return open(file_name, "w")
 
 
-def topsort_domains():
-    domains = {}
-    for domain in json_api["domains"]:
-        domains[domain["domain"]] = domain
-
-    processed = set()
-    result = []
-
-    def process(name):
-        if name in processed:
-            return
-        domain = domains[name]
-        deps = []
-        if "depends" in domain:
-            for dep in domain["depends"]:
-                process(dep)
-        result.append(domain)
-        processed.add(name)
-
-    for domain in json_api["domains"]:
-        process(domain["domain"])
-    json_api["domains"] = result
-
-
 def patch_full_qualified_refs():
     def patch_full_qualified_refs_in_domain(json, domain_name):
         if isinstance(json, list):
@@ -176,28 +169,16 @@
 
 
 def create_string_type_definition(domain):
-    if domain in ["Runtime", "Debugger", "Profiler", "HeapProfiler"]:
-        return {
-            "return_type": "String16",
-            "pass_type": "const String16&",
-            "to_pass_type": "%s",
-            "to_raw_type": "%s",
-            "to_rvalue": "%s",
-            "type": "String16",
-            "raw_type": "String16",
-            "raw_pass_type": "const String16&",
-            "raw_return_type": "String16",
-        }
     return {
-        "return_type": "String",
-        "pass_type": "const String&",
+        "return_type": string_type,
+        "pass_type": ("const %s&" % string_type),
         "to_pass_type": "%s",
         "to_raw_type": "%s",
         "to_rvalue": "%s",
-        "type": "String",
-        "raw_type": "String",
-        "raw_pass_type": "const String&",
-        "raw_return_type": "String",
+        "type": string_type,
+        "raw_type": string_type,
+        "raw_pass_type": ("const %s&" % string_type),
+        "raw_return_type": string_type,
     }
 
 
@@ -263,7 +244,6 @@
             else:
                 type_definitions[domain["domain"] + "." + type["id"]] = create_primitive_type_definition(type["type"])
 
-topsort_domains()
 patch_full_qualified_refs()
 create_type_definitions()
 
@@ -308,10 +288,18 @@
     return timestamp > max(os.path.getmtime(module_path + template),
                            current_script_timestamp, json_timestamp)
 
+if not os.path.exists(output_dirname):
+    os.mkdir(output_dirname)
+jinja_env = initialize_jinja_env(output_dirname)
 
-def generate(class_name):
-    h_template_name = "/%s_h.template" % class_name
-    cpp_template_name = "/%s_cpp.template" % class_name
+h_template_name = "/TypeBuilder_h.template"
+cpp_template_name = "/TypeBuilder_cpp.template"
+h_template = jinja_env.get_template(h_template_name)
+cpp_template = jinja_env.get_template(cpp_template_name)
+
+
+def generate(domain):
+    class_name = domain["domain"]
     h_file_name = output_dirname + "/" + class_name + ".h"
     cpp_file_name = output_dirname + "/" + class_name + ".cpp"
 
@@ -320,15 +308,14 @@
         return
 
     template_context = {
-        "class_name": class_name,
-        "api": json_api,
+        "domain": domain,
         "join_arrays": join_arrays,
         "resolve_type": resolve_type,
         "type_definition": type_definition,
-        "has_disable": has_disable
+        "has_disable": has_disable,
+        "export_macro": export_macro,
+        "output_package": output_package,
     }
-    h_template = jinja_env.get_template(h_template_name)
-    cpp_template = jinja_env.get_template(cpp_template_name)
     h_file = output_file(h_file_name)
     cpp_file = output_file(cpp_file_name)
     h_file.write(h_template.render(template_context))
@@ -337,5 +324,6 @@
     cpp_file.close()
 
 
-jinja_env = initialize_jinja_env(output_dirname)
-generate("TypeBuilder")
+for domain in json_api["domains"]:
+    if domain["domain"] in generate_domains:
+        generate(domain)
diff --git a/DispatcherBase.cpp b/DispatcherBase.cpp
index 1329e39..6979872 100644
--- a/DispatcherBase.cpp
+++ b/DispatcherBase.cpp
@@ -10,6 +10,9 @@
 namespace blink {
 namespace protocol {
 
+// static
+const char DispatcherBase::kInvalidRequest[] = "Invalid request";
+
 DispatcherBase::WeakPtr::WeakPtr(DispatcherBase* dispatcher) : m_dispatcher(dispatcher) { }
 
 DispatcherBase::WeakPtr::~WeakPtr()
diff --git a/DispatcherBase.h b/DispatcherBase.h
index 4669812..8380691 100644
--- a/DispatcherBase.h
+++ b/DispatcherBase.h
@@ -21,7 +21,8 @@
 class PLATFORM_EXPORT DispatcherBase {
     PROTOCOL_DISALLOW_COPY(DispatcherBase);
 public:
-    class WeakPtr {
+    static const char kInvalidRequest[];
+    class PLATFORM_EXPORT WeakPtr {
     public:
         explicit WeakPtr(DispatcherBase*);
         ~WeakPtr();
diff --git a/ErrorSupport.h b/ErrorSupport.h
index aee4c0e..5762057 100644
--- a/ErrorSupport.h
+++ b/ErrorSupport.h
@@ -36,4 +36,6 @@
 } // namespace platform
 } // namespace blink
 
+using blink::protocol::ErrorString;
+
 #endif // !defined(ErrorSupport_h)
diff --git a/Maybe.h b/Maybe.h
index 917d268..3af6a86 100644
--- a/Maybe.h
+++ b/Maybe.h
@@ -6,6 +6,10 @@
 #define Maybe_h
 
 #include "platform/PlatformExport.h"
+#include "platform/inspector_protocol/String16.h"
+
+#include "wtf/Assertions.h"
+#include <memory>
 
 namespace blink {
 namespace protocol {
diff --git a/TypeBuilder_cpp.template b/TypeBuilder_cpp.template
index 88e5c97..1aeef45 100644
--- a/TypeBuilder_cpp.template
+++ b/TypeBuilder_cpp.template
@@ -4,19 +4,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "platform/inspector_protocol/{{class_name}}.h"
+#include "{{output_package}}/{{domain.domain}}.h"
 
 #include "platform/inspector_protocol/DispatcherBase.h"
 
 namespace blink {
 namespace protocol {
-
-static const char kInvalidRequest[] = "Invalid request";
+namespace {{domain.domain}} {
 
 // ------------- Enum values from types.
-{% for domain in api.domains %}
-
-namespace {{domain.domain}} {
 
 const char Metainfo::domainName[] = "{{domain.domain}}";
   {% for type in domain.types %}
@@ -181,7 +177,7 @@
     {% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
     {% if "async" in command %}
 
-class PLATFORM_EXPORT {{command.name | to_title_case}}CallbackImpl : public Backend::{{command.name | to_title_case}}Callback, public DispatcherBase::Callback {
+class {{command.name | to_title_case}}CallbackImpl : public Backend::{{command.name | to_title_case}}Callback, public DispatcherBase::Callback {
 public:
     {{command.name | to_title_case}}CallbackImpl(std::unique_ptr<DispatcherBase::WeakPtr> backendImpl, int callId)
         : DispatcherBase::Callback(std::move(backendImpl), callId) { }
@@ -300,7 +296,5 @@
 }
 
 } // {{domain.domain}}
-{% endfor %}
-
 } // namespace protocol
 } // namespace blink
diff --git a/TypeBuilder_h.template b/TypeBuilder_h.template
index 79edda2..7d56d1e 100644
--- a/TypeBuilder_h.template
+++ b/TypeBuilder_h.template
@@ -4,10 +4,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef {{class_name}}_h
-#define {{class_name}}_h
+#ifndef protocol_{{domain.domain}}_h
+#define protocol_{{domain.domain}}_h
 
+{% if export_macro == "PLATFORM_EXPORT" %}
 #include "platform/PlatformExport.h"
+{% else %}
+#include "core/CoreExport.h"
+{% endif %}
 #include "platform/inspector_protocol/Array.h"
 #include "platform/inspector_protocol/BackendCallback.h"
 #include "platform/inspector_protocol/DispatcherBase.h"
@@ -18,14 +22,15 @@
 #include "platform/inspector_protocol/String16.h"
 #include "platform/inspector_protocol/Values.h"
 #include "platform/inspector_protocol/ValueConversions.h"
+{% for name in domain.dependencies %}
+#include "{{output_package}}/{{name}}.h"
+{% endfor %}
+
 #include "wtf/Assertions.h"
 #include "wtf/PtrUtil.h"
 
 namespace blink {
 namespace protocol {
-
-{% for domain in api.domains %}
-
 namespace {{domain.domain}} {
 
 // ------------- Forward and enum declarations.
@@ -48,7 +53,7 @@
 
 namespace {{type.id}}Enum {
       {% for literal in type.enum %}
-PLATFORM_EXPORT extern const char* {{ literal | dash_to_camelcase}};
+{{export_macro}} extern const char* {{ literal | dash_to_camelcase}};
       {% endfor %}
 } // {{type.id}}Enum
     {% endif %}
@@ -60,7 +65,7 @@
 namespace {{command.name | to_title_case}} {
 namespace {{param.name | to_title_case}}Enum {
         {% for literal in param.enum %}
-PLATFORM_EXPORT extern const char* {{ literal | dash_to_camelcase}};
+{{export_macro}} extern const char* {{ literal | dash_to_camelcase}};
         {% endfor %}
 } // {{param.name | to_title_case}}Enum
 } // {{command.name | to_title_case }}
@@ -74,7 +79,7 @@
     {% set type_def = type_definition(domain.domain + "." + type.id)%}
 
 // {{type.description}}
-class PLATFORM_EXPORT {{type.id}} {
+class {{export_macro}} {{type.id}} {
 public:
     static std::unique_ptr<{{type.id}}> parse(protocol::Value* value, ErrorSupport* errors);
 
@@ -82,7 +87,7 @@
     {% for property in type.properties %}
       {% if "enum" in property %}
 
-    struct PLATFORM_EXPORT {{property.name | to_title_case}}Enum {
+    struct {{export_macro}} {{property.name | to_title_case}}Enum {
         {% for literal in property.enum %}
         static const char* {{ literal | dash_to_camelcase}};
         {% endfor %}
@@ -175,13 +180,13 @@
 
 // ------------- Backend interface.
 
-class PLATFORM_EXPORT Backend {
+class {{export_macro}} Backend {
 public:
   {% for command in domain.commands %}
     {% if "redirect" in command %}{% continue %}{% endif %}
     {% if ("handlers" in command) and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
     {% if "async" in command %}
-    class PLATFORM_EXPORT {{command.name | to_title_case}}Callback : public BackendCallback {
+    class {{export_macro}} {{command.name | to_title_case}}Callback : public BackendCallback {
     public:
         virtual void sendSuccess(
             {%- for parameter in command.returns -%}
@@ -227,7 +232,7 @@
 
 // ------------- Frontend interface.
 
-class PLATFORM_EXPORT Frontend {
+class {{export_macro}} Frontend {
 public:
     Frontend(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { }
   {% for event in domain.events %}
@@ -250,7 +255,7 @@
 
 // ------------- Dispatcher.
 
-class PLATFORM_EXPORT Dispatcher {
+class {{export_macro}} Dispatcher {
 public:
     static void wire(UberDispatcher*, blink::protocol::{{domain.domain}}::Backend*);
 
@@ -260,7 +265,7 @@
 
 // ------------- Metainfo.
 
-class PLATFORM_EXPORT Metainfo {
+class {{export_macro}} Metainfo {
 public:
     using BackendClass = Backend;
     using FrontendClass = Frontend;
@@ -269,11 +274,7 @@
 };
 
 } // namespace {{domain.domain}}
-{% endfor %}
-
 } // namespace protocol
 } // namespace blink
 
-using blink::protocol::ErrorString;
-
-#endif // !defined({{class_name}}_h)
+#endif // !defined(protocol_{{domain.domain}}_h)
diff --git a/protocol.gyp b/protocol.gyp
index 88fbca0..1228097 100644
--- a/protocol.gyp
+++ b/protocol.gyp
@@ -11,42 +11,8 @@
       '<(DEPTH)/third_party/markupsafe/__init__.py',  # jinja2 dep
     ],
   },
-
   'targets': [
     {
-      # GN version: //third_party/WebKit/Source/platform/inspector_protocol_sources
-      'target_name': 'protocol_sources',
-      'type': 'none',
-      'dependencies': [
-        'protocol_version'
-      ],
-      'actions': [
-        {
-          'action_name': 'generateInspectorProtocolBackendSources',
-          'inputs': [
-            '<@(jinja_module_files)',
-            # The python script in action below.
-            'CodeGenerator.py',
-            # Input files for the script.
-            '../../devtools/protocol.json',
-            'TypeBuilder_h.template',
-            'TypeBuilder_cpp.template',
-          ],
-          'outputs': [
-            '<(blink_platform_output_dir)/inspector_protocol/TypeBuilder.cpp',
-            '<(blink_platform_output_dir)/inspector_protocol/TypeBuilder.h',
-          ],
-          'action': [
-            'python',
-            'CodeGenerator.py',
-            '../../devtools/protocol.json',
-            '--output_dir', '<(blink_platform_output_dir)/inspector_protocol',
-          ],
-          'message': 'Generating Inspector protocol backend sources from protocol.json',
-        },
-      ]
-    },
-    {
       # GN version: //third_party/WebKit/Source/platform/inspector_protocol_version
       'target_name': 'protocol_version',
       'type': 'none',
@@ -60,10 +26,6 @@
           'outputs': [
             '<(blink_platform_output_dir)/inspector_protocol/InspectorProtocolVersion.h',
           ],
-          'variables': {
-            'generator_include_dirs': [
-            ],
-          },
           'action': [
             'python',
             'generate-inspector-protocol-version',