1 //===--- MacroPPCallbacks.cpp ---------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains implementation for the macro preprocessors callbacks. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "MacroPPCallbacks.h" 14 #include "CGDebugInfo.h" 15 #include "clang/CodeGen/ModuleBuilder.h" 16 #include "clang/Lex/MacroInfo.h" 17 #include "clang/Lex/Preprocessor.h" 18 19 using namespace clang; 20 21 void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II, 22 const MacroInfo &MI, 23 Preprocessor &PP, raw_ostream &Name, 24 raw_ostream &Value) { 25 Name << II.getName(); 26 27 if (MI.isFunctionLike()) { 28 Name << '('; 29 if (!MI.param_empty()) { 30 MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end(); 31 for (; AI + 1 != E; ++AI) { 32 Name << (*AI)->getName(); 33 Name << ','; 34 } 35 36 // Last argument. 37 if ((*AI)->getName() == "__VA_ARGS__") 38 Name << "..."; 39 else 40 Name << (*AI)->getName(); 41 } 42 43 if (MI.isGNUVarargs()) 44 // #define foo(x...) 45 Name << "..."; 46 47 Name << ')'; 48 } 49 50 SmallString<128> SpellingBuffer; 51 bool First = true; 52 for (const auto &T : MI.tokens()) { 53 if (!First && T.hasLeadingSpace()) 54 Value << ' '; 55 56 Value << PP.getSpelling(T, SpellingBuffer); 57 First = false; 58 } 59 } 60 61 MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP) 62 : Gen(Gen), PP(PP), Status(NoScope) {} 63 64 // This is the expected flow of enter/exit compiler and user files: 65 // - Main File Enter 66 // - <built-in> file enter 67 // {Compiler macro definitions} - (Line=0, no scope) 68 // - (Optional) <command line> file enter 69 // {Command line macro definitions} - (Line=0, no scope) 70 // - (Optional) <command line> file exit 71 // {Command line file includes} - (Line=0, Main file scope) 72 // {macro definitions and file includes} - (Line!=0, Parent scope) 73 // - <built-in> file exit 74 // {User code macro definitions and file includes} - (Line!=0, Parent scope) 75 76 llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() { 77 if (Status == MainFileScope || Status == CommandLineIncludeScope) 78 return Scopes.back(); 79 return nullptr; 80 } 81 82 SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) { 83 if (Status == MainFileScope || EnteredCommandLineIncludeFiles) 84 return Loc; 85 86 // While parsing skipped files, location of macros is invalid. 87 // Invalid location represents line zero. 88 return SourceLocation(); 89 } 90 91 void MacroPPCallbacks::updateStatusToNextScope() { 92 switch (Status) { 93 case NoScope: 94 Status = InitializedScope; 95 break; 96 case InitializedScope: 97 Status = BuiltinScope; 98 break; 99 case BuiltinScope: 100 Status = CommandLineIncludeScope; 101 break; 102 case CommandLineIncludeScope: 103 Status = MainFileScope; 104 break; 105 case MainFileScope: 106 llvm_unreachable("There is no next scope, already in the final scope"); 107 } 108 } 109 110 void MacroPPCallbacks::FileEntered(SourceLocation Loc) { 111 SourceLocation LineLoc = getCorrectLocation(LastHashLoc); 112 switch (Status) { 113 case NoScope: 114 updateStatusToNextScope(); 115 break; 116 case InitializedScope: 117 updateStatusToNextScope(); 118 return; 119 case BuiltinScope: 120 if (PP.getSourceManager().isWrittenInCommandLineFile(Loc)) 121 return; 122 updateStatusToNextScope(); 123 [[fallthrough]]; 124 case CommandLineIncludeScope: 125 EnteredCommandLineIncludeFiles++; 126 break; 127 case MainFileScope: 128 break; 129 } 130 131 Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(), 132 LineLoc, Loc)); 133 } 134 135 void MacroPPCallbacks::FileExited(SourceLocation Loc) { 136 switch (Status) { 137 default: 138 llvm_unreachable("Do not expect to exit a file from current scope"); 139 case BuiltinScope: 140 if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc)) 141 // Skip next scope and change status to MainFileScope. 142 Status = MainFileScope; 143 return; 144 case CommandLineIncludeScope: 145 if (!EnteredCommandLineIncludeFiles) { 146 updateStatusToNextScope(); 147 return; 148 } 149 EnteredCommandLineIncludeFiles--; 150 break; 151 case MainFileScope: 152 break; 153 } 154 155 Scopes.pop_back(); 156 } 157 158 void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, 159 SrcMgr::CharacteristicKind FileType, 160 FileID PrevFID) { 161 // Only care about enter file or exit file changes. 162 if (Reason == EnterFile) 163 FileEntered(Loc); 164 else if (Reason == ExitFile) 165 FileExited(Loc); 166 } 167 168 void MacroPPCallbacks::InclusionDirective( 169 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 170 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, 171 StringRef SearchPath, StringRef RelativePath, const Module *Imported, 172 SrcMgr::CharacteristicKind FileType) { 173 174 // Record the line location of the current included file. 175 LastHashLoc = HashLoc; 176 } 177 178 void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, 179 const MacroDirective *MD) { 180 IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); 181 SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); 182 std::string NameBuffer, ValueBuffer; 183 llvm::raw_string_ostream Name(NameBuffer); 184 llvm::raw_string_ostream Value(ValueBuffer); 185 writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); 186 Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), 187 llvm::dwarf::DW_MACINFO_define, location, 188 Name.str(), Value.str()); 189 } 190 191 void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, 192 const MacroDefinition &MD, 193 const MacroDirective *Undef) { 194 IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); 195 SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); 196 Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), 197 llvm::dwarf::DW_MACINFO_undef, location, 198 Id->getName(), ""); 199 } 200