1db914a46SEugene Zelenko //===- TokenRewriter.cpp - Token-based code rewriting interface -----------===//
20621cb2eSAlp Toker //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60621cb2eSAlp Toker //
70621cb2eSAlp Toker //===----------------------------------------------------------------------===//
80621cb2eSAlp Toker //
90621cb2eSAlp Toker // This file implements the TokenRewriter class, which is used for code
100621cb2eSAlp Toker // transformations.
110621cb2eSAlp Toker //
120621cb2eSAlp Toker //===----------------------------------------------------------------------===//
130621cb2eSAlp Toker
140621cb2eSAlp Toker #include "clang/Rewrite/Core/TokenRewriter.h"
150621cb2eSAlp Toker #include "clang/Basic/SourceManager.h"
160621cb2eSAlp Toker #include "clang/Lex/Lexer.h"
170621cb2eSAlp Toker #include "clang/Lex/ScratchBuffer.h"
18db914a46SEugene Zelenko #include "clang/Lex/Token.h"
19db914a46SEugene Zelenko #include <cassert>
20db914a46SEugene Zelenko #include <cstring>
21db914a46SEugene Zelenko #include <map>
22db914a46SEugene Zelenko #include <utility>
23db914a46SEugene Zelenko
240621cb2eSAlp Toker using namespace clang;
250621cb2eSAlp Toker
TokenRewriter(FileID FID,SourceManager & SM,const LangOptions & LangOpts)260621cb2eSAlp Toker TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM,
270621cb2eSAlp Toker const LangOptions &LangOpts) {
280621cb2eSAlp Toker ScratchBuf.reset(new ScratchBuffer(SM));
290621cb2eSAlp Toker
300621cb2eSAlp Toker // Create a lexer to lex all the tokens of the main file in raw mode.
31*b3eff6b7SDuncan P. N. Exon Smith llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID);
320621cb2eSAlp Toker Lexer RawLex(FID, FromFile, SM, LangOpts);
330621cb2eSAlp Toker
340621cb2eSAlp Toker // Return all comments and whitespace as tokens.
350621cb2eSAlp Toker RawLex.SetKeepWhitespaceMode(true);
360621cb2eSAlp Toker
370621cb2eSAlp Toker // Lex the file, populating our datastructures.
380621cb2eSAlp Toker Token RawTok;
390621cb2eSAlp Toker RawLex.LexFromRawLexer(RawTok);
400621cb2eSAlp Toker while (RawTok.isNot(tok::eof)) {
410621cb2eSAlp Toker #if 0
420621cb2eSAlp Toker if (Tok.is(tok::raw_identifier)) {
430621cb2eSAlp Toker // Look up the identifier info for the token. This should use
440621cb2eSAlp Toker // IdentifierTable directly instead of PP.
450621cb2eSAlp Toker PP.LookUpIdentifierInfo(Tok);
460621cb2eSAlp Toker }
470621cb2eSAlp Toker #endif
480621cb2eSAlp Toker
490621cb2eSAlp Toker AddToken(RawTok, TokenList.end());
500621cb2eSAlp Toker RawLex.LexFromRawLexer(RawTok);
510621cb2eSAlp Toker }
520621cb2eSAlp Toker }
530621cb2eSAlp Toker
54db914a46SEugene Zelenko TokenRewriter::~TokenRewriter() = default;
550621cb2eSAlp Toker
560621cb2eSAlp Toker /// RemapIterator - Convert from token_iterator (a const iterator) to
570621cb2eSAlp Toker /// TokenRefTy (a non-const iterator).
RemapIterator(token_iterator I)580621cb2eSAlp Toker TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) {
590621cb2eSAlp Toker if (I == token_end()) return TokenList.end();
600621cb2eSAlp Toker
610621cb2eSAlp Toker // FIXME: This is horrible, we should use our own list or something to avoid
620621cb2eSAlp Toker // this.
630621cb2eSAlp Toker std::map<SourceLocation, TokenRefTy>::iterator MapIt =
640621cb2eSAlp Toker TokenAtLoc.find(I->getLocation());
650621cb2eSAlp Toker assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?");
660621cb2eSAlp Toker return MapIt->second;
670621cb2eSAlp Toker }
680621cb2eSAlp Toker
690621cb2eSAlp Toker /// AddToken - Add the specified token into the Rewriter before the other
700621cb2eSAlp Toker /// position.
710621cb2eSAlp Toker TokenRewriter::TokenRefTy
AddToken(const Token & T,TokenRefTy Where)720621cb2eSAlp Toker TokenRewriter::AddToken(const Token &T, TokenRefTy Where) {
730621cb2eSAlp Toker Where = TokenList.insert(Where, T);
740621cb2eSAlp Toker
750621cb2eSAlp Toker bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(),
760621cb2eSAlp Toker Where)).second;
770621cb2eSAlp Toker assert(InsertSuccess && "Token location already in rewriter!");
780621cb2eSAlp Toker (void)InsertSuccess;
790621cb2eSAlp Toker return Where;
800621cb2eSAlp Toker }
810621cb2eSAlp Toker
820621cb2eSAlp Toker TokenRewriter::token_iterator
AddTokenBefore(token_iterator I,const char * Val)830621cb2eSAlp Toker TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) {
840621cb2eSAlp Toker unsigned Len = strlen(Val);
850621cb2eSAlp Toker
860621cb2eSAlp Toker // Plop the string into the scratch buffer, then create a token for this
870621cb2eSAlp Toker // string.
880621cb2eSAlp Toker Token Tok;
890621cb2eSAlp Toker Tok.startToken();
900621cb2eSAlp Toker const char *Spelling;
910621cb2eSAlp Toker Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling));
920621cb2eSAlp Toker Tok.setLength(Len);
930621cb2eSAlp Toker
940621cb2eSAlp Toker // TODO: Form a whole lexer around this and relex the token! For now, just
950621cb2eSAlp Toker // set kind to tok::unknown.
960621cb2eSAlp Toker Tok.setKind(tok::unknown);
970621cb2eSAlp Toker
980621cb2eSAlp Toker return AddToken(Tok, RemapIterator(I));
990621cb2eSAlp Toker }
100