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