10b57cec5SDimitry Andric //===--- MacroPPCallbacks.cpp ---------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains implementation for the macro preprocessors callbacks. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "MacroPPCallbacks.h" 140b57cec5SDimitry Andric #include "CGDebugInfo.h" 150b57cec5SDimitry Andric #include "clang/CodeGen/ModuleBuilder.h" 160b57cec5SDimitry Andric #include "clang/Lex/MacroInfo.h" 170b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric using namespace clang; 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II, 220b57cec5SDimitry Andric const MacroInfo &MI, 230b57cec5SDimitry Andric Preprocessor &PP, raw_ostream &Name, 240b57cec5SDimitry Andric raw_ostream &Value) { 250b57cec5SDimitry Andric Name << II.getName(); 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric if (MI.isFunctionLike()) { 280b57cec5SDimitry Andric Name << '('; 290b57cec5SDimitry Andric if (!MI.param_empty()) { 300b57cec5SDimitry Andric MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end(); 310b57cec5SDimitry Andric for (; AI + 1 != E; ++AI) { 320b57cec5SDimitry Andric Name << (*AI)->getName(); 330b57cec5SDimitry Andric Name << ','; 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric // Last argument. 370b57cec5SDimitry Andric if ((*AI)->getName() == "__VA_ARGS__") 380b57cec5SDimitry Andric Name << "..."; 390b57cec5SDimitry Andric else 400b57cec5SDimitry Andric Name << (*AI)->getName(); 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric if (MI.isGNUVarargs()) 440b57cec5SDimitry Andric // #define foo(x...) 450b57cec5SDimitry Andric Name << "..."; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric Name << ')'; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric SmallString<128> SpellingBuffer; 510b57cec5SDimitry Andric bool First = true; 520b57cec5SDimitry Andric for (const auto &T : MI.tokens()) { 530b57cec5SDimitry Andric if (!First && T.hasLeadingSpace()) 540b57cec5SDimitry Andric Value << ' '; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric Value << PP.getSpelling(T, SpellingBuffer); 570b57cec5SDimitry Andric First = false; 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP) 620b57cec5SDimitry Andric : Gen(Gen), PP(PP), Status(NoScope) {} 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric // This is the expected flow of enter/exit compiler and user files: 650b57cec5SDimitry Andric // - Main File Enter 660b57cec5SDimitry Andric // - <built-in> file enter 670b57cec5SDimitry Andric // {Compiler macro definitions} - (Line=0, no scope) 680b57cec5SDimitry Andric // - (Optional) <command line> file enter 690b57cec5SDimitry Andric // {Command line macro definitions} - (Line=0, no scope) 700b57cec5SDimitry Andric // - (Optional) <command line> file exit 710b57cec5SDimitry Andric // {Command line file includes} - (Line=0, Main file scope) 720b57cec5SDimitry Andric // {macro definitions and file includes} - (Line!=0, Parent scope) 730b57cec5SDimitry Andric // - <built-in> file exit 740b57cec5SDimitry Andric // {User code macro definitions and file includes} - (Line!=0, Parent scope) 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() { 770b57cec5SDimitry Andric if (Status == MainFileScope || Status == CommandLineIncludeScope) 780b57cec5SDimitry Andric return Scopes.back(); 790b57cec5SDimitry Andric return nullptr; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) { 830b57cec5SDimitry Andric if (Status == MainFileScope || EnteredCommandLineIncludeFiles) 840b57cec5SDimitry Andric return Loc; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric // While parsing skipped files, location of macros is invalid. 870b57cec5SDimitry Andric // Invalid location represents line zero. 880b57cec5SDimitry Andric return SourceLocation(); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric void MacroPPCallbacks::updateStatusToNextScope() { 920b57cec5SDimitry Andric switch (Status) { 930b57cec5SDimitry Andric case NoScope: 940b57cec5SDimitry Andric Status = InitializedScope; 950b57cec5SDimitry Andric break; 960b57cec5SDimitry Andric case InitializedScope: 970b57cec5SDimitry Andric Status = BuiltinScope; 980b57cec5SDimitry Andric break; 990b57cec5SDimitry Andric case BuiltinScope: 1000b57cec5SDimitry Andric Status = CommandLineIncludeScope; 1010b57cec5SDimitry Andric break; 1020b57cec5SDimitry Andric case CommandLineIncludeScope: 1030b57cec5SDimitry Andric Status = MainFileScope; 1040b57cec5SDimitry Andric break; 1050b57cec5SDimitry Andric case MainFileScope: 1060b57cec5SDimitry Andric llvm_unreachable("There is no next scope, already in the final scope"); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric void MacroPPCallbacks::FileEntered(SourceLocation Loc) { 1110b57cec5SDimitry Andric SourceLocation LineLoc = getCorrectLocation(LastHashLoc); 1120b57cec5SDimitry Andric switch (Status) { 1130b57cec5SDimitry Andric case NoScope: 1140b57cec5SDimitry Andric updateStatusToNextScope(); 1150b57cec5SDimitry Andric break; 1160b57cec5SDimitry Andric case InitializedScope: 1170b57cec5SDimitry Andric updateStatusToNextScope(); 1180b57cec5SDimitry Andric return; 1190b57cec5SDimitry Andric case BuiltinScope: 1200b57cec5SDimitry Andric if (PP.getSourceManager().isWrittenInCommandLineFile(Loc)) 1210b57cec5SDimitry Andric return; 1220b57cec5SDimitry Andric updateStatusToNextScope(); 123bdd1243dSDimitry Andric [[fallthrough]]; 1240b57cec5SDimitry Andric case CommandLineIncludeScope: 1250b57cec5SDimitry Andric EnteredCommandLineIncludeFiles++; 1260b57cec5SDimitry Andric break; 1270b57cec5SDimitry Andric case MainFileScope: 1280b57cec5SDimitry Andric break; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(), 1320b57cec5SDimitry Andric LineLoc, Loc)); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric void MacroPPCallbacks::FileExited(SourceLocation Loc) { 1360b57cec5SDimitry Andric switch (Status) { 1370b57cec5SDimitry Andric default: 1380b57cec5SDimitry Andric llvm_unreachable("Do not expect to exit a file from current scope"); 1390b57cec5SDimitry Andric case BuiltinScope: 1400b57cec5SDimitry Andric if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc)) 1410b57cec5SDimitry Andric // Skip next scope and change status to MainFileScope. 1420b57cec5SDimitry Andric Status = MainFileScope; 1430b57cec5SDimitry Andric return; 1440b57cec5SDimitry Andric case CommandLineIncludeScope: 1450b57cec5SDimitry Andric if (!EnteredCommandLineIncludeFiles) { 1460b57cec5SDimitry Andric updateStatusToNextScope(); 1470b57cec5SDimitry Andric return; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric EnteredCommandLineIncludeFiles--; 1500b57cec5SDimitry Andric break; 1510b57cec5SDimitry Andric case MainFileScope: 1520b57cec5SDimitry Andric break; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric Scopes.pop_back(); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, 1590b57cec5SDimitry Andric SrcMgr::CharacteristicKind FileType, 1600b57cec5SDimitry Andric FileID PrevFID) { 1610b57cec5SDimitry Andric // Only care about enter file or exit file changes. 1620b57cec5SDimitry Andric if (Reason == EnterFile) 1630b57cec5SDimitry Andric FileEntered(Loc); 1640b57cec5SDimitry Andric else if (Reason == ExitFile) 1650b57cec5SDimitry Andric FileExited(Loc); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric void MacroPPCallbacks::InclusionDirective( 1690b57cec5SDimitry Andric SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 170bdd1243dSDimitry Andric bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, 171*0fca6ea1SDimitry Andric StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, 172*0fca6ea1SDimitry Andric bool ModuleImported, SrcMgr::CharacteristicKind FileType) { 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // Record the line location of the current included file. 1750b57cec5SDimitry Andric LastHashLoc = HashLoc; 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, 1790b57cec5SDimitry Andric const MacroDirective *MD) { 1800b57cec5SDimitry Andric IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); 1810b57cec5SDimitry Andric SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); 1820b57cec5SDimitry Andric std::string NameBuffer, ValueBuffer; 1830b57cec5SDimitry Andric llvm::raw_string_ostream Name(NameBuffer); 1840b57cec5SDimitry Andric llvm::raw_string_ostream Value(ValueBuffer); 1850b57cec5SDimitry Andric writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); 1860b57cec5SDimitry Andric Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), 1870b57cec5SDimitry Andric llvm::dwarf::DW_MACINFO_define, location, 1880b57cec5SDimitry Andric Name.str(), Value.str()); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, 1920b57cec5SDimitry Andric const MacroDefinition &MD, 1930b57cec5SDimitry Andric const MacroDirective *Undef) { 1940b57cec5SDimitry Andric IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); 1950b57cec5SDimitry Andric SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); 1960b57cec5SDimitry Andric Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), 1970b57cec5SDimitry Andric llvm::dwarf::DW_MACINFO_undef, location, 1980b57cec5SDimitry Andric Id->getName(), ""); 1990b57cec5SDimitry Andric } 200