1546bc110SAmjad Aboud //===--- MacroPPCallbacks.cpp ---------------------------------------------===//
2546bc110SAmjad Aboud //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6546bc110SAmjad Aboud //
7546bc110SAmjad Aboud //===----------------------------------------------------------------------===//
8546bc110SAmjad Aboud //
9546bc110SAmjad Aboud //  This file contains implementation for the macro preprocessors callbacks.
10546bc110SAmjad Aboud //
11546bc110SAmjad Aboud //===----------------------------------------------------------------------===//
12546bc110SAmjad Aboud 
13546bc110SAmjad Aboud #include "MacroPPCallbacks.h"
14546bc110SAmjad Aboud #include "CGDebugInfo.h"
15546bc110SAmjad Aboud #include "clang/CodeGen/ModuleBuilder.h"
16994b8befSRichard Trieu #include "clang/Lex/MacroInfo.h"
17994b8befSRichard Trieu #include "clang/Lex/Preprocessor.h"
18546bc110SAmjad Aboud 
19546bc110SAmjad Aboud using namespace clang;
20546bc110SAmjad Aboud 
writeMacroDefinition(const IdentifierInfo & II,const MacroInfo & MI,Preprocessor & PP,raw_ostream & Name,raw_ostream & Value)21546bc110SAmjad Aboud void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
22546bc110SAmjad Aboud                                             const MacroInfo &MI,
23546bc110SAmjad Aboud                                             Preprocessor &PP, raw_ostream &Name,
24546bc110SAmjad Aboud                                             raw_ostream &Value) {
25546bc110SAmjad Aboud   Name << II.getName();
26546bc110SAmjad Aboud 
27546bc110SAmjad Aboud   if (MI.isFunctionLike()) {
28546bc110SAmjad Aboud     Name << '(';
29ac506d74SFaisal Vali     if (!MI.param_empty()) {
30ac506d74SFaisal Vali       MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
31546bc110SAmjad Aboud       for (; AI + 1 != E; ++AI) {
32546bc110SAmjad Aboud         Name << (*AI)->getName();
33546bc110SAmjad Aboud         Name << ',';
34546bc110SAmjad Aboud       }
35546bc110SAmjad Aboud 
36546bc110SAmjad Aboud       // Last argument.
37546bc110SAmjad Aboud       if ((*AI)->getName() == "__VA_ARGS__")
38546bc110SAmjad Aboud         Name << "...";
39546bc110SAmjad Aboud       else
40546bc110SAmjad Aboud         Name << (*AI)->getName();
41546bc110SAmjad Aboud     }
42546bc110SAmjad Aboud 
43546bc110SAmjad Aboud     if (MI.isGNUVarargs())
44546bc110SAmjad Aboud       // #define foo(x...)
45546bc110SAmjad Aboud       Name << "...";
46546bc110SAmjad Aboud 
47546bc110SAmjad Aboud     Name << ')';
48546bc110SAmjad Aboud   }
49546bc110SAmjad Aboud 
50546bc110SAmjad Aboud   SmallString<128> SpellingBuffer;
51546bc110SAmjad Aboud   bool First = true;
52546bc110SAmjad Aboud   for (const auto &T : MI.tokens()) {
53546bc110SAmjad Aboud     if (!First && T.hasLeadingSpace())
54546bc110SAmjad Aboud       Value << ' ';
55546bc110SAmjad Aboud 
56546bc110SAmjad Aboud     Value << PP.getSpelling(T, SpellingBuffer);
57546bc110SAmjad Aboud     First = false;
58546bc110SAmjad Aboud   }
59546bc110SAmjad Aboud }
60546bc110SAmjad Aboud 
MacroPPCallbacks(CodeGenerator * Gen,Preprocessor & PP)61546bc110SAmjad Aboud MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
62546bc110SAmjad Aboud     : Gen(Gen), PP(PP), Status(NoScope) {}
63546bc110SAmjad Aboud 
64cdbfd0edSEric Christopher // This is the expected flow of enter/exit compiler and user files:
65cdbfd0edSEric Christopher // - Main File Enter
66cdbfd0edSEric Christopher //   - <built-in> file enter
67cdbfd0edSEric Christopher //     {Compiler macro definitions} - (Line=0, no scope)
68cdbfd0edSEric Christopher //     - (Optional) <command line> file enter
69cdbfd0edSEric Christopher //     {Command line macro definitions} - (Line=0, no scope)
70cdbfd0edSEric Christopher //     - (Optional) <command line> file exit
71cdbfd0edSEric Christopher //     {Command line file includes} - (Line=0, Main file scope)
72cdbfd0edSEric Christopher //       {macro definitions and file includes} - (Line!=0, Parent scope)
73cdbfd0edSEric Christopher //   - <built-in> file exit
74cdbfd0edSEric Christopher //   {User code macro definitions and file includes} - (Line!=0, Parent scope)
75546bc110SAmjad Aboud 
getCurrentScope()76546bc110SAmjad Aboud llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
77546bc110SAmjad Aboud   if (Status == MainFileScope || Status == CommandLineIncludeScope)
78546bc110SAmjad Aboud     return Scopes.back();
79546bc110SAmjad Aboud   return nullptr;
80546bc110SAmjad Aboud }
81546bc110SAmjad Aboud 
getCorrectLocation(SourceLocation Loc)82546bc110SAmjad Aboud SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
83546bc110SAmjad Aboud   if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
84546bc110SAmjad Aboud     return Loc;
85546bc110SAmjad Aboud 
86546bc110SAmjad Aboud   // While parsing skipped files, location of macros is invalid.
87546bc110SAmjad Aboud   // Invalid location represents line zero.
88546bc110SAmjad Aboud   return SourceLocation();
89546bc110SAmjad Aboud }
90546bc110SAmjad Aboud 
updateStatusToNextScope()91546bc110SAmjad Aboud void MacroPPCallbacks::updateStatusToNextScope() {
92546bc110SAmjad Aboud   switch (Status) {
93546bc110SAmjad Aboud   case NoScope:
94546bc110SAmjad Aboud     Status = InitializedScope;
95546bc110SAmjad Aboud     break;
96546bc110SAmjad Aboud   case InitializedScope:
97546bc110SAmjad Aboud     Status = BuiltinScope;
98546bc110SAmjad Aboud     break;
99546bc110SAmjad Aboud   case BuiltinScope:
100546bc110SAmjad Aboud     Status = CommandLineIncludeScope;
101546bc110SAmjad Aboud     break;
102546bc110SAmjad Aboud   case CommandLineIncludeScope:
103546bc110SAmjad Aboud     Status = MainFileScope;
104546bc110SAmjad Aboud     break;
105546bc110SAmjad Aboud   case MainFileScope:
106546bc110SAmjad Aboud     llvm_unreachable("There is no next scope, already in the final scope");
107546bc110SAmjad Aboud   }
108546bc110SAmjad Aboud }
109546bc110SAmjad Aboud 
FileEntered(SourceLocation Loc)110546bc110SAmjad Aboud void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
111546bc110SAmjad Aboud   SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
112546bc110SAmjad Aboud   switch (Status) {
113546bc110SAmjad Aboud   case NoScope:
114546bc110SAmjad Aboud     updateStatusToNextScope();
115546bc110SAmjad Aboud     break;
116546bc110SAmjad Aboud   case InitializedScope:
117546bc110SAmjad Aboud     updateStatusToNextScope();
118546bc110SAmjad Aboud     return;
119546bc110SAmjad Aboud   case BuiltinScope:
120a32a2e34SRoman Lebedev     if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
121546bc110SAmjad Aboud       return;
122546bc110SAmjad Aboud     updateStatusToNextScope();
123546bc110SAmjad Aboud     LLVM_FALLTHROUGH;
124546bc110SAmjad Aboud   case CommandLineIncludeScope:
125546bc110SAmjad Aboud     EnteredCommandLineIncludeFiles++;
126546bc110SAmjad Aboud     break;
127546bc110SAmjad Aboud   case MainFileScope:
128546bc110SAmjad Aboud     break;
129546bc110SAmjad Aboud   }
130546bc110SAmjad Aboud 
131546bc110SAmjad Aboud   Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
132546bc110SAmjad Aboud                                                               LineLoc, Loc));
133546bc110SAmjad Aboud }
134546bc110SAmjad Aboud 
FileExited(SourceLocation Loc)135546bc110SAmjad Aboud void MacroPPCallbacks::FileExited(SourceLocation Loc) {
136546bc110SAmjad Aboud   switch (Status) {
137546bc110SAmjad Aboud   default:
138546bc110SAmjad Aboud     llvm_unreachable("Do not expect to exit a file from current scope");
139546bc110SAmjad Aboud   case BuiltinScope:
140a32a2e34SRoman Lebedev     if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
141546bc110SAmjad Aboud       // Skip next scope and change status to MainFileScope.
142546bc110SAmjad Aboud       Status = MainFileScope;
143546bc110SAmjad Aboud     return;
144546bc110SAmjad Aboud   case CommandLineIncludeScope:
145546bc110SAmjad Aboud     if (!EnteredCommandLineIncludeFiles) {
146546bc110SAmjad Aboud       updateStatusToNextScope();
147546bc110SAmjad Aboud       return;
148546bc110SAmjad Aboud     }
149546bc110SAmjad Aboud     EnteredCommandLineIncludeFiles--;
150546bc110SAmjad Aboud     break;
151546bc110SAmjad Aboud   case MainFileScope:
152546bc110SAmjad Aboud     break;
153546bc110SAmjad Aboud   }
154546bc110SAmjad Aboud 
155546bc110SAmjad Aboud   Scopes.pop_back();
156546bc110SAmjad Aboud }
157546bc110SAmjad Aboud 
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)158546bc110SAmjad Aboud void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
159546bc110SAmjad Aboud                                    SrcMgr::CharacteristicKind FileType,
160546bc110SAmjad Aboud                                    FileID PrevFID) {
161546bc110SAmjad Aboud   // Only care about enter file or exit file changes.
162546bc110SAmjad Aboud   if (Reason == EnterFile)
163546bc110SAmjad Aboud     FileEntered(Loc);
164546bc110SAmjad Aboud   else if (Reason == ExitFile)
165546bc110SAmjad Aboud     FileExited(Loc);
166546bc110SAmjad Aboud }
167546bc110SAmjad Aboud 
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,Optional<FileEntryRef> File,StringRef SearchPath,StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)168546bc110SAmjad Aboud void MacroPPCallbacks::InclusionDirective(
169546bc110SAmjad Aboud     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
170*d79ad2f1SJan Svoboda     bool IsAngled, CharSourceRange FilenameRange, Optional<FileEntryRef> File,
17196fbe58bSJulie Hockett     StringRef SearchPath, StringRef RelativePath, const Module *Imported,
17296fbe58bSJulie Hockett     SrcMgr::CharacteristicKind FileType) {
173546bc110SAmjad Aboud 
174546bc110SAmjad Aboud   // Record the line location of the current included file.
175546bc110SAmjad Aboud   LastHashLoc = HashLoc;
176546bc110SAmjad Aboud }
177546bc110SAmjad Aboud 
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)178546bc110SAmjad Aboud void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
179546bc110SAmjad Aboud                                     const MacroDirective *MD) {
180546bc110SAmjad Aboud   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
181546bc110SAmjad Aboud   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
182546bc110SAmjad Aboud   std::string NameBuffer, ValueBuffer;
183546bc110SAmjad Aboud   llvm::raw_string_ostream Name(NameBuffer);
184546bc110SAmjad Aboud   llvm::raw_string_ostream Value(ValueBuffer);
185546bc110SAmjad Aboud   writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
186546bc110SAmjad Aboud   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
187546bc110SAmjad Aboud                                      llvm::dwarf::DW_MACINFO_define, location,
188546bc110SAmjad Aboud                                      Name.str(), Value.str());
189546bc110SAmjad Aboud }
190546bc110SAmjad Aboud 
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * Undef)191546bc110SAmjad Aboud void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
192204103f3SDavid Blaikie                                       const MacroDefinition &MD,
193204103f3SDavid Blaikie                                       const MacroDirective *Undef) {
194546bc110SAmjad Aboud   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
195546bc110SAmjad Aboud   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
196546bc110SAmjad Aboud   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
197546bc110SAmjad Aboud                                      llvm::dwarf::DW_MACINFO_undef, location,
198546bc110SAmjad Aboud                                      Id->getName(), "");
199546bc110SAmjad Aboud }
200