/// Determine whether two source locations come from the same file.
static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
                           SourceLocation DiagnosticLoc) {
  while (DiagnosticLoc.isMacroID())
    DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);

  if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
    return true;

  const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
  if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
    return true;

  return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
}
示例#2
0
/// \brief Retrieve the name of the immediate macro expansion.
///
/// This routine starts from a source location, and finds the name of the macro
/// responsible for its immediate expansion. It looks through any intervening
/// macro argument expansions to compute this. It returns a StringRef which
/// refers to the SourceManager-owned buffer of the source where that macro
/// name is spelled. Thus, the result shouldn't out-live that SourceManager.
///
/// This differs from Lexer::getImmediateMacroName in that any macro argument
/// location will result in the topmost function macro that accepted it.
/// e.g.
/// \code
///   MAC1( MAC2(foo) )
/// \endcode
/// for location of 'foo' token, this function will return "MAC1" while
/// Lexer::getImmediateMacroName will return "MAC2".
static StringRef getImmediateMacroName(SourceLocation Loc,
                                       const SourceManager &SM,
                                       const LangOptions &LangOpts) {
   assert(Loc.isMacroID() && "Only reasonble to call this on macros");
   // Walk past macro argument expanions.
   while (SM.isMacroArgExpansion(Loc))
     Loc = SM.getImmediateExpansionRange(Loc).first;

   // If the macro's spelling has no FileID, then it's actually a token paste
   // or stringization (or similar) and not a macro at all.
   if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc))))
     return StringRef();

   // Find the spelling location of the start of the non-argument expansion
   // range. This is where the macro name was spelled in order to begin
   // expanding this macro.
   Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first);

   // Dig out the buffer where the macro name was spelled and the extents of the
   // name so that we can render it into the expansion note.
   std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
   unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
   StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
   return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
                                                      FileID FID,
                                                      ParsedStatus PS) {
  // Check SourceManager hasn't changed.
  setSourceManager(SM);

#ifndef NDEBUG
  if (FID.isInvalid())
    return;

  const FileEntry *FE = SM.getFileEntryForID(FID);

  if (PS == IsParsed) {
    // Move the FileID from the unparsed set to the parsed set.
    UnparsedFiles.erase(FID);
    ParsedFiles.insert(std::make_pair(FID, FE));
  } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
    // Add the FileID to the unparsed set if we haven't seen it before.

    // Check for directives.
    bool FoundDirectives;
    if (PS == IsUnparsedNoDirectives)
      FoundDirectives = false;
    else
      FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);

    // Add the FileID to the unparsed set.
    UnparsedFiles.insert(std::make_pair(FID,
                                      UnparsedFileStatus(FE, FoundDirectives)));
  }
#endif
}
示例#4
0
void Replacement::setFromSourceLocation(const SourceManager &Sources,
                                        SourceLocation Start, unsigned Length,
                                        StringRef ReplacementText) {
  const std::pair<FileID, unsigned> DecomposedLocation =
      Sources.getDecomposedLoc(Start);
  const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
  this->FilePath = Entry ? Entry->getName() : InvalidLocation;
  this->ReplacementRange = Range(DecomposedLocation.second, Length);
  this->ReplacementText = ReplacementText;
}
示例#5
0
void Replacement::setFromSourceLocation(SourceManager &Sources,
                                        SourceLocation Start, unsigned Length,
                                        llvm::StringRef ReplacementText) {
  const std::pair<FileID, unsigned> DecomposedLocation =
      Sources.getDecomposedLoc(Start);
  const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
  this->FilePath = Entry != NULL ? Entry->getName() : InvalidLocation;
  this->Offset = DecomposedLocation.second;
  this->Length = Length;
  this->ReplacementText = ReplacementText;
}
示例#6
0
bool Transform::isFileModifiable(const SourceManager &SM,
                                 const SourceLocation &Loc) const {
  if (SM.isWrittenInMainFile(Loc))
    return true;

  const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc));
  if (!FE)
    return false;

  return GlobalOptions.ModifiableFiles.isFileIncluded(FE->getName());
}
示例#7
0
void Replacement::setFromSourceLocation(const SourceManager &Sources,
                                        SourceLocation Start, unsigned Length,
                                        StringRef ReplacementText) {
    const std::pair<FileID, unsigned> DecomposedLocation =
        Sources.getDecomposedLoc(Start);
    const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
    if (Entry) {
        // Make FilePath absolute so replacements can be applied correctly when
        // relative paths for files are used.
        llvm::SmallString<256> FilePath(Entry->getName());
        std::error_code EC = llvm::sys::fs::make_absolute(FilePath);
        this->FilePath = EC ? FilePath.c_str() : Entry->getName();
    } else {
        this->FilePath = InvalidLocation;
    }
    this->ReplacementRange = Range(DecomposedLocation.second, Length);
    this->ReplacementText = ReplacementText;
}
示例#8
0
/// \returns true on error.
static bool printLoc(llvm::raw_ostream &OS, SourceLocation Loc,
                     const SourceManager &SM, bool IncludeOffset) {
  if (Loc.isInvalid()) {
    return true;
  }
  Loc = SM.getExpansionLoc(Loc);
  const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(Loc);
  const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
  if (FE) {
    OS << llvm::sys::path::filename(FE->getName());
  } else {
    // This case really isn't interesting.
    return true;
  }
  if (IncludeOffset) {
    // Use the offest into the FileID to represent the location.  Using
    // a line/column can cause us to look back at the original source file,
    // which is expensive.
    OS << '@' << Decomposed.second;
  }
  return false;
}
示例#9
0
void arcmt::writeARCDiagsToPlist(const std::string &outPath,
                                 ArrayRef<StoredDiagnostic> diags,
                                 SourceManager &SM,
                                 const LangOptions &LangOpts) {
  DiagnosticIDs DiagIDs;

  // Build up a set of FIDs that we use by scanning the locations and
  // ranges of the diagnostics.
  FIDMap FM;
  SmallVector<FileID, 10> Fids;

  for (ArrayRef<StoredDiagnostic>::iterator
         I = diags.begin(), E = diags.end(); I != E; ++I) {
    const StoredDiagnostic &D = *I;

    AddFID(FM, Fids, SM, D.getLocation());

    for (StoredDiagnostic::range_iterator
           RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) {
      AddFID(FM, Fids, SM, RI->getBegin());
      AddFID(FM, Fids, SM, RI->getEnd());
    }
  }

  std::string errMsg;
  llvm::raw_fd_ostream o(outPath.c_str(), errMsg, llvm::sys::fs::F_None);
  if (!errMsg.empty()) {
    llvm::errs() << "error: could not create file: " << outPath << '\n';
    return;
  }

  // Write the plist header.
  o << PlistHeader;

  // Write the root object: a <dict> containing...
  //  - "files", an <array> mapping from FIDs to file names
  //  - "diagnostics", an <array> containing the diagnostics
  o << "<dict>\n"
       " <key>files</key>\n"
       " <array>\n";

  for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
       I!=E; ++I) {
    o << "  ";
    EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n';
  }

  o << " </array>\n"
       " <key>diagnostics</key>\n"
       " <array>\n";

  for (ArrayRef<StoredDiagnostic>::iterator
         DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) {
    
    const StoredDiagnostic &D = *DI;

    if (D.getLevel() == DiagnosticsEngine::Ignored)
      continue;

    o << "  <dict>\n";

    // Output the diagnostic.
    o << "   <key>description</key>";
    EmitString(o, D.getMessage()) << '\n';
    o << "   <key>category</key>";
    EmitString(o, DiagIDs.getCategoryNameFromID(
                          DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n';
    o << "   <key>type</key>";
    if (D.getLevel() >= DiagnosticsEngine::Error)
      EmitString(o, "error") << '\n';
    else if (D.getLevel() == DiagnosticsEngine::Warning)
      EmitString(o, "warning") << '\n';
    else
      EmitString(o, "note") << '\n';

    // Output the location of the bug.
    o << "  <key>location</key>\n";
    EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2);

    // Output the ranges (if any).
    StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end();

    if (RI != RE) {
      o << "   <key>ranges</key>\n";
      o << "   <array>\n";
      for (; RI != RE; ++RI)
        EmitRange(o, SM, LangOpts, *RI, FM, 4);
      o << "   </array>\n";
    }

    // Close up the entry.
    o << "  </dict>\n";
  }

  o << " </array>\n";

  // Finish.
  o << "</dict>\n</plist>";
}
示例#10
0
/// \brief Print out the file/line/column information and include trace.
///
/// This method handlen the emission of the diagnostic location information.
/// This includes extracting as much location information as is present for
/// the diagnostic and printing it, as well as any include stack or source
/// ranges necessary.
void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
                                       DiagnosticsEngine::Level Level,
                                       ArrayRef<CharSourceRange> Ranges,
                                       const SourceManager &SM) {
  if (PLoc.isInvalid()) {
    // At least print the file name if available:
    FileID FID = SM.getFileID(Loc);
    if (!FID.isInvalid()) {
      const FileEntry* FE = SM.getFileEntryForID(FID);
      if (FE && FE->getName()) {
        OS << FE->getName();
        if (FE->getDevice() == 0 && FE->getInode() == 0
            && FE->getFileMode() == 0) {
          // in PCH is a guess, but a good one:
          OS << " (in PCH)";
        }
        OS << ": ";
      }
    }
    return;
  }
  unsigned LineNo = PLoc.getLine();

  if (!DiagOpts->ShowLocation)
    return;

  if (DiagOpts->ShowColors)
    OS.changeColor(savedColor, true);

  OS << PLoc.getFilename();
  switch (DiagOpts->getFormat()) {
  case DiagnosticOptions::LFort: OS << ':'  << LineNo; break;
  case DiagnosticOptions::Msvc:  OS << '('  << LineNo; break;
  case DiagnosticOptions::Vi:    OS << " +" << LineNo; break;
  }

  if (DiagOpts->ShowColumn)
    // Compute the column number.
    if (unsigned ColNo = PLoc.getColumn()) {
      if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) {
        OS << ',';
        ColNo--;
      } else
        OS << ':';
      OS << ColNo;
    }
  switch (DiagOpts->getFormat()) {
  case DiagnosticOptions::LFort:
  case DiagnosticOptions::Vi:    OS << ':';    break;
  case DiagnosticOptions::Msvc:  OS << ") : "; break;
  }

  if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
    FileID CaretFileID =
      SM.getFileID(SM.getExpansionLoc(Loc));
    bool PrintedRange = false;

    for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
         RE = Ranges.end();
         RI != RE; ++RI) {
      // Ignore invalid ranges.
      if (!RI->isValid()) continue;

      SourceLocation B = SM.getExpansionLoc(RI->getBegin());
      SourceLocation E = SM.getExpansionLoc(RI->getEnd());

      // If the End location and the start location are the same and are a
      // macro location, then the range was something that came from a
      // macro expansion or _Pragma.  If this is an object-like macro, the
      // best we can do is to highlight the range.  If this is a
      // function-like macro, we'd also like to highlight the arguments.
      if (B == E && RI->getEnd().isMacroID())
        E = SM.getExpansionRange(RI->getEnd()).second;

      std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
      std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);

      // If the start or end of the range is in another file, just discard
      // it.
      if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
        continue;

      // Add in the length of the token, so that we cover multi-char
      // tokens.
      unsigned TokSize = 0;
      if (RI->isTokenRange())
        TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);

      OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
        << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
        << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
        << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
        << '}';
      PrintedRange = true;
    }

    if (PrintedRange)
      OS << ':';
  }
  OS << ' ';
}
示例#11
0
void arcmt::writeARCDiagsToPlist(const std::string &outPath,
                                 ArrayRef<StoredDiagnostic> diags,
                                 SourceManager &SM,
                                 const LangOptions &LangOpts) {
  DiagnosticIDs DiagIDs;

  // Build up a set of FIDs that we use by scanning the locations and
  // ranges of the diagnostics.
  FIDMap FM;
  SmallVector<FileID, 10> Fids;

  for (ArrayRef<StoredDiagnostic>::iterator
         I = diags.begin(), E = diags.end(); I != E; ++I) {
    const StoredDiagnostic &D = *I;

    AddFID(FM, Fids, SM, D.getLocation());

    for (StoredDiagnostic::range_iterator
           RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) {
      AddFID(FM, Fids, SM, RI->getBegin());
      AddFID(FM, Fids, SM, RI->getEnd());
    }
  }

  std::error_code EC;
  llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::F_Text);
  if (EC) {
    llvm::errs() << "error: could not create file: " << outPath << '\n';
    return;
  }

  EmitPlistHeader(o);

  // Write the root object: a <dict> containing...
  //  - "files", an <array> mapping from FIDs to file names
  //  - "diagnostics", an <array> containing the diagnostics
  o << "<dict>\n"
       " <key>files</key>\n"
       " <array>\n";

  for (FileID FID : Fids)
    EmitString(o << "  ", SM.getFileEntryForID(FID)->getName()) << '\n';

  o << " </array>\n"
       " <key>diagnostics</key>\n"
       " <array>\n";

  for (ArrayRef<StoredDiagnostic>::iterator
         DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) {

    const StoredDiagnostic &D = *DI;

    if (D.getLevel() == DiagnosticsEngine::Ignored)
      continue;

    o << "  <dict>\n";

    // Output the diagnostic.
    o << "   <key>description</key>";
    EmitString(o, D.getMessage()) << '\n';
    o << "   <key>category</key>";
    EmitString(o, DiagIDs.getCategoryNameFromID(
                          DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n';
    o << "   <key>type</key>";
    EmitString(o, getLevelName(D.getLevel())) << '\n';

    // Output the location of the bug.
    o << "  <key>location</key>\n";
    EmitLocation(o, SM, D.getLocation(), FM, 2);

    // Output the ranges (if any).
    if (!D.getRanges().empty()) {
      o << "   <key>ranges</key>\n";
      o << "   <array>\n";
      for (auto &R : D.getRanges()) {
        CharSourceRange ExpansionRange(SM.getExpansionRange(R.getAsRange()),
                                       R.isTokenRange());
        EmitRange(o, SM, Lexer::getAsCharRange(ExpansionRange, SM, LangOpts),
                  FM, 4);
      }
      o << "   </array>\n";
    }

    // Close up the entry.
    o << "  </dict>\n";
  }

  o << " </array>\n";

  // Finish.
  o << "</dict>\n</plist>";
}