1341825Sdim//===- TokenRewriter.cpp - Token-based code rewriting interface -----------===// 2274958Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6274958Sdim// 7274958Sdim//===----------------------------------------------------------------------===// 8274958Sdim// 9274958Sdim// This file implements the TokenRewriter class, which is used for code 10274958Sdim// transformations. 11274958Sdim// 12274958Sdim//===----------------------------------------------------------------------===// 13274958Sdim 14274958Sdim#include "clang/Rewrite/Core/TokenRewriter.h" 15274958Sdim#include "clang/Basic/SourceManager.h" 16274958Sdim#include "clang/Lex/Lexer.h" 17274958Sdim#include "clang/Lex/ScratchBuffer.h" 18341825Sdim#include "clang/Lex/Token.h" 19341825Sdim#include <cassert> 20341825Sdim#include <cstring> 21341825Sdim#include <map> 22341825Sdim#include <utility> 23341825Sdim 24274958Sdimusing namespace clang; 25274958Sdim 26274958SdimTokenRewriter::TokenRewriter(FileID FID, SourceManager &SM, 27274958Sdim const LangOptions &LangOpts) { 28274958Sdim ScratchBuf.reset(new ScratchBuffer(SM)); 29274958Sdim 30274958Sdim // Create a lexer to lex all the tokens of the main file in raw mode. 31274958Sdim const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); 32274958Sdim Lexer RawLex(FID, FromFile, SM, LangOpts); 33274958Sdim 34274958Sdim // Return all comments and whitespace as tokens. 35274958Sdim RawLex.SetKeepWhitespaceMode(true); 36274958Sdim 37274958Sdim // Lex the file, populating our datastructures. 38274958Sdim Token RawTok; 39274958Sdim RawLex.LexFromRawLexer(RawTok); 40274958Sdim while (RawTok.isNot(tok::eof)) { 41274958Sdim#if 0 42274958Sdim if (Tok.is(tok::raw_identifier)) { 43274958Sdim // Look up the identifier info for the token. This should use 44274958Sdim // IdentifierTable directly instead of PP. 45274958Sdim PP.LookUpIdentifierInfo(Tok); 46274958Sdim } 47274958Sdim#endif 48274958Sdim 49274958Sdim AddToken(RawTok, TokenList.end()); 50274958Sdim RawLex.LexFromRawLexer(RawTok); 51274958Sdim } 52274958Sdim} 53274958Sdim 54341825SdimTokenRewriter::~TokenRewriter() = default; 55274958Sdim 56274958Sdim/// RemapIterator - Convert from token_iterator (a const iterator) to 57274958Sdim/// TokenRefTy (a non-const iterator). 58274958SdimTokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) { 59274958Sdim if (I == token_end()) return TokenList.end(); 60274958Sdim 61274958Sdim // FIXME: This is horrible, we should use our own list or something to avoid 62274958Sdim // this. 63274958Sdim std::map<SourceLocation, TokenRefTy>::iterator MapIt = 64274958Sdim TokenAtLoc.find(I->getLocation()); 65274958Sdim assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?"); 66274958Sdim return MapIt->second; 67274958Sdim} 68274958Sdim 69274958Sdim/// AddToken - Add the specified token into the Rewriter before the other 70274958Sdim/// position. 71274958SdimTokenRewriter::TokenRefTy 72274958SdimTokenRewriter::AddToken(const Token &T, TokenRefTy Where) { 73274958Sdim Where = TokenList.insert(Where, T); 74274958Sdim 75274958Sdim bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(), 76274958Sdim Where)).second; 77274958Sdim assert(InsertSuccess && "Token location already in rewriter!"); 78274958Sdim (void)InsertSuccess; 79274958Sdim return Where; 80274958Sdim} 81274958Sdim 82274958SdimTokenRewriter::token_iterator 83274958SdimTokenRewriter::AddTokenBefore(token_iterator I, const char *Val) { 84274958Sdim unsigned Len = strlen(Val); 85274958Sdim 86274958Sdim // Plop the string into the scratch buffer, then create a token for this 87274958Sdim // string. 88274958Sdim Token Tok; 89274958Sdim Tok.startToken(); 90274958Sdim const char *Spelling; 91274958Sdim Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling)); 92274958Sdim Tok.setLength(Len); 93274958Sdim 94274958Sdim // TODO: Form a whole lexer around this and relex the token! For now, just 95274958Sdim // set kind to tok::unknown. 96274958Sdim Tok.setKind(tok::unknown); 97274958Sdim 98274958Sdim return AddToken(Tok, RemapIterator(I)); 99274958Sdim} 100