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 21namespace clang { 22namespace 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. 26CharSourceRange 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. 33template <typename T> 34CharSourceRange 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`. 49CharSourceRange getAssociatedRange(const Decl &D, ASTContext &Context); 50 51/// Returns the source-code text in the specified range. 52StringRef getText(CharSourceRange Range, const ASTContext &Context); 53 54/// Returns the source-code text corresponding to \p Node. 55template <typename T> 56StringRef 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 83template <typename T> 84StringRef 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. 91llvm::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) 106std::optional<CharSourceRange> 107getFileRangeForEdit(const CharSourceRange &EditRange, const SourceManager &SM, 108 const LangOptions &LangOpts, 109 bool IncludeMacroExpansion = true); 110inline std::optional<CharSourceRange> 111getFileRangeForEdit(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)`. 126std::optional<CharSourceRange> getFileRange(const CharSourceRange &EditRange, 127 const SourceManager &SM, 128 const LangOptions &LangOpts, 129 bool IncludeMacroExpansion); 130inline std::optional<CharSourceRange> 131getFileRange(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