/*
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

syntax = "proto3";

package kythe.proto;

// Design document: <link when written>
// This proto represents a very preliminary attempt to define a cross-reference
// service interface, based on Kythe data.
//
// Tickets are Kythe URIs (http://www.kythe.io/docs/kythe-uri-spec.html).

// XRefService provides access to a Kythe graph for fast read-only access to
// cross-reference relationships.  What constitutes a "Cross-reference" is not
// precisely defined, but generally includes non-transitive (single-step)
// relation like usage of a declaration, instantiation of a type, invocation of
// a function, direct inheritance or overrides, and so forth.  Some transitive
// relations can be converted into cross-references by precomputing a flattened
// representation of a transitive relation.  In general, though, this service
// is designed to be most efficient for single-step expansions.
//
// Key design principles:
//  - All requests must be satisfied "quickly", e.g., in time proportional to
//    the size of the returned set.
//
//  - The client should be able to batch related requests.
//
//  - The client specifies exactly what facts should be returned.
//
// There is no distinction made in the API between "node not found" and "no
// facts/edges for node".  A node is extensionally defined by its facts and
// edges, so a node without any facts or edges is not considered to exist.
service XRefService {

  // TODO(schroederc): break off Nodes/Edges into a separate service

  // Nodes returns a subset of the facts for each of the requested nodes.
  rpc Nodes(NodesRequest) returns (NodesReply) {}

  // Edges returns a subset of the outbound edges for each of a set of
  // requested nodes.
  rpc Edges(EdgesRequest) returns (EdgesReply) {}

  // Decorations returns an index of the nodes and edges associated with a
  // particular file node.
  rpc Decorations(DecorationsRequest) returns (DecorationsReply) {}

  // CrossReferences returns the global references, definitions, and
  // documentation of a set of requested nodes.
  rpc CrossReferences(CrossReferencesRequest) returns (CrossReferencesReply) {}

  // Callers takes a set of tickets for semantic objects and returns the set
  // of places where those objects were called. For example, in the program
  //   void bar() { foo(); foo(); } void baz() { foo(); } void foo() { }
  // `Callers({foo})` would return:
  //   {(bar, {first-call-anchor, second-call-anchor}),
  //    (baz, {first-call-anchor})}
  // To walk further up the call graph, you can project the first field of
  // each tuple in the result set ({bar, baz}) and feed that set back in
  // to a new Callers request.
  //
  // The core of this query is specified in terms of graph operations in the
  // Kythe repository at //kythe/docs/schema/callgraph.txt.
  rpc Callers(CallersRequest) returns (CallersReply) {}

  // Documentation takes a set of tickets for semantic objects and returns
  // documentation about them, including generated signatures and
  // user-provided text. The documentation may refer to tickets for other
  // nodes in the graph.
  rpc Documentation(DocumentationRequest) returns (DocumentationReply) {}
}

message NodesRequest {
  // The tickets of the nodes to be looked up.
  repeated string ticket = 1;

  // A collection of filter globs that specify which facts (by name) should be
  // returned for each node.  If filter is empty or unset, all available facts
  // are returned for each matching node.  The filter applies to ALL requested
  // nodes.  For different filters per node, the client must issue separate
  // requests.  See EdgesRequest for the format of the filter globs.
  repeated string filter = 2;
}

message NodeInfo {
  // The matching facts known for that node, a map from fact name to value.
  map<string, bytes> facts = 2;

  // If known and unambiguous, an anchor ticket for this node's definition
  // location.
  string definition = 5;

  reserved 1;
  reserved "ticket";
}

message NodesReply {
  // One NodeInfo, keyed by its ticket, is returned for each requested node
  // that had a non-zero number of matching facts.  Each NodeInfo will not have
  // its ticket set since it would just be a copy of the map keys.
  map<string, NodeInfo> nodes = 1;
}

message EdgesRequest {
  // The tickets of the source nodes for which edges are requested.
  // The service will return an error if no tickets are specified.
  repeated string ticket = 1;

  // The kinds of outbound edges that should be returned for each matching
  // source node.  If empty, all available edge kinds are returned.
  repeated string kind = 2;

  // A collection of filter globs that specify which facts (by name) should be
  // returned for the target node of each matching edge.  If filter is empty,
  // no facts are returned.
  //
  // The supported glob operators are:
  //   *   zero or more non-slash characters ([^/]*)
  //   ?   any single non-slash character ([^/])
  //   **  zero or more of any character (.*)
  //
  // All other characters match literally, and the glob must consume the entire
  // name in order to match.  The facts returned are the union of those matched
  // by all the globs provided.
  repeated string filter = 3;

  // The edges matching a request are organized into logical pages.  The size
  // of each page is a number of distinct edges.  Notionally: All the matching
  // edges are ordered lexicographically by (start_ticket, kind, end_ticket);
  // the page_token determines where in the ordering to start, and page_size
  // determines how many edges should be returned.
  //
  // If page_token is empty, edges will be returned starting at the beginning
  // of the sequence; otherwise the starting point named by the page_token will
  // be used.  Legal values of page_token are returned by the server in the
  // next_page_token field of the EdgesReply.  A page token should be treated
  // as an opaque value by the client, and is valid only relative to a
  // particular set of tickets and kinds.  If an invalid page token is
  // requested, the server will return an error.
  //
  // If page_size > 0, at most that number of edges will be returned by the
  // service for this request (see EdgeSet and EdgesReply below).
  // If page_size = 0, the default, the server will assume a reasonable default
  // page size.  The server will return an error if page_size < 0.
  //
  // The server is allowed to return fewer edges than the requested page_size,
  // even if more are available, save that it must return at least 1 edge if
  // any are available at all.
  int32  page_size  = 8;
  string page_token = 9;


  // TODO(fromberger): Should this interface support automatic indirection
  // through "name" nodes?
  // For now, I'm assuming name-indirecting lookup will be a separate
  // API, and that the initial clients will just make two (batching)
  // calls if they need to.
}

// An EdgeSet represents a collection of edges outbound from a single node.  The
// edges are organized into groups, each sharing a common edge kind.
//
// The number of edges represented by an EdgeSet es, denoted len(es), is the sum
// of the lengths of the repeated edge fields for all the groups in the EdgeSet.
// This count is used to determine page size in a request.
message EdgeSet {
  message Group {
    message Edge {
      string target_ticket = 1;

      // An optional integer to give an ordering between multiple edges of same
      // source and kind to one or more targets.  See https://kythe.io/schema
      // for when ordinals are used for a given edge kind.
      int32 ordinal = 2;
    }

    repeated Edge edge = 2;

    reserved 1;
    reserved "kind";
  }

  // Each group is a collection of outbound edges from source node sharing a
  // given kind, the map's keys.  In a given EdgeSet, the server will not send
  // more than one group with the same kind label.
  map<string, Group> groups = 2;

  reserved 1;
  reserved "source_ticket";
}

message EdgesReply {
  // This field will contain one EdgeSet for each source node with one or more
  // matching outbound edges, keyed by the source node's ticket.  The number of
  // edges represented by an EdgesReply er, denoted len(er), is the sum of
  // len(es) for each es in edge_sets.  This count is used to determine the page
  // size.
  map<string, EdgeSet> edge_sets = 1;

  // This field will contain one entry, keyed by ticket, for each distinct node
  // referenced by some edge in edgesets, for which there is one or more
  // matching facts.
  //
  // Rationale: This prevents us from having to copy the data to all the end
  // nodes, but allows the client to have that information without making
  // additional requests.
  map<string, NodeInfo> nodes = 2;

  // Total number of edges on all pages matching requested kinds, by kind.
  map<string, int64> total_edges_by_kind = 5;

  // If there are additional pages of edges after the ones returned in this
  // reply, next_page_token is the page token that may be passed to fetch the
  // next page in sequence after this one.  If there are no additional edges,
  // this field will be empty.
  string next_page_token = 9;
}

// A Location represents a single span of zero or more contiguous bytes of a
// file or buffer.  An empty LOCATION denotes the entirety of the referenced
// file or buffer.
//
message Location {
  // TODO(schroederc): reuse Span from common.proto

  // The ticket of the file this location belongs to.  If the location
  // represents a memory buffer, the ticket should be omitted.
  string ticket = 1;

  enum Kind {
    // The entire file; the start and end fields are ignored.
    FILE = 0;

    // The point or span of file subtended by start and end.
    SPAN = 1;
  }

  // What kind of location this is.
  Kind kind = 2;

  // A Point represents a location within a file or buffer.
  //
  // If line_number ≤ 0, the line number and column offset are considered
  // unknown and will be ignored.
  //
  // A point with line_number > 0 is said to be _normalized_ if it satisfies
  // the constraint 0 ≤ column_offset ≤ bytelen(line_number); that is, if the
  // column_offset is within the actual range of the corresponding line.  A
  // point can be normalized by adjusting line_number and column_offset so that
  // this constraint is satisfied.  This may be impossible if the column offset
  // exceeds the bounds of the file.
  message Point {
    // The offset in bytes from the beginning of the file.
    // Requires 0 ≤ byte_offset ≤ len(file).
    int32 byte_offset = 1;

    // The line number containing the point, 1-based.
    int32 line_number = 2;

    // The byte offset of the point within its line.
    int32 column_offset = 3;
  }

  // The starting point of the location.
  Point start = 3;

  // The ending point of the location.
  Point end = 4;

  // A location is _valid_ if 0 ≤ start.offset ≤ end.offset.  If a valid
  // location has start.offset = end.offset, it denotes a single point;
  // otherwise it denotes the half-closed interval [start.offset, end.offset).
  //
  // When kind = FILE, start and end should be unset or set to zero values.
}

message DecorationsRequest {
  // The location of the file to fetch decorations for.  The ticket of location
  // must be non-empty.  It is an error in any case if location is invalid.
  Location location = 1;

  enum SpanKind {
    // If the location is a SPAN, only decorations contained within the
    // specified window of the file are returned.  This is the default behavior.
    WITHIN_SPAN = 0;

    // If the location is a SPAN, any decorations that surround it are returned.
    AROUND_SPAN = 1;
  }

  // How to treat SPAN locations.
  SpanKind span_kind = 10;

  // If dirty_buffer is non-empty, the results will be adjusted (patched) to
  // account for the regions of the specified file differing from the contents
  // of the dirty buffer.
  bytes dirty_buffer = 2;

  // If true, return the encoded source text for the selected window.  Source
  // text is not affected by patching.
  bool source_text = 3;

  // If true, return reference edges whose source nodes are located in the
  // selected window.  References are affected by patching.
  bool references = 4;

  // If true, return definition locations, if possible, for each returned
  // reference target in the DecorationsReply.
  bool target_definitions = 6;

  // A collection of filter globs that specify which facts (by name) should be
  // returned for each node.  If filter is empty or unset, no node facts are
  // returned.  The filter applies to ALL referenced nodes.  See EdgesRequest
  // for the format of the filter globs.
  repeated string filter = 5;
}

message DecorationsReply {
  // The normalized location for which decorations are returned.
  Location location = 1;

  // The encoded source text for the selected window.
  bytes source_text = 2;
  string encoding = 3;

  // Represents a reference edge source ---KIND---> target.  Each source is an
  // anchor within the requested source location.
  message Reference {
    string source_ticket = 1;
    string target_ticket = 2;
    string kind = 3;

    // Starting byte offset of this references's anchor (source_ticket) span.
    Location.Point anchor_start = 10;
    // Ending byte offset of this references's anchor (source_ticket) span.
    Location.Point anchor_end = 11;

    // Anchor ticket of the target's definition.  Populated only if
    // target_definitions is true in the DecorationsRequest and the target has
    // a single unambiguous definition.  For each ticket, an Anchor will be
    // populated in the top-level definition_locations map.
    string target_definition = 4;
  }

  // The reference edges located in the specified window.
  repeated Reference reference = 4;

  // This field will contain one entry, keyed by ticket, for each distinct node
  // referenced by a reference edge that has at least 1 non-filtered fact.
  map<string, NodeInfo> nodes = 15;

  // Each anchor cited as a target definition in the references.  The map is
  // keyed by each anchor's ticket.
  map<string, Anchor> definition_locations = 16;

  // TODO(fromberger): Patch diff information.
}

message CrossReferencesRequest {
  // Set of nodes for which to return their cross-references.  Must be
  // non-empty.
  repeated string ticket = 1;

  enum DefinitionKind {
    // No definitions will be populated in the CrossReferencesReply.
    NO_DEFINITIONS = 0;

    // All known definition anchors reached by the "/kythe/edge/defines" edge
    // kind (or its variants) will be populated in the CrossReferencesReply.
    ALL_DEFINITIONS = 1;

    // Only definition anchors reached by the "/kythe/edge/defines" edge kind
    // will be populated in the CrossReferencesReply.
    FULL_DEFINITIONS = 2;

    // Only definition anchors reached by the "/kythe/edge/defines/binding" edge
    // kind will be populated in the CrossReferencesReply.
    BINDING_DEFINITIONS = 3;
  }

  // Determines what kind of definition anchors, if any, should be returned in
  // the response.  See the documentation for each DefinitionKind for more
  // information.
  DefinitionKind definition_kind = 2;

  enum DeclarationKind {
    // No declarations will be populated in the CrossDeclarationsReply.
    NO_DECLARATIONS = 0;
    // When the source node is incomplete, all known declaration anchors reached
    // by the "/kythe/edge/defines" edge kind (or its variants) will be
    // populated in the CrossDeclarationsReply.
    ALL_DECLARATIONS = 1;
  }

  // Determines what kind of declaration anchors, if any, should be returned in
  // the response.  See the documentation for each DeclarationKind for more
  // information.
  DeclarationKind declaration_kind = 7;

  enum ReferenceKind {
    // No references will be populated in the CrossReferencesReply.
    NO_REFERENCES = 0;
    // Only callgraph-related references as described in
    // http://www.kythe.io/docs/schema/callgraph.html
    CALL_REFERENCES = 1;
    // All references except those that are related to the callgraph.
    NON_CALL_REFERENCES = 2;
    // All known reference anchors reached by the "/kythe/edge/ref" edge kind
    // (or its variants) will be populated in the CrossReferencesReply.
    ALL_REFERENCES = 3;
  }

  // Determines what kind of reference anchors, if any, should be returned in
  // the response.  See the documentation for each ReferenceKind for more
  // information.
  ReferenceKind reference_kind = 3;

  enum DocumentationKind {
    // No documentation will be populated in the CrossReferencesReply.
    NO_DOCUMENTATION = 0;
    // All known documentation reached by the "/kythe/edge/documentation" edge
    // kind (or its variants) will be populated in the CrossReferencesReply.
    ALL_DOCUMENTATION = 1;
  }

  // Determines what kind of documentation anchors, if any, should be returned
  // in the response.  See the documentation for each DocumentationKind for more
  // information.
  DocumentationKind documentation_kind = 4;

  enum CallerKind {
    // No callgraph information will be populated in the CrossReferencesReply.
    NO_CALLERS = 0;
    // Callgraph information will be populated in the CrossReferencesReply.
    DIRECT_CALLERS = 1;
    // Callgraph information will be populated in the CrossReferencesReply.
    // Calls to override-related functions will also be considered.
    OVERRIDE_CALLERS = 2;
  }

  // Determines what kind of callgraph information, if any, should be returned
  // in the response.  See the documentation for each CallerKind for more
  // information.
  CallerKind caller_kind = 12;

  // Collection of filter globs that determines which facts will be returned for
  // the related nodes of each requested node.  If filter is empty or unset, no
  // node facts or related nodes are returned.  See EdgesRequest for the format
  // of the filter globs.
  repeated string filter = 5;

  // Determines whether each Anchor in the response should have its text field
  // populated.
  bool anchor_text = 6;

  // Determines whether each NodeInfo matching the above filters will have its
  // definition location populated, if known.
  bool node_definitions = 8;

  // Enable the experimental generation of signatures in the
  // CrossReferencesReply.  Enabling this currently causes multiple lookups and
  // can significantly impact latency.  Once latency concerns have been
  // addressed, this field will be removed and signatures will be returned by
  // default.
  // TODO(T156): remove this flag; always enable feature
  bool experimental_signatures = 100;

  // TODO(schroederc): snippet kinds (none, indexer-default, or always line-based)

  // The cross-references matching a request are organized into logical pages.
  // The size of each page is a number of distinct cross-references
  // (definitions, references, documentation, and related nodes).
  //
  // If page_token is empty, cross-references will be returned starting at the
  // beginning of the sequence; otherwise the starting point named by the
  // page_token will be used.  Legal values of page_token are returned by the
  // server in the next_page_token field of the CrossReferencesReply.  A page
  // token should be treated as an opaque value by the client, and is valid only
  // relative to a particular CrossReferencesRequest.  If an invalid page token
  // is requested, the server will return an error.
  //
  // If page_size > 0, at most that number of cross-references will be returned
  // by the service for this request (see ReferenceSet and CrossReferencesReply
  // below).  If page_size = 0, the default, the server will assume a reasonable
  // default page size.  The server will return an error if page_size < 0.
  //
  // The server is allowed to return fewer cross-references than the requested
  // page_size, even if more are available, save that it must return at least 1
  // edge if any are available at all.
  int32 page_size = 10;
  string page_token = 11;
}

// TODO(schroederc): eliminate duplicate serving.ExpandedAnchor message defintion

message Anchor {
  // Ticket of the anchor node
  string ticket = 1;
  // Edge kind describing the anchor's relationship with its referenced node
  string kind = 2;

  // Parent ticket of the anchor; this is the file containing the anchor
  string parent = 3;

  // Starting location of the anchor within its parent's text
  Location.Point start = 4;
  // Ending location of the anchor within its parent's text
  Location.Point end = 5;
  // The anchor's spanning text within the anchor parent's text
  string text = 6;

  // User-readable snippet of the anchor parent's text at the location of this
  // anchor
  string snippet = 7;
  // Starting location of the anchor's snippet within its parent's text
  Location.Point snippet_start = 8;
  // Ending location of the anchor's snippet within its parent's text
  Location.Point snippet_end = 9;
}

message Link {
  // Definition sites found for some ticket.
  repeated Anchor definition = 1;
}

message Printable {
  // Raw text that can be displayed to the user (but may also contain
  // markup that can be interpreted, like Doxygen comments). Links are
  // marked using []. \ is an escape character (where possible escape
  // sequences are \[, \], and \\).
  string raw_text = 1;
  // Destinations for links in raw_text. The ith Link corresponds to the link
  // starting at the ith [.
  repeated Link link = 2;
}

message CrossReferencesReply {
  message RelatedNode {
    // Ticket of the node
    string ticket = 1;
    // Edge kind describing the node's relation
    string relation_kind = 2;
    // Optional ordinal for edges of the same relation_kind.
    int32 ordinal = 3;
  }

  message RelatedAnchor {
    // The anchor covering the related object.
    Anchor anchor = 1;
    // A name for the related object.
    Printable display_name = 2;
    // Specific locations, usually within the related object, that caused
    // the relationship to exist. This field is relevant to caller sets.
    repeated Anchor site = 3;
  }

  message CrossReferenceSet {
    string ticket = 1;

    // A name for the given node.
    Printable display_name = 7;

    // The set of definitions for the given node.
    repeated RelatedAnchor definition = 2;
    // The set of declarations for the given node.
    repeated RelatedAnchor declaration = 5;
    // The set of simple references for the given node.
    repeated RelatedAnchor reference = 3;
    // The set of documentation for the given node.
    repeated RelatedAnchor documentation = 4;
    // The set of callers for the given node.
    repeated RelatedAnchor caller = 6;

    // The set of related nodes to the given node.
    repeated RelatedNode related_node = 10;
  }

  message Total {
    int64 definitions = 1;
    int64 declarations = 2;
    int64 references = 3;
    int64 documentation = 4;
    int64 callers = 5;

    map<string, int64> related_nodes_by_relation = 6;
  }
  // Total number of cross-references on all pages matching requested filters.
  Total total = 5;

  // Sets of cross-references for each requested node
  map<string, CrossReferenceSet> cross_references = 1;

  // The facts left from the requested filters of the related node facts
  map<string, NodeInfo> nodes = 2;

  // Map from the definition tickets referred to in each NodeInfo to their
  // Anchor.  This map will only be returned if the
  // CrossReferencesRequest.node_definitions switch is true.
  map<string, Anchor> definition_locations = 3;

  // If there are additional pages of cross-references after the ones returned
  // in this reply, next_page_token is the page token that may be passed to
  // fetch the next page in sequence after this one.  If there are no additional
  // cross-references, this field will be empty.
  string next_page_token = 10;
}

message CallersRequest {
  // Semantic tickets for callees (e.g., function nodes).
  repeated string semantic_object = 1;
  // Expand the semantic_object set by including nodes that participate in
  // an `overrides` relationship (in either direction) with nodes in the set.
  //
  // In the program:
  //   struct A { virtual void f(); };
  //   struct B : public A { void f() override; };
  //   struct C : public B { void f() override; };
  //   void g(B* b) { b->f(); }
  //
  // we would return the following results (for queries on the singleton
  // semantic_object set containing A::f, B::f, or C::f):
  //
  // include_overrides  A::f  B::f  C::f
  //             false    {}   {g}    {}
  //              true   {g}   {g}   {g}
  bool include_overrides = 2;
}

message CallersReply {
  // Details common to all objects that participate in the call graph.
  message CallableDetail {
    // The definition site of the object called or being blamed for a call.
    // This would be the "bar" in "void bar()" for calls blamed on bar above
    // and the "foo" in "void foo()" if it refers to foo as a callee.
    Anchor definition = 1;
    // The ticket of the callable object. This would refer to the function node
    // for "bar" or "foo". This object may be the target of a `completes` edge
    // (e.g., if the call was made to a definition rather than a declaration).
    string semantic_object = 2;
    // The unqualified identifier for this object ("bar" or "foo" above,
    // even if they were defined in some namespace or record). This field
    // should be human-readable and can be displayed in a UI.
    string identifier = 4;
    // An unambiguous (as possible) identifier for this object ("bar()" or
    // "foo()" above; if it was defined in a namespace, "ns::bar()";
    // if it took arguments, "ns::bar(int *, void *)"). This field should
    // be human-readable and can be displayed in a UI.
    string display_name = 5;
    // A parameter bound by the object referred to by `definition` above.
    message Parameter {
      enum Kind {
        // A term-level binding (like the `x` in `void foo(int x)`).
        TERM = 0;
        // A type-level binding (like the `T` in
        // `template <typename T> void foo()`).
        TYPE = 1;
      }
      // The parameter's kind.
      Kind kind = 1;
      // The parameter's (unqualified) human-readable and displayable name.
      // May be empty. May also be non-unique; for example, the identifiers for
      // the (unnamed in the source language) parameters for the function
      // `void ignore_pair(int, int)` may be "int" and "int".
      string identifier = 2;
      // The ticket that refers to the parameter.
      string ticket = 3;
    }
    // The parameters bound by the object referred to by `definition` above.
    // There is no semantic meaning to the order of this array, but it should
    // be reasonable to surface the ordering in a UI (for example, term-level
    // parameters will not be capriciously reordered).
    repeated Parameter parameter = 6;
  }
  // An object that was blamed for making a call to an object in the set passed
  // to Callers, along with the syntactic locations that caused that blame to
  // be cast.
  message Caller {
    // The object (e.g., a function) responsible for making a call.
    CallableDetail detail = 1;
    message CallSite {
      // The location where a call was found inside the blamed object.
      Anchor anchor = 1;
      // This field will be set to true iff this call site was included in the
      // results because include_overrides was true in CallersRequest.
      bool call_to_override = 2;
    }
    repeated CallSite call_site = 2;
  }
  // All objects that were blamed for making calls.
  repeated Caller caller = 1;
  // Details for the semantic objects that were passed via a CallersRequest.
  repeated CallableDetail callee = 2;
}

message DocumentationRequest {
  // Semantic tickets about which documentation is sought.
  repeated string ticket = 1;
}

message DocumentationReply {
  message Document {
    // The ticket to which this Document refers.
    string ticket = 1;
    // Documentation that can be displayed to the user.
    Printable text = 2;
    // A signature that can be displayed to the user. For variables, this
    // may just be the variable name; for functions, this may be some version
    // of the function prototype.
    Printable signature = 3;
    // The type as a signature that can be displayed to the user.
    Printable type = 4;
    // The initialization value, if any.
    Printable initializer = 5;
    // The semantic parent of this value.
    Printable defined_by = 6;
    // The node kind being defined.
    string kind = 7;
  }
  repeated Document document = 1;
}