forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			209 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- 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.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();
 | 
						|
}
 | 
						|
 | 
						|
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) {
 | 
						|
  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,
 | 
						|
                                      const MacroDirective *Undef) {
 | 
						|
  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
 | 
						|
  SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
 | 
						|
  Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
 | 
						|
                                     llvm::dwarf::DW_MACINFO_undef, location,
 | 
						|
                                     Id->getName(), "");
 | 
						|
}
 |