void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
                           bool ShouldFlattenMacros) const {
  for (auto &Piece : *this) {
    switch (Piece->getKind()) {
    case PathDiagnosticPiece::Call: {
      auto &Call = cast<PathDiagnosticCallPiece>(*Piece);
      if (auto CallEnter = Call.getCallEnterEvent())
        Current.push_back(std::move(CallEnter));
      Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);
      if (auto callExit = Call.getCallExitEvent())
        Current.push_back(std::move(callExit));
      break;
    }
    case PathDiagnosticPiece::Macro: {
      auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);
      if (ShouldFlattenMacros) {
        Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
      } else {
        Current.push_back(Piece);
        PathPieces NewPath;
        Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
        // FIXME: This probably shouldn't mutate the original path piece.
        Macro.subPieces = NewPath;
      }
      break;
    }
    case PathDiagnosticPiece::Event:
    case PathDiagnosticPiece::ControlFlow:
    case PathDiagnosticPiece::Note:
      Current.push_back(Piece);
      break;
    }
  }
}
Exemple #2
0
static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
  if (X.size() != Y.size())
    return X.size() < Y.size();
  for (unsigned i = 0, n = X.size(); i != n; ++i) {
    Optional<bool> b = comparePiece(*X[i], *Y[i]);
    if (b.hasValue())
      return b.getValue();
  }
  return None;
}
Exemple #3
0
static void compute_path_size(const PathPieces &pieces, unsigned &size) {
  for (PathPieces::const_iterator it = pieces.begin(),
                                  et = pieces.end(); it != et; ++it) {
    const PathDiagnosticPiece *piece = it->getPtr();
    if (const PathDiagnosticCallPiece *cp = 
        dyn_cast<PathDiagnosticCallPiece>(piece)) {
      compute_path_size(cp->path, size);
    }
    else
      ++size;
  }
}
Exemple #4
0
void TextPathDiagnostics::FlushDiagnosticsImpl(
                              std::vector<const PathDiagnostic *> &Diags,
                              FilesMade *) {
  for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
       et = Diags.end(); it != et; ++it) {
    const PathDiagnostic *D = *it;

    PathPieces FlatPath = D->path.flatten(/*ShouldFlattenMacros=*/true);
    for (PathPieces::const_iterator I = FlatPath.begin(), E = FlatPath.end(); 
         I != E; ++I) {
      unsigned diagID =
        Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
                                                 (*I)->getString());
      Diag.Report((*I)->getLocation().asLocation(), diagID);
    }
  }
}
Exemple #5
0
void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
                           bool ShouldFlattenMacros) const {
  for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
    PathDiagnosticPiece *Piece = I->getPtr();

    switch (Piece->getKind()) {
    case PathDiagnosticPiece::Call: {
      PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
      IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
        Call->getCallEnterEvent();
      if (CallEnter)
        Current.push_back(CallEnter);
      Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
        Call->getCallExitEvent();
      if (callExit)
        Current.push_back(callExit);
      break;
    }
    case PathDiagnosticPiece::Macro: {
      PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
      if (ShouldFlattenMacros) {
        Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
      } else {
        Current.push_back(Piece);
        PathPieces NewPath;
        Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
        // FIXME: This probably shouldn't mutate the original path piece.
        Macro->subPieces = NewPath;
      }
      break;
    }
    case PathDiagnosticPiece::Event:
    case PathDiagnosticPiece::ControlFlow:
      Current.push_back(Piece);
      break;
    }
  }
}
Exemple #6
0
static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
  if (X.size() != Y.size())
    return X.size() < Y.size();

  PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
  PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();

  for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
    Optional<bool> b = comparePiece(**X_I, **Y_I);
    if (b.hasValue())
      return b.getValue();
  }

  return None;
}
Exemple #7
0
static json::Object createThreadFlow(const PathPieces &Pieces,
                                     json::Array &Files) {
  const SourceManager &SMgr = Pieces.front()->getLocation().getManager();
  json::Array Locations;
  for (const auto &Piece : Pieces) {
    const PathDiagnosticLocation &P = Piece->getLocation();
    Locations.push_back(createThreadFlowLocation(
        createLocation(createPhysicalLocation(P.asRange(),
                                              *P.asLocation().getFileEntry(),
                                              SMgr, Files),
                       Piece->getString()),
        calculateImportance(*Piece)));
  }
  return json::Object{{"locations", std::move(Locations)}};
}
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
                                 FilesMade *filesMade) {
    
  // Create the HTML directory if it is missing.
  if (!createdDir) {
    createdDir = true;
    std::string ErrorMsg;
    Directory.createDirectoryOnDisk(true, &ErrorMsg);

    bool IsDirectory;
    if (llvm::sys::fs::is_directory(Directory.str(), IsDirectory) ||
        !IsDirectory) {
      llvm::errs() << "warning: could not create directory '"
                   << Directory.str() << "'\n"
                   << "reason: " << ErrorMsg << '\n';

      noDir = true;

      return;
    }
  }

  if (noDir)
    return;

  // First flatten out the entire path to make it easier to use.
  PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false);

  // The path as already been prechecked that all parts of the path are
  // from the same file and that it is non-empty.
  const SourceManager &SMgr = (*path.begin())->getLocation().getManager();
  assert(!path.empty());
  FileID FID =
    (*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID();
  assert(!FID.isInvalid());

  // Create a new rewriter to generate HTML.
  Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());

  // Process the path.
  unsigned n = path.size();
  unsigned max = n;

  for (PathPieces::const_reverse_iterator I = path.rbegin(), 
       E = path.rend();
        I != E; ++I, --n)
    HandlePiece(R, FID, **I, n, max);

  // Add line numbers, header, footer, etc.

  // unsigned FID = R.getSourceMgr().getMainFileID();
  html::EscapeText(R, FID);
  html::AddLineNumbers(R, FID);

  // If we have a preprocessor, relex the file and syntax highlight.
  // We might not have a preprocessor if we come from a deserialized AST file,
  // for example.

  html::SyntaxHighlight(R, FID, PP);
  html::HighlightMacros(R, FID, PP);

  // Get the full directory name of the analyzed file.

  const FileEntry* Entry = SMgr.getFileEntryForID(FID);

  // This is a cludge; basically we want to append either the full
  // working directory if we have no directory information.  This is
  // a work in progress.

  std::string DirName = "";

  if (llvm::sys::path::is_relative(Entry->getName())) {
    llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
    DirName = P.str() + "/";
  }

  // Add the name of the file as an <h1> tag.

  {
    std::string s;
    llvm::raw_string_ostream os(s);

    os << "<!-- REPORTHEADER -->\n"
      << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
          "<tr><td class=\"rowname\">File:</td><td>"
      << html::EscapeText(DirName)
      << html::EscapeText(Entry->getName())
      << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
         "<a href=\"#EndPath\">line "
      << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber()
      << ", column "
      << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
      << "</a></td></tr>\n"
         "<tr><td class=\"rowname\">Description:</td><td>"
      << D.getVerboseDescription() << "</td></tr>\n";

    // Output any other meta data.

    for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
         I!=E; ++I) {
      os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
    }

    os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
          "<h3>Annotated Source Code</h3>\n";

    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
  }

  // Embed meta-data tags.
  {
    std::string s;
    llvm::raw_string_ostream os(s);

    StringRef BugDesc = D.getVerboseDescription();
    if (!BugDesc.empty())
      os << "\n<!-- BUGDESC " << BugDesc << " -->\n";

    StringRef BugType = D.getBugType();
    if (!BugType.empty())
      os << "\n<!-- BUGTYPE " << BugType << " -->\n";

    StringRef BugCategory = D.getCategory();
    if (!BugCategory.empty())
      os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";

    os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";

    os << "\n<!-- BUGLINE "
       << path.back()->getLocation().asLocation().getExpansionLineNumber()
       << " -->\n";

    os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";

    // Mark the end of the tags.
    os << "\n<!-- BUGMETAEND -->\n";

    // Insert the text.
    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
  }

  // Add CSS, header, and footer.

  html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());

  // Get the rewrite buffer.
  const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);

  if (!Buf) {
    llvm::errs() << "warning: no diagnostics generated for main file.\n";
    return;
  }

  // Create a path for the target HTML file.
  llvm::sys::Path F(FilePrefix);
  F.makeUnique(false, NULL);

  // Rename the file with an HTML extension.
  llvm::sys::Path H(F);
  H.appendSuffix("html");
  F.renamePathOnDisk(H, NULL);

  std::string ErrorMsg;
  llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);

  if (!ErrorMsg.empty()) {
    llvm::errs() << "warning: could not create file '" << F.str()
                 << "'\n";
    return;
  }

  if (filesMade) {
    filesMade->addDiagnostic(D, getName(), llvm::sys::path::filename(H.str()));
  }

  // Emit the HTML to disk.
  for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
      os << *I;
}
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
                                 FilesMade *filesMade) {

  // Create the HTML directory if it is missing.
  if (!createdDir) {
    createdDir = true;
    if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) {
      llvm::errs() << "warning: could not create directory '"
                   << Directory << "': " << ec.message() << '\n';

      noDir = true;

      return;
    }
  }

  if (noDir)
    return;

  // First flatten out the entire path to make it easier to use.
  PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false);

  // The path as already been prechecked that all parts of the path are
  // from the same file and that it is non-empty.
  const SourceManager &SMgr = (*path.begin())->getLocation().getManager();
  assert(!path.empty());
  FileID FID =
    (*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID();
  assert(!FID.isInvalid());

  // Create a new rewriter to generate HTML.
  Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());

  // Get the function/method name
  SmallString<128> declName("unknown");
  int offsetDecl = 0;
  if (const Decl *DeclWithIssue = D.getDeclWithIssue()) {
      if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
          declName = ND->getDeclName().getAsString();
      }

      if (const Stmt *Body = DeclWithIssue->getBody()) {
          // Retrieve the relative position of the declaration which will be used
          // for the file name
          FullSourceLoc L(
              SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()),
              SMgr);
          FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr);
          offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber();
      }
  }

  // Process the path.
  unsigned n = path.size();
  unsigned max = n;

  for (PathPieces::const_reverse_iterator I = path.rbegin(),
       E = path.rend();
        I != E; ++I, --n)
    HandlePiece(R, FID, **I, n, max);

  // Add line numbers, header, footer, etc.

  // unsigned FID = R.getSourceMgr().getMainFileID();
  html::EscapeText(R, FID);
  html::AddLineNumbers(R, FID);

  // If we have a preprocessor, relex the file and syntax highlight.
  // We might not have a preprocessor if we come from a deserialized AST file,
  // for example.

  html::SyntaxHighlight(R, FID, PP);
  html::HighlightMacros(R, FID, PP);

  // Get the full directory name of the analyzed file.

  const FileEntry* Entry = SMgr.getFileEntryForID(FID);

  // This is a cludge; basically we want to append either the full
  // working directory if we have no directory information.  This is
  // a work in progress.

  llvm::SmallString<0> DirName;

  if (llvm::sys::path::is_relative(Entry->getName())) {
    llvm::sys::fs::current_path(DirName);
    DirName += '/';
  }

  int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber();
  int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber();

  // Add the name of the file as an <h1> tag.

  {
    std::string s;
    llvm::raw_string_ostream os(s);

    os << "<!-- REPORTHEADER -->\n"
      << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
          "<tr><td class=\"rowname\">File:</td><td>"
      << html::EscapeText(DirName)
      << html::EscapeText(Entry->getName())
      << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
         "<a href=\"#EndPath\">line "
      << LineNumber
      << ", column "
      << ColumnNumber
      << "</a></td></tr>\n"
         "<tr><td class=\"rowname\">Description:</td><td>"
      << D.getVerboseDescription() << "</td></tr>\n";

    // Output any other meta data.

    for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
         I!=E; ++I) {
      os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
    }

    os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
          "<h3>Annotated Source Code</h3>\n";

    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
  }

  // Embed meta-data tags.
  {
    std::string s;
    llvm::raw_string_ostream os(s);

    StringRef BugDesc = D.getVerboseDescription();
    if (!BugDesc.empty())
      os << "\n<!-- BUGDESC " << BugDesc << " -->\n";

    StringRef BugType = D.getBugType();
    if (!BugType.empty())
      os << "\n<!-- BUGTYPE " << BugType << " -->\n";

    StringRef BugCategory = D.getCategory();
    if (!BugCategory.empty())
      os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";

    os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";

    os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n";

    os  << "\n<!-- FUNCTIONNAME " <<  declName << " -->\n";

    os << "\n<!-- BUGLINE "
       << LineNumber
       << " -->\n";

    os << "\n<!-- BUGCOLUMN "
      << ColumnNumber
      << " -->\n";

    os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";

    // Mark the end of the tags.
    os << "\n<!-- BUGMETAEND -->\n";

    // Insert the text.
    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
  }

  // Add CSS, header, and footer.

  html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());

  // Get the rewrite buffer.
  const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);

  if (!Buf) {
    llvm::errs() << "warning: no diagnostics generated for main file.\n";
    return;
  }

  // Create a path for the target HTML file.
  int FD;
  SmallString<128> Model, ResultPath;

  if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
      llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");

      if (std::error_code EC =
          llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) {
          llvm::errs() << "warning: could not create file in '" << Directory
                       << "': " << EC.message() << '\n';
          return;
      }

  } else {
      int i = 1;
      std::error_code EC;
      do {
          // Find a filename which is not already used
          std::stringstream filename;
          Model = "";
          filename << "report-"
                   << llvm::sys::path::filename(Entry->getName()).str()
                   << "-" << declName.c_str()
                   << "-" << offsetDecl
                   << "-" << i << ".html";
          llvm::sys::path::append(Model, Directory,
                                  filename.str());
          EC = llvm::sys::fs::openFileForWrite(Model,
                                               FD,
                                               llvm::sys::fs::F_RW |
                                               llvm::sys::fs::F_Excl);
          if (EC && EC != std::errc::file_exists) {
              llvm::errs() << "warning: could not create file '" << Model
                           << "': " << EC.message() << '\n';
              return;
          }
          i++;
      } while (EC);
  }

  llvm::raw_fd_ostream os(FD, true);

  if (filesMade)
    filesMade->addDiagnostic(D, getName(),
                             llvm::sys::path::filename(ResultPath));

  // Emit the HTML to disk.
  for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
      os << *I;
}