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