|  | //===--- 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(), ""); | 
|  | } |