1 //===- TokenRewriter.cpp - Token-based code rewriting interface -----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the TokenRewriter class, which is used for code 10 // transformations. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Rewrite/Core/TokenRewriter.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "clang/Lex/Lexer.h" 17 #include "clang/Lex/ScratchBuffer.h" 18 #include "clang/Lex/Token.h" 19 #include <cassert> 20 #include <cstring> 21 #include <map> 22 #include <utility> 23 24 using namespace clang; 25 26 TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM, 27 const LangOptions &LangOpts) { 28 ScratchBuf.reset(new ScratchBuffer(SM)); 29 30 // Create a lexer to lex all the tokens of the main file in raw mode. 31 const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); 32 Lexer RawLex(FID, FromFile, SM, LangOpts); 33 34 // Return all comments and whitespace as tokens. 35 RawLex.SetKeepWhitespaceMode(true); 36 37 // Lex the file, populating our datastructures. 38 Token RawTok; 39 RawLex.LexFromRawLexer(RawTok); 40 while (RawTok.isNot(tok::eof)) { 41 #if 0 42 if (Tok.is(tok::raw_identifier)) { 43 // Look up the identifier info for the token. This should use 44 // IdentifierTable directly instead of PP. 45 PP.LookUpIdentifierInfo(Tok); 46 } 47 #endif 48 49 AddToken(RawTok, TokenList.end()); 50 RawLex.LexFromRawLexer(RawTok); 51 } 52 } 53 54 TokenRewriter::~TokenRewriter() = default; 55 56 /// RemapIterator - Convert from token_iterator (a const iterator) to 57 /// TokenRefTy (a non-const iterator). 58 TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) { 59 if (I == token_end()) return TokenList.end(); 60 61 // FIXME: This is horrible, we should use our own list or something to avoid 62 // this. 63 std::map<SourceLocation, TokenRefTy>::iterator MapIt = 64 TokenAtLoc.find(I->getLocation()); 65 assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?"); 66 return MapIt->second; 67 } 68 69 /// AddToken - Add the specified token into the Rewriter before the other 70 /// position. 71 TokenRewriter::TokenRefTy 72 TokenRewriter::AddToken(const Token &T, TokenRefTy Where) { 73 Where = TokenList.insert(Where, T); 74 75 bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(), 76 Where)).second; 77 assert(InsertSuccess && "Token location already in rewriter!"); 78 (void)InsertSuccess; 79 return Where; 80 } 81 82 TokenRewriter::token_iterator 83 TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) { 84 unsigned Len = strlen(Val); 85 86 // Plop the string into the scratch buffer, then create a token for this 87 // string. 88 Token Tok; 89 Tok.startToken(); 90 const char *Spelling; 91 Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling)); 92 Tok.setLength(Len); 93 94 // TODO: Form a whole lexer around this and relex the token! For now, just 95 // set kind to tok::unknown. 96 Tok.setKind(tok::unknown); 97 98 return AddToken(Tok, RemapIterator(I)); 99 } 100