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