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/Parse/Parser.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.arg_empty()) { 30 MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_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 /* 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 78 llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() { 79 if (Status == MainFileScope || Status == CommandLineIncludeScope) 80 return Scopes.back(); 81 return nullptr; 82 } 83 84 SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) { 85 if (Status == MainFileScope || EnteredCommandLineIncludeFiles) 86 return Loc; 87 88 // While parsing skipped files, location of macros is invalid. 89 // Invalid location represents line zero. 90 return SourceLocation(); 91 } 92 93 static bool isBuiltinFile(SourceManager &SM, SourceLocation Loc) { 94 StringRef Filename(SM.getPresumedLoc(Loc).getFilename()); 95 return Filename.equals("<built-in>"); 96 } 97 98 static bool isCommandLineFile(SourceManager &SM, SourceLocation Loc) { 99 StringRef Filename(SM.getPresumedLoc(Loc).getFilename()); 100 return Filename.equals("<command line>"); 101 } 102 103 void MacroPPCallbacks::updateStatusToNextScope() { 104 switch (Status) { 105 case NoScope: 106 Status = InitializedScope; 107 break; 108 case InitializedScope: 109 Status = BuiltinScope; 110 break; 111 case BuiltinScope: 112 Status = CommandLineIncludeScope; 113 break; 114 case CommandLineIncludeScope: 115 Status = MainFileScope; 116 break; 117 case MainFileScope: 118 llvm_unreachable("There is no next scope, already in the final scope"); 119 } 120 } 121 122 void MacroPPCallbacks::FileEntered(SourceLocation Loc) { 123 SourceLocation LineLoc = getCorrectLocation(LastHashLoc); 124 switch (Status) { 125 case NoScope: 126 updateStatusToNextScope(); 127 break; 128 case InitializedScope: 129 updateStatusToNextScope(); 130 return; 131 case BuiltinScope: 132 if (isCommandLineFile(PP.getSourceManager(), Loc)) 133 return; 134 updateStatusToNextScope(); 135 LLVM_FALLTHROUGH; 136 case CommandLineIncludeScope: 137 EnteredCommandLineIncludeFiles++; 138 break; 139 case MainFileScope: 140 break; 141 } 142 143 Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(), 144 LineLoc, Loc)); 145 } 146 147 void MacroPPCallbacks::FileExited(SourceLocation Loc) { 148 switch (Status) { 149 default: 150 llvm_unreachable("Do not expect to exit a file from current scope"); 151 case BuiltinScope: 152 if (!isBuiltinFile(PP.getSourceManager(), Loc)) 153 // Skip next scope and change status to MainFileScope. 154 Status = MainFileScope; 155 return; 156 case CommandLineIncludeScope: 157 if (!EnteredCommandLineIncludeFiles) { 158 updateStatusToNextScope(); 159 return; 160 } 161 EnteredCommandLineIncludeFiles--; 162 break; 163 case MainFileScope: 164 break; 165 } 166 167 Scopes.pop_back(); 168 } 169 170 void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, 171 SrcMgr::CharacteristicKind FileType, 172 FileID PrevFID) { 173 // Only care about enter file or exit file changes. 174 if (Reason == EnterFile) 175 FileEntered(Loc); 176 else if (Reason == ExitFile) 177 FileExited(Loc); 178 } 179 180 void MacroPPCallbacks::InclusionDirective( 181 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 182 bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, 183 StringRef SearchPath, StringRef RelativePath, const Module *Imported) { 184 185 // Record the line location of the current included file. 186 LastHashLoc = HashLoc; 187 } 188 189 void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, 190 const MacroDirective *MD) { 191 IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); 192 SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); 193 std::string NameBuffer, ValueBuffer; 194 llvm::raw_string_ostream Name(NameBuffer); 195 llvm::raw_string_ostream Value(ValueBuffer); 196 writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); 197 Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), 198 llvm::dwarf::DW_MACINFO_define, location, 199 Name.str(), Value.str()); 200 } 201 202 void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, 203 const MacroDefinition &MD) { 204 IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); 205 SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); 206 Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), 207 llvm::dwarf::DW_MACINFO_undef, location, 208 Id->getName(), ""); 209 } 210