123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- //===--- MacroExpander.cpp - Format C++ code --------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// \file
- /// This file contains the implementation of MacroExpander, which handles macro
- /// configuration and expansion while formatting.
- ///
- //===----------------------------------------------------------------------===//
- #include "Macros.h"
- #include "Encoding.h"
- #include "FormatToken.h"
- #include "FormatTokenLexer.h"
- #include "clang/Basic/TokenKinds.h"
- #include "clang/Format/Format.h"
- #include "clang/Lex/HeaderSearch.h"
- #include "clang/Lex/HeaderSearchOptions.h"
- #include "clang/Lex/Lexer.h"
- #include "clang/Lex/ModuleLoader.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Lex/PreprocessorOptions.h"
- #include "llvm/ADT/StringSet.h"
- #include "llvm/Support/ErrorHandling.h"
- namespace clang {
- namespace format {
- struct MacroExpander::Definition {
- StringRef Name;
- SmallVector<FormatToken *, 8> Params;
- SmallVector<FormatToken *, 8> Body;
- // Map from each argument's name to its position in the argument list.
- // With "M(x, y) x + y":
- // x -> 0
- // y -> 1
- llvm::StringMap<size_t> ArgMap;
- bool ObjectLike = true;
- };
- class MacroExpander::DefinitionParser {
- public:
- DefinitionParser(ArrayRef<FormatToken *> Tokens) : Tokens(Tokens) {
- assert(!Tokens.empty());
- Current = Tokens[0];
- }
- // Parse the token stream and return the corresponding Definition object.
- // Returns an empty definition object with a null-Name on error.
- MacroExpander::Definition parse() {
- if (!Current->is(tok::identifier))
- return {};
- Def.Name = Current->TokenText;
- nextToken();
- if (Current->is(tok::l_paren)) {
- Def.ObjectLike = false;
- if (!parseParams())
- return {};
- }
- if (!parseExpansion())
- return {};
- return Def;
- }
- private:
- bool parseParams() {
- assert(Current->is(tok::l_paren));
- nextToken();
- while (Current->is(tok::identifier)) {
- Def.Params.push_back(Current);
- Def.ArgMap[Def.Params.back()->TokenText] = Def.Params.size() - 1;
- nextToken();
- if (Current->isNot(tok::comma))
- break;
- nextToken();
- }
- if (Current->isNot(tok::r_paren))
- return false;
- nextToken();
- return true;
- }
- bool parseExpansion() {
- if (!Current->isOneOf(tok::equal, tok::eof))
- return false;
- if (Current->is(tok::equal))
- nextToken();
- parseTail();
- return true;
- }
- void parseTail() {
- while (Current->isNot(tok::eof)) {
- Def.Body.push_back(Current);
- nextToken();
- }
- Def.Body.push_back(Current);
- }
- void nextToken() {
- if (Pos + 1 < Tokens.size())
- ++Pos;
- Current = Tokens[Pos];
- Current->Finalized = true;
- }
- size_t Pos = 0;
- FormatToken *Current = nullptr;
- Definition Def;
- ArrayRef<FormatToken *> Tokens;
- };
- MacroExpander::MacroExpander(
- const std::vector<std::string> &Macros, clang::SourceManager &SourceMgr,
- const FormatStyle &Style,
- llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
- IdentifierTable &IdentTable)
- : SourceMgr(SourceMgr), Style(Style), Allocator(Allocator),
- IdentTable(IdentTable) {
- for (const std::string &Macro : Macros)
- parseDefinition(Macro);
- }
- MacroExpander::~MacroExpander() = default;
- void MacroExpander::parseDefinition(const std::string &Macro) {
- Buffers.push_back(
- llvm::MemoryBuffer::getMemBufferCopy(Macro, "<scratch space>"));
- clang::FileID FID = SourceMgr.createFileID(Buffers.back()->getMemBufferRef());
- FormatTokenLexer Lex(SourceMgr, FID, 0, Style, encoding::Encoding_UTF8,
- Allocator, IdentTable);
- const auto Tokens = Lex.lex();
- if (!Tokens.empty()) {
- DefinitionParser Parser(Tokens);
- auto Definition = Parser.parse();
- Definitions[Definition.Name] = std::move(Definition);
- }
- }
- bool MacroExpander::defined(llvm::StringRef Name) const {
- return Definitions.find(Name) != Definitions.end();
- }
- bool MacroExpander::objectLike(llvm::StringRef Name) const {
- return Definitions.find(Name)->second.ObjectLike;
- }
- llvm::SmallVector<FormatToken *, 8> MacroExpander::expand(FormatToken *ID,
- ArgsList Args) const {
- assert(defined(ID->TokenText));
- SmallVector<FormatToken *, 8> Result;
- const Definition &Def = Definitions.find(ID->TokenText)->second;
- // Expand each argument at most once.
- llvm::StringSet<> ExpandedArgs;
- // Adds the given token to Result.
- auto pushToken = [&](FormatToken *Tok) {
- Tok->MacroCtx->ExpandedFrom.push_back(ID);
- Result.push_back(Tok);
- };
- // If Tok references a parameter, adds the corresponding argument to Result.
- // Returns false if Tok does not reference a parameter.
- auto expandArgument = [&](FormatToken *Tok) -> bool {
- // If the current token references a parameter, expand the corresponding
- // argument.
- if (!Tok->is(tok::identifier) || ExpandedArgs.contains(Tok->TokenText))
- return false;
- ExpandedArgs.insert(Tok->TokenText);
- auto I = Def.ArgMap.find(Tok->TokenText);
- if (I == Def.ArgMap.end())
- return false;
- // If there are fewer arguments than referenced parameters, treat the
- // parameter as empty.
- // FIXME: Potentially fully abort the expansion instead.
- if (I->getValue() >= Args.size())
- return true;
- for (FormatToken *Arg : Args[I->getValue()]) {
- // A token can be part of a macro argument at multiple levels.
- // For example, with "ID(x) x":
- // in ID(ID(x)), 'x' is expanded first as argument to the inner
- // ID, then again as argument to the outer ID. We keep the macro
- // role the token had from the inner expansion.
- if (!Arg->MacroCtx)
- Arg->MacroCtx = MacroExpansion(MR_ExpandedArg);
- pushToken(Arg);
- }
- return true;
- };
- // Expand the definition into Result.
- for (FormatToken *Tok : Def.Body) {
- if (expandArgument(Tok))
- continue;
- // Create a copy of the tokens from the macro body, i.e. were not provided
- // by user code.
- FormatToken *New = new (Allocator.Allocate()) FormatToken;
- New->copyFrom(*Tok);
- assert(!New->MacroCtx);
- // Tokens that are not part of the user code are not formatted.
- New->MacroCtx = MacroExpansion(MR_Hidden);
- pushToken(New);
- }
- assert(Result.size() >= 1 && Result.back()->is(tok::eof));
- if (Result.size() > 1) {
- ++Result[0]->MacroCtx->StartOfExpansion;
- ++Result[Result.size() - 2]->MacroCtx->EndOfExpansion;
- }
- return Result;
- }
- } // namespace format
- } // namespace clang
|