xref: /src/contrib/llvm-project/clang/lib/CodeGen/MacroPPCallbacks.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
17442d6faSDimitry Andric //===--- MacroPPCallbacks.cpp ---------------------------------------------===//
27442d6faSDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67442d6faSDimitry Andric //
77442d6faSDimitry Andric //===----------------------------------------------------------------------===//
87442d6faSDimitry Andric //
97442d6faSDimitry Andric //  This file contains implementation for the macro preprocessors callbacks.
107442d6faSDimitry Andric //
117442d6faSDimitry Andric //===----------------------------------------------------------------------===//
127442d6faSDimitry Andric 
137442d6faSDimitry Andric #include "MacroPPCallbacks.h"
147442d6faSDimitry Andric #include "CGDebugInfo.h"
157442d6faSDimitry Andric #include "clang/CodeGen/ModuleBuilder.h"
16676fbe81SDimitry Andric #include "clang/Lex/MacroInfo.h"
17676fbe81SDimitry Andric #include "clang/Lex/Preprocessor.h"
187442d6faSDimitry Andric 
197442d6faSDimitry Andric using namespace clang;
207442d6faSDimitry Andric 
writeMacroDefinition(const IdentifierInfo & II,const MacroInfo & MI,Preprocessor & PP,raw_ostream & Name,raw_ostream & Value)217442d6faSDimitry Andric void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
227442d6faSDimitry Andric                                             const MacroInfo &MI,
237442d6faSDimitry Andric                                             Preprocessor &PP, raw_ostream &Name,
247442d6faSDimitry Andric                                             raw_ostream &Value) {
257442d6faSDimitry Andric   Name << II.getName();
267442d6faSDimitry Andric 
277442d6faSDimitry Andric   if (MI.isFunctionLike()) {
287442d6faSDimitry Andric     Name << '(';
29de51d671SDimitry Andric     if (!MI.param_empty()) {
30de51d671SDimitry Andric       MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
317442d6faSDimitry Andric       for (; AI + 1 != E; ++AI) {
327442d6faSDimitry Andric         Name << (*AI)->getName();
337442d6faSDimitry Andric         Name << ',';
347442d6faSDimitry Andric       }
357442d6faSDimitry Andric 
367442d6faSDimitry Andric       // Last argument.
377442d6faSDimitry Andric       if ((*AI)->getName() == "__VA_ARGS__")
387442d6faSDimitry Andric         Name << "...";
397442d6faSDimitry Andric       else
407442d6faSDimitry Andric         Name << (*AI)->getName();
417442d6faSDimitry Andric     }
427442d6faSDimitry Andric 
437442d6faSDimitry Andric     if (MI.isGNUVarargs())
447442d6faSDimitry Andric       // #define foo(x...)
457442d6faSDimitry Andric       Name << "...";
467442d6faSDimitry Andric 
477442d6faSDimitry Andric     Name << ')';
487442d6faSDimitry Andric   }
497442d6faSDimitry Andric 
507442d6faSDimitry Andric   SmallString<128> SpellingBuffer;
517442d6faSDimitry Andric   bool First = true;
527442d6faSDimitry Andric   for (const auto &T : MI.tokens()) {
537442d6faSDimitry Andric     if (!First && T.hasLeadingSpace())
547442d6faSDimitry Andric       Value << ' ';
557442d6faSDimitry Andric 
567442d6faSDimitry Andric     Value << PP.getSpelling(T, SpellingBuffer);
577442d6faSDimitry Andric     First = false;
587442d6faSDimitry Andric   }
597442d6faSDimitry Andric }
607442d6faSDimitry Andric 
MacroPPCallbacks(CodeGenerator * Gen,Preprocessor & PP)617442d6faSDimitry Andric MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
627442d6faSDimitry Andric     : Gen(Gen), PP(PP), Status(NoScope) {}
637442d6faSDimitry Andric 
647442d6faSDimitry Andric // This is the expected flow of enter/exit compiler and user files:
657442d6faSDimitry Andric // - Main File Enter
667442d6faSDimitry Andric //   - <built-in> file enter
677442d6faSDimitry Andric //     {Compiler macro definitions} - (Line=0, no scope)
687442d6faSDimitry Andric //     - (Optional) <command line> file enter
697442d6faSDimitry Andric //     {Command line macro definitions} - (Line=0, no scope)
707442d6faSDimitry Andric //     - (Optional) <command line> file exit
717442d6faSDimitry Andric //     {Command line file includes} - (Line=0, Main file scope)
727442d6faSDimitry Andric //       {macro definitions and file includes} - (Line!=0, Parent scope)
737442d6faSDimitry Andric //   - <built-in> file exit
747442d6faSDimitry Andric //   {User code macro definitions and file includes} - (Line!=0, Parent scope)
757442d6faSDimitry Andric 
getCurrentScope()767442d6faSDimitry Andric llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
777442d6faSDimitry Andric   if (Status == MainFileScope || Status == CommandLineIncludeScope)
787442d6faSDimitry Andric     return Scopes.back();
797442d6faSDimitry Andric   return nullptr;
807442d6faSDimitry Andric }
817442d6faSDimitry Andric 
getCorrectLocation(SourceLocation Loc)827442d6faSDimitry Andric SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
837442d6faSDimitry Andric   if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
847442d6faSDimitry Andric     return Loc;
857442d6faSDimitry Andric 
867442d6faSDimitry Andric   // While parsing skipped files, location of macros is invalid.
877442d6faSDimitry Andric   // Invalid location represents line zero.
887442d6faSDimitry Andric   return SourceLocation();
897442d6faSDimitry Andric }
907442d6faSDimitry Andric 
updateStatusToNextScope()917442d6faSDimitry Andric void MacroPPCallbacks::updateStatusToNextScope() {
927442d6faSDimitry Andric   switch (Status) {
937442d6faSDimitry Andric   case NoScope:
947442d6faSDimitry Andric     Status = InitializedScope;
957442d6faSDimitry Andric     break;
967442d6faSDimitry Andric   case InitializedScope:
977442d6faSDimitry Andric     Status = BuiltinScope;
987442d6faSDimitry Andric     break;
997442d6faSDimitry Andric   case BuiltinScope:
1007442d6faSDimitry Andric     Status = CommandLineIncludeScope;
1017442d6faSDimitry Andric     break;
1027442d6faSDimitry Andric   case CommandLineIncludeScope:
1037442d6faSDimitry Andric     Status = MainFileScope;
1047442d6faSDimitry Andric     break;
1057442d6faSDimitry Andric   case MainFileScope:
1067442d6faSDimitry Andric     llvm_unreachable("There is no next scope, already in the final scope");
1077442d6faSDimitry Andric   }
1087442d6faSDimitry Andric }
1097442d6faSDimitry Andric 
FileEntered(SourceLocation Loc)1107442d6faSDimitry Andric void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
1117442d6faSDimitry Andric   SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
1127442d6faSDimitry Andric   switch (Status) {
1137442d6faSDimitry Andric   case NoScope:
1147442d6faSDimitry Andric     updateStatusToNextScope();
1157442d6faSDimitry Andric     break;
1167442d6faSDimitry Andric   case InitializedScope:
1177442d6faSDimitry Andric     updateStatusToNextScope();
1187442d6faSDimitry Andric     return;
1197442d6faSDimitry Andric   case BuiltinScope:
120676fbe81SDimitry Andric     if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
1217442d6faSDimitry Andric       return;
1227442d6faSDimitry Andric     updateStatusToNextScope();
123e3b55780SDimitry Andric     [[fallthrough]];
1247442d6faSDimitry Andric   case CommandLineIncludeScope:
1257442d6faSDimitry Andric     EnteredCommandLineIncludeFiles++;
1267442d6faSDimitry Andric     break;
1277442d6faSDimitry Andric   case MainFileScope:
1287442d6faSDimitry Andric     break;
1297442d6faSDimitry Andric   }
1307442d6faSDimitry Andric 
1317442d6faSDimitry Andric   Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
1327442d6faSDimitry Andric                                                               LineLoc, Loc));
1337442d6faSDimitry Andric }
1347442d6faSDimitry Andric 
FileExited(SourceLocation Loc)1357442d6faSDimitry Andric void MacroPPCallbacks::FileExited(SourceLocation Loc) {
1367442d6faSDimitry Andric   switch (Status) {
1377442d6faSDimitry Andric   default:
1387442d6faSDimitry Andric     llvm_unreachable("Do not expect to exit a file from current scope");
1397442d6faSDimitry Andric   case BuiltinScope:
140676fbe81SDimitry Andric     if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
1417442d6faSDimitry Andric       // Skip next scope and change status to MainFileScope.
1427442d6faSDimitry Andric       Status = MainFileScope;
1437442d6faSDimitry Andric     return;
1447442d6faSDimitry Andric   case CommandLineIncludeScope:
1457442d6faSDimitry Andric     if (!EnteredCommandLineIncludeFiles) {
1467442d6faSDimitry Andric       updateStatusToNextScope();
1477442d6faSDimitry Andric       return;
1487442d6faSDimitry Andric     }
1497442d6faSDimitry Andric     EnteredCommandLineIncludeFiles--;
1507442d6faSDimitry Andric     break;
1517442d6faSDimitry Andric   case MainFileScope:
1527442d6faSDimitry Andric     break;
1537442d6faSDimitry Andric   }
1547442d6faSDimitry Andric 
1557442d6faSDimitry Andric   Scopes.pop_back();
1567442d6faSDimitry Andric }
1577442d6faSDimitry Andric 
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)1587442d6faSDimitry Andric void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
1597442d6faSDimitry Andric                                    SrcMgr::CharacteristicKind FileType,
1607442d6faSDimitry Andric                                    FileID PrevFID) {
1617442d6faSDimitry Andric   // Only care about enter file or exit file changes.
1627442d6faSDimitry Andric   if (Reason == EnterFile)
1637442d6faSDimitry Andric     FileEntered(Loc);
1647442d6faSDimitry Andric   else if (Reason == ExitFile)
1657442d6faSDimitry Andric     FileExited(Loc);
1667442d6faSDimitry Andric }
1677442d6faSDimitry Andric 
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * SuggestedModule,bool ModuleImported,SrcMgr::CharacteristicKind FileType)1687442d6faSDimitry Andric void MacroPPCallbacks::InclusionDirective(
1697442d6faSDimitry Andric     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
170e3b55780SDimitry Andric     bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
171ac9a064cSDimitry Andric     StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
172ac9a064cSDimitry Andric     bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
1737442d6faSDimitry Andric 
1747442d6faSDimitry Andric   // Record the line location of the current included file.
1757442d6faSDimitry Andric   LastHashLoc = HashLoc;
1767442d6faSDimitry Andric }
1777442d6faSDimitry Andric 
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)1787442d6faSDimitry Andric void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
1797442d6faSDimitry Andric                                     const MacroDirective *MD) {
1807442d6faSDimitry Andric   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
1817442d6faSDimitry Andric   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
1827442d6faSDimitry Andric   std::string NameBuffer, ValueBuffer;
1837442d6faSDimitry Andric   llvm::raw_string_ostream Name(NameBuffer);
1847442d6faSDimitry Andric   llvm::raw_string_ostream Value(ValueBuffer);
1857442d6faSDimitry Andric   writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
1867442d6faSDimitry Andric   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
1877442d6faSDimitry Andric                                      llvm::dwarf::DW_MACINFO_define, location,
1887442d6faSDimitry Andric                                      Name.str(), Value.str());
1897442d6faSDimitry Andric }
1907442d6faSDimitry Andric 
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * Undef)1917442d6faSDimitry Andric void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
19257091882SDimitry Andric                                       const MacroDefinition &MD,
19357091882SDimitry Andric                                       const MacroDirective *Undef) {
1947442d6faSDimitry Andric   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
1957442d6faSDimitry Andric   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
1967442d6faSDimitry Andric   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
1977442d6faSDimitry Andric                                      llvm::dwarf::DW_MACINFO_undef, location,
1987442d6faSDimitry Andric                                      Id->getName(), "");
1997442d6faSDimitry Andric }
200