xref: /llvm-project/clang/lib/Rewrite/TokenRewriter.cpp (revision b3eff6b7bb31e7ef059a3d238de138849839fbbd)
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