ymandel created this revision.
ymandel added a reviewer: ilya-biryukov.
ymandel added a project: clang.
Herald added subscribers: jfb, mgorny.

The standard matcher API uses StringRefs to identify bound nodes.  This patch
introduces a strong type thats allows distinguishing ids from arbitrary text in
APIs.  It additionally adds a templated version which can indicate the AST type
to which the id is bound.

This patch is the second in a series intended to improve the abstractions
available to users for writing source-to-source transformations.  A full
discussion of the end goal can be found on the cfe-dev list with subject "[RFC]
Easier source-to-source transformations with clang tooling".


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D59329

Files:
  clang/include/clang/Tooling/Refactoring/NodeId.h
  clang/lib/Tooling/Refactoring/CMakeLists.txt
  clang/lib/Tooling/Refactoring/NodeId.cpp

Index: clang/lib/Tooling/Refactoring/NodeId.cpp
===================================================================
--- /dev/null
+++ clang/lib/Tooling/Refactoring/NodeId.cpp
@@ -0,0 +1,27 @@
+//===--- NodeId.cpp - NodeId implementation ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/NodeId.h"
+#include <atomic>
+
+namespace clang {
+namespace tooling {
+
+// For guaranteeing unique ids on NodeId creation.
+static size_t nextId() {
+  // Start with a relatively high number to avoid bugs if the user mixes
+  // explicitly-numbered ids with those generated with `NextId()`. Similarly, we
+  // choose a number that allows generated ids to be easily recognized.
+  static std::atomic<size_t> Next(2222);
+  return Next.fetch_add(1, std::memory_order_relaxed);
+}
+
+NodeId::NodeId() : NodeId(nextId()) {}
+
+} // namespace tooling
+} // namespace clang
Index: clang/lib/Tooling/Refactoring/CMakeLists.txt
===================================================================
--- clang/lib/Tooling/Refactoring/CMakeLists.txt
+++ clang/lib/Tooling/Refactoring/CMakeLists.txt
@@ -12,6 +12,7 @@
   Rename/USRFinder.cpp
   Rename/USRFindingAction.cpp
   Rename/USRLocFinder.cpp
+  NodeId.cpp
 
   LINK_LIBS
   clangAST
Index: clang/include/clang/Tooling/Refactoring/NodeId.h
===================================================================
--- /dev/null
+++ clang/include/clang/Tooling/Refactoring/NodeId.h
@@ -0,0 +1,85 @@
+//===--- NodeId.h - NodeId class ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file defines abstractions for the bound identifiers used in AST
+/// matchers.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_NODE_ID_H_
+#define LLVM_CLANG_TOOLING_REFACTOR_NODE_ID_H_
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+namespace tooling {
+
+/// A strong type for AST node identifiers.  The standard API uses StringRefs
+/// for identifiers.  The strong type allows us to distinguish ids from
+/// arbitrary text snippets in various APIs.
+class NodeId {
+public:
+  explicit NodeId(std::string Id) : Id(std::move(Id)) {}
+
+  /// Creates a NodeId whose name is based on \p Id. Guarantees that unique ids
+  /// map to unique NodeIds.
+  explicit NodeId(size_t Id) : Id("id" + std::to_string(Id)) {}
+
+  /// Creates a NodeId with a generated name. The name is guaranteed to be
+  /// unique with respect to other generated names.
+  NodeId();
+
+  llvm::StringRef id() const { return Id; }
+
+  /// Gets the AST node in \p Result corresponding to this NodeId, if
+  /// any. Otherwise, returns null.
+  template <typename Node>
+  const Node *
+  getNodeAs(const ast_matchers::MatchFinder::MatchResult &Result) const {
+    return Result.Nodes.getNodeAs<Node>(Id);
+  }
+
+private:
+  std::string Id;
+};
+
+/// Refinement of NodeId that identifies the intended node type for the id. This
+/// additional information allows us to select appropriate overloads or
+/// constrain use of various combinators. It also allows us to distinguish when
+/// a \c Expr node is intended as a \c Stmt, which influences the intended
+/// source range for the node.  \p Node is the AST node type corresponding to
+/// this id.
+template <typename Node> class TypedNodeId : public NodeId {
+public:
+  using NodeId::NodeId;
+  using MatcherType = ast_matchers::internal::Matcher<Node>;
+
+  /// Creates a matcher corresponding to the AST-node type of this id and bound
+  /// to this id. Intended for settings where the type of matcher is
+  /// obvious/uninteresting. For example,
+  ///
+  ///   ExprId Arg;
+  ///   auto Matcher = callExpr(callee(isFunctionNamed("foo")),
+  ///                           hasArgument(0, Arg.bind()));
+  MatcherType bind() const {
+    return ast_matchers::internal::BindableMatcher<Node>(
+               ast_matchers::internal::TrueMatcher())
+        .bind(id());
+  }
+};
+
+using ExprId = TypedNodeId<Expr>;
+using StmtId = TypedNodeId<Stmt>;
+using DeclId = TypedNodeId<Decl>;
+using TypeId = TypedNodeId<Type>;
+
+} // namespace tooling
+} // namespace clang
+#endif // LLVM_CLANG_TOOLING_REFACTOR_NODE_ID_H_
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to