xref: /openbsd-src/gnu/llvm/clang/lib/Rewrite/TokenRewriter.cpp (revision a9ac8606c53d55cee9c3a39778b249c51df111ef)
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