Skip to content

Commit

Permalink
[dotnet] Finalize nullability in internal devtools generator (#15088)
Browse files Browse the repository at this point in the history
* [dotnet] Move devtools generator into a specific project

* rename generator name in generate_devtools

* Revert "rename generator name in generate_devtools"

This reverts commit efc80ed.

* Revert "[dotnet] Move devtools generator into a specific project"

This reverts commit c1c4441.

* Modernize and prepare devtools generator for source generation

* Enable nullability in devtools generator in bazel build.
  • Loading branch information
RenderMichael authored Jan 16, 2025
1 parent b9f768f commit 835c8a0
Show file tree
Hide file tree
Showing 22 changed files with 133 additions and 171 deletions.
2 changes: 1 addition & 1 deletion third_party/dotnet/devtools/src/generator/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ load("//dotnet:defs.bzl", "csharp_binary", "framework")
csharp_binary(
name = "generator",
srcs = glob(["**/*.cs"]),
nullable = "annotations",
nullable = "enable",
# Used as a tool in our build, so just target one framework
target_frameworks = ["net8.0"],
visibility = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public sealed class CodeGenerationSettings
/// Gets the version number of the runtime.
/// </summary>
[JsonPropertyName("runtimeVersion")]
public string RuntimeVersion { get; set; }
public string? RuntimeVersion { get; set; }

[JsonPropertyName("definitionTemplates")]
public CodeGenerationDefinitionTemplateSettings DefinitionTemplates { get; set; } = new CodeGenerationDefinitionTemplateSettings();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
public class CodeGenerationTemplateSettings
{
[JsonPropertyName("templatePath")]
public string TemplatePath { get; set; }
[JsonRequired]
public string TemplatePath { get; set; } = null!;

[JsonPropertyName("outputPath")]
public string OutputPath { get; set; }
[JsonRequired]
public string OutputPath { get; set; } = null!;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class CodeGeneratorBase<T> : ICodeGenerator<T>
where T : IDefinition
where T : class, IDefinition
{
private readonly Lazy<CodeGenerationSettings> m_settings;
private readonly Lazy<TemplatesManager> m_templatesManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
/// <summary>
/// Represents the current context of the code generator.
/// </summary>
public sealed class CodeGeneratorContext
public sealed class CodeGeneratorContext(DomainDefinition domain, Dictionary<string, TypeInfo> knownTypes)
{
public DomainDefinition Domain { get; set; }
public DomainDefinition Domain { get; } = domain;

public Dictionary<string, TypeInfo> KnownTypes { get; set; }
public Dictionary<string, TypeInfo> KnownTypes { get; } = knownTypes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
/// <summary>
/// Represents information about a Chrome Debugger Protocol command.
/// </summary>
public sealed class CommandInfo
public sealed class CommandInfo(string commandName, string fullTypeName, string fullResponseTypeName)
{
public string CommandName { get; set; }
public string CommandName { get; } = commandName;

public string FullTypeName { get; set; }
public string FullTypeName { get; } = fullTypeName;

public string FullResponseTypeName { get; set; }
public string FullResponseTypeName { get; } = fullResponseTypeName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
/// <summary>
/// Represents information about a Chrome Debugger Protocol event.
/// </summary>
public sealed class EventInfo
public sealed class EventInfo(string eventName, string fullTypeName)
{
public string EventName { get; set; }
public string EventName { get; } = eventName;

public string FullTypeName { get; set; }
public string FullTypeName { get; } = fullTypeName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICodeGenerator<T>
where T : IDefinition
where T : class, IDefinition
{
/// <summary>
/// Generates one or more code files for the specified IDefinition item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using OpenQA.Selenium.DevToolsGenerator.ProtocolDefinition;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;

Expand All @@ -22,7 +23,7 @@ public override IDictionary<string, string> GenerateCode(ProtocolDefinition.Prot
{
if (string.IsNullOrWhiteSpace(Settings.TemplatesPath))
{
Settings.TemplatesPath = Path.GetDirectoryName(Settings.TemplatesPath);
Settings.TemplatesPath = Path.GetDirectoryName(Settings.TemplatesPath)!;
}

ICollection<DomainDefinition> domains = protocolDefinition.Domains;
Expand All @@ -44,11 +45,11 @@ public override IDictionary<string, string> GenerateCode(ProtocolDefinition.Prot
foreach (var command in domain.Commands)
{
commands.Add(new CommandInfo
{
CommandName = $"{domain.Name}.{command.Name}",
FullTypeName = $"{domain.Name.Dehumanize()}.{command.Name.Dehumanize()}CommandSettings",
FullResponseTypeName = $"{domain.Name.Dehumanize()}.{command.Name.Dehumanize()}CommandResponse"
});
(
commandName: $"{domain.Name}.{command.Name}",
fullTypeName: $"{domain.Name.Dehumanize()}.{command.Name.Dehumanize()}CommandSettings",
fullResponseTypeName: $"{domain.Name.Dehumanize()}.{command.Name.Dehumanize()}CommandResponse"
));
}
}

Expand All @@ -60,10 +61,10 @@ public override IDictionary<string, string> GenerateCode(ProtocolDefinition.Prot
foreach (var @event in domain.Events)
{
events.Add(new EventInfo
{
EventName = $"{domain.Name}.{@event.Name}",
FullTypeName = $"{domain.Name.Dehumanize()}.{@event.Name.Dehumanize()}EventArgs"
});
(
eventName: $"{domain.Name}.{@event.Name}",
fullTypeName: $"{domain.Name.Dehumanize()}.{@event.Name.Dehumanize()}EventArgs")
);
}
}

Expand Down Expand Up @@ -102,7 +103,7 @@ public override IDictionary<string, string> GenerateCode(ProtocolDefinition.Prot
return result;
}

private Dictionary<string, TypeInfo> GetTypesInDomain(ICollection<DomainDefinition> domains)
private static Dictionary<string, TypeInfo> GetTypesInDomain(ICollection<DomainDefinition> domains)
{
var knownTypes = new Dictionary<string, TypeInfo>(StringComparer.OrdinalIgnoreCase);

Expand All @@ -116,9 +117,9 @@ private Dictionary<string, TypeInfo> GetTypesInDomain(ICollection<DomainDefiniti
{
if (propertyType.Type == "string" && type.Enum != null && propertyType.Enum.Count > 0)
{
TypeDefinition propertyTypeDefinition = new TypeDefinition()
string id = $"{type.Id.Dehumanize()}{propertyType.Name.Dehumanize()}Values";
TypeDefinition propertyTypeDefinition = new TypeDefinition(id)
{
Id = type.Id.Dehumanize() + propertyType.Name.Dehumanize() + "Values",
Type = propertyType.Type,
Description = $"Enumerated values for {domain.Name}.{type.Id}.{propertyType.Name}"
};
Expand All @@ -136,35 +137,33 @@ private Dictionary<string, TypeInfo> GetTypesInDomain(ICollection<DomainDefiniti
switch (type.Type)
{
case "object":
typeInfo = new TypeInfo
{
IsPrimitive = false,
TypeName = type.Id.Dehumanize(),
};
typeInfo = new TypeInfo(typeName: type.Id.Dehumanize(), isPrimitive: false);
break;

case "string":
if (type.Enum != null && type.Enum.Count > 0)
{
typeInfo = new TypeInfo
typeInfo = new TypeInfo(typeName: type.Id.Dehumanize(), isPrimitive: false)
{
ByRef = true,
IsPrimitive = false,
TypeName = type.Id.Dehumanize(),
};
}
else
{
typeInfo = new TypeInfo
{
IsPrimitive = true,
TypeName = "string"
};
typeInfo = new TypeInfo("string", isPrimitive: true);
}

break;

case "array":
if ((type.Items == null || string.IsNullOrWhiteSpace(type.Items.Type)) &&
type.Items.TypeReference != "StringIndex" && type.Items.TypeReference != "FilterEntry")
if (type.Items is null)
{
throw new InvalidOperationException("Type definition's Type was array but Items is missing");
}

if (string.IsNullOrWhiteSpace(type.Items.Type) &&
type.Items.TypeReference != "StringIndex" &&
type.Items.TypeReference != "FilterEntry")
{
throw new NotImplementedException("Did not expect a top-level domain array type to specify a TypeReference");
}
Expand Down Expand Up @@ -199,28 +198,23 @@ private Dictionary<string, TypeInfo> GetTypesInDomain(ICollection<DomainDefiniti
default:
throw new NotImplementedException($"Did not expect a top-level domain array type to specify items of type {type.Items.Type}");
}
typeInfo = new TypeInfo
{
IsPrimitive = true,
TypeName = $"{itemType}[]"
};
typeInfo = new TypeInfo(typeName: $"{itemType}[]", isPrimitive: true);
break;

case "number":
typeInfo = new TypeInfo
typeInfo = new TypeInfo("double", isPrimitive: true)
{
ByRef = true,
IsPrimitive = true,
TypeName = "double"
};
break;

case "integer":
typeInfo = new TypeInfo
typeInfo = new TypeInfo("long", isPrimitive: true)
{
ByRef = true,
IsPrimitive = true,
TypeName = "long"
};
break;

default:
throw new InvalidOperationException($"Unknown Type Definition Type: {type.Id}");
}
Expand All @@ -232,11 +226,9 @@ private Dictionary<string, TypeInfo> GetTypesInDomain(ICollection<DomainDefiniti

foreach (var embeddedEnumType in embeddedTypes)
{
TypeInfo propertyTypeInfo = new TypeInfo
TypeInfo propertyTypeInfo = new TypeInfo(typeName: embeddedEnumType.Id, isPrimitive: false)
{
TypeName = embeddedEnumType.Id,
ByRef = true,
IsPrimitive = false,
Namespace = domain.Name.Dehumanize(),
SourcePath = $"{domain.Name}.{embeddedEnumType.Id}"
};
Expand All @@ -257,7 +249,7 @@ private Dictionary<string, string> GenerateCode(ICollection<DomainDefinition> do
//Generate types/events/commands for all domains.
foreach (var domain in domains)
{
var context = new CodeGeneratorContext { Domain = domain, KnownTypes = knownTypes };
var context = new CodeGeneratorContext(domain, knownTypes);
foreach (KeyValuePair<string, string> x in domainGenerator.GenerateCode(domain, context))
{
result.Add(x.Key, x.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ public TemplatesManager(CodeGenerationSettings settings)
public Func<object, string> GetGeneratorForTemplate(CodeGenerationTemplateSettings templateSettings)
{
var templatePath = templateSettings.TemplatePath;
if (m_templateGenerators.ContainsKey(templatePath))
if (m_templateGenerators.TryGetValue(templatePath, out Func<object, string>? value))
{
return m_templateGenerators[templatePath];
return value;
}

var targetTemplate = templatePath;
Expand All @@ -47,7 +47,7 @@ public Func<object, string> GetGeneratorForTemplate(CodeGenerationTemplateSettin

if (!File.Exists(targetTemplate))
{
throw new FileNotFoundException($"Unable to locate a template at {targetTemplate} - please ensure that a template file exists at this location.");
throw new FileNotFoundException($"Unable to locate a template at {targetTemplate} - please ensure that a template file exists at this location.", targetTemplate);
}

var templateContents = File.ReadAllText(targetTemplate);
Expand All @@ -59,7 +59,7 @@ public Func<object, string> GetGeneratorForTemplate(CodeGenerationTemplateSettin
throw new HandlebarsException("{{humanize}} helper must have exactly one argument");
}

var str = arguments[0].ToString();
var str = arguments[0].ToString()!;

//Some overrides for values that start with '-' -- this fixes two instances in Runtime.UnserializableValue
if (str.StartsWith("-"))
Expand Down
10 changes: 5 additions & 5 deletions third_party/dotnet/devtools/src/generator/CodeGen/TypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
/// <summary>
/// Represents information about a Chrome Debugger Protocol type.
/// </summary>
public sealed class TypeInfo
public sealed class TypeInfo(string typeName, bool isPrimitive)
{
public bool ByRef { get; set; }

public string Namespace { get; set; }
public string? Namespace { get; set; }

public bool IsPrimitive { get; set; }
public bool IsPrimitive { get; } = isPrimitive;

public string TypeName { get; set; }
public string TypeName { get; } = typeName;

public string SourcePath { get; set; }
public string? SourcePath { get; set; }
}
}
Loading

0 comments on commit 835c8a0

Please sign in to comment.