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