xref: /openbsd-src/gnu/llvm/clang/lib/CodeGen/MacroPPCallbacks.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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