1e5dd7070Spatrick //===--- MacroPPCallbacks.cpp ---------------------------------------------===//
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 contains implementation for the macro preprocessors callbacks.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "MacroPPCallbacks.h"
14e5dd7070Spatrick #include "CGDebugInfo.h"
15e5dd7070Spatrick #include "clang/CodeGen/ModuleBuilder.h"
16e5dd7070Spatrick #include "clang/Lex/MacroInfo.h"
17e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
18e5dd7070Spatrick
19e5dd7070Spatrick using namespace clang;
20e5dd7070Spatrick
writeMacroDefinition(const IdentifierInfo & II,const MacroInfo & MI,Preprocessor & PP,raw_ostream & Name,raw_ostream & Value)21e5dd7070Spatrick void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
22e5dd7070Spatrick const MacroInfo &MI,
23e5dd7070Spatrick Preprocessor &PP, raw_ostream &Name,
24e5dd7070Spatrick raw_ostream &Value) {
25e5dd7070Spatrick Name << II.getName();
26e5dd7070Spatrick
27e5dd7070Spatrick if (MI.isFunctionLike()) {
28e5dd7070Spatrick Name << '(';
29e5dd7070Spatrick if (!MI.param_empty()) {
30e5dd7070Spatrick MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
31e5dd7070Spatrick for (; AI + 1 != E; ++AI) {
32e5dd7070Spatrick Name << (*AI)->getName();
33e5dd7070Spatrick Name << ',';
34e5dd7070Spatrick }
35e5dd7070Spatrick
36e5dd7070Spatrick // Last argument.
37e5dd7070Spatrick if ((*AI)->getName() == "__VA_ARGS__")
38e5dd7070Spatrick Name << "...";
39e5dd7070Spatrick else
40e5dd7070Spatrick Name << (*AI)->getName();
41e5dd7070Spatrick }
42e5dd7070Spatrick
43e5dd7070Spatrick if (MI.isGNUVarargs())
44e5dd7070Spatrick // #define foo(x...)
45e5dd7070Spatrick Name << "...";
46e5dd7070Spatrick
47e5dd7070Spatrick Name << ')';
48e5dd7070Spatrick }
49e5dd7070Spatrick
50e5dd7070Spatrick SmallString<128> SpellingBuffer;
51e5dd7070Spatrick bool First = true;
52e5dd7070Spatrick for (const auto &T : MI.tokens()) {
53e5dd7070Spatrick if (!First && T.hasLeadingSpace())
54e5dd7070Spatrick Value << ' ';
55e5dd7070Spatrick
56e5dd7070Spatrick Value << PP.getSpelling(T, SpellingBuffer);
57e5dd7070Spatrick First = false;
58e5dd7070Spatrick }
59e5dd7070Spatrick }
60e5dd7070Spatrick
MacroPPCallbacks(CodeGenerator * Gen,Preprocessor & PP)61e5dd7070Spatrick MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
62e5dd7070Spatrick : Gen(Gen), PP(PP), Status(NoScope) {}
63e5dd7070Spatrick
64e5dd7070Spatrick // This is the expected flow of enter/exit compiler and user files:
65e5dd7070Spatrick // - Main File Enter
66e5dd7070Spatrick // - <built-in> file enter
67e5dd7070Spatrick // {Compiler macro definitions} - (Line=0, no scope)
68e5dd7070Spatrick // - (Optional) <command line> file enter
69e5dd7070Spatrick // {Command line macro definitions} - (Line=0, no scope)
70e5dd7070Spatrick // - (Optional) <command line> file exit
71e5dd7070Spatrick // {Command line file includes} - (Line=0, Main file scope)
72e5dd7070Spatrick // {macro definitions and file includes} - (Line!=0, Parent scope)
73e5dd7070Spatrick // - <built-in> file exit
74e5dd7070Spatrick // {User code macro definitions and file includes} - (Line!=0, Parent scope)
75e5dd7070Spatrick
getCurrentScope()76e5dd7070Spatrick llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
77e5dd7070Spatrick if (Status == MainFileScope || Status == CommandLineIncludeScope)
78e5dd7070Spatrick return Scopes.back();
79e5dd7070Spatrick return nullptr;
80e5dd7070Spatrick }
81e5dd7070Spatrick
getCorrectLocation(SourceLocation Loc)82e5dd7070Spatrick SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
83e5dd7070Spatrick if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
84e5dd7070Spatrick return Loc;
85e5dd7070Spatrick
86e5dd7070Spatrick // While parsing skipped files, location of macros is invalid.
87e5dd7070Spatrick // Invalid location represents line zero.
88e5dd7070Spatrick return SourceLocation();
89e5dd7070Spatrick }
90e5dd7070Spatrick
updateStatusToNextScope()91e5dd7070Spatrick void MacroPPCallbacks::updateStatusToNextScope() {
92e5dd7070Spatrick switch (Status) {
93e5dd7070Spatrick case NoScope:
94e5dd7070Spatrick Status = InitializedScope;
95e5dd7070Spatrick break;
96e5dd7070Spatrick case InitializedScope:
97e5dd7070Spatrick Status = BuiltinScope;
98e5dd7070Spatrick break;
99e5dd7070Spatrick case BuiltinScope:
100e5dd7070Spatrick Status = CommandLineIncludeScope;
101e5dd7070Spatrick break;
102e5dd7070Spatrick case CommandLineIncludeScope:
103e5dd7070Spatrick Status = MainFileScope;
104e5dd7070Spatrick break;
105e5dd7070Spatrick case MainFileScope:
106e5dd7070Spatrick llvm_unreachable("There is no next scope, already in the final scope");
107e5dd7070Spatrick }
108e5dd7070Spatrick }
109e5dd7070Spatrick
FileEntered(SourceLocation Loc)110e5dd7070Spatrick void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
111e5dd7070Spatrick SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
112e5dd7070Spatrick switch (Status) {
113e5dd7070Spatrick case NoScope:
114e5dd7070Spatrick updateStatusToNextScope();
115e5dd7070Spatrick break;
116e5dd7070Spatrick case InitializedScope:
117e5dd7070Spatrick updateStatusToNextScope();
118e5dd7070Spatrick return;
119e5dd7070Spatrick case BuiltinScope:
120e5dd7070Spatrick if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
121e5dd7070Spatrick return;
122e5dd7070Spatrick updateStatusToNextScope();
123*12c85518Srobert [[fallthrough]];
124e5dd7070Spatrick case CommandLineIncludeScope:
125e5dd7070Spatrick EnteredCommandLineIncludeFiles++;
126e5dd7070Spatrick break;
127e5dd7070Spatrick case MainFileScope:
128e5dd7070Spatrick break;
129e5dd7070Spatrick }
130e5dd7070Spatrick
131e5dd7070Spatrick Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
132e5dd7070Spatrick LineLoc, Loc));
133e5dd7070Spatrick }
134e5dd7070Spatrick
FileExited(SourceLocation Loc)135e5dd7070Spatrick void MacroPPCallbacks::FileExited(SourceLocation Loc) {
136e5dd7070Spatrick switch (Status) {
137e5dd7070Spatrick default:
138e5dd7070Spatrick llvm_unreachable("Do not expect to exit a file from current scope");
139e5dd7070Spatrick case BuiltinScope:
140e5dd7070Spatrick if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
141e5dd7070Spatrick // Skip next scope and change status to MainFileScope.
142e5dd7070Spatrick Status = MainFileScope;
143e5dd7070Spatrick return;
144e5dd7070Spatrick case CommandLineIncludeScope:
145e5dd7070Spatrick if (!EnteredCommandLineIncludeFiles) {
146e5dd7070Spatrick updateStatusToNextScope();
147e5dd7070Spatrick return;
148e5dd7070Spatrick }
149e5dd7070Spatrick EnteredCommandLineIncludeFiles--;
150e5dd7070Spatrick break;
151e5dd7070Spatrick case MainFileScope:
152e5dd7070Spatrick break;
153e5dd7070Spatrick }
154e5dd7070Spatrick
155e5dd7070Spatrick Scopes.pop_back();
156e5dd7070Spatrick }
157e5dd7070Spatrick
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)158e5dd7070Spatrick void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
159e5dd7070Spatrick SrcMgr::CharacteristicKind FileType,
160e5dd7070Spatrick FileID PrevFID) {
161e5dd7070Spatrick // Only care about enter file or exit file changes.
162e5dd7070Spatrick if (Reason == EnterFile)
163e5dd7070Spatrick FileEntered(Loc);
164e5dd7070Spatrick else if (Reason == ExitFile)
165e5dd7070Spatrick FileExited(Loc);
166e5dd7070Spatrick }
167e5dd7070Spatrick
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)168e5dd7070Spatrick void MacroPPCallbacks::InclusionDirective(
169e5dd7070Spatrick SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
170*12c85518Srobert bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
171e5dd7070Spatrick StringRef SearchPath, StringRef RelativePath, const Module *Imported,
172e5dd7070Spatrick SrcMgr::CharacteristicKind FileType) {
173e5dd7070Spatrick
174e5dd7070Spatrick // Record the line location of the current included file.
175e5dd7070Spatrick LastHashLoc = HashLoc;
176e5dd7070Spatrick }
177e5dd7070Spatrick
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)178e5dd7070Spatrick void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
179e5dd7070Spatrick const MacroDirective *MD) {
180e5dd7070Spatrick IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
181e5dd7070Spatrick SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
182e5dd7070Spatrick std::string NameBuffer, ValueBuffer;
183e5dd7070Spatrick llvm::raw_string_ostream Name(NameBuffer);
184e5dd7070Spatrick llvm::raw_string_ostream Value(ValueBuffer);
185e5dd7070Spatrick writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
186e5dd7070Spatrick Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
187e5dd7070Spatrick llvm::dwarf::DW_MACINFO_define, location,
188e5dd7070Spatrick Name.str(), Value.str());
189e5dd7070Spatrick }
190e5dd7070Spatrick
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * Undef)191e5dd7070Spatrick void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
192e5dd7070Spatrick const MacroDefinition &MD,
193e5dd7070Spatrick const MacroDirective *Undef) {
194e5dd7070Spatrick IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
195e5dd7070Spatrick SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
196e5dd7070Spatrick Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
197e5dd7070Spatrick llvm::dwarf::DW_MACINFO_undef, location,
198e5dd7070Spatrick Id->getName(), "");
199e5dd7070Spatrick }
200