1 //===--- SourceCode.h - Source code manipulation routines -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides functions that simplify extraction of source code. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_TOOLING_TRANSFORMER_SOURCECODE_H 14 #define LLVM_CLANG_TOOLING_TRANSFORMER_SOURCECODE_H 15 16 #include "clang/AST/ASTContext.h" 17 #include "clang/Basic/SourceLocation.h" 18 #include "clang/Basic/TokenKinds.h" 19 #include <optional> 20 21 namespace clang { 22 namespace tooling { 23 24 /// Extends \p Range to include the token \p Terminator, if it immediately 25 /// follows the end of the range. Otherwise, returns \p Range unchanged. 26 CharSourceRange maybeExtendRange(CharSourceRange Range, 27 tok::TokenKind Terminator, 28 ASTContext &Context); 29 30 /// Returns the source range spanning the node, extended to include \p Next, if 31 /// it immediately follows \p Node. Otherwise, returns the normal range of \p 32 /// Node. See comments on `getExtendedText()` for examples. 33 template <typename T> 34 CharSourceRange getExtendedRange(const T &Node, tok::TokenKind Next, 35 ASTContext &Context) { 36 return maybeExtendRange(CharSourceRange::getTokenRange(Node.getSourceRange()), 37 Next, Context); 38 } 39 40 /// Returns the logical source range of the node extended to include associated 41 /// comments and whitespace before and after the node, and associated 42 /// terminators. The returned range consists of file locations, if valid file 43 /// locations can be found for the associated content; otherwise, an invalid 44 /// range is returned. 45 /// 46 /// Note that parsing comments is disabled by default. In order to select a 47 /// range containing associated comments, you may need to invoke the tool with 48 /// `-fparse-all-comments`. 49 CharSourceRange getAssociatedRange(const Decl &D, ASTContext &Context); 50 51 /// Returns the source-code text in the specified range. 52 StringRef getText(CharSourceRange Range, const ASTContext &Context); 53 54 /// Returns the source-code text corresponding to \p Node. 55 template <typename T> 56 StringRef getText(const T &Node, const ASTContext &Context) { 57 return getText(CharSourceRange::getTokenRange(Node.getSourceRange()), 58 Context); 59 } 60 61 /// Returns the source text of the node, extended to include \p Next, if it 62 /// immediately follows the node. Otherwise, returns the text of just \p Node. 63 /// 64 /// For example, given statements S1 and S2 below: 65 /// \code 66 /// { 67 /// // S1: 68 /// if (!x) return foo(); 69 /// // S2: 70 /// if (!x) { return 3; } 71 /// } 72 /// \endcode 73 /// then 74 /// \code 75 /// getText(S1, Context) = "if (!x) return foo()" 76 /// getExtendedText(S1, tok::TokenKind::semi, Context) 77 /// = "if (!x) return foo();" 78 /// getExtendedText(*S1.getThen(), tok::TokenKind::semi, Context) 79 /// = "return foo();" 80 /// getExtendedText(*S2.getThen(), tok::TokenKind::semi, Context) 81 /// = getText(S2, Context) = "{ return 3; }" 82 /// \endcode 83 template <typename T> 84 StringRef getExtendedText(const T &Node, tok::TokenKind Next, 85 ASTContext &Context) { 86 return getText(getExtendedRange(Node, Next, Context), Context); 87 } 88 89 /// Determines whether \p Range is one that can be edited by a rewrite; 90 /// generally, one that starts and ends within a particular file. 91 llvm::Error validateEditRange(const CharSourceRange &Range, 92 const SourceManager &SM); 93 94 /// Attempts to resolve the given range to one that can be edited by a rewrite; 95 /// generally, one that starts and ends within a particular file. If a value is 96 /// returned, it satisfies \c validateEditRange. 97 /// 98 /// If \c IncludeMacroExpansion is true, a limited set of cases involving source 99 /// locations in macro expansions is supported. For example, if we're looking to 100 /// rewrite the int literal 3 to 6, and we have the following definition: 101 /// #define DO_NOTHING(x) x 102 /// then 103 /// foo(DO_NOTHING(3)) 104 /// will be rewritten to 105 /// foo(6) 106 std::optional<CharSourceRange> 107 getFileRangeForEdit(const CharSourceRange &EditRange, const SourceManager &SM, 108 const LangOptions &LangOpts, 109 bool IncludeMacroExpansion = true); 110 inline std::optional<CharSourceRange> 111 getFileRangeForEdit(const CharSourceRange &EditRange, const ASTContext &Context, 112 bool IncludeMacroExpansion = true) { 113 return getFileRangeForEdit(EditRange, Context.getSourceManager(), 114 Context.getLangOpts(), IncludeMacroExpansion); 115 } 116 117 /// Attempts to resolve the given range to one that starts and ends in a 118 /// particular file. 119 /// 120 /// If \c IncludeMacroExpansion is true, a limited set of cases involving source 121 /// locations in macro expansions is supported. For example, if we're looking to 122 /// get the range of the int literal 3, and we have the following definition: 123 /// #define DO_NOTHING(x) x 124 /// foo(DO_NOTHING(3)) 125 /// the returned range will hold the source text `DO_NOTHING(3)`. 126 std::optional<CharSourceRange> getFileRange(const CharSourceRange &EditRange, 127 const SourceManager &SM, 128 const LangOptions &LangOpts, 129 bool IncludeMacroExpansion); 130 inline std::optional<CharSourceRange> 131 getFileRange(const CharSourceRange &EditRange, const ASTContext &Context, 132 bool IncludeMacroExpansion) { 133 return getFileRange(EditRange, Context.getSourceManager(), 134 Context.getLangOpts(), IncludeMacroExpansion); 135 } 136 137 } // namespace tooling 138 } // namespace clang 139 #endif // LLVM_CLANG_TOOLING_TRANSFORMER_SOURCECODE_H 140