kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/indexer/proto/proto_graph_builder.cc (about) 1 /* 2 * Copyright 2018 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 #include "kythe/cxx/indexer/proto/proto_graph_builder.h" 18 19 #include <functional> 20 #include <utility> 21 22 #include "absl/log/log.h" 23 #include "absl/strings/str_cat.h" 24 #include "kythe/cxx/common/indexing/KytheGraphRecorder.h" 25 #include "kythe/cxx/common/vname_ordering.h" 26 #include "kythe/cxx/indexer/proto/comments.h" 27 28 namespace kythe { 29 30 using ::kythe::proto::VName; 31 32 namespace { 33 // Pretty-prints a VName. 34 std::string StringifyNode(const VName& v_name) { 35 return absl::StrCat(v_name.path(), ":", v_name.signature()); 36 } 37 38 // Pretty-prints a NodeKindID. 39 std::string StringifyKind(NodeKindID kind) { 40 return std::string(spelling_of(kind)); 41 } 42 43 // Pretty-prints an EdgeKindID. 44 std::string StringifyKind(EdgeKindID kind) { 45 return std::string(spelling_of(kind)); 46 } 47 } // anonymous namespace 48 49 ProtoGraphBuilder::ProtoGraphBuilder( 50 KytheGraphRecorder* recorder, 51 std::function<proto::VName(const std::string&)> vname_for_rel_path) 52 : recorder_(recorder), vname_for_rel_path_(std::move(vname_for_rel_path)) { 53 builtin_rpc_type_constructor_.set_language(kLanguageName); 54 builtin_rpc_type_constructor_.set_signature("rpc#builtin"); 55 } 56 57 void ProtoGraphBuilder::SetText(const VName& node_name, 58 const std::string& content) { 59 VLOG(1) << "Setting text (length = " << content.length() 60 << ") for: " << StringifyNode(node_name); 61 recorder_->AddProperty(VNameRef(node_name), kythe::PropertyID::kText, 62 content); 63 current_file_contents_ = content; 64 } 65 66 void ProtoGraphBuilder::MaybeAddEdgeFromMetadata(const Location& location, 67 const VName& target) { 68 if (meta_ == nullptr) { 69 return; 70 } 71 auto rules = meta_->rules().equal_range(location.begin); 72 for (auto rule = rules.first; rule != rules.second; ++rule) { 73 if (location.end == rule->second.end) { 74 EdgeKindID edge_kind; 75 if (of_spelling(rule->second.edge_out, &edge_kind)) { 76 VName source(rule->second.vname); 77 source.set_corpus(target.corpus()); 78 if (rule->second.reverse_edge) { 79 AddEdge(source, target, edge_kind); 80 } else { 81 AddEdge(target, source, edge_kind); 82 } 83 } 84 } 85 } 86 } 87 88 void ProtoGraphBuilder::MaybeAddMetadataFileRules(const VName& file) { 89 if (meta_ == nullptr) { 90 return; 91 } 92 for (const auto& rule : meta_->file_scope_rules()) { 93 EdgeKindID edge_kind; 94 if (of_spelling(rule.edge_out, &edge_kind)) { 95 VName source(rule.vname); 96 source.set_corpus(file.corpus()); 97 if (rule.reverse_edge) { 98 AddEdge(source, file, edge_kind); 99 } else { 100 AddEdge(file, source, edge_kind); 101 } 102 } 103 } 104 } 105 106 void ProtoGraphBuilder::AddNode(const VName& node_name, NodeKindID node_kind) { 107 VLOG(1) << "Writing node: " << StringifyNode(node_name) << "[" 108 << StringifyKind(node_kind) << "]"; 109 recorder_->AddProperty(VNameRef(node_name), node_kind); 110 } 111 112 void ProtoGraphBuilder::AddEdge(const VName& start, const VName& end, 113 EdgeKindID start_to_end_kind) { 114 VLOG(1) << "Writing edge: " << StringifyNode(start) << " >-->--[" 115 << StringifyKind(start_to_end_kind) << "]-->--> " 116 << StringifyNode(end); 117 recorder_->AddEdge(VNameRef(start), start_to_end_kind, VNameRef(end)); 118 } 119 120 void ProtoGraphBuilder::AddEdge(const VName& start, const VName& end, 121 EdgeKindID start_to_end_kind, int ordinal) { 122 VLOG(1) << "Writing edge: " << StringifyNode(start) << " >-->--[" 123 << StringifyKind(start_to_end_kind) << "]-->--> " 124 << StringifyNode(end) << " : " << ordinal; 125 recorder_->AddEdge(VNameRef(start), start_to_end_kind, VNameRef(end), 126 ordinal); 127 } 128 129 VName ProtoGraphBuilder::CreateAndAddAnchorNode(const Location& location) { 130 VName anchor = location.file; 131 anchor.set_language(kLanguageName); 132 133 auto* const signature = anchor.mutable_signature(); 134 absl::StrAppend(signature, "@", location.begin, ":", location.end); 135 136 AddNode(anchor, NodeKindID::kAnchor); 137 recorder_->AddProperty(VNameRef(anchor), PropertyID::kLocationStartOffset, 138 location.begin); 139 recorder_->AddProperty(VNameRef(anchor), PropertyID::kLocationEndOffset, 140 location.end); 141 142 return anchor; 143 } 144 145 VName ProtoGraphBuilder::CreateAndAddDocNode(const Location& location, 146 const VName& element) { 147 VName doc = location.file; 148 doc.set_language(kLanguageName); 149 doc.set_signature( 150 absl::StrCat("doc-", location.begin, "-", element.signature())); 151 152 // Adjust the text to splice out comment markers, as per 153 // http://www.kythe.io/docs/schema/#doc 154 AddNode(doc, NodeKindID::kDoc); 155 std::string comment = StripCommentMarkers(current_file_contents_.substr( 156 location.begin, location.end - location.begin)); 157 recorder_->AddProperty(VNameRef(doc), PropertyID::kText, comment); 158 return doc; 159 } 160 161 void ProtoGraphBuilder::AddImport(const std::string& import, 162 const Location& location) { 163 VName dep = vname_for_rel_path_(import); 164 LOG(INFO) << "DEPENDENCY : " << URI(dep).ToString(); 165 VName anchor = CreateAndAddAnchorNode(location); 166 AddEdge(anchor, dep, EdgeKindID::kRefIncludes); 167 } 168 169 void ProtoGraphBuilder::AddNamespace(const VName& package, 170 const Location& location) { 171 VName anchor = CreateAndAddAnchorNode(location); 172 AddNode(package, NodeKindID::kPackage); 173 AddEdge(anchor, package, EdgeKindID::kRef); 174 } 175 176 void ProtoGraphBuilder::AddValueToEnum(const VName& enum_type, 177 const VName& value, 178 const Location& location) { 179 VName anchor = CreateAndAddAnchorNode(location); 180 AddNode(value, NodeKindID::kVariable); 181 AddEdge(anchor, value, EdgeKindID::kDefinesBinding); 182 MaybeAddEdgeFromMetadata(location, value); 183 AddEdge(value, enum_type, EdgeKindID::kChildOf); 184 } 185 186 void ProtoGraphBuilder::AddFieldToMessage(const VName* parent, 187 const VName& message, 188 const VName* oneof, 189 const VName& field, 190 const Location& location) { 191 VName anchor = CreateAndAddAnchorNode(location); 192 AddNode(field, NodeKindID::kVariable); 193 recorder_->AddProperty(VNameRef(field), PropertyID::kSubkind, "field"); 194 AddEdge(anchor, field, EdgeKindID::kDefinesBinding); 195 MaybeAddEdgeFromMetadata(location, field); 196 if (parent != nullptr) { 197 AddEdge(field, *parent, EdgeKindID::kChildOf); 198 } 199 if (parent == nullptr || !VNameEquals(message, *parent)) { 200 // Extension; add an edge to the message being extended. 201 AddEdge(field, message, EdgeKindID::kExtends); 202 } 203 if (oneof != nullptr) { 204 AddEdge(field, *oneof, EdgeKindID::kChildOf); 205 } 206 } 207 208 void ProtoGraphBuilder::AddOneofToMessage(const VName& message, 209 const VName& oneof, 210 const Location& location) { 211 VName anchor = CreateAndAddAnchorNode(location); 212 AddNode(oneof, NodeKindID::kSum); 213 AddEdge(anchor, oneof, EdgeKindID::kDefinesBinding); 214 MaybeAddEdgeFromMetadata(location, oneof); 215 AddEdge(oneof, message, EdgeKindID::kChildOf); 216 } 217 218 void ProtoGraphBuilder::AddMethodToService(const VName& service, 219 const VName& method, 220 const Location& location) { 221 VName anchor = CreateAndAddAnchorNode(location); 222 AddNode(method, NodeKindID::kFunction); 223 AddEdge(anchor, method, EdgeKindID::kDefinesBinding); 224 MaybeAddEdgeFromMetadata(location, method); 225 AddEdge(method, service, EdgeKindID::kChildOf); 226 } 227 228 void ProtoGraphBuilder::AddMethodType(const VName& method, const VName& input, 229 const VName& output) { 230 if (!builtin_rpc_type_emitted_) { 231 AddNode(builtin_rpc_type_constructor_, NodeKindID::kTBuiltin); 232 builtin_rpc_type_emitted_ = true; 233 } 234 235 VName method_type = method; 236 method_type.set_signature(absl::StrCat("type::", method.signature(), 237 "::", output.signature(), 238 "::", input.signature())); 239 AddNode(method_type, NodeKindID::kTApp); 240 AddEdge(method_type, builtin_rpc_type_constructor_, EdgeKindID::kParam, 0); 241 AddEdge(method_type, output, EdgeKindID::kParam, 1); 242 AddEdge(method_type, input, EdgeKindID::kParam, 2); 243 244 AddEdge(method, method_type, EdgeKindID::kHasType); 245 } 246 247 void ProtoGraphBuilder::AddEnumType(const VName* parent, const VName& enum_type, 248 const Location& location) { 249 VName anchor = CreateAndAddAnchorNode(location); 250 AddNode(enum_type, NodeKindID::kSum); 251 AddEdge(anchor, enum_type, EdgeKindID::kDefinesBinding); 252 MaybeAddEdgeFromMetadata(location, enum_type); 253 if (parent != nullptr) { 254 AddEdge(enum_type, *parent, EdgeKindID::kChildOf); 255 } 256 } 257 258 void ProtoGraphBuilder::AddMessageType(const VName* parent, 259 const VName& message, 260 const Location& location) { 261 VName anchor = CreateAndAddAnchorNode(location); 262 AddNode(message, NodeKindID::kRecord); 263 AddEdge(anchor, message, EdgeKindID::kDefinesBinding); 264 MaybeAddEdgeFromMetadata(location, message); 265 if (parent != nullptr) { 266 AddEdge(message, *parent, EdgeKindID::kChildOf); 267 } 268 } 269 270 void ProtoGraphBuilder::AddReference(const VName& referent, 271 const Location& location) { 272 VName anchor = CreateAndAddAnchorNode(location); 273 AddEdge(anchor, referent, EdgeKindID::kRef); 274 } 275 276 void ProtoGraphBuilder::AddTyping(const VName& term, const VName& type) { 277 AddEdge(term, type, EdgeKindID::kHasType); 278 } 279 280 void ProtoGraphBuilder::AddService(const VName* parent, const VName& service, 281 const Location& location) { 282 VName anchor = CreateAndAddAnchorNode(location); 283 AddNode(service, NodeKindID::kInterface); 284 AddEdge(anchor, service, EdgeKindID::kDefinesBinding); 285 MaybeAddEdgeFromMetadata(location, service); 286 if (parent != nullptr) { 287 AddEdge(service, *parent, EdgeKindID::kChildOf); 288 } 289 } 290 291 void ProtoGraphBuilder::AddDocComment(const VName& element, 292 const Location& location) { 293 VName doc = CreateAndAddDocNode(location, element); 294 AddEdge(doc, element, EdgeKindID::kDocuments); 295 } 296 297 void ProtoGraphBuilder::AddCodeFact(const VName& element, 298 const MarkedSource& code) { 299 recorder_->AddMarkedSource(VNameRef(element), code); 300 } 301 302 void ProtoGraphBuilder::SetDeprecated(const VName& node_name) { 303 VLOG(1) << "Adding deprecation tag for " << StringifyNode(node_name); 304 recorder_->AddProperty(VNameRef(node_name), kythe::PropertyID::kTagDeprecated, 305 ""); 306 } 307 308 } // namespace kythe