#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 << ',';
}
if ((*AI)->getName() == "__VA_ARGS__")
Name << "...";
else
Name << (*AI)->getName();
}
if (MI.isGNUVarargs())
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) {}
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;
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))
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) {
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, Optional<FileEntryRef> File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
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(), "");
}