clang: lib/Format/MacroExpander.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

16

28#include "llvm/ADT/StringSet.h"

29#include "llvm/Support/ErrorHandling.h"

30

32namespace format {

33

38

39

40

41

42

43 llvm::StringMap<size_t> ArgMap;

44

46};

47

49public:

51 assert(!Tokens.empty());

52 Current = Tokens[0];

53 }

54

55

56

58 if (Current->isNot(tok::identifier))

59 return {};

61 nextToken();

62 if (Current->is(tok::l_paren)) {

64 if (!parseParams())

65 return {};

66 }

67 if (!parseExpansion())

68 return {};

69

70 return Def;

71 }

72

73private:

74 bool parseParams() {

75 assert(Current->is(tok::l_paren));

76 nextToken();

77 while (Current->is(tok::identifier)) {

78 Def.Params.push_back(Current);

80 nextToken();

81 if (Current->isNot(tok::comma))

82 break;

83 nextToken();

84 }

85 if (Current->isNot(tok::r_paren))

86 return false;

87 nextToken();

88 return true;

89 }

90

91 bool parseExpansion() {

92 if (!Current->isOneOf(tok::equal, tok::eof))

93 return false;

94 if (Current->is(tok::equal))

95 nextToken();

96 parseTail();

97 return true;

98 }

99

100 void parseTail() {

101 while (Current->isNot(tok::eof)) {

102 Def.Body.push_back(Current);

103 nextToken();

104 }

105 Def.Body.push_back(Current);

106 }

107

108 void nextToken() {

109 if (Pos + 1 < Tokens.size())

110 ++Pos;

111 Current = Tokens[Pos];

113 }

114

115 size_t Pos = 0;

116 FormatToken *Current = nullptr;

118 ArrayRef<FormatToken *> Tokens;

119};

120

122 const std::vectorstd::string &Macros, SourceManager &SourceMgr,

124 llvm::SpecificBumpPtrAllocator &Allocator,

126 : SourceMgr(SourceMgr), Style(Style), Allocator(Allocator),

127 IdentTable(IdentTable) {

128 for (const std::string &Macro : Macros)

129 parseDefinition(Macro);

130}

131

133

134void MacroExpander::parseDefinition(const std::string &Macro) {

135 Buffers.push_back(

136 llvm::MemoryBuffer::getMemBufferCopy(Macro, ""));

137 FileID FID = SourceMgr.createFileID(Buffers.back()->getMemBufferRef());

139 Allocator, IdentTable);

140 const auto Tokens = Lex.lex();

141 if (!Tokens.empty()) {

142 DefinitionParser Parser(Tokens);

143 auto Definition = Parser.parse();

144 if (Definition.ObjectLike) {

145 ObjectLike[Definition.Name] = std::move(Definition);

146 } else {

147 FunctionLike[Definition.Name][Definition.Params.size()] =

148 std::move(Definition);

149 }

150 }

151}

152

154 return FunctionLike.contains(Name) || ObjectLike.contains(Name);

155}

156

158 return ObjectLike.contains(Name);

159}

160

162 auto it = FunctionLike.find(Name);

163 return it != FunctionLike.end() && it->second.contains(Arity);

164}

165

168 std::optional OptionalArgs) const {

169 if (OptionalArgs)

170 assert(hasArity(ID->TokenText, OptionalArgs->size()));

171 else

174 ? FunctionLike.find(ID->TokenText)

175 ->second.find(OptionalArgs.value().size())

176 ->second

177 : ObjectLike.find(ID->TokenText)->second;

178 ArgsList Args = OptionalArgs ? OptionalArgs.value() : ArgsList();

180

181 llvm::StringSet<> ExpandedArgs;

182

183

185 Tok->MacroCtx->ExpandedFrom.push_back(ID);

186 Result.push_back(Tok);

187 };

188

189

190

191 auto expandArgument = [&](FormatToken *Tok) -> bool {

192

193

194 if (Tok->isNot(tok::identifier))

195 return false;

196 if (!ExpandedArgs.insert(Tok->TokenText).second)

197 return false;

198 auto I = Def.ArgMap.find(Tok->TokenText);

199 if (I == Def.ArgMap.end())

200 return false;

201

202

203

204 if (I->getValue() >= Args.size())

205 return true;

206 for (FormatToken *Arg : Args[I->getValue()]) {

207

208

209

210

211

212 if (!Arg->MacroCtx)

214 pushToken(Arg);

215 }

216 return true;

217 };

218

219

221 if (expandArgument(Tok))

222 continue;

223

224

228

230 pushToken(New);

231 }

232 assert(Result.size() >= 1 && Result.back()->is(tok::eof));

233 if (Result.size() > 1) {

234 ++Result[0]->MacroCtx->StartOfExpansion;

235 ++Result[Result.size() - 2]->MacroCtx->EndOfExpansion;

236 } else {

237

238 Result[0]->MacroCtx->StartOfExpansion = 1;

239 Result[0]->MacroCtx->EndOfExpansion = 1;

240 }

242}

243

244}

245}

Contains functions for text encoding manipulation.

This file contains FormatTokenLexer, which tokenizes a source file into a token stream suitable for C...

This file contains the declaration of the FormatToken, a wrapper around Token with additional informa...

Various functions to configurably format source code.

This file contains the main building blocks of macro support in clang-format.

Defines the clang::Preprocessor interface.

Defines the clang::TokenKind enum and support functions.

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

Implements an efficient mapping from strings to IdentifierInfo nodes.

Parser - This implements a parser for the C family of languages.

This class handles loading and caching of source files into memory.

FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, SourceLocation::UIntTy LoadedOffset=0)

Create a new FileID that represents the specified file being #included from the specified IncludePosi...

MacroExpander::Definition parse()

DefinitionParser(ArrayRef< FormatToken * > Tokens)

bool objectLike(StringRef Name) const

Returns whetherh there is an object-like overload, i.e.

SmallVector< FormatToken *, 8 > expand(FormatToken *ID, std::optional< ArgsList > OptionalArgs) const

Returns the expanded stream of format tokens for ID, where each element in Args is a positional argum...

ArrayRef< SmallVector< FormatToken *, 8 > > ArgsList

bool hasArity(StringRef Name, unsigned Arity) const

Returns whether macro Name provides an overload with the given arity.

MacroExpander(const std::vector< std::string > &Macros, SourceManager &SourceMgr, const FormatStyle &Style, llvm::SpecificBumpPtrAllocator< FormatToken > &Allocator, IdentifierTable &IdentTable)

Construct a macro expander from a set of macro definitions.

bool defined(StringRef Name) const

Returns whether any macro Name is defined, regardless of overloads.

@ MR_Hidden

The token was expanded from a macro definition, and is not visible as part of the macro call.

@ MR_ExpandedArg

The token was expanded from a macro argument when formatting the expanded token sequence.

The JSON file list parser is used to communicate input to InstallAPI.

@ Result

The result type of a method or function.

The FormatStyle is used to configure the formatting to follow specific guidelines.

A wrapper around a Token storing information about the whitespace characters preceding it.

StringRef TokenText

The raw text of the token.

unsigned Finalized

If true, this token has been fully formatted (indented and potentially re-formatted inside),...

std::optional< MacroExpansion > MacroCtx

bool is(tok::TokenKind Kind) const

bool isOneOf(A K1, B K2) const

void copyFrom(const FormatToken &Tok)

SmallVector< FormatToken *, 8 > Params

SmallVector< FormatToken *, 8 > Body

llvm::StringMap< size_t > ArgMap

Contains information on the token's role in a macro expansion.