1a7dea167SDimitry Andric //===--- SourceCode.cpp - 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 #include "clang/Tooling/Transformer/SourceCode.h"
13a7dea167SDimitry Andric #include "clang/Lex/Lexer.h"
14a7dea167SDimitry Andric 
15a7dea167SDimitry Andric using namespace clang;
16a7dea167SDimitry Andric 
17a7dea167SDimitry Andric StringRef clang::tooling::getText(CharSourceRange Range,
18a7dea167SDimitry Andric                                   const ASTContext &Context) {
19a7dea167SDimitry Andric   return Lexer::getSourceText(Range, Context.getSourceManager(),
20a7dea167SDimitry Andric                               Context.getLangOpts());
21a7dea167SDimitry Andric }
22a7dea167SDimitry Andric 
23a7dea167SDimitry Andric CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range,
24a7dea167SDimitry Andric                                                  tok::TokenKind Next,
25a7dea167SDimitry Andric                                                  ASTContext &Context) {
26a7dea167SDimitry Andric   Optional<Token> Tok = Lexer::findNextToken(
27a7dea167SDimitry Andric       Range.getEnd(), Context.getSourceManager(), Context.getLangOpts());
28a7dea167SDimitry Andric   if (!Tok || !Tok->is(Next))
29a7dea167SDimitry Andric     return Range;
30a7dea167SDimitry Andric   return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation());
31a7dea167SDimitry Andric }
32a7dea167SDimitry Andric 
33a7dea167SDimitry Andric llvm::Optional<CharSourceRange>
34a7dea167SDimitry Andric clang::tooling::getRangeForEdit(const CharSourceRange &EditRange,
35a7dea167SDimitry Andric                                 const SourceManager &SM,
36a7dea167SDimitry Andric                                 const LangOptions &LangOpts) {
37a7dea167SDimitry Andric   // FIXME: makeFileCharRange() has the disadvantage of stripping off "identity"
38a7dea167SDimitry Andric   // macros. For example, if we're looking to rewrite the int literal 3 to 6,
39a7dea167SDimitry Andric   // and we have the following definition:
40a7dea167SDimitry Andric   //    #define DO_NOTHING(x) x
41a7dea167SDimitry Andric   // then
42a7dea167SDimitry Andric   //    foo(DO_NOTHING(3))
43a7dea167SDimitry Andric   // will be rewritten to
44a7dea167SDimitry Andric   //    foo(6)
45a7dea167SDimitry Andric   // rather than the arguably better
46a7dea167SDimitry Andric   //    foo(DO_NOTHING(6))
47a7dea167SDimitry Andric   // Decide whether the current behavior is desirable and modify if not.
48a7dea167SDimitry Andric   CharSourceRange Range = Lexer::makeFileCharRange(EditRange, SM, LangOpts);
49a7dea167SDimitry Andric   if (Range.isInvalid())
50a7dea167SDimitry Andric     return None;
51a7dea167SDimitry Andric 
52a7dea167SDimitry Andric   if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
53a7dea167SDimitry Andric     return None;
54a7dea167SDimitry Andric   if (SM.isInSystemHeader(Range.getBegin()) ||
55a7dea167SDimitry Andric       SM.isInSystemHeader(Range.getEnd()))
56a7dea167SDimitry Andric     return None;
57a7dea167SDimitry Andric 
58a7dea167SDimitry Andric   std::pair<FileID, unsigned> BeginInfo = SM.getDecomposedLoc(Range.getBegin());
59a7dea167SDimitry Andric   std::pair<FileID, unsigned> EndInfo = SM.getDecomposedLoc(Range.getEnd());
60a7dea167SDimitry Andric   if (BeginInfo.first != EndInfo.first ||
61a7dea167SDimitry Andric       BeginInfo.second > EndInfo.second)
62a7dea167SDimitry Andric     return None;
63a7dea167SDimitry Andric 
64a7dea167SDimitry Andric   return Range;
65a7dea167SDimitry Andric }
66