200 lines · cpp
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-exception6//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 19using namespace clang;20 21void 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 else40 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 61MacroPPCallbacks::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 Enter66// - <built-in> file enter67// {Compiler macro definitions} - (Line=0, no scope)68// - (Optional) <command line> file enter69// {Command line macro definitions} - (Line=0, no scope)70// - (Optional) <command line> file exit71// {Command line file includes} - (Line=0, Main file scope)72// {macro definitions and file includes} - (Line!=0, Parent scope)73// - <built-in> file exit74// {User code macro definitions and file includes} - (Line!=0, Parent scope)75 76llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {77 if (Status == MainFileScope || Status == CommandLineIncludeScope)78 return Scopes.back();79 return nullptr;80}81 82SourceLocation 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 91void 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 110void 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 135void 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 158void 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 168void 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 178void 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 NameBuffer, ValueBuffer);189}190 191void 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