• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, {{"&", "&amp;"}, {"<", "&lt;"}});
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, "&#x2F;");
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