clang: lib/Analysis/MacroExpansionContext.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

10#include "llvm/Support/Debug.h"

11#include

12

13#define DEBUG_TYPE "macro-expansion-context"

14

17

19namespace detail {

23 MacroExpansionContext::ExpansionRangeMap &ExpansionRanges;

24

25public:

28 MacroExpansionContext::ExpansionRangeMap &ExpansionRanges)

29 : PP(PP), SM(SM), ExpansionRanges(ExpansionRanges) {}

30

33

35 return;

36

38 assert(MacroNameBegin == SM.getExpansionLoc(Range.getBegin()));

39

41

43 return SM.getExpansionLoc(

45

46

47 return SM.getExpansionLoc(Range.getEnd()).getLocWithOffset(1);

48 }();

49

50 (void)PP;

51 LLVM_DEBUG(llvm::dbgs() << "MacroExpands event: '";

53 llvm::dbgs()

54 << "' with length " << MacroName.getLength() << " at ";

55 MacroNameBegin.print(llvm::dbgs(), SM);

56 llvm::dbgs() << ", expansion end at ";

57 ExpansionEnd.print(llvm::dbgs(), SM); llvm::dbgs() << '\n';);

58

59

60

61 MacroExpansionContext::ExpansionRangeMap::iterator It;

62 bool Inserted;

63 std::tie(It, Inserted) =

64 ExpansionRanges.try_emplace(MacroNameBegin, ExpansionEnd);

65 if (Inserted) {

66 LLVM_DEBUG(llvm::dbgs() << "maps ";

67 It->getFirst().print(llvm::dbgs(), SM); llvm::dbgs() << " to ";

68 It->getSecond().print(llvm::dbgs(), SM);

69 llvm::dbgs() << '\n';);

70 } else {

71 if (SM.isBeforeInTranslationUnit(It->getSecond(), ExpansionEnd)) {

72 It->getSecond() = ExpansionEnd;

73 LLVM_DEBUG(

74 llvm::dbgs() << "remaps "; It->getFirst().print(llvm::dbgs(), SM);

75 llvm::dbgs() << " to "; It->getSecond().print(llvm::dbgs(), SM);

76 llvm::dbgs() << '\n';);

77 }

78 }

79 }

80};

81}

82}

83

84using namespace clang;

85

87 : LangOpts(LangOpts) {}

88

90 PP = &NewPP;

92

93

94 PP->addPPCallbacks(std::make_uniquedetail::MacroExpansionRangeRecorder(

95 *PP, *SM, ExpansionRanges));

96

98}

99

100std::optional

102 if (MacroExpansionLoc.isMacroID())

103 return std::nullopt;

104

105

106 if (ExpansionRanges.find_as(MacroExpansionLoc) == ExpansionRanges.end())

107 return std::nullopt;

108

109

110 const auto It = ExpandedTokens.find_as(MacroExpansionLoc);

111 if (It == ExpandedTokens.end())

112 return StringRef{""};

113

114

115 return It->getSecond().str();

116}

117

118std::optional

120 if (MacroExpansionLoc.isMacroID())

121 return std::nullopt;

122

123 const auto It = ExpansionRanges.find_as(MacroExpansionLoc);

124 if (It == ExpansionRanges.end())

125 return std::nullopt;

126

127 assert(It->getFirst() != It->getSecond() &&

128 "Every macro expansion must cover a non-empty range.");

129

132 LangOpts);

133}

134

137}

140}

141

143 std::vector<std::pair<SourceLocation, SourceLocation>> LocalExpansionRanges;

144 LocalExpansionRanges.reserve(ExpansionRanges.size());

145 for (const auto &Record : ExpansionRanges)

146 LocalExpansionRanges.emplace_back(

147 std::make_pair(Record.getFirst(), Record.getSecond()));

148 llvm::sort(LocalExpansionRanges);

149

150 OS << "\n=============== ExpansionRanges ===============\n";

151 for (const auto &Record : LocalExpansionRanges) {

152 OS << "> ";

153 Record.first.print(OS, *SM);

154 OS << ", ";

155 Record.second.print(OS, *SM);

156 OS << '\n';

157 }

158}

159

161 std::vector<std::pair<SourceLocation, MacroExpansionText>>

162 LocalExpandedTokens;

163 LocalExpandedTokens.reserve(ExpandedTokens.size());

164 for (const auto &Record : ExpandedTokens)

165 LocalExpandedTokens.emplace_back(

166 std::make_pair(Record.getFirst(), Record.getSecond()));

167 llvm::sort(LocalExpandedTokens);

168

169 OS << "\n=============== ExpandedTokens ===============\n";

170 for (const auto &Record : LocalExpandedTokens) {

171 OS << "> ";

172 Record.first.print(OS, *SM);

173 OS << " -> '" << Record.second << "'\n";

174 }

175}

176

178 assert(Tok.isNot(tok::raw_identifier));

179

180

182 return;

183

185

186

187

188

189 OS << II->getName() << ' ';

192 } else {

193 char Tmp[256];

194 if (Tok.getLength() < sizeof(Tmp)) {

195 const char *TokPtr = Tmp;

196

197 unsigned Len = PP.getSpelling(Tok, TokPtr);

198 OS.write(TokPtr, Len);

199 } else {

200 OS << "";

201 }

202 }

203}

204

205void MacroExpansionContext::onTokenLexed(const Token &Tok) {

208 return;

209

210 LLVM_DEBUG(llvm::dbgs() << "lexed macro expansion token '";

211 dumpTokenInto(*PP, llvm::dbgs(), Tok); llvm::dbgs() << "' at ";

212 SLoc.print(llvm::dbgs(), *SM); llvm::dbgs() << '\n';);

213

214

216

217 MacroExpansionText TokenAsString;

218 llvm::raw_svector_ostream OS(TokenAsString);

219

220

221

222

224

225 ExpansionMap::iterator It;

226 bool Inserted;

227 std::tie(It, Inserted) =

228 ExpandedTokens.try_emplace(CurrExpansionLoc, std::move(TokenAsString));

229 if (!Inserted)

230 It->getSecond().append(TokenAsString);

231}

232

static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)

llvm::MachO::Record Record

static void dumpTokenInto(const clang::Preprocessor &PP, llvm::raw_ostream &OS, clang::Token Tok)

static CharSourceRange getCharRange(SourceRange R)

One of these records is kept for each identifier that is lexed.

StringRef getName() const

Return the actual identifier string.

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)

Returns a string for the source that the range encompasses.

MacroArgs - An instance of this class captures information about the formal arguments specified to a ...

A description of the current definition of a macro.

void registerForPreprocessor(Preprocessor &PP)

Register the necessary callbacks to the Preprocessor to record the expansion events and the generated...

LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const

LLVM_DUMP_METHOD void dumpExpandedTexts() const

LLVM_DUMP_METHOD void dumpExpansionRanges() const

MacroExpansionContext(const LangOptions &LangOpts)

Creates a MacroExpansionContext.

LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const

std::optional< StringRef > getExpandedText(SourceLocation MacroExpansionLoc) const

std::optional< StringRef > getOriginalText(SourceLocation MacroExpansionLoc) const

This interface provides a way to observe the actions of the preprocessor as it does its thing.

Engages in a tight little dance with the lexer to efficiently preprocess tokens.

void addPPCallbacks(std::unique_ptr< PPCallbacks > C)

SourceManager & getSourceManager() const

StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const

Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...

void setTokenWatcher(llvm::unique_function< void(const clang::Token &)> F)

Register a function that would be called on each token in the final expanded token stream.

Encodes a location in the source.

void print(raw_ostream &OS, const SourceManager &SM) const

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

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

SourceLocation getExpansionLoc(SourceLocation Loc) const

Given a SourceLocation object Loc, return the expansion location referenced by the ID.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

Token - This structure provides full information about a lexed token.

IdentifierInfo * getIdentifierInfo() const

bool isLiteral() const

Return true if this is a "literal", like a numeric constant, string, etc.

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

unsigned getLength() const

bool isNot(tok::TokenKind K) const

bool isAnnotation() const

Return true if this is any of tok::annot_* kind tokens.

bool needsCleaning() const

Return true if this token has trigraphs or escaped newlines in it.

const char * getLiteralData() const

getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...

void MacroExpands(const Token &MacroName, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override

Called by Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is found.

MacroExpansionRangeRecorder(const Preprocessor &PP, SourceManager &SM, MacroExpansionContext::ExpansionRangeMap &ExpansionRanges)

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