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