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