#ifndef LLVM_SUPPORT_GRAPHWRITER_H
#define LLVM_SUPPORT_GRAPHWRITER_H
-#include "llvm/Support/DOTGraphTraits.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/GraphTraits.h"
+#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/Path.h"
-#include <vector>
+#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <vector>
namespace llvm {
namespace DOT { // Private functions...
std::string EscapeString(const std::string &Label);
+
+ /// \brief Get a color string for this node number. Simply round-robin selects
+ /// from a reasonable number of colors.
+ StringRef getColorString(unsigned NodeNumber);
}
namespace GraphProgram {
};
}
-void DisplayGraph(const sys::Path& Filename, bool wait=true, GraphProgram::Name program = GraphProgram::DOT);
+bool DisplayGraph(StringRef Filename, bool wait = true,
+ GraphProgram::Name program = GraphProgram::DOT);
template<typename GraphType>
class GraphWriter {
// If we should include the address of the node in the label, do so now.
if (DTraits.hasNodeAddressLabel(Node, G))
- O << "|" << (void*)Node;
+ O << "|" << static_cast<const void*>(Node);
+
+ std::string NodeDesc = DTraits.getNodeDescription(Node, G);
+ if (!NodeDesc.empty())
+ O << "|" << DOT::EscapeString(NodeDesc);
}
std::string edgeSourceLabels;
// If we should include the address of the node in the label, do so now.
if (DTraits.hasNodeAddressLabel(Node, G))
- O << "|" << (void*)Node;
+ O << "|" << static_cast<const void*>(Node);
+
+ std::string NodeDesc = DTraits.getNodeDescription(Node, G);
+ if (!NodeDesc.empty())
+ O << "|" << DOT::EscapeString(NodeDesc);
}
if (DTraits.hasEdgeDestLabels()) {
/// emitSimpleNode - Outputs a simple (non-record) node
void emitSimpleNode(const void *ID, const std::string &Attr,
- const std::string &Label, unsigned NumEdgeSources = 0,
- const std::vector<std::string> *EdgeSourceLabels = 0) {
+ const std::string &Label, unsigned NumEdgeSources = 0,
+ const std::vector<std::string> *EdgeSourceLabels = nullptr) {
O << "\tNode" << ID << "[ ";
if (!Attr.empty())
O << Attr << ",";
return O;
}
-template<typename GraphType>
-sys::Path WriteGraph(const GraphType &G, const Twine &Name,
- bool ShortNames = false, const Twine &Title = "") {
- std::string ErrMsg;
- sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
- if (Filename.isEmpty()) {
- errs() << "Error: " << ErrMsg << "\n";
- return Filename;
- }
- Filename.appendComponent((Name + ".dot").str());
- if (Filename.makeUnique(true,&ErrMsg)) {
- errs() << "Error: " << ErrMsg << "\n";
- return sys::Path();
+std::string createGraphFilename(const Twine &Name, int &FD);
+
+template <typename GraphType>
+std::string WriteGraph(const GraphType &G, const Twine &Name,
+ bool ShortNames = false, const Twine &Title = "") {
+ int FD;
+ // Windows can't always handle long paths, so limit the length of the name.
+ std::string N = Name.str();
+ N = N.substr(0, std::min<std::size_t>(N.size(), 140));
+ std::string Filename = createGraphFilename(N, FD);
+ raw_fd_ostream O(FD, /*shouldClose=*/ true);
+
+ if (FD == -1) {
+ errs() << "error opening file '" << Filename << "' for writing!\n";
+ return "";
}
- errs() << "Writing '" << Filename.str() << "'... ";
-
- std::string ErrorInfo;
- raw_fd_ostream O(Filename.c_str(), ErrorInfo);
-
- if (ErrorInfo.empty()) {
- llvm::WriteGraph(O, G, ShortNames, Title);
- errs() << " done. \n";
- } else {
- errs() << "error opening file '" << Filename.str() << "' for writing!\n";
- Filename.clear();
- }
+ llvm::WriteGraph(O, G, ShortNames, Title);
+ errs() << " done. \n";
return Filename;
}
void ViewGraph(const GraphType &G, const Twine &Name,
bool ShortNames = false, const Twine &Title = "",
GraphProgram::Name Program = GraphProgram::DOT) {
- sys::Path Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
+ std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
- if (Filename.isEmpty())
+ if (Filename.empty())
return;
DisplayGraph(Filename, true, Program);