From b0e914d7d41106cd3b1602c9b00696c832930421 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 09:52:33 +0100 Subject: [PATCH 01/14] [JsonGen] Fix spurious warnings --- .../source/documentation_generator.py | 43 ++++++++++--------- JsonGenerator/source/json_loader.py | 24 ++++++++--- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/JsonGenerator/source/documentation_generator.py b/JsonGenerator/source/documentation_generator.py index 110f17a..aedef74 100644 --- a/JsonGenerator/source/documentation_generator.py +++ b/JsonGenerator/source/documentation_generator.py @@ -221,12 +221,12 @@ def ExampleObj(name, obj, root=False): if obj_type == "string": json_data += "{ }" if obj.get("opaque") else ('"%s"' % (default if default else "...")) elif obj_type == "integer": - if default and not str(default).isnumeric(): + if default and not str(default).lstrip('-+').isnumeric(): raise DocumentationError("'%s': invalid example syntax for this integer type (see '%s')" % (name, default)) json_data += '%s' % (default if default else 0) elif obj_type == "number": - if default and not str(default).replace('.','').isnumeric(): + if default and not str(default).replace('.','').lstrip('-+').isnumeric(): raise DocumentationError("'%s': invalid example syntax for this numeric (floating-point) type (see '%s')" % (name, default)) if default and '.' not in str(default): @@ -384,23 +384,25 @@ def MethodDump(method, props, classname, section, header, is_notification=False, if is_notification: method = "client.events.1." + method elif is_property: - method = "%s.1.%s%s" % (classname, method, ("@" + props["index"]["example"]) if "index" in props and "example" in props["index"] else "") + method = "%s.1.%s%s" % (classname, method, ("@" + str(props["index"]["example"])) if "index" in props and "example" in props["index"] else "") else: method = "%s.1.%s" % (classname, method) if "id" in props and "example" in props["id"]: method = props["id"]["example"] + "." + method - jsonError = "Failed to generate JSON example" + jsonError = "Failed to generate JSON example for %s" % method jsonResponse = jsonError jsonRequest = jsonError if is_property: if not writeonly: MdHeader("Get Request", 4) + + text = '{ "jsonrpc": "2.0", "id": 42, "method": "%s" }' % method + try: - jsonRequest = json.dumps(json.loads('{ "jsonrpc": "2.0", "id": 42, "method": "%s" }' % method, - object_pairs_hook=OrderedDict), indent=2) + jsonRequest = json.dumps(json.loads(text, object_pairs_hook=OrderedDict), indent=2) except: jsonRequest = jsonError log.Error(jsonError) @@ -409,11 +411,12 @@ def MethodDump(method, props, classname, section, header, is_notification=False, MdHeader("Get Response", 4) parameters = (props["result"] if "result" in props else (props["params"] if "params" in props else None)) + text = '{ "jsonrpc": "2.0", "id": 42, %s }' % ExampleObj("result", parameters, True) + try: - jsonResponse = json.dumps(json.loads('{ "jsonrpc": "2.0", "id": 42, %s }' % ExampleObj("result", parameters, True), - object_pairs_hook=OrderedDict), indent=2) + jsonResponse = json.dumps(json.loads(text, object_pairs_hook=OrderedDict), indent=2) except: - jsonResponse = jsonError + jsonResponse = jsonError log.Error(jsonError) MdCode(jsonResponse, "json") @@ -437,18 +440,18 @@ def MethodDump(method, props, classname, section, header, is_notification=False, MdCode(jsonRequest, "json") if not is_notification and not is_property: - if "result" in props: - MdHeader("Response", 4) - try: - jsonResponse = json.dumps(json.loads('{ "jsonrpc": "2.0", "id": 42, %s }' % ExampleObj("result", props["result"], True), - object_pairs_hook=OrderedDict), indent=2) - except: - jsonResponse = jsonError - log.Error(jsonError) + if "result" not in props: + props["result"] = { "type": "null" } - MdCode(jsonResponse, "json") - elif "noresult" not in props or not props["noresult"]: - raise DocumentationError("'%s': missing 'result' in this method" % method) + MdHeader("Response", 4) + try: + jsonResponse = json.dumps(json.loads('{ "jsonrpc": "2.0", "id": 42, %s }' % ExampleObj("result", props["result"], True), + object_pairs_hook=OrderedDict), indent=2) + except: + jsonResponse = jsonError + log.Error(jsonError) + + MdCode(jsonResponse, "json") if is_property: MdHeader("Set Response", 4) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index d767ebc..ce79dbd 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -102,6 +102,12 @@ def __init__(self, name, parent, schema, included=None): self.name = name self.original_name = schema.get("@originalname") self.description = schema.get("description") + + if not self.description: + # Copy over the summary from the property + if parent and parent.parent and isinstance(parent.parent, JsonProperty) and parent.parent.summary: + self.description = parent.parent.summary + self.iterator = schema.get("iterator") self.original_type = schema.get("original_type") self.do_create = (self.original_type == None) @@ -406,7 +412,9 @@ def __DetermineSize(self): biggest = e if same: - log.Warn("'%s': specified enum values are same as implicit" % self.print_name) + if not self.original_type: + log.Warn("'%s': specified enum values are same as implicit" % self.print_name) + self.cpp_enumerator_values = [] if self.bitmask and not is_bitmap: @@ -506,7 +514,7 @@ def __init__(self, name, parent, schema, included = None): self._properties.append(new_obj) if not new_obj.description and not isinstance(self, JsonMethod): - log.DocIssue("'%s': element missing description" % new_obj.print_name) + log.DocIssue("'%s': element is missing description" % new_obj.print_name) # Handle aggregate objects if isinstance(new_obj, JsonObject): @@ -701,13 +709,13 @@ def __init__(self, name, parent, schema, included=None, property=False): if "hint" in schema: method_schema["hint"] = schema["hint"] - JsonObject.__init__(self, name, parent, method_schema, included=included) - self.alternative = None self.summary = schema.get("summary") self.deprecated = schema.get("deprecated") self.obsolete = schema.get("obsolete") + JsonObject.__init__(self, name, parent, method_schema, included=included) + if not self.summary: log.DocIssue("'%s': method is missing summary" % self.print_name) @@ -989,7 +997,7 @@ def _FindCpp(element, schema): # Tags all objects that used to be $references if isinstance(schema, jsonref.JsonRef) and isinstance(schema, dict): - if "description" in schema.__reference__ or "example" in schema.__reference__ or "default" in schema.__reference__: + if "description" in schema.__reference__ or "example" in schema.__reference__ or "default" in schema.__reference__ or "summary" in schema.__reference__: # Need a copy, there an override on one of the properites if idx == None: parent[parent_name] = copy.deepcopy(schema) @@ -1003,6 +1011,9 @@ def _FindCpp(element, schema): if "description" in schema.__reference__: new_schema["description"] = schema.__reference__["description"] + if "summary" in schema.__reference__: + new_schema["summary"] = schema.__reference__["summary"] + if "example" in schema.__reference__: new_schema["example"] = schema.__reference__["example"] @@ -1048,6 +1059,9 @@ def _FindCpp(element, schema): if "description" in schema: parent[parent_name]["description"] = schema["description"] + if "summary" in schema: + parent[parent_name]["summary"] = schema["summary"] + if "example" in schema: parent[parent_name]["example"] = schema["example"] From eeff2ceafba58f382c052f5811d3dfd6f0ab2d86 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 10:10:29 +0100 Subject: [PATCH 02/14] Don't complain on invalid case of alt/obsolete methods --- JsonGenerator/source/json_loader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index ce79dbd..bb47fb0 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -731,9 +731,9 @@ def __init__(self, name, parent, schema, included=None, property=False): if "alt" in schema: self.alternative = schema.get("alt") - if not self.alternative.islower(): + if not self.alternative.islower() and not (schema.get("altisdeprecated") or schema.get("altisobsolete")): log.Warn("'%s' (alternative): mixedCase identifiers are supported, however all-lowercase names are recommended" % self.alternative) - elif "_" in self.alternative: + elif "_" in self.alternative and not (schema.get("altisdeprecated") or schema.get("altisobsolete")): log.Warn("'%s' (alternative): snake_case identifiers are supported, however flatcase names are recommended" % self.alternative) else: self.alternative = None From 33befe687b0c2ee6344f1d8e7cfbe8074addc2d7 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 10:22:13 +0100 Subject: [PATCH 03/14] Note deprecated alt in methods and props --- JsonGenerator/source/header_loader.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/JsonGenerator/source/header_loader.py b/JsonGenerator/source/header_loader.py index 6eedd2b..e9b1d71 100644 --- a/JsonGenerator/source/header_loader.py +++ b/JsonGenerator/source/header_loader.py @@ -658,7 +658,7 @@ def BuildResult(vars, is_property=False): obj["summary"] = method.retval.meta.brief.strip() if method.retval.meta.details: - obj["description"] = method.retval.meta.details + obj["description"] = method.retval.meta.details.strip() if method.retval.meta.retval: errors = [] @@ -678,6 +678,8 @@ def BuildResult(vars, is_property=False): if method.retval.meta.alt: idx = prefix + method.retval.meta.alt obj["alt"] = idx + obj["altisdeprecated"] = method.retval.meta.alt_is_deprecated + obj["altisobsolete"] = method.retval.meta.alt_is_obsolete if config.LEGACY_ALT: idx = prefix + method.retval.meta.alt @@ -759,7 +761,7 @@ def BuildResult(vars, is_property=False): obj["summary"] = method.retval.meta.brief.strip() if method.retval.meta.details: - obj["description"] = method.retval.meta.details + obj["description"] = method.retval.meta.details.strip() if params: obj["params"] = params From 8ef0ca4f5fb3f4595aa75399b6961866900d63e3 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 10:27:27 +0100 Subject: [PATCH 04/14] Pick up brief for nested PODs --- JsonGenerator/source/header_loader.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/JsonGenerator/source/header_loader.py b/JsonGenerator/source/header_loader.py index e9b1d71..9481c3e 100644 --- a/JsonGenerator/source/header_loader.py +++ b/JsonGenerator/source/header_loader.py @@ -257,6 +257,9 @@ def GenerateObject(ctype, was_typdef): properties[name] = props properties[name]["type"] = "object" properties[name]["original_type"] = StripFrameworkNamespace(p.type.Type().full_name) + + if p.meta.brief: + properties[name]["description"] = p.meta.brief else: properties[name] = ConvertParameter(p) From 41904f396f15e883043741ebf340c7c5e3704f1a Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 10:44:57 +0100 Subject: [PATCH 05/14] deprecated alt in setter/getter --- JsonGenerator/source/header_loader.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/JsonGenerator/source/header_loader.py b/JsonGenerator/source/header_loader.py index 9481c3e..c15605a 100644 --- a/JsonGenerator/source/header_loader.py +++ b/JsonGenerator/source/header_loader.py @@ -681,8 +681,12 @@ def BuildResult(vars, is_property=False): if method.retval.meta.alt: idx = prefix + method.retval.meta.alt obj["alt"] = idx - obj["altisdeprecated"] = method.retval.meta.alt_is_deprecated - obj["altisobsolete"] = method.retval.meta.alt_is_obsolete + + if method.retval.meta.alt_is_deprecated: + obj["altisdeprecated"] = method.retval.meta.alt_is_deprecated + + if method.retval.meta.alt_is_obsolete: + obj["altisobsolete"] = method.retval.meta.alt_is_obsolete if config.LEGACY_ALT: idx = prefix + method.retval.meta.alt @@ -781,8 +785,12 @@ def BuildResult(vars, is_property=False): if method.retval.meta.alt: obj["alt"] = method.retval.meta.alt - obj["altisdeprecated"] = method.retval.meta.alt_is_deprecated - obj["altisobsolete"] = method.retval.meta.alt_is_obsolete + + if method.retval.meta.alt_is_deprecated: + obj["altisdeprecated"] = method.retval.meta.alt_is_deprecated + + if method.retval.meta.alt_is_obsolete: + obj["altisobsolete"] = method.retval.meta.alt_is_obsolete events[prefix + method_name] = obj From 1389981e185cae127f87233ccf6fbab9ce86edc1 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 11:15:01 +0100 Subject: [PATCH 06/14] By default warnings are now off --- JsonGenerator/JsonGenerator.py | 6 +++--- cmake/FindJsonGenerator.cmake.in | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/JsonGenerator/JsonGenerator.py b/JsonGenerator/JsonGenerator.py index 3dcb953..22c6f0a 100755 --- a/JsonGenerator/JsonGenerator.py +++ b/JsonGenerator/JsonGenerator.py @@ -41,7 +41,7 @@ if __name__ == "__main__": argparser, args = config.Parse(sys.argv) - log = logger.Create(NAME, args.verbose, not args.no_duplicates_warnings, not args.no_style_warnings) + log = logger.Create(NAME, args.verbose, not args.no_warnings, not args.no_style_warnings) trackers.SetLogger(log) json_loader.SetLogger(log) @@ -59,8 +59,6 @@ else: files.append(p) - joint_headers = {} - for path in files: trackers.object_tracker.Reset() @@ -71,6 +69,8 @@ schemas, additional_includes, temp_files = json_loader.Load(log, path, args.if_dir, args.cppif_dir, args.includePaths) + joint_headers = {} + for schema in schemas: if schema: warnings = config.GENERATED_JSON diff --git a/cmake/FindJsonGenerator.cmake.in b/cmake/FindJsonGenerator.cmake.in index 6fa1ec7..7588b7e 100644 --- a/cmake/FindJsonGenerator.cmake.in +++ b/cmake/FindJsonGenerator.cmake.in @@ -30,7 +30,7 @@ function(JsonGenerator) message(FATAL_ERROR "JsonGenerator path ${JSON_GENERATOR} invalid.") endif() - set(optionsArgs CODE STUBS DOCS LEGACY_ALT AUTO_PREFIX NO_INCLUDES NO_STYLE_WARNINGS COPY_CTOR NO_REF_NAMES NO_INTERFACES_SECTION VERBOSE FORCE_GENERATE) + set(optionsArgs CODE STUBS DOCS LEGACY_ALT AUTO_PREFIX NO_INCLUDES NO_WARNINGS NO_STYLE_WARNINGS DUPLICATE_OBJ_WARNINGS COPY_CTOR NO_REF_NAMES NO_INTERFACES_SECTION VERBOSE FORCE_GENERATE) set(oneValueArgs OUTPUT CPP_OUTPUT IFDIR CPPIFDIR INDENT DEF_STRING DEF_INT_SIZE PATH FORMAT) set(multiValueArgs INPUT INCLUDE_PATH NAMESPACE) @@ -68,10 +68,18 @@ function(JsonGenerator) list(APPEND _execute_command "--no-includes") endif() + if(Argument_NO_WARNINGS) + list(APPEND _execute_command "--no-warnings") + endif() + if(Argument_NO_STYLE_WARNINGS) list(APPEND _execute_command "--no-style-warnings") endif() + if(DUPLICATE_OBJ_WARNINGS) + list(APPEND _execute_command "--duplicate-obj-warnings") + endif() + if(Argument_COPY_CTOR) list(APPEND _execute_command "--copy-ctor") endif() From fac816d924ecbfbdb7c929fc62011b203c4335d3 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 11:24:24 +0100 Subject: [PATCH 07/14] by default obj duplicates are off --- JsonGenerator/source/config.py | 17 +++++++++++------ JsonGenerator/source/trackers.py | 15 ++++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/JsonGenerator/source/config.py b/JsonGenerator/source/config.py index f86c1df..dfde4e2 100644 --- a/JsonGenerator/source/config.py +++ b/JsonGenerator/source/config.py @@ -33,7 +33,6 @@ # Configurables CLASSNAME_FROM_REF = True DEFAULT_INT_SIZE = 32 -SHOW_WARNINGS = True DOC_ISSUES = True DEFAULT_DEFINITIONS_FILE = "../../ProxyStubGenerator/default.h" FRAMEWORK_NAMESPACE = "WPEFramework" @@ -136,6 +135,12 @@ def Parse(cmdline): action="store_true", default=False, help= "force code generation even if destination appears up-to-date (default: force disabled)") + argparser.add_argument( + "--no-warnings", + dest="no_warnings", + action="store_true", + default=False, + help= "disable all warnings (default: warnings enabled)") json_group = argparser.add_argument_group("JSON parser arguments (optional)") json_group.add_argument("-i", @@ -151,11 +156,11 @@ def Parse(cmdline): action="store_true", default=False, help="do not derive class names from $refs (default: derive class names from $ref)") - json_group.add_argument("--no-duplicates-warnings", - dest="no_duplicates_warnings", + json_group.add_argument("--duplicate-obj-warnings", + dest="duplicate_obj_warnings", action="store_true", - default=not SHOW_WARNINGS, - help="suppress duplicate object warnings (default: show all duplicate object warnings)") + default=False, + help="enable duplicate object warnings (default: do not show duplicate object warnings)") cpp_group = argparser.add_argument_group("C++ parser arguments (optional)") cpp_group.add_argument("-j", @@ -298,7 +303,7 @@ def Parse(cmdline): args = argparser.parse_args(cmdline[1:]) DOC_ISSUES = not args.no_style_warnings - NO_DUP_WARNINGS = args.no_duplicates_warnings + NO_DUP_WARNINGS = not args.duplicate_obj_warnings INDENT_SIZE = args.indent_size ALWAYS_EMIT_COPY_CTOR = args.copy_ctor KEEP_EMPTY = args.keep_empty diff --git a/JsonGenerator/source/trackers.py b/JsonGenerator/source/trackers.py index 3647633..4e9832c 100644 --- a/JsonGenerator/source/trackers.py +++ b/JsonGenerator/source/trackers.py @@ -173,10 +173,11 @@ def _CompareType(lhs, rhs): props = newObj.schema["properties"] for obj in self.objects[:-1]: if _CompareObject(obj.schema["properties"], props): - if not config.GENERATED_JSON and not config.NO_DUP_WARNINGS and (not is_ref and not IsInRef(obj)): + if not config.GENERATED_JSON and (not is_ref and not IsInRef(obj)): warning = "'%s': duplicate object (same as '%s') - consider using $ref" % (newObj.print_name, obj.print_name) + if log: - if len(props) > 2: + if not config.NO_DUP_WARNINGS: log.Warn(warning) else: log.Info(warning) @@ -247,9 +248,13 @@ def __Compare(lhs, rhs): is_ref = IsInRef(newObj) for obj in self.objects[:-1]: if __Compare(obj.schema, newObj.schema): - if not config.GENERATED_JSON and not config.NO_DUP_WARNINGS and (not is_ref and not IsInRef(obj)): - log.Warn("'%s': duplicate enums (same as '%s') - consider using $ref" % - (newObj.print_name, obj.print_name)) + if not config.GENERATED_JSON and (not is_ref and not IsInRef(obj)): + warning = "'%s': duplicate enums (same as '%s') - consider using $ref" % (newObj.print_name, obj.print_name) + + if not config.NO_DUP_WARNINGS: + log.Warn(warning) + else: + log.Info(warning) return obj From d1522052da16dd4c60e143e88d9c13c44fca1085 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 13:05:46 +0100 Subject: [PATCH 08/14] Don't complain of format mix on inclued .json --- JsonGenerator/source/json_loader.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index bb47fb0..05bd9c8 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -726,7 +726,11 @@ def __init__(self, name, parent, schema, included=None, property=False): elif (self.rpc_format == config.RpcFormat.EXTENDED) and not property and not isinstance(self.params, (JsonObject, JsonArray, JsonNull)): raise JsonParseError("With 'extended' format parameters to a method or event need to be an object or an array: '%s'" % self.print_name) elif (self.rpc_format == config.RpcFormat.COLLAPSED) and isinstance(self.params, JsonObject) and (len(self.params.properties) == 1): - log.Warn("'%s': with 'collapsed' format methods and events with one parameter should not have an outer object" % self.print_name) + warning = "'%s': with 'collapsed' format methods and events with one parameter should not have an outer object" % self.print_name + if included: + log.Info(warning) + else: + log.Warn(warning) if "alt" in schema: self.alternative = schema.get("alt") From 9acb08c5dadbeace138fdac80c8bf924d0aca3ca Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 13:22:21 +0100 Subject: [PATCH 09/14] don't warn on collapsed with extra object, it's just a hint --- JsonGenerator/source/json_loader.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index 05bd9c8..22ebf90 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -726,11 +726,7 @@ def __init__(self, name, parent, schema, included=None, property=False): elif (self.rpc_format == config.RpcFormat.EXTENDED) and not property and not isinstance(self.params, (JsonObject, JsonArray, JsonNull)): raise JsonParseError("With 'extended' format parameters to a method or event need to be an object or an array: '%s'" % self.print_name) elif (self.rpc_format == config.RpcFormat.COLLAPSED) and isinstance(self.params, JsonObject) and (len(self.params.properties) == 1): - warning = "'%s': with 'collapsed' format methods and events with one parameter should not have an outer object" % self.print_name - if included: - log.Info(warning) - else: - log.Warn(warning) + log.Info("'%s': with 'collapsed' format methods and events with one parameter can omit the outer object" % self.print_name) if "alt" in schema: self.alternative = schema.get("alt") From 30fc35ac9467243fce8ac6f1c1c2fda7ecadb70d Mon Sep 17 00:00:00 2001 From: sebaszm Date: Thu, 11 Jan 2024 15:43:51 +0100 Subject: [PATCH 10/14] introduce legacy mode --- JsonGenerator/source/json_loader.py | 39 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index 22ebf90..b6ad830 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -102,11 +102,17 @@ def __init__(self, name, parent, schema, included=None): self.name = name self.original_name = schema.get("@originalname") self.description = schema.get("description") + self.grand_parent = None - if not self.description: - # Copy over the summary from the property - if parent and parent.parent and isinstance(parent.parent, JsonProperty) and parent.parent.summary: - self.description = parent.parent.summary + if not isinstance(self, JsonRpcSchema): + self.grand_parent = self + + while self.grand_parent and not isinstance(self.grand_parent, JsonMethod): + self.grand_parent = self.grand_parent.parent + + if self.grand_parent: + if not self.description: + self.description = self.grand_parent.summary self.iterator = schema.get("iterator") self.original_type = schema.get("original_type") @@ -123,17 +129,19 @@ def __init__(self, name, parent, schema, included=None): if self.name[0] == "_": raise JsonParseError("Identifiers must not start with an underscore (reserved by the generator): '%s'" % self.print_name) - if not self.name.islower(): - log.Warn("'%s': mixedCase identifiers are supported, however all-lowercase names are recommended" % self.print_name) - elif "_" in self.name: - log.Warn("'%s': snake_case identifiers are supported, however flatcase names are recommended" % self.print_name) + if not self.grand_parent or not self.grand_parent.parent.legacy: + if not self.name.islower(): + log.Warn("'%s': mixedCase identifiers are supported, however all-lowercase names are recommended" % self.print_name) + elif "_" in self.name: + log.Warn("'%s': snake_case identifiers are supported, however flatcase names are recommended" % self.print_name) if self.original_name: # identifier comming from the C++ world if self.original_name[0] == "_": raise JsonParseError("'%s': identifiers must not start with an underscore (reserved by the generator)" % self.original_name) - if "_" in self.original_name: - log.Warn("'%s': snake_case identifiers are supported, however mixedCase names are recommended " % self.original_name) + if not self.grand_parent or not self.grand_parent.parent.legacy: + if "_" in self.original_name: + log.Warn("'%s': snake_case identifiers are supported, however PascalCase names are recommended " % self.original_name) # Do some sanity check on the description text if self.description and not isinstance(self, JsonMethod): @@ -731,10 +739,11 @@ def __init__(self, name, parent, schema, included=None, property=False): if "alt" in schema: self.alternative = schema.get("alt") - if not self.alternative.islower() and not (schema.get("altisdeprecated") or schema.get("altisobsolete")): - log.Warn("'%s' (alternative): mixedCase identifiers are supported, however all-lowercase names are recommended" % self.alternative) - elif "_" in self.alternative and not (schema.get("altisdeprecated") or schema.get("altisobsolete")): - log.Warn("'%s' (alternative): snake_case identifiers are supported, however flatcase names are recommended" % self.alternative) + if not self.grand_parent and self.grand_parent.parent.legacy: + if not self.alternative.islower() and not (schema.get("altisdeprecated") or schema.get("altisobsolete")): + log.Warn("'%s' (alternative): mixedCase identifiers are supported, however all-lowercase names are recommended" % self.alternative) + elif "_" in self.alternative and not (schema.get("altisdeprecated") or schema.get("altisobsolete")): + log.Warn("'%s' (alternative): snake_case identifiers are supported, however flatcase names are recommended" % self.alternative) else: self.alternative = None @@ -804,6 +813,7 @@ def __init__(self, name, schema): self.info = None self.base_schema = schema.get("$schema") self.jsonrpc_version = schema.get("jsonrpc") + self.legacy = False self.namespace = None self.methods = [] self.includes = [] @@ -814,6 +824,7 @@ def __init__(self, name, schema): if "info" in schema: self.info = schema["info"] + self.legacy = schema["info"].get("legacy") self.namespace = self.info.get("namespace") From 9d1720475b2d72408badd598f32fcfbcb2804d5a Mon Sep 17 00:00:00 2001 From: sebaszm Date: Fri, 12 Jan 2024 10:55:33 +0100 Subject: [PATCH 11/14] Warn on missing maxlength --- JsonGenerator/source/class_emitter.py | 4 ++-- JsonGenerator/source/emitter.py | 3 +++ JsonGenerator/source/json_loader.py | 2 +- ProxyStubGenerator/StubGenerator.py | 16 +++++++++------- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/JsonGenerator/source/class_emitter.py b/JsonGenerator/source/class_emitter.py index 4449882..1e0580d 100644 --- a/JsonGenerator/source/class_emitter.py +++ b/JsonGenerator/source/class_emitter.py @@ -120,7 +120,7 @@ def _EmitEnum(enum): log.Info("Emitting enum {}".format(enum.cpp_class)) if enum.description: - emit.Line("// " + enum.description) + emit.Line("// " + enum.description.split("\n",1)[0]) emit.Line("enum%s %s : uint%i_t {" % (" class" if enum.is_scoped else "", enum.cpp_class, enum.size)) emit.Indent() @@ -314,7 +314,7 @@ def _EmitValidator(json_obj): emit.Indent() for prop in json_obj.properties: - comment = prop.print_name if isinstance(prop, JsonMethod) else prop.description + comment = prop.print_name if isinstance(prop, JsonMethod) else prop.description.split("\n",1)[0] if prop.description else "" emit.Line("%s %s;%s" % (prop.short_cpp_type, prop.cpp_name, (" // " + comment) if comment else "")) if IsObjectRestricted(json_obj): diff --git a/JsonGenerator/source/emitter.py b/JsonGenerator/source/emitter.py index d2ae9b0..76992b9 100644 --- a/JsonGenerator/source/emitter.py +++ b/JsonGenerator/source/emitter.py @@ -35,6 +35,9 @@ def __exit__(self, exc_type, exc_value, traceback): self.file.close() def Line(self, text = ""): + if "\n" in text: + assert("Invalid characters in the emitted line") + if text != "": commented = "// " if "//" in text else "" text = (" " * self.indent) + str(text) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index b6ad830..22abf5c 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -111,7 +111,7 @@ def __init__(self, name, parent, schema, included=None): self.grand_parent = self.grand_parent.parent if self.grand_parent: - if not self.description: + if not self.description and isinstance(parent, JsonProperty): self.description = self.grand_parent.summary self.iterator = schema.get("iterator") diff --git a/ProxyStubGenerator/StubGenerator.py b/ProxyStubGenerator/StubGenerator.py index bf13f0a..380dfbc 100755 --- a/ProxyStubGenerator/StubGenerator.py +++ b/ProxyStubGenerator/StubGenerator.py @@ -760,10 +760,10 @@ def _FindLength(length_name, variable_name): self.max_length = _FindLength(self.identifier.meta.maxlength, (name[1:] + "Len")) if (is_buffer and not self.length and self.is_input): - raise TypenameError(self.identifier, "'%s': an input raw buffer requires a @length tag" % self.trace_proto) + raise TypenameError(self.identifier, "'%s': an outbound buffer requires a @length tag" % self.trace_proto) if (is_buffer and (not self.length and not self.max_length) and self.is_output): - raise TypenameError(self.identifier, "'%s': an output-only raw buffer requires a @maxlength tag" % self.trace_proto) + raise TypenameError(self.identifier, "'%s': an inbound-only buffer requires a @maxlength tag" % self.trace_proto) self.is_buffer = ((self.length or self.max_length) and is_buffer) @@ -773,16 +773,18 @@ def _FindLength(length_name, variable_name): if self.is_input and self.is_output: log.WarnLine(self.identifier, \ - "'%s': maximum length of this input/output buffer is assumed to be same as @length, use @maxlength to disambiguate" % \ + "'%s': maximum length of this inbound/outbound buffer is assumed to be same as @length, use @maxlength to disambiguate" % \ (self.trace_proto)) - else: - log.InfoLine(self.identifier, "'%s': @maxlength not specified, assuming same as @length" % self.trace_proto) + elif self.is_input_only: + log.InfoLine(self.identifier, "'%s': @maxlength not specified for this inbound buffer, assuming same as @length" % self.trace_proto) + elif self.is_output_only and not self.length.is_output: + raise TypenameError(self.identifier, "'%s': @maxlength not specified for this inbound buffer" % self.trace_proto) if (self.is_buffer and self.is_output and not self.max_length): - raise TypenameError(self.identifier, "'%s': can't deduce maximum length of the buffer, use @maxlength" % self.trace_proto) + raise TypenameError(self.identifier, "'%s': can't deduce maximum length of this inbound buffer, use @maxlength" % self.trace_proto) if (self.is_buffer and self.max_length and not self.length): - log.WarnLine(self.identifier, "'%s': length of returned buffer is not specified; using @maxlength, but this may be inefficient" % self.trace_proto) + log.WarnLine(self.identifier, "'%s': length of this inbound buffer is not specified; using @maxlength, but this may be inefficient" % self.trace_proto) self.length = self.max_length # Is it a hresult? From 4de4bfb6ac8c8efe06aa86afc25b56bd7506c9f5 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Fri, 12 Jan 2024 11:26:03 +0100 Subject: [PATCH 12/14] fix regression --- JsonGenerator/source/json_loader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/JsonGenerator/source/json_loader.py b/JsonGenerator/source/json_loader.py index 22abf5c..0f26ac7 100644 --- a/JsonGenerator/source/json_loader.py +++ b/JsonGenerator/source/json_loader.py @@ -111,7 +111,9 @@ def __init__(self, name, parent, schema, included=None): self.grand_parent = self.grand_parent.parent if self.grand_parent: - if not self.description and isinstance(parent, JsonProperty): + if not self.description and \ + (((self.root.rpc_format == config.RpcFormat.COMPLIANT) and (self.grand_parent == parent.parent)) \ + or (((self.root.rpc_format != config.RpcFormat.COMPLIANT) and (self.grand_parent == parent)))): self.description = self.grand_parent.summary self.iterator = schema.get("iterator") From 54a94707cfe8a19c1abe19bc0f8a8da071c9ef2d Mon Sep 17 00:00:00 2001 From: sebaszm Date: Fri, 12 Jan 2024 12:41:25 +0100 Subject: [PATCH 13/14] maxlength is redunant if length specified for immediate buffer length --- ProxyStubGenerator/StubGenerator.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ProxyStubGenerator/StubGenerator.py b/ProxyStubGenerator/StubGenerator.py index 380dfbc..5de115e 100755 --- a/ProxyStubGenerator/StubGenerator.py +++ b/ProxyStubGenerator/StubGenerator.py @@ -637,7 +637,7 @@ def _FindLength(length_name, variable_name): if length_name: if length_name[0] == "void": return EmitIdentifier(-2, interface, \ - CppParser.Temporary(self.identifier.parent, ["uint8_t", variable_name], ["sizeof(%s)" % self.kind], []), variable_name) + CppParser.Temporary(self.identifier.parent, ["static constexpr uint8_t", variable_name], ["sizeof(%s)" % self.kind], []), variable_name) elif length_name[0] == "return": result = "result" @@ -654,10 +654,10 @@ def _FindLength(length_name, variable_name): if matches: return EmitIdentifier(-2, interface, \ - CppParser.Temporary(self.identifier.parent, ["uint8_t", variable_name], ["sizeof(_%s)" % matches[0].name], []), variable_name) + CppParser.Temporary(self.identifier.parent, ("static constexpr %s %s" % (length_type, variable_name)).split(), ["sizeof(_%s)" % matches[0].name]), variable_name) else: return EmitIdentifier(-2, interface, \ - CppParser.Temporary(self.identifier.parent, ["uint8_t", variable_name], ["".join(length_name)], []), variable_name,) + CppParser.Temporary(self.identifier.parent, ("static constexpr %s %s" % (length_type, variable_name)).split(), ["".join(length_name)]), variable_name) matches = [v for v in self.identifier.parent.vars if v.name == "".join(length_name)] @@ -675,7 +675,7 @@ def _FindLength(length_name, variable_name): length_type = "uint8_t" return EmitIdentifier(-2, interface, \ - CppParser.Temporary(self.identifier.parent, [length_type, variable_name], [str(value)], []), variable_name) + CppParser.Temporary(self.identifier.parent, ("static constexpr %s %s" % (length_type, variable_name)).split(), [str(value)]), variable_name) except (SyntaxError, NameError): raise TypenameError(self.identifier, "'%s': unable to parse this length expression ('%s')" % (self.trace_proto, "".join(length_name))) @@ -777,7 +777,7 @@ def _FindLength(length_name, variable_name): (self.trace_proto)) elif self.is_input_only: log.InfoLine(self.identifier, "'%s': @maxlength not specified for this inbound buffer, assuming same as @length" % self.trace_proto) - elif self.is_output_only and not self.length.is_output: + elif self.is_output_only and not self.length.is_output and ("constexpr" not in self.length.identifier.specifiers): raise TypenameError(self.identifier, "'%s': @maxlength not specified for this inbound buffer" % self.trace_proto) if (self.is_buffer and self.is_output and not self.max_length): From f21f76c171c3d72434e7c6155dca052d6762ad88 Mon Sep 17 00:00:00 2001 From: sebaszm Date: Fri, 12 Jan 2024 13:18:38 +0100 Subject: [PATCH 14/14] don't need maxlengh if point to same variable --- ProxyStubGenerator/StubGenerator.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ProxyStubGenerator/StubGenerator.py b/ProxyStubGenerator/StubGenerator.py index 5de115e..7ca8744 100755 --- a/ProxyStubGenerator/StubGenerator.py +++ b/ProxyStubGenerator/StubGenerator.py @@ -775,10 +775,8 @@ def _FindLength(length_name, variable_name): log.WarnLine(self.identifier, \ "'%s': maximum length of this inbound/outbound buffer is assumed to be same as @length, use @maxlength to disambiguate" % \ (self.trace_proto)) - elif self.is_input_only: + elif self.is_output_only: log.InfoLine(self.identifier, "'%s': @maxlength not specified for this inbound buffer, assuming same as @length" % self.trace_proto) - elif self.is_output_only and not self.length.is_output and ("constexpr" not in self.length.identifier.specifiers): - raise TypenameError(self.identifier, "'%s': @maxlength not specified for this inbound buffer" % self.trace_proto) if (self.is_buffer and self.is_output and not self.max_length): raise TypenameError(self.identifier, "'%s': can't deduce maximum length of this inbound buffer, use @maxlength" % self.trace_proto)