diff --git a/clang/include/clang/Tooling/Refactoring/NodeId.h b/clang/include/clang/Tooling/Refactoring/NodeId.h new file mode 100644 --- /dev/null +++ b/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 + +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 + const Node * + getNodeAs(const ast_matchers::MatchFinder::MatchResult &Result) const { + return Result.Nodes.getNodeAs(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 class TypedNodeId : public NodeId { +public: + using NodeId::NodeId; + using MatcherType = ast_matchers::internal::Matcher; + + /// 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( + ast_matchers::internal::TrueMatcher()) + .bind(id()); + } +}; + +using ExprId = TypedNodeId; +using StmtId = TypedNodeId; +using DeclId = TypedNodeId; +using TypeId = TypedNodeId; + +} // namespace tooling +} // namespace clang +#endif // LLVM_CLANG_TOOLING_REFACTOR_NODE_ID_H_ diff --git a/clang/lib/Tooling/Refactoring/CMakeLists.txt b/clang/lib/Tooling/Refactoring/CMakeLists.txt --- a/clang/lib/Tooling/Refactoring/CMakeLists.txt +++ b/clang/lib/Tooling/Refactoring/CMakeLists.txt @@ -12,6 +12,7 @@ Rename/USRFinder.cpp Rename/USRFindingAction.cpp Rename/USRLocFinder.cpp + NodeId.cpp LINK_LIBS clangAST diff --git a/clang/lib/Tooling/Refactoring/NodeId.cpp b/clang/lib/Tooling/Refactoring/NodeId.cpp new file mode 100644 --- /dev/null +++ b/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 + +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 Next(2222); + return Next.fetch_add(1, std::memory_order_relaxed); +} + +NodeId::NodeId() : NodeId(nextId()) {} + +} // namespace tooling +} // namespace clang