diff options
Diffstat (limited to 'include/clang/Tooling/Refactoring')
25 files changed, 712 insertions, 84 deletions
diff --git a/include/clang/Tooling/Refactoring/ASTSelection.h b/include/clang/Tooling/Refactoring/ASTSelection.h index aa02a6899e8fc..b87ed28b30ade 100644 --- a/include/clang/Tooling/Refactoring/ASTSelection.h +++ b/include/clang/Tooling/Refactoring/ASTSelection.h @@ -1,9 +1,8 @@ //===--- ASTSelection.h - Clang refactoring library -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/AtomicChange.h b/include/clang/Tooling/Refactoring/AtomicChange.h index bfe042fc53c52..32e4624fc8e78 100644 --- a/include/clang/Tooling/Refactoring/AtomicChange.h +++ b/include/clang/Tooling/Refactoring/AtomicChange.h @@ -1,9 +1,8 @@ //===--- AtomicChange.h - AtomicChange class --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/include/clang/Tooling/Refactoring/Extract/Extract.h b/include/clang/Tooling/Refactoring/Extract/Extract.h index 2fd76d252c62b..930991328ca0b 100644 --- a/include/clang/Tooling/Refactoring/Extract/Extract.h +++ b/include/clang/Tooling/Refactoring/Extract/Extract.h @@ -1,9 +1,8 @@ //===--- Extract.h - Clang refactoring library ----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RangeSelector.h b/include/clang/Tooling/Refactoring/RangeSelector.h new file mode 100644 index 0000000000000..b117e4d82ad46 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RangeSelector.h @@ -0,0 +1,89 @@ +//===--- RangeSelector.h - Source-selection library ---------*- 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 +/// Defines a combinator library supporting the definition of _selectors_, +/// which select source ranges based on (bound) AST nodes. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RANGE_SELECTOR_H_ +#define LLVM_CLANG_TOOLING_REFACTOR_RANGE_SELECTOR_H_ + +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/Error.h" +#include <functional> +#include <string> + +namespace clang { +namespace tooling { +using RangeSelector = std::function<Expected<CharSourceRange>( + const ast_matchers::MatchFinder::MatchResult &)>; + +inline RangeSelector charRange(CharSourceRange R) { + return [R](const ast_matchers::MatchFinder::MatchResult &) + -> Expected<CharSourceRange> { return R; }; +} + +/// Selects from the start of \p Begin and to the end of \p End. +RangeSelector range(RangeSelector Begin, RangeSelector End); + +/// Convenience version of \c range where end-points are bound nodes. +RangeSelector range(std::string BeginID, std::string EndID); + +/// Selects the (empty) range [B,B) when \p Selector selects the range [B,E). +RangeSelector before(RangeSelector Selector); + +/// Selects the the point immediately following \p Selector. That is, the +/// (empty) range [E,E), when \p Selector selects either +/// * the CharRange [B,E) or +/// * the TokenRange [B,E'] where the token at E' spans the range [E,E'). +RangeSelector after(RangeSelector Selector); + +/// Selects a node, including trailing semicolon (for non-expression +/// statements). \p ID is the node's binding in the match result. +RangeSelector node(std::string ID); + +/// Selects a node, including trailing semicolon (always). Useful for selecting +/// expression statements. \p ID is the node's binding in the match result. +RangeSelector statement(std::string ID); + +/// Given a \c MemberExpr, selects the member token. \p ID is the node's +/// binding in the match result. +RangeSelector member(std::string ID); + +/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr or \c +/// CxxCtorInitializer) selects the name's token. Only selects the final +/// identifier of a qualified name, but not any qualifiers or template +/// arguments. For example, for `::foo::bar::baz` and `::foo::bar::baz<int>`, +/// it selects only `baz`. +/// +/// \param ID is the node's binding in the match result. +RangeSelector name(std::string ID); + +// Given a \c CallExpr (bound to \p ID), selects the arguments' source text (all +// source between the call's parentheses). +RangeSelector callArgs(std::string ID); + +// Given a \c CompoundStmt (bound to \p ID), selects the source of the +// statements (all source between the braces). +RangeSelector statements(std::string ID); + +// Given a \c InitListExpr (bound to \p ID), selects the range of the elements +// (all source between the braces). +RangeSelector initListElements(std::string ID); + +/// Selects the range from which `S` was expanded (possibly along with other +/// source), if `S` is an expansion, and `S` itself, otherwise. Corresponds to +/// `SourceManager::getExpansionRange`. +RangeSelector expansion(RangeSelector S); +} // namespace tooling +} // namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RANGE_SELECTOR_H_ diff --git a/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h index bd314f03cd3a3..41a448f035a40 100644 --- a/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h +++ b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h @@ -1,9 +1,8 @@ //===--- RecursiveSymbolVisitor.h - Clang refactoring library -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/include/clang/Tooling/Refactoring/RefactoringAction.h b/include/clang/Tooling/Refactoring/RefactoringAction.h index c4080237f1c35..d4294ddb2f669 100644 --- a/include/clang/Tooling/Refactoring/RefactoringAction.h +++ b/include/clang/Tooling/Refactoring/RefactoringAction.h @@ -1,9 +1,8 @@ //===--- RefactoringAction.h - Clang refactoring library ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRule.h b/include/clang/Tooling/Refactoring/RefactoringActionRule.h index ce4a91cbbadce..0c6e38af381f0 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRule.h +++ b/include/clang/Tooling/Refactoring/RefactoringActionRule.h @@ -1,9 +1,8 @@ //===--- RefactoringActionRule.h - Clang refactoring library -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h index 355a6a55f22fd..6a6dd83731e97 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h +++ b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h @@ -1,9 +1,8 @@ //===--- RefactoringActionRuleRequirements.h - Clang refactoring library --===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRules.h b/include/clang/Tooling/Refactoring/RefactoringActionRules.h index 33206d9a5dd1e..e9606fd6018ee 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRules.h +++ b/include/clang/Tooling/Refactoring/RefactoringActionRules.h @@ -1,9 +1,8 @@ //===--- RefactoringActionRules.h - Clang refactoring library -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h index 75b6c8f70d173..cc6ae83202f15 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h +++ b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h @@ -1,9 +1,8 @@ //===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h b/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h index dc1d998396db2..967e7b5860ff2 100644 --- a/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h +++ b/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h @@ -1,9 +1,8 @@ //===--- RefactoringDiagnostic.h - ------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringOption.h b/include/clang/Tooling/Refactoring/RefactoringOption.h index 5011223cce690..659e02b48e5c2 100644 --- a/include/clang/Tooling/Refactoring/RefactoringOption.h +++ b/include/clang/Tooling/Refactoring/RefactoringOption.h @@ -1,9 +1,8 @@ //===--- RefactoringOption.h - Clang refactoring library ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h b/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h index aea8fa549392b..d58b11355a260 100644 --- a/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h +++ b/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h @@ -1,9 +1,8 @@ //===--- RefactoringOptionVisitor.h - Clang refactoring library -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringOptions.h b/include/clang/Tooling/Refactoring/RefactoringOptions.h index e45c0a09fd67b..f25f526e146cc 100644 --- a/include/clang/Tooling/Refactoring/RefactoringOptions.h +++ b/include/clang/Tooling/Refactoring/RefactoringOptions.h @@ -1,9 +1,8 @@ //===--- RefactoringOptions.h - Clang refactoring library -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h b/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h index 005eb877bf0fd..2035c02bc17ad 100644 --- a/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h +++ b/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h @@ -1,9 +1,8 @@ //===--- RefactoringResultConsumer.h - Clang refactoring library ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h index 882ab824b6390..5271a54075eab 100644 --- a/include/clang/Tooling/Refactoring/RefactoringRuleContext.h +++ b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h @@ -1,9 +1,8 @@ //===--- RefactoringRuleContext.h - Clang refactoring library -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/Rename/RenamingAction.h b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h index 5771a1c2d1328..b04bc3e2d2023 100644 --- a/include/clang/Tooling/Refactoring/Rename/RenamingAction.h +++ b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h @@ -1,9 +1,8 @@ //===--- RenamingAction.h - Clang refactoring library ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// @@ -55,6 +54,8 @@ public: static const RefactoringDescriptor &describe(); + const NamedDecl *getRenameDecl() const; + private: RenameOccurrences(const NamedDecl *ND, std::string NewName) : ND(ND), NewName(std::move(NewName)) {} diff --git a/include/clang/Tooling/Refactoring/Rename/SymbolName.h b/include/clang/Tooling/Refactoring/Rename/SymbolName.h index 42e0a5cb6697d..9131a4565da7d 100644 --- a/include/clang/Tooling/Refactoring/Rename/SymbolName.h +++ b/include/clang/Tooling/Refactoring/Rename/SymbolName.h @@ -1,9 +1,8 @@ //===--- SymbolName.h - Clang refactoring library -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h b/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h index 0f853011978f1..3b903cb822f39 100644 --- a/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h +++ b/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h @@ -1,9 +1,8 @@ //===--- SymbolOccurrences.h - Clang refactoring library ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/clang/Tooling/Refactoring/Rename/USRFinder.h b/include/clang/Tooling/Refactoring/Rename/USRFinder.h index 3622bd0daf855..30f7f0a0008cf 100644 --- a/include/clang/Tooling/Refactoring/Rename/USRFinder.h +++ b/include/clang/Tooling/Refactoring/Rename/USRFinder.h @@ -1,9 +1,8 @@ //===--- USRFinder.h - Clang refactoring library --------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h b/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h index ebc9790e9cb63..726987d9d46ac 100644 --- a/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h +++ b/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h @@ -1,9 +1,8 @@ //===--- USRFindingAction.h - Clang refactoring library -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h b/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h index e1228e9f39f76..7a7dd76c4238f 100644 --- a/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h +++ b/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h @@ -1,9 +1,8 @@ //===--- USRLocFinder.h - Clang refactoring library -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/include/clang/Tooling/Refactoring/SourceCode.h b/include/clang/Tooling/Refactoring/SourceCode.h new file mode 100644 index 0000000000000..498dbea96c701 --- /dev/null +++ b/include/clang/Tooling/Refactoring/SourceCode.h @@ -0,0 +1,77 @@ +//===--- SourceCode.h - Source code manipulation routines -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides functions that simplify extraction of source code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H +#define LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H + +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TokenKinds.h" + +namespace clang { +namespace tooling { + +/// Extends \p Range to include the token \p Next, if it immediately follows the +/// end of the range. Otherwise, returns \p Range unchanged. +CharSourceRange maybeExtendRange(CharSourceRange Range, tok::TokenKind Next, + ASTContext &Context); + +/// Returns the source range spanning the node, extended to include \p Next, if +/// it immediately follows \p Node. Otherwise, returns the normal range of \p +/// Node. See comments on `getExtendedText()` for examples. +template <typename T> +CharSourceRange getExtendedRange(const T &Node, tok::TokenKind Next, + ASTContext &Context) { + return maybeExtendRange(CharSourceRange::getTokenRange(Node.getSourceRange()), + Next, Context); +} + +/// Returns the source-code text in the specified range. +StringRef getText(CharSourceRange Range, const ASTContext &Context); + +/// Returns the source-code text corresponding to \p Node. +template <typename T> +StringRef getText(const T &Node, const ASTContext &Context) { + return getText(CharSourceRange::getTokenRange(Node.getSourceRange()), + Context); +} + +/// Returns the source text of the node, extended to include \p Next, if it +/// immediately follows the node. Otherwise, returns the text of just \p Node. +/// +/// For example, given statements S1 and S2 below: +/// \code +/// { +/// // S1: +/// if (!x) return foo(); +/// // S2: +/// if (!x) { return 3; } +/// } +/// \endcode +/// then +/// \code +/// getText(S1, Context) = "if (!x) return foo()" +/// getExtendedText(S1, tok::TokenKind::semi, Context) +/// = "if (!x) return foo();" +/// getExtendedText(*S1.getThen(), tok::TokenKind::semi, Context) +/// = "return foo();" +/// getExtendedText(*S2.getThen(), tok::TokenKind::semi, Context) +/// = getText(S2, Context) = "{ return 3; }" +/// \endcode +template <typename T> +StringRef getExtendedText(const T &Node, tok::TokenKind Next, + ASTContext &Context) { + return getText(getExtendedRange(Node, Next, Context), Context); +} +} // namespace tooling +} // namespace clang +#endif // LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H diff --git a/include/clang/Tooling/Refactoring/Stencil.h b/include/clang/Tooling/Refactoring/Stencil.h new file mode 100644 index 0000000000000..e57a576e55755 --- /dev/null +++ b/include/clang/Tooling/Refactoring/Stencil.h @@ -0,0 +1,173 @@ +//===--- Stencil.h - Stencil 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 the *Stencil* abstraction: a code-generating object, +/// parameterized by named references to (bound) AST nodes. Given a match +/// result, a stencil can be evaluated to a string of source code. +/// +/// A stencil is similar in spirit to a format string: it is composed of a +/// series of raw text strings, references to nodes (the parameters) and helper +/// code-generation operations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_ +#define LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_ + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Refactoring/RangeSelector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// A stencil is represented as a sequence of "parts" that can each individually +/// generate a code string based on a match result. The different kinds of +/// parts include (raw) text, references to bound nodes and assorted operations +/// on bound nodes. +/// +/// Users can create custom Stencil operations by implementing this interface. +class StencilPartInterface { +public: + virtual ~StencilPartInterface() = default; + + /// Evaluates this part to a string and appends it to \c Result. \c Result is + /// undefined in the case of an error. + virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match, + std::string *Result) const = 0; + + virtual bool isEqual(const StencilPartInterface &other) const = 0; + + const void *typeId() const { return TypeId; } + +protected: + StencilPartInterface(const void *DerivedId) : TypeId(DerivedId) {} + + // Since this is an abstract class, copying/assigning only make sense for + // derived classes implementing `clone()`. + StencilPartInterface(const StencilPartInterface &) = default; + StencilPartInterface &operator=(const StencilPartInterface &) = default; + + /// Unique identifier of the concrete type of this instance. Supports safe + /// downcasting. + const void *TypeId; +}; + +/// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result +/// in a copy of the underlying pointee object. +class StencilPart { +public: + explicit StencilPart(std::shared_ptr<StencilPartInterface> Impl) + : Impl(std::move(Impl)) {} + + /// See `StencilPartInterface::eval()`. + llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match, + std::string *Result) const { + return Impl->eval(Match, Result); + } + + bool operator==(const StencilPart &Other) const { + if (Impl == Other.Impl) + return true; + if (Impl == nullptr || Other.Impl == nullptr) + return false; + return Impl->isEqual(*Other.Impl); + } + +private: + std::shared_ptr<StencilPartInterface> Impl; +}; + +/// A sequence of code fragments, references to parameters and code-generation +/// operations that together can be evaluated to (a fragment of) source code, +/// given a match result. +class Stencil { +public: + Stencil() = default; + + /// Composes a stencil from a series of parts. + template <typename... Ts> static Stencil cat(Ts &&... Parts) { + Stencil S; + S.Parts = {wrap(std::forward<Ts>(Parts))...}; + return S; + } + + /// Appends data from a \p OtherStencil to this stencil. + void append(Stencil OtherStencil); + + // Evaluates the stencil given a match result. Requires that the nodes in the + // result includes any ids referenced in the stencil. References to missing + // nodes will result in an invalid_argument error. + llvm::Expected<std::string> + eval(const ast_matchers::MatchFinder::MatchResult &Match) const; + + // Allow Stencils to operate as std::function, for compatibility with + // Transformer's TextGenerator. + llvm::Expected<std::string> + operator()(const ast_matchers::MatchFinder::MatchResult &Result) const { + return eval(Result); + } + +private: + friend bool operator==(const Stencil &A, const Stencil &B); + static StencilPart wrap(llvm::StringRef Text); + static StencilPart wrap(RangeSelector Selector); + static StencilPart wrap(StencilPart Part) { return Part; } + + std::vector<StencilPart> Parts; +}; + +inline bool operator==(const Stencil &A, const Stencil &B) { + return A.Parts == B.Parts; +} + +inline bool operator!=(const Stencil &A, const Stencil &B) { return !(A == B); } + +// Functions for conveniently building stencils. +namespace stencil { +/// Convenience wrapper for Stencil::cat that can be imported with a using decl. +template <typename... Ts> Stencil cat(Ts &&... Parts) { + return Stencil::cat(std::forward<Ts>(Parts)...); +} + +/// \returns exactly the text provided. +StencilPart text(llvm::StringRef Text); + +/// \returns the source corresponding to the selected range. +StencilPart selection(RangeSelector Selector); + +/// \returns the source corresponding to the identified node. +/// FIXME: Deprecated. Write `selection(node(Id))` instead. +inline StencilPart node(llvm::StringRef Id) { + return selection(tooling::node(Id)); +} + +/// Variant of \c node() that identifies the node as a statement, for purposes +/// of deciding whether to include any trailing semicolon. Only relevant for +/// Expr nodes, which, by default, are *not* considered as statements. +/// \returns the source corresponding to the identified node, considered as a +/// statement. +/// FIXME: Deprecated. Write `selection(statement(Id))` instead. +inline StencilPart sNode(llvm::StringRef Id) { + return selection(tooling::statement(Id)); +} + +/// For debug use only; semantics are not guaranteed. +/// +/// \returns the string resulting from calling the node's print() method. +StencilPart dPrint(llvm::StringRef Id); +} // namespace stencil +} // namespace tooling +} // namespace clang +#endif // LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_ diff --git a/include/clang/Tooling/Refactoring/Transformer.h b/include/clang/Tooling/Refactoring/Transformer.h new file mode 100644 index 0000000000000..6d9c5a37cc18f --- /dev/null +++ b/include/clang/Tooling/Refactoring/Transformer.h @@ -0,0 +1,308 @@ +//===--- Transformer.h - Clang source-rewriting library ---------*- 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 +/// Defines a library supporting the concise specification of clang-based +/// source-to-source transformations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_TRANSFORMER_H_ +#define LLVM_CLANG_TOOLING_REFACTOR_TRANSFORMER_H_ + +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/RangeSelector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Error.h" +#include <deque> +#include <functional> +#include <string> +#include <type_traits> +#include <utility> + +namespace clang { +namespace tooling { + +// Note that \p TextGenerator is allowed to fail, e.g. when trying to access a +// matched node that was not bound. Allowing this to fail simplifies error +// handling for interactive tools like clang-query. +using TextGenerator = std::function<Expected<std::string>( + const ast_matchers::MatchFinder::MatchResult &)>; + +/// Wraps a string as a TextGenerator. +inline TextGenerator text(std::string M) { + return [M](const ast_matchers::MatchFinder::MatchResult &) + -> Expected<std::string> { return M; }; +} + +// Description of a source-code edit, expressed in terms of an AST node. +// Includes: an ID for the (bound) node, a selector for source related to the +// node, a replacement and, optionally, an explanation for the edit. +// +// * Target: the source code impacted by the rule. This identifies an AST node, +// or part thereof (\c Part), whose source range indicates the extent of the +// replacement applied by the replacement term. By default, the extent is the +// node matched by the pattern term (\c NodePart::Node). Target's are typed +// (\c Kind), which guides the determination of the node extent. +// +// * Replacement: a function that produces a replacement string for the target, +// based on the match result. +// +// * Note: (optional) a note specifically for this edit, potentially referencing +// elements of the match. This will be displayed to the user, where possible; +// for example, in clang-tidy diagnostics. Use of notes should be rare -- +// explanations of the entire rewrite should be set in the rule +// (`RewriteRule::Explanation`) instead. Notes serve the rare cases wherein +// edit-specific diagnostics are required. +// +// `ASTEdit` should be built using the `change` convenience functions. For +// example, +// \code +// change(name(fun), text("Frodo")) +// \endcode +// Or, if we use Stencil for the TextGenerator: +// \code +// using stencil::cat; +// change(statement(thenNode), cat("{", thenNode, "}")) +// change(callArgs(call), cat(x, ",", y)) +// \endcode +// Or, if you are changing the node corresponding to the rule's matcher, you can +// use the single-argument override of \c change: +// \code +// change(cat("different_expr")) +// \endcode +struct ASTEdit { + RangeSelector TargetRange; + TextGenerator Replacement; + TextGenerator Note; +}; + +/// Format of the path in an include directive -- angle brackets or quotes. +enum class IncludeFormat { + Quoted, + Angled, +}; + +/// Description of a source-code transformation. +// +// A *rewrite rule* describes a transformation of source code. A simple rule +// contains each of the following components: +// +// * Matcher: the pattern term, expressed as clang matchers (with Transformer +// extensions). +// +// * Edits: a set of Edits to the source code, described with ASTEdits. +// +// * Explanation: explanation of the rewrite. This will be displayed to the +// user, where possible; for example, in clang-tidy diagnostics. +// +// However, rules can also consist of (sub)rules, where the first that matches +// is applied and the rest are ignored. So, the above components are gathered +// as a `Case` and a rule is a list of cases. +// +// Rule cases have an additional, implicit, component: the parameters. These are +// portions of the pattern which are left unspecified, yet bound in the pattern +// so that we can reference them in the edits. +// +// The \c Transformer class can be used to apply the rewrite rule and obtain the +// corresponding replacements. +struct RewriteRule { + struct Case { + ast_matchers::internal::DynTypedMatcher Matcher; + SmallVector<ASTEdit, 1> Edits; + TextGenerator Explanation; + // Include paths to add to the file affected by this case. These are + // bundled with the `Case`, rather than the `RewriteRule`, because each case + // might have different associated changes to the includes. + std::vector<std::pair<std::string, IncludeFormat>> AddedIncludes; + }; + // We expect RewriteRules will most commonly include only one case. + SmallVector<Case, 1> Cases; + + // ID used as the default target of each match. The node described by the + // matcher is should always be bound to this id. + static constexpr llvm::StringLiteral RootID = "___root___"; +}; + +/// Convenience function for constructing a simple \c RewriteRule. +RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, + SmallVector<ASTEdit, 1> Edits, + TextGenerator Explanation = nullptr); + +/// Convenience overload of \c makeRule for common case of only one edit. +inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, + ASTEdit Edit, + TextGenerator Explanation = nullptr) { + SmallVector<ASTEdit, 1> Edits; + Edits.emplace_back(std::move(Edit)); + return makeRule(std::move(M), std::move(Edits), std::move(Explanation)); +} + +/// For every case in Rule, adds an include directive for the given header. The +/// common use is assumed to be a rule with only one case. For example, to +/// replace a function call and add headers corresponding to the new code, one +/// could write: +/// \code +/// auto R = makeRule(callExpr(callee(functionDecl(hasName("foo")))), +/// change(text("bar()"))); +/// AddInclude(R, "path/to/bar_header.h"); +/// AddInclude(R, "vector", IncludeFormat::Angled); +/// \endcode +void addInclude(RewriteRule &Rule, llvm::StringRef Header, + IncludeFormat Format = IncludeFormat::Quoted); + +/// Applies the first rule whose pattern matches; other rules are ignored. +/// +/// N.B. All of the rules must use the same kind of matcher (that is, share a +/// base class in the AST hierarchy). However, this constraint is caused by an +/// implementation detail and should be lifted in the future. +// +// `applyFirst` is like an `anyOf` matcher with an edit action attached to each +// of its cases. Anywhere you'd use `anyOf(m1.bind("id1"), m2.bind("id2"))` and +// then dispatch on those ids in your code for control flow, `applyFirst` lifts +// that behavior to the rule level. So, you can write `applyFirst({makeRule(m1, +// action1), makeRule(m2, action2), ...});` +// +// For example, consider a type `T` with a deterministic serialization function, +// `serialize()`. For performance reasons, we would like to make it +// non-deterministic. Therefore, we want to drop the expectation that +// `a.serialize() = b.serialize() iff a = b` (although we'll maintain +// `deserialize(a.serialize()) = a`). +// +// We have three cases to consider (for some equality function, `eq`): +// ``` +// eq(a.serialize(), b.serialize()) --> eq(a,b) +// eq(a, b.serialize()) --> eq(deserialize(a), b) +// eq(a.serialize(), b) --> eq(a, deserialize(b)) +// ``` +// +// `applyFirst` allows us to specify each independently: +// ``` +// auto eq_fun = functionDecl(...); +// auto method_call = cxxMemberCallExpr(...); +// +// auto two_calls = callExpr(callee(eq_fun), hasArgument(0, method_call), +// hasArgument(1, method_call)); +// auto left_call = +// callExpr(callee(eq_fun), callExpr(hasArgument(0, method_call))); +// auto right_call = +// callExpr(callee(eq_fun), callExpr(hasArgument(1, method_call))); +// +// RewriteRule R = applyFirst({makeRule(two_calls, two_calls_action), +// makeRule(left_call, left_call_action), +// makeRule(right_call, right_call_action)}); +// ``` +RewriteRule applyFirst(ArrayRef<RewriteRule> Rules); + +/// Replaces a portion of the source text with \p Replacement. +ASTEdit change(RangeSelector Target, TextGenerator Replacement); + +/// Replaces the entirety of a RewriteRule's match with \p Replacement. For +/// example, to replace a function call, one could write: +/// \code +/// makeRule(callExpr(callee(functionDecl(hasName("foo")))), +/// change(text("bar()"))) +/// \endcode +inline ASTEdit change(TextGenerator Replacement) { + return change(node(RewriteRule::RootID), std::move(Replacement)); +} + +/// Inserts \p Replacement before \p S, leaving the source selected by \S +/// unchanged. +inline ASTEdit insertBefore(RangeSelector S, TextGenerator Replacement) { + return change(before(std::move(S)), std::move(Replacement)); +} + +/// Inserts \p Replacement after \p S, leaving the source selected by \S +/// unchanged. +inline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) { + return change(after(std::move(S)), std::move(Replacement)); +} + +/// Removes the source selected by \p S. +inline ASTEdit remove(RangeSelector S) { + return change(std::move(S), text("")); +} + +/// The following three functions are a low-level part of the RewriteRule +/// API. We expose them for use in implementing the fixtures that interpret +/// RewriteRule, like Transformer and TransfomerTidy, or for more advanced +/// users. +// +// FIXME: These functions are really public, if advanced, elements of the +// RewriteRule API. Recast them as such. Or, just declare these functions +// public and well-supported and move them out of `detail`. +namespace detail { +/// Builds a single matcher for the rule, covering all of the rule's cases. +ast_matchers::internal::DynTypedMatcher buildMatcher(const RewriteRule &Rule); + +/// Returns the \c Case of \c Rule that was selected in the match result. +/// Assumes a matcher built with \c buildMatcher. +const RewriteRule::Case & +findSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result, + const RewriteRule &Rule); + +/// A source "transformation," represented by a character range in the source to +/// be replaced and a corresponding replacement string. +struct Transformation { + CharSourceRange Range; + std::string Replacement; +}; + +/// Attempts to translate `Edits`, which are in terms of AST nodes bound in the +/// match `Result`, into Transformations, which are in terms of the source code +/// text. +/// +/// Returns an empty vector if any of the edits apply to portions of the source +/// that are ineligible for rewriting (certain interactions with macros, for +/// example). Fails if any invariants are violated relating to bound nodes in +/// the match. However, it does not fail in the case of conflicting edits -- +/// conflict handling is left to clients. We recommend use of the \c +/// AtomicChange or \c Replacements classes for assistance in detecting such +/// conflicts. +Expected<SmallVector<Transformation, 1>> +translateEdits(const ast_matchers::MatchFinder::MatchResult &Result, + llvm::ArrayRef<ASTEdit> Edits); +} // namespace detail + +/// Handles the matcher and callback registration for a single rewrite rule, as +/// defined by the arguments of the constructor. +class Transformer : public ast_matchers::MatchFinder::MatchCallback { +public: + using ChangeConsumer = + std::function<void(Expected<clang::tooling::AtomicChange> Change)>; + + /// \param Consumer Receives each rewrite or error. Will not necessarily be + /// called for each match; for example, if the rewrite is not applicable + /// because of macros, but doesn't fail. Note that clients are responsible + /// for handling the case that independent \c AtomicChanges conflict with each + /// other. + Transformer(RewriteRule Rule, ChangeConsumer Consumer) + : Rule(std::move(Rule)), Consumer(std::move(Consumer)) {} + + /// N.B. Passes `this` pointer to `MatchFinder`. So, this object should not + /// be moved after this call. + void registerMatchers(ast_matchers::MatchFinder *MatchFinder); + + /// Not called directly by users -- called by the framework, via base class + /// pointer. + void run(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + RewriteRule Rule; + /// Receives each successful rewrites as an \c AtomicChange. + ChangeConsumer Consumer; +}; +} // namespace tooling +} // namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_TRANSFORMER_H_ |
