-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
APIv2: protoreflect.FileDescriptor should be able to preserve source info #859
Comments
Thanks for the issue.
More of an oversight. The |
@dsnet, thanks for the fast reply! That is reassuring to hear. cc @pedgeio |
@dsnet do you want a hand with this or should we leave it to you? I have an interest in this being available sooner than later |
FWIW, C++ provides a // Updates |*out_location| to the source location of the complete
// extent of this message declaration. Returns false and leaves
// |*out_location| unchanged iff location information was not available.
bool GetSourceLocation(SourceLocation* out_location) const;
// NB, all indices are zero-based.
struct SourceLocation {
int start_line;
int end_line;
int start_column;
int end_column;
// Doc comments found at the source location.
// See the comments in SourceCodeInfo.Location (descriptor.proto) for details.
std::string leading_comments;
std::string trailing_comments;
std::vector<std::string> leading_detached_comments;
}; Something similar doesn't seem unreasonable. I agree that we should preserve this information round-trip. |
It would be great if |
FYI there's a bunch of code from jhump/protoreflect desc that could be ported over here with an intermediate amount of work. https://github.com/jhump/protoreflect/blob/f0c0d116896c934f55895bc1cbaf3a43c0dd58a3/desc/descriptor.go#L311 That might be a good starting point. I'd love to be able to use https://godoc.org/google.golang.org/protobuf/reflect/protoreflect right now but without writing a heavy adapter layer, this is what I'd need. Let me know what you think. |
The first step is to come up with a concrete API design. I expect implementation should be fairly straightforward once we have that. A few questions to answer:
|
Note for self: Once we add this, we'll also want to update the protogen package to make use of it. (It has its own, more specialized handling of location information.) |
Thanks @pedgeio for point to that prior work. I'm out of the office for this week, and will be back on Monday. I think a relevant question to answer first is whether
One argument for first-class support is that the |
This is just a rough sketch of what I have in my head, I'm sure there are edge cases I'm not considering right now. To answer 1, sticking with the design of // SourceCodeInfo represents the source code info of an element.
type SourceCodeInfo interface {
GetStartLine() uint32
// returns GetStartLine() if not set in SourceCodeInfo.Location
GetEndLine() uint32
GetStartColumn() uint32
GetEndColumn() uint32
GetLeadingComments() string
GetTrailingComments() string
GetLeadingDetachedComments() string
} Then in the simplest form, you would just add this to type Descriptor interface {
...
// SourceCodeInfo returns the SourceCodeInfo for this Descriptor.
//
// Support for this functionality is optional and may return nil.
SourceCodeInfo() SourceCodeInfo
} This would be the simplest for the end-user. Point three is where this gets interesting though, and touches on jhump/protoreflect#212 and jhump/protoreflect#209. |
Note that |
@neild whoops mental copy/paste error, missed that :-) @dsnet on whether this should be a first-class citizen, I'm going to just give my vote/pleading that it should be - this would make stuff a lot easier for a lot people. You can do the lookups one time within a |
I'm inclined to agree.
The downside to this is that SourceCodeInfo is not always tied to a descriptor declaration, and can be tied to pretty much anything. Another possible design: type FileDescriptor interface {
...
SourceLocations() SourceLocations
}
type SourceLocations interface {
Len() int
Get(int) SourceLocation
ByDescriptor(Descriptor) SourceLocation
ByPath([]int32) SourceLocation
}
type SourceLocation struct {
StartLine, StartColumn int
EndLine, EndColumn int
LeadingComments string
TrailingComments string
// DetachedComments is a copy of the detached comments.
// This is rarely populated, and perhaps a copy is okay.
// Alternatively, we can make this an opaque type.
DetachedComments []string
} |
I'd be 100% on board with that solution as well - that solves @neild's third point in a cleaner way. A few notes:
|
Semi-related: protocolbuffers/protobuf#6188 |
One issue that comes to mind with the above signature for |
We do need a way to get a full list of Returning I don't have a strong opinion on |
Yea I actually re-read the proposal and realized the relative need for I'd argue for fileDescriptorOne := ...
fileDescriptorTwo := ...
// some FieldDescriptor from fileDescriptorOne
fieldDescriptor := fileDescriptorOne.Messages().Get(1).Fields().Get(2)
// invalid
sourceLocation := fileDescriptorTwo.SourceLocations().ByDescriptor(fieldDescriptor) |
Just re-pinging here :-) Let me know if you need any help/hoping you had a good week off @dsnet. One thing I noticed is that you might actually want to expose fileDescriptor := ...
// some FieldDescriptor from fileDescriptor
fieldDescriptor := fileDescriptor.Messages().Get(1).Fields().Get(2)
// get the base location
fileDescriptor.SourceLocations().ByPath(fieldDescriptor.GetSourceLocationPath())
// get the source location of the field name
fileDescriptor.SourceLocations().ByPath(append(fieldDescriptor.GetSourceLocationPath(), 1))
// get the source location of the field number
fileDescriptor.SourceLocations().ByPath(append(fieldDescriptor.GetSourceLocationPath(), 2)) This isn't particularly clean, but this is the general idea. |
Just an update to avoid leaving you hanging. Right now my attention is focused on getting CL/175458 merged, which is a signifcant change to the This issue is my next priority afterwards. I can assure you that |
OK no worries - thanks for the update, really appreciate it. Let me know if I can help in any way. |
Please take a look: https://go-review.googlesource.com/c/protobuf/+/183157 |
Bare minimum API for preserving SourceLocations is submitted. No convenience methods for looking up locations by path were added. I filed #899 for that. |
With the current state of the api-v2 branch, there is no way to construct a
protoreflect.FileDescriptor
(using "sanctioned" APIs) and be able to retain the source info.Is this intentional?
The only way I can find is to use the mechanism that generated code uses -- using
protoimpl.FileBuilder
to create it instead ofprotodesc.NewFile
. And that involves type asserting the result tointerface{ProtoLegacyRawDesc() []byte}
and calling that method, which is documented as likely to be removed in the future.Should I have to deal with that myself -- like provide a wrapper struct that embeds a file descriptor and also retains source info? It would also have to provide custom methods to convert back to a proto since the
ToFileDescriptor
would return a descriptor proto that does not have the source info.Maybe
NewFile
should at least be parameterized (or a new peer function) that makes creation of a descriptor with source info possible.The text was updated successfully, but these errors were encountered: