blob: 48dea7d54b1e93ddce7f491a56b2cf5db2441d64 [file] [log] [blame]
Amjad Aboud546bc112017-02-09 22:07:24 +00001//===--- 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
19using namespace clang;
20
21void 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 << '(';
Faisal Valiac506d72017-07-17 17:18:43 +000029 if (!MI.param_empty()) {
30 MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
Amjad Aboud546bc112017-02-09 22:07:24 +000031 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
61MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
62 : Gen(Gen), PP(PP), Status(NoScope) {}
63
Eric Christophercdbfd0e2017-02-10 00:20:26 +000064// 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)
Amjad Aboud546bc112017-02-09 22:07:24 +000075
76llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
77 if (Status == MainFileScope || Status == CommandLineIncludeScope)
78 return Scopes.back();
79 return nullptr;
80}
81
82SourceLocation 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
91static bool isBuiltinFile(SourceManager &SM, SourceLocation Loc) {
92 StringRef Filename(SM.getPresumedLoc(Loc).getFilename());
93 return Filename.equals("<built-in>");
94}
95
96static bool isCommandLineFile(SourceManager &SM, SourceLocation Loc) {
97 StringRef Filename(SM.getPresumedLoc(Loc).getFilename());
98 return Filename.equals("<command line>");
99}
100
101void MacroPPCallbacks::updateStatusToNextScope() {
102 switch (Status) {
103 case NoScope:
104 Status = InitializedScope;
105 break;
106 case InitializedScope:
107 Status = BuiltinScope;
108 break;
109 case BuiltinScope:
110 Status = CommandLineIncludeScope;
111 break;
112 case CommandLineIncludeScope:
113 Status = MainFileScope;
114 break;
115 case MainFileScope:
116 llvm_unreachable("There is no next scope, already in the final scope");
117 }
118}
119
120void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
121 SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
122 switch (Status) {
Amjad Aboud546bc112017-02-09 22:07:24 +0000123 case NoScope:
124 updateStatusToNextScope();
125 break;
126 case InitializedScope:
127 updateStatusToNextScope();
128 return;
129 case BuiltinScope:
130 if (isCommandLineFile(PP.getSourceManager(), Loc))
131 return;
132 updateStatusToNextScope();
133 LLVM_FALLTHROUGH;
134 case CommandLineIncludeScope:
135 EnteredCommandLineIncludeFiles++;
136 break;
137 case MainFileScope:
138 break;
139 }
140
141 Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
142 LineLoc, Loc));
143}
144
145void MacroPPCallbacks::FileExited(SourceLocation Loc) {
146 switch (Status) {
147 default:
148 llvm_unreachable("Do not expect to exit a file from current scope");
149 case BuiltinScope:
150 if (!isBuiltinFile(PP.getSourceManager(), Loc))
151 // Skip next scope and change status to MainFileScope.
152 Status = MainFileScope;
153 return;
154 case CommandLineIncludeScope:
155 if (!EnteredCommandLineIncludeFiles) {
156 updateStatusToNextScope();
157 return;
158 }
159 EnteredCommandLineIncludeFiles--;
160 break;
161 case MainFileScope:
162 break;
163 }
164
165 Scopes.pop_back();
166}
167
168void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
169 SrcMgr::CharacteristicKind FileType,
170 FileID PrevFID) {
171 // Only care about enter file or exit file changes.
172 if (Reason == EnterFile)
173 FileEntered(Loc);
174 else if (Reason == ExitFile)
175 FileExited(Loc);
176}
177
178void MacroPPCallbacks::InclusionDirective(
179 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
180 bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
Julie Hockett96fbe582018-05-10 19:05:36 +0000181 StringRef SearchPath, StringRef RelativePath, const Module *Imported,
182 SrcMgr::CharacteristicKind FileType) {
Amjad Aboud546bc112017-02-09 22:07:24 +0000183
184 // Record the line location of the current included file.
185 LastHashLoc = HashLoc;
186}
187
188void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
189 const MacroDirective *MD) {
190 IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
191 SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
192 std::string NameBuffer, ValueBuffer;
193 llvm::raw_string_ostream Name(NameBuffer);
194 llvm::raw_string_ostream Value(ValueBuffer);
195 writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
196 Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
197 llvm::dwarf::DW_MACINFO_define, location,
198 Name.str(), Value.str());
199}
200
201void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
David Blaikie204103f2017-04-26 20:58:21 +0000202 const MacroDefinition &MD,
203 const MacroDirective *Undef) {
Amjad Aboud546bc112017-02-09 22:07:24 +0000204 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}