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   default:
126     llvm_unreachable("Do not expect to enter a file from current scope");
127   case NoScope:
128     updateStatusToNextScope();
129     break;
130   case InitializedScope:
131     updateStatusToNextScope();
132     return;
133   case BuiltinScope:
134     if (isCommandLineFile(PP.getSourceManager(), Loc))
135       return;
136     updateStatusToNextScope();
137     LLVM_FALLTHROUGH;
138   case CommandLineIncludeScope:
139     EnteredCommandLineIncludeFiles++;
140     break;
141   case MainFileScope:
142     break;
143   }
144 
145   Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
146                                                               LineLoc, Loc));
147 }
148 
149 void MacroPPCallbacks::FileExited(SourceLocation Loc) {
150   switch (Status) {
151   default:
152     llvm_unreachable("Do not expect to exit a file from current scope");
153   case BuiltinScope:
154     if (!isBuiltinFile(PP.getSourceManager(), Loc))
155       // Skip next scope and change status to MainFileScope.
156       Status = MainFileScope;
157     return;
158   case CommandLineIncludeScope:
159     if (!EnteredCommandLineIncludeFiles) {
160       updateStatusToNextScope();
161       return;
162     }
163     EnteredCommandLineIncludeFiles--;
164     break;
165   case MainFileScope:
166     break;
167   }
168 
169   Scopes.pop_back();
170 }
171 
172 void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
173                                    SrcMgr::CharacteristicKind FileType,
174                                    FileID PrevFID) {
175   // Only care about enter file or exit file changes.
176   if (Reason == EnterFile)
177     FileEntered(Loc);
178   else if (Reason == ExitFile)
179     FileExited(Loc);
180 }
181 
182 void MacroPPCallbacks::InclusionDirective(
183     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
184     bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
185     StringRef SearchPath, StringRef RelativePath, const Module *Imported) {
186 
187   // Record the line location of the current included file.
188   LastHashLoc = HashLoc;
189 }
190 
191 void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
192                                     const MacroDirective *MD) {
193   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
194   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
195   std::string NameBuffer, ValueBuffer;
196   llvm::raw_string_ostream Name(NameBuffer);
197   llvm::raw_string_ostream Value(ValueBuffer);
198   writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
199   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
200                                      llvm::dwarf::DW_MACINFO_define, location,
201                                      Name.str(), Value.str());
202 }
203 
204 void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
205                                       const MacroDefinition &MD) {
206   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
207   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
208   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
209                                      llvm::dwarf::DW_MACINFO_undef, location,
210                                      Id->getName(), "");
211 }
212