Skip to content

Commit

Permalink
feat(cxx_indexer): support ++ and -- for influence and r/w refs (#4908)
Browse files Browse the repository at this point in the history
* feat(cxx_indexer): support ++ and -- for influence and r/w refs
  • Loading branch information
zrlk committed May 5, 2021
1 parent 9035307 commit fe3b10d
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 28 deletions.
4 changes: 3 additions & 1 deletion kythe/cxx/indexer/cxx/GraphObserver.h
Expand Up @@ -834,7 +834,9 @@ class GraphObserver {
/// No specific determination. Similar to a read.
kUnknown,
/// This use site is a write.
kWrite
kWrite,
/// This use site is both a read and a write.
kReadWrite,
};

/// \brief Records a use site for some decl with additional semantic
Expand Down
33 changes: 26 additions & 7 deletions kythe/cxx/indexer/cxx/IndexerASTHooks.cc
Expand Up @@ -1330,10 +1330,8 @@ bool IndexerASTVisitor::VisitMemberExpr(const clang::MemberExpr* E) {
auto StmtId = BuildNodeIdForImplicitStmt(E);
if (auto RCC = RangeInCurrentContext(StmtId, Range)) {
RecordBlame(FieldDecl, *RCC);
auto semantic = IsUsedAsWrite(E) ? GraphObserver::UseKind::kWrite
: GraphObserver::UseKind::kUnknown;
Observer.recordSemanticDeclUseLocation(
*RCC, BuildNodeIdForRefToDecl(FieldDecl), semantic,
*RCC, BuildNodeIdForRefToDecl(FieldDecl), UseKindFor(E),
GraphObserver::Claimability::Unclaimable, IsImplicit(*RCC));
if (E->hasExplicitTemplateArgs()) {
// We still want to link the template args.
Expand Down Expand Up @@ -2169,6 +2167,29 @@ bool IndexerASTVisitor::TraverseBinaryOperator(clang::BinaryOperator* BO) {
return Base::TraverseBinaryOperator(BO);
}

bool IndexerASTVisitor::TraverseUnaryOperator(clang::UnaryOperator* UO) {
if (!DataflowEdges) {
return Base::TraverseUnaryOperator(UO);
}
if (UO->getOpcode() != clang::UO_PostDec &&
UO->getOpcode() != clang::UO_PreDec &&
UO->getOpcode() != clang::UO_PostInc &&
UO->getOpcode() != clang::UO_PreInc) {
return Base::TraverseUnaryOperator(UO);
}
if (auto* lval = UO->getSubExpr(); lval != nullptr) {
if (!WalkUpFromUnaryOperator(UO)) return false;
auto* lvhead = UsedAsReadWrite(FindLValueHead(lval));
if (!TraverseStmt(lval)) return false;
if (auto* influenced = GetInfluencedDeclFromLValueHead(lvhead)) {
Observer.recordInfluences(BuildNodeIdForDecl(influenced),
BuildNodeIdForDecl(influenced));
}
return true;
}
return Base::TraverseUnaryOperator(UO);
}

bool IndexerASTVisitor::TraverseInitListExpr(clang::InitListExpr* ILE) {
if (ILE == nullptr) return true;
// Because we visit implicit code, the default traversal will visit both
Expand Down Expand Up @@ -2267,8 +2288,6 @@ bool IndexerASTVisitor::VisitDeclRefOrIvarRefExpr(
if (auto RCC = RangeInCurrentContext(StmtId, Range)) {
GraphObserver::NodeId DeclId = BuildNodeIdForRefToDecl(FoundDecl);
RecordBlame(FoundDecl, *RCC);
auto semantic = IsUsedAsWrite(Expr) ? GraphObserver::UseKind::kWrite
: GraphObserver::UseKind::kUnknown;
if (DataflowEdges) {
if (!Job->InfluenceSets.empty() &&
(FoundDecl->getKind() == clang::Decl::Kind::Var ||
Expand All @@ -2277,8 +2296,8 @@ bool IndexerASTVisitor::VisitDeclRefOrIvarRefExpr(
}
}
Observer.recordSemanticDeclUseLocation(
*RCC, DeclId, semantic, GraphObserver::Claimability::Unclaimable,
this->IsImplicit(*RCC));
*RCC, DeclId, UseKindFor(Expr),
GraphObserver::Claimability::Unclaimable, this->IsImplicit(*RCC));
for (const auto& S : Supports) {
S->InspectDeclRef(*this, SL, *RCC, DeclId, FoundDecl);
}
Expand Down
21 changes: 15 additions & 6 deletions kythe/cxx/indexer/cxx/IndexerASTHooks.h
Expand Up @@ -26,6 +26,7 @@

#include "GraphObserver.h"
#include "IndexerLibrarySupport.h"
#include "absl/container/flat_hash_map.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
Expand Down Expand Up @@ -134,6 +135,7 @@ class IndexerASTVisitor : public RecursiveTypeVisitor<IndexerASTVisitor> {
bool TraverseCallExpr(clang::CallExpr* CE);
bool TraverseReturnStmt(clang::ReturnStmt* RS);
bool TraverseBinaryOperator(clang::BinaryOperator* BO);
bool TraverseUnaryOperator(clang::UnaryOperator* BO);

bool TraverseInitListExpr(clang::InitListExpr* ILE);
bool VisitInitListExpr(const clang::InitListExpr* ILE);
Expand Down Expand Up @@ -969,15 +971,22 @@ class IndexerASTVisitor : public RecursiveTypeVisitor<IndexerASTVisitor> {
/// \brief Returns whether `Decl` should be indexed.
bool ShouldIndex(const clang::Decl* Decl);

/// \brief Returns whether `stmt` is used as a write target.
bool IsUsedAsWrite(const clang::Stmt* stmt) {
return is_used_as_write_.find(stmt) != is_used_as_write_.end();
GraphObserver::UseKind UseKindFor(const clang::Stmt* stmt) {
auto i = use_kinds_.find(stmt);
return i == use_kinds_.end() ? GraphObserver::UseKind::kUnknown : i->second;
}

/// \brief Marks that `stmt` was used as a write target.
/// \return `stmt` as passed.
const clang::Stmt* UsedAsWrite(const clang::Stmt* stmt) {
if (stmt != nullptr) is_used_as_write_.insert(stmt);
if (stmt != nullptr) use_kinds_[stmt] = GraphObserver::UseKind::kWrite;
return stmt;
}

/// \brief Marks that `stmt` was used as a read+write target.
/// \return `stmt` as passed.
const clang::Stmt* UsedAsReadWrite(const clang::Stmt* stmt) {
if (stmt != nullptr) use_kinds_[stmt] = GraphObserver::UseKind::kReadWrite;
return stmt;
}

Expand Down Expand Up @@ -1024,8 +1033,8 @@ class IndexerASTVisitor : public RecursiveTypeVisitor<IndexerASTVisitor> {
/// it should be excluded from template instance indexing.
std::shared_ptr<re2::RE2> TemplateInstanceExcludePathPattern = nullptr;

/// \brief AST nodes we know are used in a write context.
absl::flat_hash_set<const clang::Stmt*> is_used_as_write_;
/// \brief AST nodes we know are used in specific ways.
absl::flat_hash_map<const clang::Stmt*, GraphObserver::UseKind> use_kinds_;
};

/// \brief An `ASTConsumer` that passes events to a `GraphObserver`.
Expand Down
28 changes: 14 additions & 14 deletions kythe/cxx/indexer/cxx/KytheGraphObserver.cc
Expand Up @@ -63,19 +63,6 @@ struct ClaimedStringFormatter {
absl::string_view ConvertRef(llvm::StringRef ref) {
return absl::string_view(ref.data(), ref.size());
}

EdgeKindID EdgeKindForUseKind(GraphObserver::UseKind kind,
GraphObserver::Implicit i) {
switch (kind) {
case GraphObserver::UseKind::kUnknown:
return (i == GraphObserver::Implicit::Yes ? EdgeKindID::kRefImplicit
: EdgeKindID::kRef);
case GraphObserver::UseKind::kWrite:
return (i == GraphObserver::Implicit::Yes ? EdgeKindID::kRefWritesImplicit
: EdgeKindID::kRefWrites);
}
}

} // anonymous namespace

using clang::SourceLocation;
Expand Down Expand Up @@ -1093,7 +1080,20 @@ void KytheGraphObserver::recordBlameLocation(
void KytheGraphObserver::recordSemanticDeclUseLocation(
const GraphObserver::Range& source_range, const NodeId& node, UseKind kind,
Claimability claimability, Implicit i) {
RecordAnchor(source_range, node, EdgeKindForUseKind(kind, i), claimability);
if (kind == GraphObserver::UseKind::kUnknown ||
kind == GraphObserver::UseKind::kReadWrite) {
auto out_kind =
(i == GraphObserver::Implicit::Yes ? EdgeKindID::kRefImplicit
: EdgeKindID::kRef);
RecordAnchor(source_range, node, out_kind, claimability);
}
if (kind == GraphObserver::UseKind::kWrite ||
kind == GraphObserver::UseKind::kReadWrite) {
auto out_kind =
(i == GraphObserver::Implicit::Yes ? EdgeKindID::kRefWritesImplicit
: EdgeKindID::kRefWrites);
RecordAnchor(source_range, node, out_kind, claimability);
}
}

void KytheGraphObserver::recordInitLocation(
Expand Down
8 changes: 8 additions & 0 deletions kythe/cxx/indexer/cxx/testdata/BUILD
Expand Up @@ -3300,6 +3300,14 @@ cc_indexer_test(
tags = ["df"],
)

cc_indexer_test(
name = "df_unary",
srcs = ["df/df_unary.cc"],
experimental_record_dataflow_edges = True,
ignore_dups = True,
tags = ["df"],
)

cc_indexer_test(
name = "df_var_ref_blame",
srcs = ["df/df_var_ref_blame.cc"],
Expand Down
24 changes: 24 additions & 0 deletions kythe/cxx/indexer/cxx/testdata/df/df_unary.cc
@@ -0,0 +1,24 @@
// Unary {post,pre}{inc,dec}rements are included in the influence graph.
void f() {
int x, y, z;
//- @x ref VarX
//- @x ref/writes VarX
x++;
//- @x ref VarX
//- @x ref/writes VarX
++x;
//- @x ref VarX
//- @x ref/writes VarX
x--;
//- @x ref VarX
//- @x ref/writes VarX
--x;
//- VarX influences VarX
//- !{ @x ref/writes VarX }
//- !{ @z ref/writes VarZ }
//- !{ @y ref VarY }
//- @z ref VarZ
//- @x ref VarX
//- @y ref/writes VarY
y = x + z;
}

0 comments on commit fe3b10d

Please sign in to comment.