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