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/// Determines whether \p Range is one that can be read from. If 95/// `AllowSystemHeaders` is false, a range that falls within a system header 96/// fails validation. 97llvm::Error validateRange(const CharSourceRange &Range, const SourceManager &SM, 98 bool AllowSystemHeaders); 99 100/// Attempts to resolve the given range to one that can be edited by a rewrite; 101/// generally, one that starts and ends within a particular file. If a value is 102/// returned, it satisfies \c validateEditRange. 103/// 104/// If \c IncludeMacroExpansion is true, a limited set of cases involving source 105/// locations in macro expansions is supported. For example, if we're looking to 106/// rewrite the int literal 3 to 6, and we have the following definition: 107/// #define DO_NOTHING(x) x 108/// then 109/// foo(DO_NOTHING(3)) 110/// will be rewritten to 111/// foo(6) 112std::optional<CharSourceRange> 113getFileRangeForEdit(const CharSourceRange &EditRange, const SourceManager &SM, 114 const LangOptions &LangOpts, 115 bool IncludeMacroExpansion = true); 116inline std::optional<CharSourceRange> 117getFileRangeForEdit(const CharSourceRange &EditRange, const ASTContext &Context, 118 bool IncludeMacroExpansion = true) { 119 return getFileRangeForEdit(EditRange, Context.getSourceManager(), 120 Context.getLangOpts(), IncludeMacroExpansion); 121} 122 123/// Attempts to resolve the given range to one that starts and ends in a 124/// particular file. 125/// 126/// If \c IncludeMacroExpansion is true, a limited set of cases involving source 127/// locations in macro expansions is supported. For example, if we're looking to 128/// get the range of the int literal 3, and we have the following definition: 129/// #define DO_NOTHING(x) x 130/// foo(DO_NOTHING(3)) 131/// the returned range will hold the source text `DO_NOTHING(3)`. 132std::optional<CharSourceRange> getFileRange(const CharSourceRange &EditRange, 133 const SourceManager &SM, 134 const LangOptions &LangOpts, 135 bool IncludeMacroExpansion); 136inline std::optional<CharSourceRange> 137getFileRange(const CharSourceRange &EditRange, const ASTContext &Context, 138 bool IncludeMacroExpansion) { 139 return getFileRange(EditRange, Context.getSourceManager(), 140 Context.getLangOpts(), IncludeMacroExpansion); 141} 142 143} // namespace tooling 144} // namespace clang 145#endif // LLVM_CLANG_TOOLING_TRANSFORMER_SOURCECODE_H 146