Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Support/GraphWriter.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- GraphWriter.cpp - Implements GraphWriter support routines ----------===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
// This file implements misc. GraphWriter support routines.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "llvm/Support/GraphWriter.h"
15
#include "llvm/ADT/SmallString.h"
16
#include "llvm/ADT/SmallVector.h"
17
#include "llvm/ADT/StringRef.h"
18
#include "llvm/Config/config.h"
19
#include "llvm/Support/CommandLine.h"
20
#include "llvm/Support/Compiler.h"
21
#include "llvm/Support/ErrorHandling.h"
22
#include "llvm/Support/ErrorOr.h"
23
#include "llvm/Support/FileSystem.h"
24
#include "llvm/Support/Program.h"
25
#include "llvm/Support/raw_ostream.h"
26
#include <cassert>
27
#include <system_error>
28
#include <string>
29
#include <vector>
30
31
using namespace llvm;
32
33
static cl::opt<bool> ViewBackground("view-background", cl::Hidden,
34
  cl::desc("Execute graph viewer in the background. Creates tmp file litter."));
35
36
19
std::string llvm::DOT::EscapeString(const std::string &Label) {
37
19
  std::string Str(Label);
38
1.50k
  for (unsigned i = 0; 
i != Str.length()1.50k
;
++i1.48k
)
39
1.48k
  switch (Str[i]) {
40
0
    case '\n':
41
0
      Str.insert(Str.begin()+i, '\\');  // Escape character...
42
0
      ++i;
43
0
      Str[i] = 'n';
44
0
      break;
45
0
    case '\t':
46
0
      Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
47
0
      ++i;
48
0
      Str[i] = ' ';
49
0
      break;
50
37
    case '\\':
51
37
      if (i+1 != Str.length())
52
37
        switch (Str[i+1]) {
53
37
          case 'l': continue; // don't disturb \l
54
0
          
case '|': 0
case '{': 0
case '}':
55
0
            Str.erase(Str.begin()+i); continue;
56
0
          default: break;
57
0
        }
58
0
        
LLVM_FALLTHROUGH0
;
59
0
    
case '{': 0
case '}':
60
0
    
case '<': 0
case '>':
61
0
    
case '|': 0
case '"':
62
0
      Str.insert(Str.begin()+i, '\\');  // Escape character...
63
0
      ++i;  // don't infinite loop
64
0
      break;
65
1.48k
  }
66
19
  return Str;
67
19
}
68
69
/// \brief Get a color string for this node number. Simply round-robin selects
70
/// from a reasonable number of colors.
71
0
StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
72
0
  static const int NumColors = 20;
73
0
  static const char* Colors[NumColors] = {
74
0
    "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa",
75
0
    "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff",
76
0
    "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"};
77
0
  return Colors[ColorNumber % NumColors];
78
0
}
79
80
0
std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
81
0
  FD = -1;
82
0
  SmallString<128> Filename;
83
0
  std::error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename);
84
0
  if (
EC0
) {
85
0
    errs() << "Error: " << EC.message() << "\n";
86
0
    return "";
87
0
  }
88
0
89
0
  errs() << "Writing '" << Filename << "'... ";
90
0
  return Filename.str();
91
0
}
92
93
// Execute the graph viewer. Return true if there were errors.
94
static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
95
                            StringRef Filename, bool wait,
96
0
                            std::string &ErrMsg) {
97
0
  assert(args.back() == nullptr);
98
0
  if (
wait0
) {
99
0
    if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0,
100
0
                            &ErrMsg)) {
101
0
      errs() << "Error: " << ErrMsg << "\n";
102
0
      return true;
103
0
    }
104
0
    sys::fs::remove(Filename);
105
0
    errs() << " done. \n";
106
0
  } else {
107
0
    sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg);
108
0
    errs() << "Remember to erase graph file: " << Filename << "\n";
109
0
  }
110
0
  return false;
111
0
}
112
113
namespace {
114
115
struct GraphSession {
116
  std::string LogBuffer;
117
118
0
  bool TryFindProgram(StringRef Names, std::string &ProgramPath) {
119
0
    raw_string_ostream Log(LogBuffer);
120
0
    SmallVector<StringRef, 8> parts;
121
0
    Names.split(parts, '|');
122
0
    for (auto Name : parts) {
123
0
      if (ErrorOr<std::string> 
P0
= sys::findProgramByName(Name)) {
124
0
        ProgramPath = *P;
125
0
        return true;
126
0
      }
127
0
      Log << "  Tried '" << Name << "'\n";
128
0
    }
129
0
    return false;
130
0
  }
131
};
132
133
} // end anonymous namespace
134
135
0
static const char *getProgramName(GraphProgram::Name program) {
136
0
  switch (program) {
137
0
  case GraphProgram::DOT:
138
0
    return "dot";
139
0
  case GraphProgram::FDP:
140
0
    return "fdp";
141
0
  case GraphProgram::NEATO:
142
0
    return "neato";
143
0
  case GraphProgram::TWOPI:
144
0
    return "twopi";
145
0
  case GraphProgram::CIRCO:
146
0
    return "circo";
147
0
  }
148
0
  
llvm_unreachable0
("bad kind");
149
0
}
150
151
bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
152
0
                        GraphProgram::Name program) {
153
0
  std::string Filename = FilenameRef;
154
0
  std::string ErrMsg;
155
0
  std::string ViewerPath;
156
0
  GraphSession S;
157
0
158
0
#ifdef __APPLE__
159
0
  wait &= !ViewBackground;
160
0
  if (
S.TryFindProgram("open", ViewerPath)0
) {
161
0
    std::vector<const char *> args;
162
0
    args.push_back(ViewerPath.c_str());
163
0
    if (wait)
164
0
      args.push_back("-W");
165
0
    args.push_back(Filename.c_str());
166
0
    args.push_back(nullptr);
167
0
    errs() << "Trying 'open' program... ";
168
0
    if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
169
0
      return false;
170
0
  }
171
0
#endif
172
0
  
if (0
S.TryFindProgram("xdg-open", ViewerPath)0
) {
173
0
    std::vector<const char *> args;
174
0
    args.push_back(ViewerPath.c_str());
175
0
    args.push_back(Filename.c_str());
176
0
    args.push_back(nullptr);
177
0
    errs() << "Trying 'xdg-open' program... ";
178
0
    if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
179
0
      return false;
180
0
  }
181
0
182
0
  // Graphviz
183
0
  
if (0
S.TryFindProgram("Graphviz", ViewerPath)0
) {
184
0
    std::vector<const char *> args;
185
0
    args.push_back(ViewerPath.c_str());
186
0
    args.push_back(Filename.c_str());
187
0
    args.push_back(nullptr);
188
0
189
0
    errs() << "Running 'Graphviz' program... ";
190
0
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
191
0
  }
192
0
193
0
  // xdot
194
0
  
if (0
S.TryFindProgram("xdot|xdot.py", ViewerPath)0
) {
195
0
    std::vector<const char *> args;
196
0
    args.push_back(ViewerPath.c_str());
197
0
    args.push_back(Filename.c_str());
198
0
199
0
    args.push_back("-f");
200
0
    args.push_back(getProgramName(program));
201
0
202
0
    args.push_back(nullptr);
203
0
204
0
    errs() << "Running 'xdot.py' program... ";
205
0
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
206
0
  }
207
0
208
0
  enum ViewerKind {
209
0
    VK_None,
210
0
    VK_OSXOpen,
211
0
    VK_XDGOpen,
212
0
    VK_Ghostview,
213
0
    VK_CmdStart
214
0
  };
215
0
  ViewerKind Viewer = VK_None;
216
0
#ifdef __APPLE__
217
0
  if (
!Viewer && 0
S.TryFindProgram("open", ViewerPath)0
)
218
0
    Viewer = VK_OSXOpen;
219
0
#endif
220
0
  if (
!Viewer && 0
S.TryFindProgram("gv", ViewerPath)0
)
221
0
    Viewer = VK_Ghostview;
222
0
  if (
!Viewer && 0
S.TryFindProgram("xdg-open", ViewerPath)0
)
223
0
    Viewer = VK_XDGOpen;
224
#ifdef LLVM_ON_WIN32
225
  if (!Viewer && S.TryFindProgram("cmd", ViewerPath)) {
226
    Viewer = VK_CmdStart;
227
  }
228
#endif
229
230
0
  // PostScript or PDF graph generator + PostScript/PDF viewer
231
0
  std::string GeneratorPath;
232
0
  if (Viewer &&
233
0
      (S.TryFindProgram(getProgramName(program), GeneratorPath) ||
234
0
       
S.TryFindProgram("dot|fdp|neato|twopi|circo", GeneratorPath)0
)) {
235
0
    std::string OutputFilename =
236
0
        Filename + (Viewer == VK_CmdStart ? 
".pdf"0
:
".ps"0
);
237
0
238
0
    std::vector<const char *> args;
239
0
    args.push_back(GeneratorPath.c_str());
240
0
    if (Viewer == VK_CmdStart)
241
0
      args.push_back("-Tpdf");
242
0
    else
243
0
      args.push_back("-Tps");
244
0
    args.push_back("-Nfontname=Courier");
245
0
    args.push_back("-Gsize=7.5,10");
246
0
    args.push_back(Filename.c_str());
247
0
    args.push_back("-o");
248
0
    args.push_back(OutputFilename.c_str());
249
0
    args.push_back(nullptr);
250
0
251
0
    errs() << "Running '" << GeneratorPath << "' program... ";
252
0
253
0
    if (ExecGraphViewer(GeneratorPath, args, Filename, true, ErrMsg))
254
0
      return true;
255
0
256
0
    // The lifetime of StartArg must include the call of ExecGraphViewer
257
0
    // because the args are passed as vector of char*.
258
0
    std::string StartArg;
259
0
260
0
    args.clear();
261
0
    args.push_back(ViewerPath.c_str());
262
0
    switch (Viewer) {
263
0
    case VK_OSXOpen:
264
0
      args.push_back("-W");
265
0
      args.push_back(OutputFilename.c_str());
266
0
      break;
267
0
    case VK_XDGOpen:
268
0
      wait = false;
269
0
      args.push_back(OutputFilename.c_str());
270
0
      break;
271
0
    case VK_Ghostview:
272
0
      args.push_back("--spartan");
273
0
      args.push_back(OutputFilename.c_str());
274
0
      break;
275
0
    case VK_CmdStart:
276
0
      args.push_back("/S");
277
0
      args.push_back("/C");
278
0
      StartArg =
279
0
          (StringRef("start ") + (wait ? 
"/WAIT "0
:
""0
) + OutputFilename).str();
280
0
      args.push_back(StartArg.c_str());
281
0
      break;
282
0
    case VK_None:
283
0
      llvm_unreachable("Invalid viewer");
284
0
    }
285
0
    args.push_back(nullptr);
286
0
287
0
    ErrMsg.clear();
288
0
    return ExecGraphViewer(ViewerPath, args, OutputFilename, wait, ErrMsg);
289
0
  }
290
0
291
0
  // dotty
292
0
  
if (0
S.TryFindProgram("dotty", ViewerPath)0
) {
293
0
    std::vector<const char *> args;
294
0
    args.push_back(ViewerPath.c_str());
295
0
    args.push_back(Filename.c_str());
296
0
    args.push_back(nullptr);
297
0
298
0
// Dotty spawns another app and doesn't wait until it returns
299
#ifdef LLVM_ON_WIN32
300
    wait = false;
301
#endif
302
    errs() << "Running 'dotty' program... ";
303
0
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
304
0
  }
305
0
306
0
  errs() << "Error: Couldn't find a usable graph viewer program:\n";
307
0
  errs() << S.LogBuffer << "\n";
308
0
  return true;
309
0
}