kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/common/kythe_metadata_file.h (about)

     1  /*
     2   * Copyright 2015 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  #ifndef KYTHE_CXX_COMMON_KYTHE_METADATA_FILE_H_
    18  #define KYTHE_CXX_COMMON_KYTHE_METADATA_FILE_H_
    19  
    20  #include <map>
    21  #include <memory>
    22  #include <optional>
    23  
    24  #include "absl/strings/string_view.h"
    25  #include "kythe/proto/metadata.pb.h"
    26  #include "kythe/proto/storage.pb.h"
    27  
    28  namespace kythe {
    29  
    30  class MetadataFile {
    31   public:
    32    /// \brief An additional semantic to apply to the given (C++) node.
    33    enum class Semantic {
    34      kNone,       ///< No special semantics.
    35      kWrite,      ///< Write semantics.
    36      kReadWrite,  ///< Read+write semantics.
    37      kTakeAlias,  ///< Alias-taking semantics.
    38    };
    39  
    40    /// \brief A single metadata rule.
    41    struct Rule {
    42      unsigned begin = 0;    ///< Beginning of the range to match.
    43      unsigned end = 0;      ///< End of the range to match.
    44      std::string edge_in;   ///< Edge kind to match from anchor over [begin,end).
    45      std::string edge_out;  ///< Edge to create.
    46      proto::VName vname;    ///< VName to create edge to or from.
    47      bool reverse_edge = false;  ///< If false, draw edge to vname; if true, draw
    48                                  ///< from.
    49      bool generate_anchor = false;  ///< If this rule should generate an anchor.
    50      unsigned anchor_begin = 0;     ///< The beginning of the anchor.
    51      unsigned anchor_end = 0;       ///< The end of the anchor.
    52      bool whole_file = false;       ///< Whether to ignore begin/end
    53      Semantic semantic =
    54          Semantic::kNone;  ///< Whether to apply special semantics.
    55    };
    56  
    57    /// Creates a new MetadataFile from a list of rules ranging from `begin` to
    58    /// `end`.
    59    template <typename InputIterator>
    60    static std::unique_ptr<MetadataFile> LoadFromRules(absl::string_view id,
    61                                                       InputIterator begin,
    62                                                       InputIterator end) {
    63      std::unique_ptr<MetadataFile> meta_file = std::make_unique<MetadataFile>();
    64      meta_file->id_ = std::string(id);
    65      for (auto rule = begin; rule != end; ++rule) {
    66        if (rule->whole_file) {
    67          meta_file->file_scope_rules_.push_back(*rule);
    68        } else {
    69          meta_file->rules_.emplace(rule->begin, *rule);
    70        }
    71      }
    72      return meta_file;
    73    }
    74  
    75    //// Attempts to convert `mapping` to a `Rule`.
    76    static std::optional<MetadataFile::Rule> LoadMetaElement(
    77        const kythe::proto::metadata::MappingRule& mapping);
    78  
    79    /// Rules to apply keyed on `begin`.
    80    const std::multimap<unsigned, Rule>& rules() const { return rules_; }
    81  
    82    /// File-scoped rules.
    83    const std::vector<Rule>& file_scope_rules() const {
    84      return file_scope_rules_;
    85    }
    86  
    87    absl::string_view id() const { return id_; }
    88  
    89   private:
    90    /// Rules to apply keyed on `begin`.
    91    std::multimap<unsigned, Rule> rules_;
    92  
    93    std::vector<Rule> file_scope_rules_;
    94  
    95    std::string id_;
    96  };
    97  
    98  /// \brief Provides interested MetadataSupport classes with the ability to
    99  /// look up VNames for arbitrary required inputs (including metadata files).
   100  /// \return true and merges `path`'s VName into `out` on success; false on
   101  /// failure.
   102  using VNameLookup =
   103      std::function<bool(const std::string& path, proto::VName* out)>;
   104  
   105  /// \brief Converts from arbitrary metadata formats to those supported by Kythe.
   106  ///
   107  /// Some metadata producers may be unable to directly generate Kythe metadata.
   108  /// It may also be difficult to ensure that the data they do produce is
   109  /// converted before a Kythe tool runs. This interface allows tools to
   110  /// support arbitrary metadata formats by converting them to kythe::MetadataFile
   111  /// instances on demand.
   112  class MetadataSupport {
   113   public:
   114    virtual ~MetadataSupport() {}
   115    /// \brief Attempt to parse the file originally named `raw_filename` with
   116    /// decoded filename `filename` and contents in `buffer` to be applied
   117    /// to a target file with contents `target_buffer`.
   118    /// \return A `MetadataFile` on success; otherwise, null.
   119    virtual std::unique_ptr<kythe::MetadataFile> ParseFile(
   120        const std::string& raw_filename, const std::string& filename,
   121        absl::string_view buffer, absl::string_view target_buffer) {
   122      return nullptr;
   123    }
   124  
   125    /// \brief Use `lookup` when generating VNames (if necessary).
   126    virtual void UseVNameLookup(VNameLookup lookup) {}
   127  };
   128  
   129  /// \brief A collection of metadata support implementations.
   130  ///
   131  /// Each `MetadataSupport` is tried in order. The first one to return
   132  /// a non-null result from `ParseFile` is elected to provide metadata for a
   133  /// given (`filename`, `buffer`) pair.
   134  ///
   135  /// If the metadata file ends in .h, we assume that it is a valid C++ header
   136  /// that begins with a comment marker followed immediately by a base64-encoded
   137  /// buffer. We will decode and parse this buffer using the filename with the .h
   138  /// removed (as some support implementations discriminate based on extension).
   139  /// The comment mark, the contents of the comment, and any relevant control
   140  /// characters must be 7-bit ASCII. The character set used for base64 encoding
   141  /// is A-Za-z0-9+/ in that order, possibly followed by = or == for padding.
   142  ///
   143  /// If search_string is set, `buffer` will be scanned for a comment marker
   144  /// followed by a space followed by search_string. Should this comment be
   145  /// found, it will be decoded as above.
   146  ///
   147  /// If the comment is a //-style comment, the base64 string must be unbroken.
   148  /// If the comment is a /* */-style comment, newlines (\n) are permitted.
   149  class MetadataSupports {
   150   public:
   151    void Add(std::unique_ptr<MetadataSupport> support) {
   152      supports_.push_back(std::move(support));
   153    }
   154  
   155    std::unique_ptr<kythe::MetadataFile> ParseFile(
   156        const std::string& filename, absl::string_view buffer,
   157        const std::string& search_string, absl::string_view target_buffer) const;
   158  
   159    void UseVNameLookup(VNameLookup lookup) const;
   160  
   161   private:
   162    std::vector<std::unique_ptr<MetadataSupport>> supports_;
   163  };
   164  
   165  /// \brief Enables support for raw JSON-encoded metadata files.
   166  class KytheMetadataSupport : public MetadataSupport {
   167   public:
   168    std::unique_ptr<kythe::MetadataFile> ParseFile(
   169        const std::string& raw_filename, const std::string& filename,
   170        absl::string_view buffer, absl::string_view target_buffer) override;
   171  
   172   private:
   173    /// \brief Load the JSON-encoded metadata from `json`.
   174    /// \return null on failure.
   175    static std::unique_ptr<MetadataFile> LoadFromJSON(absl::string_view id,
   176                                                      absl::string_view json);
   177  };
   178  
   179  }  // namespace kythe
   180  
   181  #endif  // KYTHE_CXX_COMMON_KYTHE_METADATA_FILE_H_