xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/MacroPPCallbacks.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- MacroPPCallbacks.cpp ---------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file contains implementation for the macro preprocessors callbacks.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "MacroPPCallbacks.h"
140b57cec5SDimitry Andric #include "CGDebugInfo.h"
150b57cec5SDimitry Andric #include "clang/CodeGen/ModuleBuilder.h"
160b57cec5SDimitry Andric #include "clang/Lex/MacroInfo.h"
170b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace clang;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
220b57cec5SDimitry Andric                                             const MacroInfo &MI,
230b57cec5SDimitry Andric                                             Preprocessor &PP, raw_ostream &Name,
240b57cec5SDimitry Andric                                             raw_ostream &Value) {
250b57cec5SDimitry Andric   Name << II.getName();
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric   if (MI.isFunctionLike()) {
280b57cec5SDimitry Andric     Name << '(';
290b57cec5SDimitry Andric     if (!MI.param_empty()) {
300b57cec5SDimitry Andric       MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
310b57cec5SDimitry Andric       for (; AI + 1 != E; ++AI) {
320b57cec5SDimitry Andric         Name << (*AI)->getName();
330b57cec5SDimitry Andric         Name << ',';
340b57cec5SDimitry Andric       }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric       // Last argument.
370b57cec5SDimitry Andric       if ((*AI)->getName() == "__VA_ARGS__")
380b57cec5SDimitry Andric         Name << "...";
390b57cec5SDimitry Andric       else
400b57cec5SDimitry Andric         Name << (*AI)->getName();
410b57cec5SDimitry Andric     }
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric     if (MI.isGNUVarargs())
440b57cec5SDimitry Andric       // #define foo(x...)
450b57cec5SDimitry Andric       Name << "...";
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     Name << ')';
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   SmallString<128> SpellingBuffer;
510b57cec5SDimitry Andric   bool First = true;
520b57cec5SDimitry Andric   for (const auto &T : MI.tokens()) {
530b57cec5SDimitry Andric     if (!First && T.hasLeadingSpace())
540b57cec5SDimitry Andric       Value << ' ';
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric     Value << PP.getSpelling(T, SpellingBuffer);
570b57cec5SDimitry Andric     First = false;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
620b57cec5SDimitry Andric     : Gen(Gen), PP(PP), Status(NoScope) {}
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric // This is the expected flow of enter/exit compiler and user files:
650b57cec5SDimitry Andric // - Main File Enter
660b57cec5SDimitry Andric //   - <built-in> file enter
670b57cec5SDimitry Andric //     {Compiler macro definitions} - (Line=0, no scope)
680b57cec5SDimitry Andric //     - (Optional) <command line> file enter
690b57cec5SDimitry Andric //     {Command line macro definitions} - (Line=0, no scope)
700b57cec5SDimitry Andric //     - (Optional) <command line> file exit
710b57cec5SDimitry Andric //     {Command line file includes} - (Line=0, Main file scope)
720b57cec5SDimitry Andric //       {macro definitions and file includes} - (Line!=0, Parent scope)
730b57cec5SDimitry Andric //   - <built-in> file exit
740b57cec5SDimitry Andric //   {User code macro definitions and file includes} - (Line!=0, Parent scope)
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
770b57cec5SDimitry Andric   if (Status == MainFileScope || Status == CommandLineIncludeScope)
780b57cec5SDimitry Andric     return Scopes.back();
790b57cec5SDimitry Andric   return nullptr;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
830b57cec5SDimitry Andric   if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
840b57cec5SDimitry Andric     return Loc;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   // While parsing skipped files, location of macros is invalid.
870b57cec5SDimitry Andric   // Invalid location represents line zero.
880b57cec5SDimitry Andric   return SourceLocation();
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric void MacroPPCallbacks::updateStatusToNextScope() {
920b57cec5SDimitry Andric   switch (Status) {
930b57cec5SDimitry Andric   case NoScope:
940b57cec5SDimitry Andric     Status = InitializedScope;
950b57cec5SDimitry Andric     break;
960b57cec5SDimitry Andric   case InitializedScope:
970b57cec5SDimitry Andric     Status = BuiltinScope;
980b57cec5SDimitry Andric     break;
990b57cec5SDimitry Andric   case BuiltinScope:
1000b57cec5SDimitry Andric     Status = CommandLineIncludeScope;
1010b57cec5SDimitry Andric     break;
1020b57cec5SDimitry Andric   case CommandLineIncludeScope:
1030b57cec5SDimitry Andric     Status = MainFileScope;
1040b57cec5SDimitry Andric     break;
1050b57cec5SDimitry Andric   case MainFileScope:
1060b57cec5SDimitry Andric     llvm_unreachable("There is no next scope, already in the final scope");
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
1110b57cec5SDimitry Andric   SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
1120b57cec5SDimitry Andric   switch (Status) {
1130b57cec5SDimitry Andric   case NoScope:
1140b57cec5SDimitry Andric     updateStatusToNextScope();
1150b57cec5SDimitry Andric     break;
1160b57cec5SDimitry Andric   case InitializedScope:
1170b57cec5SDimitry Andric     updateStatusToNextScope();
1180b57cec5SDimitry Andric     return;
1190b57cec5SDimitry Andric   case BuiltinScope:
1200b57cec5SDimitry Andric     if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
1210b57cec5SDimitry Andric       return;
1220b57cec5SDimitry Andric     updateStatusToNextScope();
123bdd1243dSDimitry Andric     [[fallthrough]];
1240b57cec5SDimitry Andric   case CommandLineIncludeScope:
1250b57cec5SDimitry Andric     EnteredCommandLineIncludeFiles++;
1260b57cec5SDimitry Andric     break;
1270b57cec5SDimitry Andric   case MainFileScope:
1280b57cec5SDimitry Andric     break;
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
1320b57cec5SDimitry Andric                                                               LineLoc, Loc));
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric void MacroPPCallbacks::FileExited(SourceLocation Loc) {
1360b57cec5SDimitry Andric   switch (Status) {
1370b57cec5SDimitry Andric   default:
1380b57cec5SDimitry Andric     llvm_unreachable("Do not expect to exit a file from current scope");
1390b57cec5SDimitry Andric   case BuiltinScope:
1400b57cec5SDimitry Andric     if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
1410b57cec5SDimitry Andric       // Skip next scope and change status to MainFileScope.
1420b57cec5SDimitry Andric       Status = MainFileScope;
1430b57cec5SDimitry Andric     return;
1440b57cec5SDimitry Andric   case CommandLineIncludeScope:
1450b57cec5SDimitry Andric     if (!EnteredCommandLineIncludeFiles) {
1460b57cec5SDimitry Andric       updateStatusToNextScope();
1470b57cec5SDimitry Andric       return;
1480b57cec5SDimitry Andric     }
1490b57cec5SDimitry Andric     EnteredCommandLineIncludeFiles--;
1500b57cec5SDimitry Andric     break;
1510b57cec5SDimitry Andric   case MainFileScope:
1520b57cec5SDimitry Andric     break;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   Scopes.pop_back();
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
1590b57cec5SDimitry Andric                                    SrcMgr::CharacteristicKind FileType,
1600b57cec5SDimitry Andric                                    FileID PrevFID) {
1610b57cec5SDimitry Andric   // Only care about enter file or exit file changes.
1620b57cec5SDimitry Andric   if (Reason == EnterFile)
1630b57cec5SDimitry Andric     FileEntered(Loc);
1640b57cec5SDimitry Andric   else if (Reason == ExitFile)
1650b57cec5SDimitry Andric     FileExited(Loc);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric void MacroPPCallbacks::InclusionDirective(
1690b57cec5SDimitry Andric     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
170bdd1243dSDimitry Andric     bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
171*0fca6ea1SDimitry Andric     StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
172*0fca6ea1SDimitry Andric     bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   // Record the line location of the current included file.
1750b57cec5SDimitry Andric   LastHashLoc = HashLoc;
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
1790b57cec5SDimitry Andric                                     const MacroDirective *MD) {
1800b57cec5SDimitry Andric   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
1810b57cec5SDimitry Andric   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
1820b57cec5SDimitry Andric   std::string NameBuffer, ValueBuffer;
1830b57cec5SDimitry Andric   llvm::raw_string_ostream Name(NameBuffer);
1840b57cec5SDimitry Andric   llvm::raw_string_ostream Value(ValueBuffer);
1850b57cec5SDimitry Andric   writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
1860b57cec5SDimitry Andric   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
1870b57cec5SDimitry Andric                                      llvm::dwarf::DW_MACINFO_define, location,
1880b57cec5SDimitry Andric                                      Name.str(), Value.str());
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
1920b57cec5SDimitry Andric                                       const MacroDefinition &MD,
1930b57cec5SDimitry Andric                                       const MacroDirective *Undef) {
1940b57cec5SDimitry Andric   IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
1950b57cec5SDimitry Andric   SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
1960b57cec5SDimitry Andric   Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
1970b57cec5SDimitry Andric                                      llvm::dwarf::DW_MACINFO_undef, location,
1980b57cec5SDimitry Andric                                      Id->getName(), "");
1990b57cec5SDimitry Andric }
200