Coverage Report

Created: 2024-01-17 10:31

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