Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 1 | package protoparse |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 5 | "strings" |
| 6 | |
| 7 | "github.com/golang/protobuf/proto" |
| 8 | dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" |
| 9 | |
| 10 | "github.com/jhump/protoreflect/desc/internal" |
| 11 | ) |
| 12 | |
| 13 | func (r *parseResult) generateSourceCodeInfo() *dpb.SourceCodeInfo { |
| 14 | if r.nodes == nil { |
| 15 | // skip files that do not have AST info (these will be files |
| 16 | // that came from well-known descriptors, instead of from source) |
| 17 | return nil |
| 18 | } |
| 19 | |
| 20 | sci := sourceCodeInfo{commentsUsed: map[*comment]struct{}{}} |
| 21 | path := make([]int32, 0, 10) |
| 22 | |
| 23 | fn := r.getFileNode(r.fd).(*fileNode) |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 24 | sci.newLocWithoutComments(fn, nil) |
| 25 | |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 26 | if fn.syntax != nil { |
| 27 | sci.newLoc(fn.syntax, append(path, internal.File_syntaxTag)) |
| 28 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 29 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 30 | var depIndex, optIndex, msgIndex, enumIndex, extendIndex, svcIndex int32 |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 31 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 32 | for _, child := range fn.decls { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 33 | switch { |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 34 | case child.imp != nil: |
| 35 | sci.newLoc(child.imp, append(path, internal.File_dependencyTag, int32(depIndex))) |
| 36 | depIndex++ |
| 37 | case child.pkg != nil: |
| 38 | sci.newLoc(child.pkg, append(path, internal.File_packageTag)) |
| 39 | case child.option != nil: |
| 40 | r.generateSourceCodeInfoForOption(&sci, child.option, false, &optIndex, append(path, internal.File_optionsTag)) |
| 41 | case child.message != nil: |
| 42 | r.generateSourceCodeInfoForMessage(&sci, child.message, nil, append(path, internal.File_messagesTag, msgIndex)) |
| 43 | msgIndex++ |
| 44 | case child.enum != nil: |
| 45 | r.generateSourceCodeInfoForEnum(&sci, child.enum, append(path, internal.File_enumsTag, enumIndex)) |
| 46 | enumIndex++ |
| 47 | case child.extend != nil: |
| 48 | r.generateSourceCodeInfoForExtensions(&sci, child.extend, &extendIndex, &msgIndex, append(path, internal.File_extensionsTag), append(dup(path), internal.File_messagesTag)) |
| 49 | case child.service != nil: |
| 50 | r.generateSourceCodeInfoForService(&sci, child.service, append(path, internal.File_servicesTag, svcIndex)) |
| 51 | svcIndex++ |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 52 | } |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 53 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 54 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 55 | return &dpb.SourceCodeInfo{Location: sci.locs} |
| 56 | } |
| 57 | |
| 58 | func (r *parseResult) generateSourceCodeInfoForOption(sci *sourceCodeInfo, n *optionNode, compact bool, uninterpIndex *int32, path []int32) { |
| 59 | if !compact { |
| 60 | sci.newLocWithoutComments(n, path) |
| 61 | } |
| 62 | subPath := r.interpretedOptions[n] |
| 63 | if len(subPath) > 0 { |
| 64 | p := path |
| 65 | if subPath[0] == -1 { |
| 66 | // used by "default" and "json_name" field pseudo-options |
| 67 | // to attribute path to parent element (since those are |
| 68 | // stored directly on the descriptor, not its options) |
| 69 | p = make([]int32, len(path)-1) |
| 70 | copy(p, path) |
| 71 | subPath = subPath[1:] |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 72 | } |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 73 | sci.newLoc(n, append(p, subPath...)) |
| 74 | return |
| 75 | } |
| 76 | |
| 77 | // it's an uninterpreted option |
| 78 | optPath := append(path, internal.UninterpretedOptionsTag, *uninterpIndex) |
| 79 | *uninterpIndex++ |
| 80 | sci.newLoc(n, optPath) |
| 81 | var valTag int32 |
| 82 | switch n.val.(type) { |
| 83 | case *compoundIdentNode: |
| 84 | valTag = internal.Uninterpreted_identTag |
| 85 | case *intLiteralNode: |
| 86 | valTag = internal.Uninterpreted_posIntTag |
| 87 | case *compoundIntNode: |
| 88 | valTag = internal.Uninterpreted_negIntTag |
| 89 | case *compoundFloatNode: |
| 90 | valTag = internal.Uninterpreted_doubleTag |
| 91 | case *compoundStringNode: |
| 92 | valTag = internal.Uninterpreted_stringTag |
| 93 | case *aggregateLiteralNode: |
| 94 | valTag = internal.Uninterpreted_aggregateTag |
| 95 | } |
| 96 | if valTag != 0 { |
| 97 | sci.newLoc(n.val, append(optPath, valTag)) |
| 98 | } |
| 99 | for j, nn := range n.name.parts { |
| 100 | optNmPath := append(optPath, internal.Uninterpreted_nameTag, int32(j)) |
| 101 | sci.newLoc(nn, optNmPath) |
| 102 | sci.newLoc(nn.text, append(optNmPath, internal.UninterpretedName_nameTag)) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 103 | } |
| 104 | } |
| 105 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 106 | func (r *parseResult) generateSourceCodeInfoForMessage(sci *sourceCodeInfo, n msgDecl, fieldPath []int32, path []int32) { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 107 | sci.newLoc(n, path) |
| 108 | |
| 109 | var decls []*messageElement |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 110 | switch n := n.(type) { |
| 111 | case *messageNode: |
| 112 | decls = n.decls |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 113 | case *groupNode: |
| 114 | decls = n.decls |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 115 | case *mapFieldNode: |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 116 | // map entry so nothing else to do |
| 117 | return |
| 118 | } |
| 119 | |
| 120 | sci.newLoc(n.messageName(), append(path, internal.Message_nameTag)) |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 121 | // matching protoc, which emits the corresponding field type name (for group fields) |
| 122 | // right after the source location for the group message name |
| 123 | if fieldPath != nil { |
| 124 | sci.newLoc(n.messageName(), append(fieldPath, internal.Field_typeNameTag)) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 125 | } |
| 126 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 127 | var optIndex, fieldIndex, oneOfIndex, extendIndex, nestedMsgIndex int32 |
| 128 | var nestedEnumIndex, extRangeIndex, reservedRangeIndex, reservedNameIndex int32 |
| 129 | for _, child := range decls { |
| 130 | switch { |
| 131 | case child.option != nil: |
| 132 | r.generateSourceCodeInfoForOption(sci, child.option, false, &optIndex, append(path, internal.Message_optionsTag)) |
| 133 | case child.field != nil: |
| 134 | r.generateSourceCodeInfoForField(sci, child.field, append(path, internal.Message_fieldsTag, fieldIndex)) |
| 135 | fieldIndex++ |
| 136 | case child.group != nil: |
| 137 | fldPath := append(path, internal.Message_fieldsTag, fieldIndex) |
| 138 | r.generateSourceCodeInfoForField(sci, child.group, fldPath) |
| 139 | fieldIndex++ |
| 140 | r.generateSourceCodeInfoForMessage(sci, child.group, fldPath, append(dup(path), internal.Message_nestedMessagesTag, nestedMsgIndex)) |
| 141 | nestedMsgIndex++ |
| 142 | case child.mapField != nil: |
| 143 | r.generateSourceCodeInfoForField(sci, child.mapField, append(path, internal.Message_fieldsTag, fieldIndex)) |
| 144 | fieldIndex++ |
| 145 | case child.oneOf != nil: |
| 146 | r.generateSourceCodeInfoForOneOf(sci, child.oneOf, &fieldIndex, &nestedMsgIndex, append(path, internal.Message_fieldsTag), append(dup(path), internal.Message_nestedMessagesTag), append(dup(path), internal.Message_oneOfsTag, oneOfIndex)) |
| 147 | oneOfIndex++ |
| 148 | case child.nested != nil: |
| 149 | r.generateSourceCodeInfoForMessage(sci, child.nested, nil, append(path, internal.Message_nestedMessagesTag, nestedMsgIndex)) |
| 150 | nestedMsgIndex++ |
| 151 | case child.enum != nil: |
| 152 | r.generateSourceCodeInfoForEnum(sci, child.enum, append(path, internal.Message_enumsTag, nestedEnumIndex)) |
| 153 | nestedEnumIndex++ |
| 154 | case child.extend != nil: |
| 155 | r.generateSourceCodeInfoForExtensions(sci, child.extend, &extendIndex, &nestedMsgIndex, append(path, internal.Message_extensionsTag), append(dup(path), internal.Message_nestedMessagesTag)) |
| 156 | case child.extensionRange != nil: |
| 157 | r.generateSourceCodeInfoForExtensionRanges(sci, child.extensionRange, &extRangeIndex, append(path, internal.Message_extensionRangeTag)) |
| 158 | case child.reserved != nil: |
| 159 | if len(child.reserved.names) > 0 { |
| 160 | resPath := append(path, internal.Message_reservedNameTag) |
| 161 | sci.newLoc(child.reserved, resPath) |
| 162 | for _, rn := range child.reserved.names { |
| 163 | sci.newLoc(rn, append(resPath, reservedNameIndex)) |
| 164 | reservedNameIndex++ |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 165 | } |
| 166 | } |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 167 | if len(child.reserved.ranges) > 0 { |
| 168 | resPath := append(path, internal.Message_reservedRangeTag) |
| 169 | sci.newLoc(child.reserved, resPath) |
| 170 | for _, rr := range child.reserved.ranges { |
| 171 | r.generateSourceCodeInfoForReservedRange(sci, rr, append(resPath, reservedRangeIndex)) |
| 172 | reservedRangeIndex++ |
| 173 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 174 | } |
| 175 | } |
| 176 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 177 | } |
| 178 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 179 | func (r *parseResult) generateSourceCodeInfoForEnum(sci *sourceCodeInfo, n *enumNode, path []int32) { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 180 | sci.newLoc(n, path) |
| 181 | sci.newLoc(n.name, append(path, internal.Enum_nameTag)) |
| 182 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 183 | var optIndex, valIndex, reservedNameIndex, reservedRangeIndex int32 |
| 184 | for _, child := range n.decls { |
| 185 | switch { |
| 186 | case child.option != nil: |
| 187 | r.generateSourceCodeInfoForOption(sci, child.option, false, &optIndex, append(path, internal.Enum_optionsTag)) |
| 188 | case child.value != nil: |
| 189 | r.generateSourceCodeInfoForEnumValue(sci, child.value, append(path, internal.Enum_valuesTag, valIndex)) |
| 190 | valIndex++ |
| 191 | case child.reserved != nil: |
| 192 | if len(child.reserved.names) > 0 { |
| 193 | resPath := append(path, internal.Enum_reservedNameTag) |
| 194 | sci.newLoc(child.reserved, resPath) |
| 195 | for _, rn := range child.reserved.names { |
| 196 | sci.newLoc(rn, append(resPath, reservedNameIndex)) |
| 197 | reservedNameIndex++ |
| 198 | } |
| 199 | } |
| 200 | if len(child.reserved.ranges) > 0 { |
| 201 | resPath := append(path, internal.Enum_reservedRangeTag) |
| 202 | sci.newLoc(child.reserved, resPath) |
| 203 | for _, rr := range child.reserved.ranges { |
| 204 | r.generateSourceCodeInfoForReservedRange(sci, rr, append(resPath, reservedRangeIndex)) |
| 205 | reservedRangeIndex++ |
| 206 | } |
| 207 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 208 | } |
| 209 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 210 | } |
| 211 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 212 | func (r *parseResult) generateSourceCodeInfoForEnumValue(sci *sourceCodeInfo, n *enumValueNode, path []int32) { |
| 213 | sci.newLoc(n, path) |
| 214 | sci.newLoc(n.name, append(path, internal.EnumVal_nameTag)) |
| 215 | sci.newLoc(n.getNumber(), append(path, internal.EnumVal_numberTag)) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 216 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 217 | // enum value options |
| 218 | if n.options != nil { |
| 219 | optsPath := append(path, internal.EnumVal_optionsTag) |
| 220 | sci.newLoc(n.options, optsPath) |
| 221 | var optIndex int32 |
| 222 | for _, opt := range n.options.decls { |
| 223 | r.generateSourceCodeInfoForOption(sci, opt, true, &optIndex, optsPath) |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | func (r *parseResult) generateSourceCodeInfoForReservedRange(sci *sourceCodeInfo, n *rangeNode, path []int32) { |
| 229 | sci.newLoc(n, path) |
| 230 | sci.newLoc(n.stNode, append(path, internal.ReservedRange_startTag)) |
| 231 | if n.stNode != n.enNode { |
| 232 | sci.newLoc(n.enNode, append(path, internal.ReservedRange_endTag)) |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | func (r *parseResult) generateSourceCodeInfoForExtensions(sci *sourceCodeInfo, n *extendNode, extendIndex, msgIndex *int32, extendPath, msgPath []int32) { |
| 237 | sci.newLoc(n, extendPath) |
| 238 | for _, decl := range n.decls { |
| 239 | switch { |
| 240 | case decl.field != nil: |
| 241 | r.generateSourceCodeInfoForField(sci, decl.field, append(extendPath, *extendIndex)) |
| 242 | *extendIndex++ |
| 243 | case decl.group != nil: |
| 244 | fldPath := append(extendPath, *extendIndex) |
| 245 | r.generateSourceCodeInfoForField(sci, decl.group, fldPath) |
| 246 | *extendIndex++ |
| 247 | r.generateSourceCodeInfoForMessage(sci, decl.group, fldPath, append(msgPath, *msgIndex)) |
| 248 | *msgIndex++ |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | func (r *parseResult) generateSourceCodeInfoForOneOf(sci *sourceCodeInfo, n *oneOfNode, fieldIndex, nestedMsgIndex *int32, fieldPath, nestedMsgPath, oneOfPath []int32) { |
| 254 | sci.newLoc(n, oneOfPath) |
| 255 | sci.newLoc(n.name, append(oneOfPath, internal.OneOf_nameTag)) |
| 256 | |
| 257 | var optIndex int32 |
| 258 | for _, child := range n.decls { |
| 259 | switch { |
| 260 | case child.option != nil: |
| 261 | r.generateSourceCodeInfoForOption(sci, child.option, false, &optIndex, append(oneOfPath, internal.OneOf_optionsTag)) |
| 262 | case child.field != nil: |
| 263 | r.generateSourceCodeInfoForField(sci, child.field, append(fieldPath, *fieldIndex)) |
| 264 | *fieldIndex++ |
| 265 | case child.group != nil: |
| 266 | fldPath := append(fieldPath, *fieldIndex) |
| 267 | r.generateSourceCodeInfoForField(sci, child.group, fldPath) |
| 268 | *fieldIndex++ |
| 269 | r.generateSourceCodeInfoForMessage(sci, child.group, fldPath, append(nestedMsgPath, *nestedMsgIndex)) |
| 270 | *nestedMsgIndex++ |
| 271 | } |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | func (r *parseResult) generateSourceCodeInfoForField(sci *sourceCodeInfo, n fieldDecl, path []int32) { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 276 | isGroup := false |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 277 | var opts *compactOptionsNode |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 278 | var extendee *extendNode |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 279 | var fieldType string |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 280 | switch n := n.(type) { |
| 281 | case *fieldNode: |
| 282 | opts = n.options |
| 283 | extendee = n.extendee |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 284 | fieldType = n.fldType.val |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 285 | case *mapFieldNode: |
| 286 | opts = n.options |
| 287 | case *groupNode: |
| 288 | isGroup = true |
| 289 | extendee = n.extendee |
| 290 | case *syntheticMapField: |
| 291 | // shouldn't get here since we don't recurse into fields from a mapNode |
| 292 | // in generateSourceCodeInfoForMessage... but just in case |
| 293 | return |
| 294 | } |
| 295 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 296 | if isGroup { |
| 297 | // comments will appear on group message |
| 298 | sci.newLocWithoutComments(n, path) |
| 299 | if extendee != nil { |
| 300 | sci.newLoc(extendee.extendee, append(path, internal.Field_extendeeTag)) |
| 301 | } |
| 302 | if n.fieldLabel() != nil { |
| 303 | // no comments here either (label is first token for group, so we want |
| 304 | // to leave the comments to be associated with the group message instead) |
| 305 | sci.newLocWithoutComments(n.fieldLabel(), append(path, internal.Field_labelTag)) |
| 306 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 307 | sci.newLoc(n.fieldType(), append(path, internal.Field_typeTag)) |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 308 | // let the name comments be attributed to the group name |
| 309 | sci.newLocWithoutComments(n.fieldName(), append(path, internal.Field_nameTag)) |
| 310 | } else { |
| 311 | sci.newLoc(n, path) |
| 312 | if extendee != nil { |
| 313 | sci.newLoc(extendee.extendee, append(path, internal.Field_extendeeTag)) |
| 314 | } |
| 315 | if n.fieldLabel() != nil { |
| 316 | sci.newLoc(n.fieldLabel(), append(path, internal.Field_labelTag)) |
| 317 | } |
| 318 | n.fieldType() |
| 319 | var tag int32 |
| 320 | if _, isScalar := fieldTypes[fieldType]; isScalar { |
| 321 | tag = internal.Field_typeTag |
| 322 | } else { |
| 323 | // this is a message or an enum, so attribute type location |
| 324 | // to the type name field |
| 325 | tag = internal.Field_typeNameTag |
| 326 | } |
| 327 | sci.newLoc(n.fieldType(), append(path, tag)) |
| 328 | sci.newLoc(n.fieldName(), append(path, internal.Field_nameTag)) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 329 | } |
| 330 | sci.newLoc(n.fieldTag(), append(path, internal.Field_numberTag)) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 331 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 332 | if opts != nil { |
| 333 | optsPath := append(path, internal.Field_optionsTag) |
| 334 | sci.newLoc(opts, optsPath) |
| 335 | var optIndex int32 |
| 336 | for _, opt := range opts.decls { |
| 337 | r.generateSourceCodeInfoForOption(sci, opt, true, &optIndex, optsPath) |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | func (r *parseResult) generateSourceCodeInfoForExtensionRanges(sci *sourceCodeInfo, n *extensionRangeNode, extRangeIndex *int32, path []int32) { |
| 343 | sci.newLoc(n, path) |
| 344 | for _, child := range n.ranges { |
| 345 | path := append(path, *extRangeIndex) |
| 346 | *extRangeIndex++ |
| 347 | sci.newLoc(child, path) |
| 348 | sci.newLoc(child.stNode, append(path, internal.ExtensionRange_startTag)) |
| 349 | if child.stNode != child.enNode { |
| 350 | sci.newLoc(child.enNode, append(path, internal.ExtensionRange_endTag)) |
| 351 | } |
| 352 | if n.options != nil { |
| 353 | optsPath := append(path, internal.ExtensionRange_optionsTag) |
| 354 | sci.newLoc(n.options, optsPath) |
| 355 | var optIndex int32 |
| 356 | for _, opt := range n.options.decls { |
| 357 | r.generateSourceCodeInfoForOption(sci, opt, true, &optIndex, optsPath) |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | func (r *parseResult) generateSourceCodeInfoForService(sci *sourceCodeInfo, n *serviceNode, path []int32) { |
| 364 | sci.newLoc(n, path) |
| 365 | sci.newLoc(n.name, append(path, internal.Service_nameTag)) |
| 366 | var optIndex, rpcIndex int32 |
| 367 | for _, child := range n.decls { |
| 368 | switch { |
| 369 | case child.option != nil: |
| 370 | r.generateSourceCodeInfoForOption(sci, child.option, false, &optIndex, append(path, internal.Service_optionsTag)) |
| 371 | case child.rpc != nil: |
| 372 | r.generateSourceCodeInfoForMethod(sci, child.rpc, append(path, internal.Service_methodsTag, rpcIndex)) |
| 373 | rpcIndex++ |
| 374 | } |
| 375 | } |
| 376 | } |
| 377 | |
| 378 | func (r *parseResult) generateSourceCodeInfoForMethod(sci *sourceCodeInfo, n *methodNode, path []int32) { |
| 379 | sci.newLoc(n, path) |
| 380 | sci.newLoc(n.name, append(path, internal.Method_nameTag)) |
| 381 | if n.input.streamKeyword != nil { |
| 382 | sci.newLoc(n.input.streamKeyword, append(path, internal.Method_inputStreamTag)) |
| 383 | } |
| 384 | sci.newLoc(n.input.msgType, append(path, internal.Method_inputTag)) |
| 385 | if n.output.streamKeyword != nil { |
| 386 | sci.newLoc(n.output.streamKeyword, append(path, internal.Method_outputStreamTag)) |
| 387 | } |
| 388 | sci.newLoc(n.output.msgType, append(path, internal.Method_outputTag)) |
| 389 | |
| 390 | optsPath := append(path, internal.Method_optionsTag) |
| 391 | var optIndex int32 |
| 392 | for _, opt := range n.options { |
| 393 | r.generateSourceCodeInfoForOption(sci, opt, false, &optIndex, optsPath) |
| 394 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 395 | } |
| 396 | |
| 397 | type sourceCodeInfo struct { |
| 398 | locs []*dpb.SourceCodeInfo_Location |
| 399 | commentsUsed map[*comment]struct{} |
| 400 | } |
| 401 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 402 | func (sci *sourceCodeInfo) newLocWithoutComments(n node, path []int32) { |
| 403 | dup := make([]int32, len(path)) |
| 404 | copy(dup, path) |
| 405 | sci.locs = append(sci.locs, &dpb.SourceCodeInfo_Location{ |
| 406 | Path: dup, |
| 407 | Span: makeSpan(n.start(), n.end()), |
| 408 | }) |
| 409 | } |
| 410 | |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 411 | func (sci *sourceCodeInfo) newLoc(n node, path []int32) { |
| 412 | leadingComments := n.leadingComments() |
| 413 | trailingComments := n.trailingComments() |
| 414 | if sci.commentUsed(leadingComments) { |
| 415 | leadingComments = nil |
| 416 | } |
| 417 | if sci.commentUsed(trailingComments) { |
| 418 | trailingComments = nil |
| 419 | } |
| 420 | detached := groupComments(leadingComments) |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 421 | var trail *string |
| 422 | if str, ok := combineComments(trailingComments); ok { |
| 423 | trail = proto.String(str) |
| 424 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 425 | var lead *string |
| 426 | if len(leadingComments) > 0 && leadingComments[len(leadingComments)-1].end.Line >= n.start().Line-1 { |
| 427 | lead = proto.String(detached[len(detached)-1]) |
| 428 | detached = detached[:len(detached)-1] |
| 429 | } |
| 430 | dup := make([]int32, len(path)) |
| 431 | copy(dup, path) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 432 | sci.locs = append(sci.locs, &dpb.SourceCodeInfo_Location{ |
| 433 | LeadingDetachedComments: detached, |
| 434 | LeadingComments: lead, |
| 435 | TrailingComments: trail, |
| 436 | Path: dup, |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 437 | Span: makeSpan(n.start(), n.end()), |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 438 | }) |
| 439 | } |
| 440 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 441 | func makeSpan(start, end *SourcePos) []int32 { |
| 442 | if start.Line == end.Line { |
| 443 | return []int32{int32(start.Line) - 1, int32(start.Col) - 1, int32(end.Col) - 1} |
| 444 | } |
| 445 | return []int32{int32(start.Line) - 1, int32(start.Col) - 1, int32(end.Line) - 1, int32(end.Col) - 1} |
| 446 | } |
| 447 | |
| 448 | func (sci *sourceCodeInfo) commentUsed(c []comment) bool { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 449 | if len(c) == 0 { |
| 450 | return false |
| 451 | } |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 452 | if _, ok := sci.commentsUsed[&c[0]]; ok { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 453 | return true |
| 454 | } |
| 455 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 456 | sci.commentsUsed[&c[0]] = struct{}{} |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 457 | return false |
| 458 | } |
| 459 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 460 | func groupComments(comments []comment) []string { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 461 | if len(comments) == 0 { |
| 462 | return nil |
| 463 | } |
| 464 | |
| 465 | var groups []string |
| 466 | singleLineStyle := comments[0].text[:2] == "//" |
| 467 | line := comments[0].end.Line |
| 468 | start := 0 |
| 469 | for i := 1; i < len(comments); i++ { |
| 470 | c := comments[i] |
| 471 | prevSingleLine := singleLineStyle |
| 472 | singleLineStyle = strings.HasPrefix(comments[i].text, "//") |
| 473 | if !singleLineStyle || prevSingleLine != singleLineStyle || c.start.Line > line+1 { |
| 474 | // new group! |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 475 | if str, ok := combineComments(comments[start:i]); ok { |
| 476 | groups = append(groups, str) |
| 477 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 478 | start = i |
| 479 | } |
| 480 | line = c.end.Line |
| 481 | } |
| 482 | // don't forget last group |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 483 | if str, ok := combineComments(comments[start:]); ok { |
| 484 | groups = append(groups, str) |
| 485 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 486 | return groups |
| 487 | } |
| 488 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 489 | func combineComments(comments []comment) (string, bool) { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 490 | if len(comments) == 0 { |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 491 | return "", false |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 492 | } |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 493 | var buf bytes.Buffer |
| 494 | for _, c := range comments { |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 495 | if c.text[:2] == "//" { |
| 496 | buf.WriteString(c.text[2:]) |
| 497 | } else { |
| 498 | lines := strings.Split(c.text[2:len(c.text)-2], "\n") |
| 499 | first := true |
| 500 | for _, l := range lines { |
| 501 | if first { |
| 502 | first = false |
| 503 | } else { |
| 504 | buf.WriteByte('\n') |
| 505 | } |
| 506 | |
| 507 | // strip a prefix of whitespace followed by '*' |
| 508 | j := 0 |
| 509 | for j < len(l) { |
| 510 | if l[j] != ' ' && l[j] != '\t' { |
| 511 | break |
| 512 | } |
| 513 | j++ |
| 514 | } |
| 515 | if j == len(l) { |
| 516 | l = "" |
| 517 | } else if l[j] == '*' { |
| 518 | l = l[j+1:] |
| 519 | } else if j > 0 { |
| 520 | l = " " + l[j:] |
| 521 | } |
| 522 | |
| 523 | buf.WriteString(l) |
| 524 | } |
| 525 | } |
| 526 | } |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 527 | return buf.String(), true |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 528 | } |
| 529 | |
Scott Baker | 4a35a70 | 2019-11-26 08:17:33 -0800 | [diff] [blame] | 530 | func dup(p []int32) []int32 { |
| 531 | return append(([]int32)(nil), p...) |
Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 532 | } |