Skip to content

Commit

Permalink
feat(cxx_indexer): emit symbols for extern C function defns (kythe#6104)
Browse files Browse the repository at this point in the history
* feat(cxx_indexer): emit symbols for extern C function defns

Symbols for extern "C" function definitions are emitted
as name nodes in the symbol language. A function definition
node is `named` its name node. The name node uses the corpus
of the function it names. (The node kind, language, edge kind,
and edge direction are all up for discussion.)

* fix: symbol -> csymbol; condition csymbols on a flag
  • Loading branch information
zrlk authored Apr 18, 2024
1 parent 79907b6 commit 1a5bd22
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 1 deletion.
5 changes: 5 additions & 0 deletions kythe/cxx/indexer/cxx/GraphObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,11 @@ class GraphObserver {
virtual void assignUsr(const NodeId& Node, llvm::StringRef Usr,
int ByteSize) {}

/// \brief Assigns a link name to node.
/// \param node The target node.
/// \param name The link name for the node.
virtual void assignLinkName(const NodeId& node, llvm::StringRef name) {}

/// \brief Describes whether an enum is scoped (`enum class`).
enum class EnumKind {
Scoped, ///< This enum is scoped (an `enum class`).
Expand Down
6 changes: 6 additions & 0 deletions kythe/cxx/indexer/cxx/IndexerASTHooks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3582,6 +3582,12 @@ bool IndexerASTVisitor::VisitFunctionDecl(clang::FunctionDecl* Decl) {
Subkind, std::nullopt);
Observer.recordMarkedSource(DeclNode, Marks.GenerateMarkedSource(DeclNode));
Observer.recordVisibility(DeclNode, Decl->getAccess());
if (options_.RecordCSymbols &&
Decl->getLanguageLinkage() == clang::LanguageLinkage::CLanguageLinkage &&
!mangle_context_->shouldMangleDeclName(Decl)) {
// extern "C" symbols are undecorated.
Observer.assignLinkName(DeclNode, Decl->getNameAsString());
}
AssignUSR(DeclNode, Decl);
for (const auto& S : Supports) {
S->InspectFunctionDecl(*this, DeclNode, Decl,
Expand Down
9 changes: 8 additions & 1 deletion kythe/cxx/indexer/cxx/IndexerASTHooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "absl/strings/string_view.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Mangle.h"
#include "clang/Sema/SemaConsumer.h"
#include "indexed_parent_map.h"
#include "indexer_worklist.h"
Expand Down Expand Up @@ -125,6 +126,8 @@ struct IndexerOptions {
std::shared_ptr<const re2::RE2> AnalysisExcludePathPattern = nullptr;
/// \brief If true, record types of variable initializers.
bool RecordVariableInitTypes = false;
/// \brief If true, record csymbols for certain decls.
bool RecordCSymbols = false;
};

/// \brief An AST visitor that extracts information for a translation unit and
Expand All @@ -149,7 +152,8 @@ class IndexerASTVisitor : public RecursiveTypeVisitor<IndexerASTVisitor> {
},
// These enums are intentionally compatible.
static_cast<SemanticHash::OnUnimplemented>(
options_.IgnoreUnimplemented)) {}
options_.IgnoreUnimplemented)),
mangle_context_(C.createMangleContext()) {}

bool VisitDecl(const clang::Decl* Decl);
bool TraverseFieldDecl(clang::FieldDecl* Decl);
Expand Down Expand Up @@ -1101,6 +1105,9 @@ class IndexerASTVisitor : public RecursiveTypeVisitor<IndexerASTVisitor> {

/// \brief Used for calculating semantic hashes.
SemanticHash Hash;

/// A name-mangling context for the current AST context.
std::unique_ptr<clang::MangleContext> mangle_context_;
};

/// \brief An `ASTConsumer` that passes events to a `GraphObserver`.
Expand Down
11 changes: 11 additions & 0 deletions kythe/cxx/indexer/cxx/KytheGraphObserver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,17 @@ void KytheGraphObserver::assignUsr(const NodeId& node, llvm::StringRef usr,
recorder_->AddEdge(usr_vname, EdgeKindID::kClangUsr, node_vname);
}

void KytheGraphObserver::assignLinkName(const NodeId& node,
llvm::StringRef name) {
VNameRef node_vname = VNameRefFromNodeId(node);
VNameRef linkname_vname;
linkname_vname.set_language("csymbol");
linkname_vname.set_corpus(node_vname.corpus());
linkname_vname.set_signature(name);
recorder_->AddProperty(linkname_vname, NodeKindID::kName);
recorder_->AddEdge(node_vname, EdgeKindID::kNamed, linkname_vname);
}

void KytheGraphObserver::recordFlatSource(const NodeId& node_id,
std::string_view source) {
VNameRef node_vname = VNameRefFromNodeId(node_id);
Expand Down
2 changes: 2 additions & 0 deletions kythe/cxx/indexer/cxx/KytheGraphObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ class KytheGraphObserver : public GraphObserver {
void assignUsr(const NodeId& node, llvm::StringRef usr,
int byte_size) override;

void assignLinkName(const NodeId& node, llvm::StringRef name) override;

void recordTVarNode(
const NodeId& node,
const std::optional<MarkedSource>& marked_source) override;
Expand Down
3 changes: 3 additions & 0 deletions kythe/cxx/indexer/cxx/KytheIndexerMain.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ ABSL_FLAG(bool, experimental_set_aliases_as_writes, false,
"Set protobuf aliases as writes.");
ABSL_FLAG(bool, experimental_record_variable_init_types, false,
"Record the types of variable initializers.");
ABSL_FLAG(bool, experimental_record_c_symbols, false,
"Record csymbols for certain decls.");

namespace kythe {
namespace {
Expand Down Expand Up @@ -123,6 +125,7 @@ int main(int argc, char* argv[]) {
};
options.RecordVariableInitTypes =
absl::GetFlag(FLAGS_experimental_record_variable_init_types);
options.RecordCSymbols = absl::GetFlag(FLAGS_experimental_record_c_symbols);
std::optional<FileHashRecorder> recorder;
if (!absl::GetFlag(FLAGS_record_hashes_file).empty()) {
recorder.emplace(absl::GetFlag(FLAGS_record_hashes_file));
Expand Down
26 changes: 26 additions & 0 deletions kythe/cxx/indexer/cxx/testdata/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,32 @@ cc_indexer_test(
use_compilation_corpus_as_default = True,
)

cc_write_kzip(
name = "extern_c_symbol_kzip",
srcs = ["basic/extern_c_symbol.cc"],
corpus = "unit",
vnames_config = "basic/vname_corpus.json",
)

cc_indexer_test(
name = "extern_c_symbol",
srcs = [":extern_c_symbol_kzip"],
check_for_singletons = True,
experimental_record_c_symbols = True,
ignore_dups = True,
ignore_unimplemented = True,
tags = ["basic"],
use_compilation_corpus_as_default = True,
)

cc_indexer_test(
name = "c_symbol",
srcs = ["basic/c_symbol.c"],
experimental_record_c_symbols = True,
std = "c99",
tags = ["basic"],
)

cc_indexer_test(
name = "vardecl_double_shadowed_local_anchor",
srcs = ["basic/vardecl_double_shadowed_local_anchor.cc"],
Expand Down
4 changes: 4 additions & 0 deletions kythe/cxx/indexer/cxx/testdata/basic/c_symbol.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// C functions are given names.
//- @f defines/binding FnF
//- FnF named vname("f","","","","csymbol")
void f() {}
10 changes: 10 additions & 0 deletions kythe/cxx/indexer/cxx/testdata/basic/extern_c_symbol.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// extern "C" function definitions are given names.
//- @f defines/binding FnF
//- !{ FnF named _ }
void f();
//- @g defines/binding FnG
//- FnG named vname("g","file","","","csymbol")
extern "C" void g() {}
//- @h defines/binding FnH
//- !{ FnH named _ }
extern "C" void h();
1 change: 1 addition & 0 deletions tools/build_rules/verifier_test/cc_indexer_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ _INDEXER_FLAGS = {
"record_call_directness": False,
"experimental_analysis_exclude_path_pattern": "",
"experimental_record_variable_init_types": False,
"experimental_record_c_symbols": False,
}

def _compiler_options(ctx, extractor_toolchain, copts, cc_info):
Expand Down

0 comments on commit 1a5bd22

Please sign in to comment.