aaboud updated this revision to Diff 46034.
aaboud marked 6 inline comments as done.
aaboud added a comment.

Added comments explaining the implementation.


http://reviews.llvm.org/D16135

Files:
  include/clang/AST/ASTConsumer.h
  lib/AST/ASTConsumer.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CGDebugInfo.h
  lib/CodeGen/CMakeLists.txt
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenModule.h
  lib/CodeGen/MacroPPCallbacks.cpp
  lib/CodeGen/MacroPPCallbacks.h
  lib/CodeGen/ModuleBuilder.cpp
  lib/Parse/ParseAST.cpp

Index: lib/Parse/ParseAST.cpp
===================================================================
--- lib/Parse/ParseAST.cpp
+++ lib/Parse/ParseAST.cpp
@@ -128,6 +128,12 @@
       new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
   Parser &P = *ParseOP.get();
 
+  std::unique_ptr<PPCallbacks> Callbacks =
+      Consumer->CreatePreprocessorCallbacks(S.getPreprocessor());
+  if (Callbacks) {
+    S.getPreprocessor().addPPCallbacks(std::move(Callbacks));
+  }
+
   llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>
       CleanupPrettyStack(llvm::SavePrettyStackState());
   PrettyStackTraceParserEntry CrashInfo(P);
Index: lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- lib/CodeGen/ModuleBuilder.cpp
+++ lib/CodeGen/ModuleBuilder.cpp
@@ -20,6 +20,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Lex/PPCallbacks.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/LLVMContext.h"
@@ -234,6 +235,11 @@
     void HandleDependentLibrary(llvm::StringRef Lib) override {
       Builder->AddDependentLib(Lib);
     }
+
+    std::unique_ptr<PPCallbacks>
+    CreatePreprocessorCallbacks(Preprocessor &PP) override {
+      return Builder->createPreprocessorCallbacks(PP);
+    }
   };
 }
 
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -24,6 +24,7 @@
 #include "CodeGenPGO.h"
 #include "CodeGenTBAA.h"
 #include "CoverageMappingGen.h"
+#include "MacroPPCallbacks.h"
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CharUnits.h"
@@ -208,6 +209,16 @@
   CUDARuntime = CreateNVCUDARuntime(*this);
 }
 
+std::unique_ptr<PPCallbacks>
+CodeGenModule::createPreprocessorCallbacks(Preprocessor &PP) {
+  // Enable generating macro debug info only in FullDebugInfo mode.
+  if (CodeGenOpts.getDebugInfo() < CodeGenOptions::FullDebugInfo ||
+      !getModuleDebugInfo())
+    return nullptr;
+
+  return std::make_unique<MacroPPCallbacks>(*getModuleDebugInfo(), PP);
+}
+
 void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) {
   Replacements[Name] = C;
 }
Index: lib/CodeGen/MacroPPCallbacks.h
===================================================================
--- lib/CodeGen/MacroPPCallbacks.h
+++ lib/CodeGen/MacroPPCallbacks.h
@@ -0,0 +1,82 @@
+//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines implementation for the macro preprocessors callbacks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Parse/Parser.h"
+#include <vector>
+
+namespace llvm {
+class DIMacroFile;
+}
+namespace clang {
+
+namespace CodeGen {
+class CGDebugInfo;
+}
+class MacroPPCallbacks : public PPCallbacks {
+  /// Debug info code generator
+  CodeGen::CGDebugInfo &DebugInfo;
+  /// Preprocessor
+  Preprocessor &PP;
+  /// Location (used for line number) for recent included file.
+  SourceLocation LastHashLoc;
+  /// Location (used for file name) for first included file (source main).
+  SourceLocation FirstIncludeFile;
+  /// Indicates that first file inclusion occurred.
+  bool FirstInclude;
+  /// Indicates that DIMacroFile entry was created for first included file.
+  bool FirstIncludeDone;
+  /// Counts current number of command line included files, which was entered
+  /// and was not exited yet.
+  int CommandIncludeFiles;
+  /// Number of fake files that should skip that were not exited yet.
+  int SkipFiles;
+  /// Parent contains all entered files that were not exited yet according to
+  /// the inclusion order.
+  std::vector<llvm::DIMacroFile *> Parents;
+
+  /// Use the passed preprocessor to calculate the macro name and value from
+  /// the given macro info and identifier info.
+  static void getMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
+                                 Preprocessor &PP, raw_ostream &Name,
+                                 raw_ostream &Value);
+
+public:
+  MacroPPCallbacks(CodeGen::CGDebugInfo &DI, Preprocessor &PP);
+
+  /// Callback invoked whenever a source file is entered or exited.
+  ///
+  /// \param Loc Indicates the new location.
+  /// \param PrevFID the file that was exited if \p Reason is ExitFile.
+  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                   SrcMgr::CharacteristicKind FileType,
+                   FileID PrevFID = FileID()) override;
+
+  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+                          StringRef FileName, bool IsAngled,
+                          CharSourceRange FilenameRange, const FileEntry *File,
+                          StringRef SearchPath, StringRef RelativePath,
+                          const Module *Imported) override;
+
+  /// Hook called whenever a macro definition is seen.
+  void MacroDefined(const Token &MacroNameTok,
+                    const MacroDirective *MD) override;
+
+  /// Hook called whenever a macro \#undef is seen.
+  ///
+  /// MD is released immediately following this callback.
+  void MacroUndefined(const Token &MacroNameTok,
+                      const MacroDefinition &MD) override;
+};
+
+} // end namespace clang
Index: lib/CodeGen/CMakeLists.txt
===================================================================
--- lib/CodeGen/CMakeLists.txt
+++ lib/CodeGen/CMakeLists.txt
@@ -70,6 +70,7 @@
   CodeGenTypes.cpp
   CoverageMappingGen.cpp
   ItaniumCXXABI.cpp
+  MacroPPCallbacks.cpp
   MicrosoftCXXABI.cpp
   ModuleBuilder.cpp
   ObjectFilePCHContainerOperations.cpp
Index: lib/CodeGen/CGDebugInfo.h
===================================================================
--- lib/CodeGen/CGDebugInfo.h
+++ lib/CodeGen/CGDebugInfo.h
@@ -376,6 +376,15 @@
 
   void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
 
+  /// Get Macro debug info.
+  llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, bool IsUndef,
+                             SourceLocation LineLoc, StringRef Name,
+                             StringRef Value);
+  /// Get Macro File debug info.
+  llvm::DIMacroFile *CreateMacroFile(llvm::DIMacroFile *Parent,
+                                     SourceLocation LineLoc,
+                                     SourceLocation FileLoc);
+
 private:
   /// Emit call to llvm.dbg.declare for a variable declaration.
   void EmitDeclare(const VarDecl *decl, llvm::Value *AI,
Index: lib/CodeGen/CodeGenAction.cpp
===================================================================
--- lib/CodeGen/CodeGenAction.cpp
+++ lib/CodeGen/CodeGenAction.cpp
@@ -227,6 +227,11 @@
       Gen->HandleDependentLibrary(Opts);
     }
 
+    std::unique_ptr<PPCallbacks>
+    CreatePreprocessorCallbacks(Preprocessor &PP) override {
+      return Gen->CreatePreprocessorCallbacks(PP);
+    }
+
     static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
                                      unsigned LocCookie) {
       SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -2096,6 +2096,25 @@
                                         FullName);
 }
 
+llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, bool IsUndef,
+                                        SourceLocation LineLoc, StringRef Name,
+                                        StringRef Value) {
+  unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
+  unsigned MType = IsUndef
+      ? llvm::dwarf::DW_MACINFO_undef
+      : llvm::dwarf::DW_MACINFO_define;
+  return DBuilder.createMacro(Parent, Line, MType, Name, Value);
+}
+
+llvm::DIMacroFile *CGDebugInfo::CreateMacroFile(llvm::DIMacroFile *Parent,
+                                                SourceLocation LineLoc,
+                                                SourceLocation FileLoc) {
+  llvm::DIFile *FName = getOrCreateFile(FileLoc);
+  unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
+
+  return DBuilder.createMacroFile(Parent, Line, FName, llvm::DIMacroNodeArray());
+}
+
 static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
   Qualifiers Quals;
   do {
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -76,6 +76,8 @@
 class CXXDestructorDecl;
 class Module;
 class CoverageSourceInfo;
+class Preprocessor;
+class PPCallbacks;
 
 namespace CodeGen {
 
@@ -585,6 +587,8 @@
 
   CGDebugInfo *getModuleDebugInfo() { return DebugInfo; }
 
+  std::unique_ptr<PPCallbacks> createPreprocessorCallbacks(Preprocessor &PP);
+
   llvm::MDNode *getNoObjCARCExceptionsMetadata() {
     if (!NoObjCARCExceptionsMetadata)
       NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None);
Index: lib/CodeGen/MacroPPCallbacks.cpp
===================================================================
--- lib/CodeGen/MacroPPCallbacks.cpp
+++ lib/CodeGen/MacroPPCallbacks.cpp
@@ -0,0 +1,171 @@
+//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===//
+//
+//                     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 <vector>
+
+using namespace clang;
+
+void MacroPPCallbacks::getMacroDefinition(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())
+      Name << "..."; // #define foo(x...)
+
+    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(CodeGen::CGDebugInfo &DI, Preprocessor &PP)
+    : DebugInfo(DI), PP(PP), FirstInclude(false), FirstIncludeDone(false),
+      // SkipFiles is equal to 2, because Preprocessor opens two fake files
+      //   "<built-in>" and "<command-line>" without invoking the "FileChange"
+      //   callback. We should not create DIMacroFile for these fake files.
+      // CommandIncludeFiles counts the number of currently processed files,
+      //   which are included from command line. Initialized to zero.
+      CommandIncludeFiles(0), SkipFiles(2) {
+  Parents.push_back(nullptr);
+}
+
+void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                                   SrcMgr::CharacteristicKind FileType,
+                                   FileID PrevFID) {
+  switch (Reason) {
+  case EnterFile:
+    if (!FirstInclude) {
+      // First included file is always the source main file.
+      // Record its location.
+      FirstInclude = true;
+      FirstIncludeFile = Loc;
+      // Can not create DIMacroFile for source main file and push it to parent
+      // list at this point. Because, command line macros should have nullptr
+      // parent.
+    }
+    if (CommandIncludeFiles) {
+      // Preprocessor just entered a file included from command line.
+      // Create DIMacroFile entry for source main file if such was not created.
+      if (FirstInclude && !FirstIncludeDone) {
+        assert(FirstIncludeFile.isValid());
+        Parents.push_back(DebugInfo.CreateMacroFile(
+            Parents.back(), SourceLocation(), FirstIncludeFile));
+        FirstIncludeDone = true;
+      }
+      // Create DIMacroFile entry for command line included file.
+      Parents.push_back(
+          DebugInfo.CreateMacroFile(Parents.back(), SourceLocation(), Loc));
+    } else if (!SkipFiles)
+      // There is no more files to skip create DIMacroFile entry for current
+      // included file.
+      Parents.push_back(
+          DebugInfo.CreateMacroFile(Parents.back(), LastHashLoc, Loc));
+    return;
+  case ExitFile:
+    if (CommandIncludeFiles) {
+      // Preprocessor just exited a file included from command line.
+      // Removed the DIMacroFile entry from the parent stack and decrease the
+      // command line included files counter.
+      Parents.pop_back();
+      --CommandIncludeFiles;
+    } else if (SkipFiles) {
+      // Exiting one of the fake files that should be skipped.
+      // Decrease the skip files counter.
+      if (!(--SkipFiles)) {
+        // This was the last file to skip, create DIMacroFile entry for source
+        // main file if such was not created.
+        if (FirstInclude && !FirstIncludeDone) {
+          assert(FirstIncludeFile.isValid());
+          DebugInfo.CreateMacroFile(Parents.back(), SourceLocation(),
+                                    FirstIncludeFile);
+          FirstIncludeDone = true;
+        }
+      }
+    } else
+      // Exiting an actual include file removed its DIMacroFile entry from the
+      // parent stack.
+      Parents.pop_back();
+    return;
+  default:
+    return;
+  }
+}
+
+void MacroPPCallbacks::InclusionDirective(
+    SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+    bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+    StringRef SearchPath, StringRef RelativePath, const Module *Imported) {
+  // FIXME: find a better way to check if this is #include
+  if (FileName.empty())
+    return;
+
+  // If preprocessor did not exit all skip files, the current include file must
+  // be included from command line.
+  if (SkipFiles)
+    // Increase the command line include files counter.
+    CommandIncludeFiles++;
+
+  // Record the location, i.e. line number, of the current included file.
+  LastHashLoc = HashLoc;
+}
+
+void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
+                                    const MacroDirective *MD) {
+  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+  SourceLocation location;
+  // While parsing skipped files location of macros is invalid.
+  // Invalid location represents line zero.
+  if (!SkipFiles)
+    location = MacroNameTok.getLocation();
+  std::string NameBuffer, ValueBuffer;
+  llvm::raw_string_ostream Name(NameBuffer);
+  llvm::raw_string_ostream Value(ValueBuffer);
+  getMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
+  DebugInfo.CreateMacro(Parents.back(), false, location, Name.str(),
+                        Value.str());
+}
+
+void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
+                                      const MacroDefinition &MD) {
+  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+  SourceLocation location = MacroNameTok.getLocation();
+  DebugInfo.CreateMacro(Parents.back(), true, location, Id->getName(), "");
+}
Index: lib/AST/ASTConsumer.cpp
===================================================================
--- lib/AST/ASTConsumer.cpp
+++ lib/AST/ASTConsumer.cpp
@@ -15,6 +15,7 @@
 #include "llvm/Bitcode/BitstreamReader.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclGroup.h"
+#include "clang/Lex/PPCallbacks.h"
 using namespace clang;
 
 bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
@@ -30,3 +31,8 @@
 void ASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
   HandleTopLevelDecl(DeclGroupRef(D));
 }
+
+std::unique_ptr<PPCallbacks>
+ASTConsumer::CreatePreprocessorCallbacks(Preprocessor &PP) {
+  return nullptr;
+}
Index: include/clang/AST/ASTConsumer.h
===================================================================
--- include/clang/AST/ASTConsumer.h
+++ include/clang/AST/ASTConsumer.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_AST_ASTCONSUMER_H
 
 #include "llvm/ADT/StringRef.h"
+#include <memory>
 
 namespace clang {
   class ASTContext;
@@ -29,6 +30,8 @@
   class VarDecl;
   class FunctionDecl;
   class ImportDecl;
+  class PPCallbacks;
+  class Preprocessor;
 
 /// ASTConsumer - This is an abstract interface that should be implemented by
 /// clients that read ASTs.  This abstraction layer allows the client to be
@@ -152,6 +155,12 @@
   /// body may be parsed anyway if it is needed (for instance, if it contains
   /// the code completion point or is constexpr).
   virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
+
+  /// If the consumer is interested in notifications from Preprocessor,
+  /// for example: notifications on macro definitions, etc., it should return
+  /// a pointer to a PPCallbacks here.
+  /// The caller takes ownership on the returned pointer.
+  virtual std::unique_ptr<PPCallbacks> CreatePreprocessorCallbacks(Preprocessor &PP);
 };
 
 } // end namespace clang.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to