xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCode.cpp (revision a7dea1671b87c07d2d266f836bfa8b58efc7c134)
1*a7dea167SDimitry Andric //===--- SourceCode.cpp - Source code manipulation routines -----*- C++ -*-===//
2*a7dea167SDimitry Andric //
3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*a7dea167SDimitry Andric //
7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8*a7dea167SDimitry Andric //
9*a7dea167SDimitry Andric //  This file provides functions that simplify extraction of source code.
10*a7dea167SDimitry Andric //
11*a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12*a7dea167SDimitry Andric #include "clang/Tooling/Transformer/SourceCode.h"
13*a7dea167SDimitry Andric #include "clang/Lex/Lexer.h"
14*a7dea167SDimitry Andric 
15*a7dea167SDimitry Andric using namespace clang;
16*a7dea167SDimitry Andric 
17*a7dea167SDimitry Andric StringRef clang::tooling::getText(CharSourceRange Range,
18*a7dea167SDimitry Andric                                   const ASTContext &Context) {
19*a7dea167SDimitry Andric   return Lexer::getSourceText(Range, Context.getSourceManager(),
20*a7dea167SDimitry Andric                               Context.getLangOpts());
21*a7dea167SDimitry Andric }
22*a7dea167SDimitry Andric 
23*a7dea167SDimitry Andric CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range,
24*a7dea167SDimitry Andric                                                  tok::TokenKind Next,
25*a7dea167SDimitry Andric                                                  ASTContext &Context) {
26*a7dea167SDimitry Andric   Optional<Token> Tok = Lexer::findNextToken(
27*a7dea167SDimitry Andric       Range.getEnd(), Context.getSourceManager(), Context.getLangOpts());
28*a7dea167SDimitry Andric   if (!Tok || !Tok->is(Next))
29*a7dea167SDimitry Andric     return Range;
30*a7dea167SDimitry Andric   return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation());
31*a7dea167SDimitry Andric }
32*a7dea167SDimitry Andric 
33*a7dea167SDimitry Andric llvm::Optional<CharSourceRange>
34*a7dea167SDimitry Andric clang::tooling::getRangeForEdit(const CharSourceRange &EditRange,
35*a7dea167SDimitry Andric                                 const SourceManager &SM,
36*a7dea167SDimitry Andric                                 const LangOptions &LangOpts) {
37*a7dea167SDimitry Andric   // FIXME: makeFileCharRange() has the disadvantage of stripping off "identity"
38*a7dea167SDimitry Andric   // macros. For example, if we're looking to rewrite the int literal 3 to 6,
39*a7dea167SDimitry Andric   // and we have the following definition:
40*a7dea167SDimitry Andric   //    #define DO_NOTHING(x) x
41*a7dea167SDimitry Andric   // then
42*a7dea167SDimitry Andric   //    foo(DO_NOTHING(3))
43*a7dea167SDimitry Andric   // will be rewritten to
44*a7dea167SDimitry Andric   //    foo(6)
45*a7dea167SDimitry Andric   // rather than the arguably better
46*a7dea167SDimitry Andric   //    foo(DO_NOTHING(6))
47*a7dea167SDimitry Andric   // Decide whether the current behavior is desirable and modify if not.
48*a7dea167SDimitry Andric   CharSourceRange Range = Lexer::makeFileCharRange(EditRange, SM, LangOpts);
49*a7dea167SDimitry Andric   if (Range.isInvalid())
50*a7dea167SDimitry Andric     return None;
51*a7dea167SDimitry Andric 
52*a7dea167SDimitry Andric   if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
53*a7dea167SDimitry Andric     return None;
54*a7dea167SDimitry Andric   if (SM.isInSystemHeader(Range.getBegin()) ||
55*a7dea167SDimitry Andric       SM.isInSystemHeader(Range.getEnd()))
56*a7dea167SDimitry Andric     return None;
57*a7dea167SDimitry Andric 
58*a7dea167SDimitry Andric   std::pair<FileID, unsigned> BeginInfo = SM.getDecomposedLoc(Range.getBegin());
59*a7dea167SDimitry Andric   std::pair<FileID, unsigned> EndInfo = SM.getDecomposedLoc(Range.getEnd());
60*a7dea167SDimitry Andric   if (BeginInfo.first != EndInfo.first ||
61*a7dea167SDimitry Andric       BeginInfo.second > EndInfo.second)
62*a7dea167SDimitry Andric     return None;
63*a7dea167SDimitry Andric 
64*a7dea167SDimitry Andric   return Range;
65*a7dea167SDimitry Andric }
66