reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
//===--- MacroPPCallbacks.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file contains implementation for the macro preprocessors callbacks.
//
//===----------------------------------------------------------------------===//

#include "MacroPPCallbacks.h"
#include "CGDebugInfo.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"

using namespace clang;

void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
                                            const MacroInfo &MI,
                                            Preprocessor &PP, raw_ostream &Name,
                                            raw_ostream &Value) {
  Name << II.getName();

  if (MI.isFunctionLike()) {
    Name << '(';
    if (!MI.param_empty()) {
      MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
      for (; AI + 1 != E; ++AI) {
        Name << (*AI)->getName();
        Name << ',';
      }

      // Last argument.
      if ((*AI)->getName() == "__VA_ARGS__")
        Name << "...";
      else
        Name << (*AI)->getName();
    }

    if (MI.isGNUVarargs())
      // #define foo(x...)
      Name << "...";

    Name << ')';
  }

  SmallString<128> SpellingBuffer;
  bool First = true;
  for (const auto &T : MI.tokens()) {
    if (!First && T.hasLeadingSpace())
      Value << ' ';

    Value << PP.getSpelling(T, SpellingBuffer);
    First = false;
  }
}

MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
    : Gen(Gen), PP(PP), Status(NoScope) {}

// This is the expected flow of enter/exit compiler and user files:
// - Main File Enter
//   - <built-in> file enter
//     {Compiler macro definitions} - (Line=0, no scope)
//     - (Optional) <command line> file enter
//     {Command line macro definitions} - (Line=0, no scope)
//     - (Optional) <command line> file exit
//     {Command line file includes} - (Line=0, Main file scope)
//       {macro definitions and file includes} - (Line!=0, Parent scope)
//   - <built-in> file exit
//   {User code macro definitions and file includes} - (Line!=0, Parent scope)

llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
  if (Status == MainFileScope || Status == CommandLineIncludeScope)
    return Scopes.back();
  return nullptr;
}

SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
  if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
    return Loc;

  // While parsing skipped files, location of macros is invalid.
  // Invalid location represents line zero.
  return SourceLocation();
}

void MacroPPCallbacks::updateStatusToNextScope() {
  switch (Status) {
  case NoScope:
    Status = InitializedScope;
    break;
  case InitializedScope:
    Status = BuiltinScope;
    break;
  case BuiltinScope:
    Status = CommandLineIncludeScope;
    break;
  case CommandLineIncludeScope:
    Status = MainFileScope;
    break;
  case MainFileScope:
    llvm_unreachable("There is no next scope, already in the final scope");
  }
}

void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
  SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
  switch (Status) {
  case NoScope:
    updateStatusToNextScope();
    break;
  case InitializedScope:
    updateStatusToNextScope();
    return;
  case BuiltinScope:
    if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
      return;
    updateStatusToNextScope();
    LLVM_FALLTHROUGH;
  case CommandLineIncludeScope:
    EnteredCommandLineIncludeFiles++;
    break;
  case MainFileScope:
    break;
  }

  Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
                                                              LineLoc, Loc));
}

void MacroPPCallbacks::FileExited(SourceLocation Loc) {
  switch (Status) {
  default:
    llvm_unreachable("Do not expect to exit a file from current scope");
  case BuiltinScope:
    if (!PP.getSourceManager().isWrittenInBuiltinFile(Loc))
      // Skip next scope and change status to MainFileScope.
      Status = MainFileScope;
    return;
  case CommandLineIncludeScope:
    if (!EnteredCommandLineIncludeFiles) {
      updateStatusToNextScope();
      return;
    }
    EnteredCommandLineIncludeFiles--;
    break;
  case MainFileScope:
    break;
  }

  Scopes.pop_back();
}

void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
                                   SrcMgr::CharacteristicKind FileType,
                                   FileID PrevFID) {
  // Only care about enter file or exit file changes.
  if (Reason == EnterFile)
    FileEntered(Loc);
  else if (Reason == ExitFile)
    FileExited(Loc);
}

void MacroPPCallbacks::InclusionDirective(
    SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
    bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
    StringRef SearchPath, StringRef RelativePath, const Module *Imported,
    SrcMgr::CharacteristicKind FileType) {

  // Record the line location of the current included file.
  LastHashLoc = HashLoc;
}

void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
                                    const MacroDirective *MD) {
  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
  SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
  std::string NameBuffer, ValueBuffer;
  llvm::raw_string_ostream Name(NameBuffer);
  llvm::raw_string_ostream Value(ValueBuffer);
  writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
  Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
                                     llvm::dwarf::DW_MACINFO_define, location,
                                     Name.str(), Value.str());
}

void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
                                      const MacroDefinition &MD,
                                      const MacroDirective *Undef) {
  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
  SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
  Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
                                     llvm::dwarf::DW_MACINFO_undef, location,
                                     Id->getName(), "");
}