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_