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