/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/CodeGen/MacroPPCallbacks.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 1.43k | raw_ostream &Value) { |
25 | 1.43k | Name << II.getName(); |
26 | | |
27 | 1.43k | if (MI.isFunctionLike()) { |
28 | 15 | Name << '('; |
29 | 15 | if (!MI.param_empty()) { |
30 | 15 | MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end(); |
31 | 35 | for (; AI + 1 != E; ++AI20 ) { |
32 | 20 | Name << (*AI)->getName(); |
33 | 20 | Name << ','; |
34 | 20 | } |
35 | | |
36 | | // Last argument. |
37 | 15 | if ((*AI)->getName() == "__VA_ARGS__") |
38 | 0 | Name << "..."; |
39 | 15 | else |
40 | 15 | Name << (*AI)->getName(); |
41 | 15 | } |
42 | | |
43 | 15 | if (MI.isGNUVarargs()) |
44 | | // #define foo(x...) |
45 | 0 | Name << "..."; |
46 | | |
47 | 15 | Name << ')'; |
48 | 15 | } |
49 | | |
50 | 1.43k | SmallString<128> SpellingBuffer; |
51 | 1.43k | bool First = true; |
52 | 1.78k | for (const auto &T : MI.tokens()) { |
53 | 1.78k | if (!First && T.hasLeadingSpace()384 ) |
54 | 172 | Value << ' '; |
55 | | |
56 | 1.78k | Value << PP.getSpelling(T, SpellingBuffer); |
57 | 1.78k | First = false; |
58 | 1.78k | } |
59 | 1.43k | } |
60 | | |
61 | | MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP) |
62 | 5 | : 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 | 1.48k | llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() { |
77 | 1.48k | if (Status == MainFileScope || Status == CommandLineIncludeScope1.43k ) |
78 | 60 | return Scopes.back(); |
79 | 1.42k | return nullptr; |
80 | 1.48k | } |
81 | | |
82 | 1.49k | SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) { |
83 | 1.49k | if (Status == MainFileScope || EnteredCommandLineIncludeFiles1.44k ) |
84 | 55 | return Loc; |
85 | | |
86 | | // While parsing skipped files, location of macros is invalid. |
87 | | // Invalid location represents line zero. |
88 | 1.43k | return SourceLocation(); |
89 | 1.49k | } |
90 | | |
91 | 20 | void MacroPPCallbacks::updateStatusToNextScope() { |
92 | 20 | switch (Status) { |
93 | 5 | case NoScope: |
94 | 5 | Status = InitializedScope; |
95 | 5 | break; |
96 | 5 | case InitializedScope: |
97 | 5 | Status = BuiltinScope; |
98 | 5 | break; |
99 | 5 | case BuiltinScope: |
100 | 5 | Status = CommandLineIncludeScope; |
101 | 5 | break; |
102 | 5 | case CommandLineIncludeScope: |
103 | 5 | Status = MainFileScope; |
104 | 5 | break; |
105 | 0 | case MainFileScope: |
106 | 0 | llvm_unreachable("There is no next scope, already in the final scope"); |
107 | 20 | } |
108 | 20 | } |
109 | | |
110 | 29 | void MacroPPCallbacks::FileEntered(SourceLocation Loc) { |
111 | 29 | SourceLocation LineLoc = getCorrectLocation(LastHashLoc); |
112 | 29 | switch (Status) { |
113 | 5 | case NoScope: |
114 | 5 | updateStatusToNextScope(); |
115 | 5 | break; |
116 | 5 | case InitializedScope: |
117 | 5 | updateStatusToNextScope(); |
118 | 5 | return; |
119 | 9 | case BuiltinScope: |
120 | 9 | if (PP.getSourceManager().isWrittenInCommandLineFile(Loc)) |
121 | 4 | return; |
122 | 5 | updateStatusToNextScope(); |
123 | 5 | LLVM_FALLTHROUGH; |
124 | 5 | case CommandLineIncludeScope: |
125 | 5 | EnteredCommandLineIncludeFiles++; |
126 | 5 | break; |
127 | 10 | case MainFileScope: |
128 | 10 | break; |
129 | 29 | } |
130 | | |
131 | 20 | Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(), |
132 | 20 | LineLoc, Loc)); |
133 | 20 | } |
134 | | |
135 | 24 | void MacroPPCallbacks::FileExited(SourceLocation Loc) { |
136 | 24 | switch (Status) { |
137 | 0 | default: |
138 | 0 | llvm_unreachable("Do not expect to exit a file from current scope"); |
139 | 4 | case BuiltinScope: |
140 | 4 | if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc)) |
141 | | // Skip next scope and change status to MainFileScope. |
142 | 0 | Status = MainFileScope; |
143 | 4 | return; |
144 | 10 | case CommandLineIncludeScope: |
145 | 10 | if (!EnteredCommandLineIncludeFiles) { |
146 | 5 | updateStatusToNextScope(); |
147 | 5 | return; |
148 | 5 | } |
149 | 5 | EnteredCommandLineIncludeFiles--; |
150 | 5 | break; |
151 | 10 | case MainFileScope: |
152 | 10 | break; |
153 | 24 | } |
154 | | |
155 | 15 | Scopes.pop_back(); |
156 | 15 | } |
157 | | |
158 | | void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, |
159 | | SrcMgr::CharacteristicKind FileType, |
160 | 62 | FileID PrevFID) { |
161 | | // Only care about enter file or exit file changes. |
162 | 62 | if (Reason == EnterFile) |
163 | 29 | FileEntered(Loc); |
164 | 33 | else if (Reason == ExitFile) |
165 | 24 | FileExited(Loc); |
166 | 62 | } |
167 | | |
168 | | void MacroPPCallbacks::InclusionDirective( |
169 | | SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, |
170 | | bool IsAngled, CharSourceRange FilenameRange, Optional<FileEntryRef> File, |
171 | | StringRef SearchPath, StringRef RelativePath, const Module *Imported, |
172 | 15 | SrcMgr::CharacteristicKind FileType) { |
173 | | |
174 | | // Record the line location of the current included file. |
175 | 15 | LastHashLoc = HashLoc; |
176 | 15 | } |
177 | | |
178 | | void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, |
179 | 1.43k | const MacroDirective *MD) { |
180 | 1.43k | IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); |
181 | 1.43k | SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); |
182 | 1.43k | std::string NameBuffer, ValueBuffer; |
183 | 1.43k | llvm::raw_string_ostream Name(NameBuffer); |
184 | 1.43k | llvm::raw_string_ostream Value(ValueBuffer); |
185 | 1.43k | writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); |
186 | 1.43k | Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), |
187 | 1.43k | llvm::dwarf::DW_MACINFO_define, location, |
188 | 1.43k | Name.str(), Value.str()); |
189 | 1.43k | } |
190 | | |
191 | | void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, |
192 | | const MacroDefinition &MD, |
193 | 30 | const MacroDirective *Undef) { |
194 | 30 | IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); |
195 | 30 | SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); |
196 | 30 | Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), |
197 | 30 | llvm::dwarf::DW_MACINFO_undef, location, |
198 | 30 | Id->getName(), ""); |
199 | 30 | } |