|
@@ -0,0 +1,211 @@
|
|
|
+//===--- MacroPPCallbacks.cpp ---------------------------------------------===//
|
|
|
+//
|
|
|
+// The LLVM Compiler Infrastructure
|
|
|
+//
|
|
|
+// This file is distributed under the University of Illinois Open Source
|
|
|
+// License. See LICENSE.TXT for details.
|
|
|
+//
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+//
|
|
|
+// This file contains implementation for the macro preprocessors callbacks.
|
|
|
+//
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+
|
|
|
+#include "MacroPPCallbacks.h"
|
|
|
+#include "CGDebugInfo.h"
|
|
|
+#include "clang/CodeGen/ModuleBuilder.h"
|
|
|
+#include "clang/Parse/Parser.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.arg_empty()) {
|
|
|
+ MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_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();
|
|
|
+}
|
|
|
+
|
|
|
+static bool isBuiltinFile(SourceManager &SM, SourceLocation Loc) {
|
|
|
+ StringRef Filename(SM.getPresumedLoc(Loc).getFilename());
|
|
|
+ return Filename.equals("<built-in>");
|
|
|
+}
|
|
|
+
|
|
|
+static bool isCommandLineFile(SourceManager &SM, SourceLocation Loc) {
|
|
|
+ StringRef Filename(SM.getPresumedLoc(Loc).getFilename());
|
|
|
+ return Filename.equals("<command line>");
|
|
|
+}
|
|
|
+
|
|
|
+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) {
|
|
|
+ default:
|
|
|
+ llvm_unreachable("Do not expect to enter a file from current scope");
|
|
|
+ case NoScope:
|
|
|
+ updateStatusToNextScope();
|
|
|
+ break;
|
|
|
+ case InitializedScope:
|
|
|
+ updateStatusToNextScope();
|
|
|
+ return;
|
|
|
+ case BuiltinScope:
|
|
|
+ if (isCommandLineFile(PP.getSourceManager(), 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 (!isBuiltinFile(PP.getSourceManager(), 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) {
|
|
|
+
|
|
|
+ // 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) {
|
|
|
+ IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
|
|
|
+ SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
|
|
|
+ Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
|
|
|
+ llvm::dwarf::DW_MACINFO_undef, location,
|
|
|
+ Id->getName(), "");
|
|
|
+}
|