Merge pull request #18470 from kkm000/kkm/17661-filenamegen

C# tools: support generated filename corner cases
pull/18483/head
Jan Tattermusch 6 years ago committed by GitHub
commit 1805e2e431
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs
  2. 45
      src/csharp/Grpc.Tools/GeneratorServices.cs

@ -33,11 +33,14 @@ namespace Grpc.Tools.Tests
[TestCase("foo.proto", "Foo.cs", "FooGrpc.cs")] [TestCase("foo.proto", "Foo.cs", "FooGrpc.cs")]
[TestCase("sub/foo.proto", "Foo.cs", "FooGrpc.cs")] [TestCase("sub/foo.proto", "Foo.cs", "FooGrpc.cs")]
[TestCase("one_two.proto", "OneTwo.cs", "OneTwoGrpc.cs")] [TestCase("one_two.proto", "OneTwo.cs", "OneTwoGrpc.cs")]
[TestCase("__one_two!.proto", "OneTwo!.cs", "OneTwo!Grpc.cs")] [TestCase("ONE_TWO.proto", "ONETWO.cs", "ONETWOGrpc.cs")]
[TestCase("one(two).proto", "One(two).cs", "One(two)Grpc.cs")] [TestCase("one.two.proto", "OneTwo.cs", "One.twoGrpc.cs")]
[TestCase("one_(two).proto", "One(two).cs", "One(two)Grpc.cs")] [TestCase("one123two.proto", "One123Two.cs", "One123twoGrpc.cs")]
[TestCase("one two.proto", "One two.cs", "One twoGrpc.cs")] [TestCase("__one_two!.proto", "OneTwo.cs", "OneTwo!Grpc.cs")]
[TestCase("one_ two.proto", "One two.cs", "One twoGrpc.cs")] [TestCase("one(two).proto", "OneTwo.cs", "One(two)Grpc.cs")]
[TestCase("one_(two).proto", "OneTwo.cs", "One(two)Grpc.cs")]
[TestCase("one two.proto", "OneTwo.cs", "One twoGrpc.cs")]
[TestCase("one_ two.proto", "OneTwo.cs", "One twoGrpc.cs")]
[TestCase("one .proto", "One.cs", "One Grpc.cs")] [TestCase("one .proto", "One.cs", "One Grpc.cs")]
public void NameMangling(string proto, string expectCs, string expectGrpcCs) public void NameMangling(string proto, string expectCs, string expectGrpcCs)
{ {

@ -66,29 +66,28 @@ namespace Grpc.Tools
public override string[] GetPossibleOutputs(ITaskItem protoItem) public override string[] GetPossibleOutputs(ITaskItem protoItem)
{ {
bool doGrpc = GrpcOutputPossible(protoItem); bool doGrpc = GrpcOutputPossible(protoItem);
string filename = LowerUnderscoreToUpperCamel(
Path.GetFileNameWithoutExtension(protoItem.ItemSpec));
var outputs = new string[doGrpc ? 2 : 1]; var outputs = new string[doGrpc ? 2 : 1];
string basename = Path.GetFileNameWithoutExtension(protoItem.ItemSpec);
string outdir = protoItem.GetMetadata(Metadata.OutputDir); string outdir = protoItem.GetMetadata(Metadata.OutputDir);
string fileStem = Path.Combine(outdir, filename); string filename = LowerUnderscoreToUpperCamelProtocWay(basename);
outputs[0] = fileStem + ".cs"; outputs[0] = Path.Combine(outdir, filename) + ".cs";
if (doGrpc) if (doGrpc)
{ {
// Override outdir if kGrpcOutputDir present, default to proto output. // Override outdir if kGrpcOutputDir present, default to proto output.
outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir); string grpcdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
if (outdir != "") filename = LowerUnderscoreToUpperCamelGrpcWay(basename);
{ outputs[1] = Path.Combine(
fileStem = Path.Combine(outdir, filename); grpcdir != "" ? grpcdir : outdir, filename) + "Grpc.cs";
}
outputs[1] = fileStem + "Grpc.cs";
} }
return outputs; return outputs;
} }
string LowerUnderscoreToUpperCamel(string str) // This is how the gRPC codegen currently construct its output filename.
// See src/compiler/generator_helpers.h:118.
string LowerUnderscoreToUpperCamelGrpcWay(string str)
{ {
// See src/compiler/generator_helpers.h:118
var result = new StringBuilder(str.Length, str.Length); var result = new StringBuilder(str.Length, str.Length);
bool cap = true; bool cap = true;
foreach (char c in str) foreach (char c in str)
@ -109,6 +108,26 @@ namespace Grpc.Tools
} }
return result.ToString(); return result.ToString();
} }
// This is how the protoc codegen constructs its output filename.
// See protobuf/compiler/csharp/csharp_helpers.cc:137.
// Note that protoc explicitly discards non-ASCII letters.
string LowerUnderscoreToUpperCamelProtocWay(string str)
{
var result = new StringBuilder(str.Length, str.Length);
bool cap = true;
foreach (char c in str)
{
char upperC = char.ToUpperInvariant(c);
bool isAsciiLetter = 'A' <= upperC && upperC <= 'Z';
if (isAsciiLetter || ('0' <= c && c <= '9'))
{
result.Append(cap ? upperC : c);
}
cap = !isAsciiLetter;
}
return result.ToString();
}
}; };
// C++ generator services. // C++ generator services.

Loading…
Cancel
Save