1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Author: kenton@google.com (Kenton Varda)
9 // Based on original Protocol Buffers design by
10 // Sanjay Ghemawat, Jeff Dean, and others.
11 #include "google/protobuf/compiler/csharp/csharp_doc_comment.h"
12
13 #include "absl/strings/str_replace.h"
14 #include "absl/strings/str_split.h"
15 #include "google/protobuf/compiler/csharp/csharp_options.h"
16 #include "google/protobuf/descriptor.h"
17 #include "google/protobuf/io/printer.h"
18
19 namespace google {
20 namespace protobuf {
21 namespace compiler {
22 namespace csharp {
23
24 // Functions to create C# XML documentation comments.
25 // Currently this only includes documentation comments containing text specified
26 // as comments in the .proto file; documentation comments generated just from
27 // field/message/enum/proto names is inlined in the relevant code. If more
28 // control is required, that code can be moved here.
29
WriteDocCommentBodyImpl(io::Printer * printer,SourceLocation location)30 void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
31 std::string comments = location.leading_comments.empty()
32 ? location.trailing_comments
33 : location.leading_comments;
34 if (comments.empty()) {
35 return;
36 }
37 // XML escaping... no need for apostrophes etc as the whole text is going to
38 // be a child node of a summary element, not part of an attribute.
39 comments = absl::StrReplaceAll(comments, {{"&", "&"}, {"<", "<"}});
40 std::vector<std::string> lines;
41 lines = absl::StrSplit(comments, "\n", absl::AllowEmpty());
42 // TODO: We really should work out which part to put in the summary and which
43 // to put in the remarks... but that needs to be part of a bigger effort to
44 // understand the markdown better anyway.
45 printer->Print("/// <summary>\n");
46 bool last_was_empty = false;
47 // We squash multiple blank lines down to one, and remove any trailing blank
48 // lines. We need to preserve the blank lines themselves, as this is relevant
49 // in the markdown. Note that we can't remove leading or trailing whitespace
50 // as *that's* relevant in markdown too. (We don't skip "just whitespace"
51 // lines, either.)
52 for (std::vector<std::string>::iterator it = lines.begin(); it != lines.end();
53 ++it) {
54 std::string line = *it;
55 if (line.empty()) {
56 last_was_empty = true;
57 } else {
58 if (last_was_empty) {
59 printer->Print("///\n");
60 }
61 last_was_empty = false;
62 // If the comment has an extra slash at the start then this can cause the
63 // C# compiler to complain when generating the XML documentation Issue
64 // https://github.com/grpc/grpc/issues/35905
65 if (line[0] == '/') {
66 line.replace(0, 1, "/");
67 }
68 printer->Print("///$line$\n", "line", line);
69 }
70 }
71 printer->Print("/// </summary>\n");
72 }
73
74 template <typename DescriptorType>
WriteDocCommentBody(io::Printer * printer,const DescriptorType * descriptor)75 static void WriteDocCommentBody(io::Printer* printer,
76 const DescriptorType* descriptor) {
77 SourceLocation location;
78 if (descriptor->GetSourceLocation(&location)) {
79 WriteDocCommentBodyImpl(printer, location);
80 }
81 }
82
WriteMessageDocComment(io::Printer * printer,const Options * options,const Descriptor * message)83 void WriteMessageDocComment(io::Printer* printer, const Options* options,
84 const Descriptor* message) {
85 if (options->strip_nonfunctional_codegen) return;
86 WriteDocCommentBody(printer, message);
87 }
88
WritePropertyDocComment(io::Printer * printer,const Options * options,const FieldDescriptor * field)89 void WritePropertyDocComment(io::Printer* printer, const Options* options,
90 const FieldDescriptor* field) {
91 if (options->strip_nonfunctional_codegen) return;
92 WriteDocCommentBody(printer, field);
93 }
94
WriteEnumDocComment(io::Printer * printer,const Options * options,const EnumDescriptor * enumDescriptor)95 void WriteEnumDocComment(io::Printer* printer, const Options* options,
96 const EnumDescriptor* enumDescriptor) {
97 if (options->strip_nonfunctional_codegen) return;
98 WriteDocCommentBody(printer, enumDescriptor);
99 }
WriteEnumValueDocComment(io::Printer * printer,const Options * options,const EnumValueDescriptor * value)100 void WriteEnumValueDocComment(io::Printer* printer, const Options* options,
101 const EnumValueDescriptor* value) {
102 if (options->strip_nonfunctional_codegen) return;
103 WriteDocCommentBody(printer, value);
104 }
105
WriteMethodDocComment(io::Printer * printer,const Options * options,const MethodDescriptor * method)106 void WriteMethodDocComment(io::Printer* printer, const Options* options,
107 const MethodDescriptor* method) {
108 if (options->strip_nonfunctional_codegen) return;
109 WriteDocCommentBody(printer, method);
110 }
111
112 } // namespace csharp
113 } // namespace compiler
114 } // namespace protobuf
115 } // namespace google
116