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