xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/MacroPPCallbacks.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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  
writeMacroDefinition(const IdentifierInfo & II,const MacroInfo & MI,Preprocessor & PP,raw_ostream & Name,raw_ostream & Value)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.param_empty()) {
30        MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_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  
MacroPPCallbacks(CodeGenerator * Gen,Preprocessor & PP)61  MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
62      : 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  
getCurrentScope()76  llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
77    if (Status == MainFileScope || Status == CommandLineIncludeScope)
78      return Scopes.back();
79    return nullptr;
80  }
81  
getCorrectLocation(SourceLocation Loc)82  SourceLocation 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  
updateStatusToNextScope()91  void MacroPPCallbacks::updateStatusToNextScope() {
92    switch (Status) {
93    case NoScope:
94      Status = InitializedScope;
95      break;
96    case InitializedScope:
97      Status = BuiltinScope;
98      break;
99    case BuiltinScope:
100      Status = CommandLineIncludeScope;
101      break;
102    case CommandLineIncludeScope:
103      Status = MainFileScope;
104      break;
105    case MainFileScope:
106      llvm_unreachable("There is no next scope, already in the final scope");
107    }
108  }
109  
FileEntered(SourceLocation Loc)110  void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
111    SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
112    switch (Status) {
113    case NoScope:
114      updateStatusToNextScope();
115      break;
116    case InitializedScope:
117      updateStatusToNextScope();
118      return;
119    case BuiltinScope:
120      if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
121        return;
122      updateStatusToNextScope();
123      [[fallthrough]];
124    case CommandLineIncludeScope:
125      EnteredCommandLineIncludeFiles++;
126      break;
127    case MainFileScope:
128      break;
129    }
130  
131    Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
132                                                                LineLoc, Loc));
133  }
134  
FileExited(SourceLocation Loc)135  void MacroPPCallbacks::FileExited(SourceLocation Loc) {
136    switch (Status) {
137    default:
138      llvm_unreachable("Do not expect to exit a file from current scope");
139    case BuiltinScope:
140      if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
141        // Skip next scope and change status to MainFileScope.
142        Status = MainFileScope;
143      return;
144    case CommandLineIncludeScope:
145      if (!EnteredCommandLineIncludeFiles) {
146        updateStatusToNextScope();
147        return;
148      }
149      EnteredCommandLineIncludeFiles--;
150      break;
151    case MainFileScope:
152      break;
153    }
154  
155    Scopes.pop_back();
156  }
157  
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)158  void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
159                                     SrcMgr::CharacteristicKind FileType,
160                                     FileID PrevFID) {
161    // Only care about enter file or exit file changes.
162    if (Reason == EnterFile)
163      FileEntered(Loc);
164    else if (Reason == ExitFile)
165      FileExited(Loc);
166  }
167  
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * SuggestedModule,bool ModuleImported,SrcMgr::CharacteristicKind FileType)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 *SuggestedModule,
172      bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
173  
174    // Record the line location of the current included file.
175    LastHashLoc = HashLoc;
176  }
177  
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)178  void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
179                                      const MacroDirective *MD) {
180    IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
181    SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
182    std::string NameBuffer, ValueBuffer;
183    llvm::raw_string_ostream Name(NameBuffer);
184    llvm::raw_string_ostream Value(ValueBuffer);
185    writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
186    Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
187                                       llvm::dwarf::DW_MACINFO_define, location,
188                                       Name.str(), Value.str());
189  }
190  
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * Undef)191  void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
192                                        const MacroDefinition &MD,
193                                        const MacroDirective *Undef) {
194    IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
195    SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
196    Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
197                                       llvm::dwarf::DW_MACINFO_undef, location,
198                                       Id->getName(), "");
199  }
200