Skip to content

Commit d3438a1

Browse files
author
Daniel Kroening
committed
added source_locationt::full_path()
1 parent 70b98fe commit d3438a1

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

src/goto-analyzer/show_on_source.cpp

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*******************************************************************\
2+
3+
Module: goto-analyzer
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "show_on_source.h"
10+
11+
#include <util/file_util.h>
12+
#include <util/message.h>
13+
#include <util/unicode.h>
14+
15+
#include <analyses/ai.h>
16+
17+
#include <fstream>
18+
19+
/// get the name of the file referred to at a location loc,
20+
/// if any
21+
static optionalt<std::string>
22+
show_location(const ai_baset &ai, ai_baset::locationt loc)
23+
{
24+
const auto abstract_state = ai.abstract_state_before(loc);
25+
if(abstract_state->is_top())
26+
return {};
27+
28+
if(loc->source_location.get_line().empty())
29+
return {};
30+
31+
return loc->source_location.full_path();
32+
}
33+
34+
/// get the source files with non-top abstract states
35+
static std::set<std::string>
36+
get_source_files(const goto_modelt &goto_model, const ai_baset &ai)
37+
{
38+
std::set<std::string> files;
39+
40+
for(const auto &f : goto_model.goto_functions.function_map)
41+
{
42+
forall_goto_program_instructions(i_it, f.second.body)
43+
{
44+
const auto file = show_location(ai, i_it);
45+
if(file.has_value())
46+
files.insert(file.value());
47+
}
48+
}
49+
50+
return files;
51+
}
52+
53+
/// print a string with indent to match given sample line
54+
static void print_with_indent(
55+
const std::string &src,
56+
const std::string &indent_line,
57+
std::ostream &out)
58+
{
59+
const std::size_t p = indent_line.find_first_not_of(" \t");
60+
const std::string indent =
61+
p == std::string::npos ? std::string("") : std::string(indent_line, 0, p);
62+
std::istringstream in(src);
63+
std::string src_line;
64+
while(std::getline(in, src_line))
65+
out << indent << src_line << '\n';
66+
}
67+
68+
/// output source code annotated with abstract states for given file
69+
void show_on_source(
70+
const std::string &source_file,
71+
const goto_modelt &goto_model,
72+
const ai_baset &ai,
73+
message_handlert &message_handler)
74+
{
75+
#ifdef _MSC_VER
76+
std::ifstream in(widen(source_file));
77+
#else
78+
std::ifstream in(source_file);
79+
#endif
80+
81+
messaget message(message_handler);
82+
83+
if(!in)
84+
{
85+
message.warning() << "Failed to open `" << source_file << "'"
86+
<< messaget::eom;
87+
return;
88+
}
89+
90+
std::map<std::size_t, ai_baset::locationt> line_map;
91+
92+
// Collect line numbers with non-top abstract states.
93+
// We pick the _first_ state for each line.
94+
for(const auto &f : goto_model.goto_functions.function_map)
95+
{
96+
forall_goto_program_instructions(i_it, f.second.body)
97+
{
98+
const auto file = show_location(ai, i_it);
99+
if(file.has_value() && file.value() == source_file)
100+
{
101+
const std::size_t line_no =
102+
stoull(id2string(i_it->source_location.get_line()));
103+
if(line_map.find(line_no) == line_map.end())
104+
line_map[line_no] = i_it;
105+
}
106+
}
107+
}
108+
109+
// now print file to message handler
110+
const namespacet ns(goto_model.symbol_table);
111+
112+
std::string line;
113+
for(std::size_t line_no = 1; std::getline(in, line); line_no++)
114+
{
115+
const auto map_it = line_map.find(line_no);
116+
if(map_it != line_map.end())
117+
{
118+
auto abstract_state = ai.abstract_state_before(map_it->second);
119+
std::ostringstream state_str;
120+
abstract_state->output(state_str, ai, ns);
121+
if(!state_str.str().empty())
122+
{
123+
message.result() << messaget::blue;
124+
print_with_indent(state_str.str(), line, message.result());
125+
message.result() << messaget::reset;
126+
}
127+
}
128+
129+
message.result() << line << messaget::eom;
130+
}
131+
}
132+
133+
/// output source code annotated with abstract states
134+
void show_on_source(
135+
const goto_modelt &goto_model,
136+
const ai_baset &ai,
137+
message_handlert &message_handler)
138+
{
139+
// first gather the source files that have something to show
140+
const auto source_files = get_source_files(goto_model, ai);
141+
142+
// now show file-by-file
143+
for(const auto &source_file : source_files)
144+
show_on_source(source_file, goto_model, ai, message_handler);
145+
}

src/util/source_location.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ void source_locationt::merge(const source_locationt &from)
7171
}
7272
}
7373

74+
/// Get a path to the file, including working directory.
75+
/// \return Full path unless the file name is empty or refers
76+
/// to a built-in, in which case {} is returned.
77+
optionalt<std::string> source_locationt::full_path() const
78+
{
79+
const auto file = id2string(get_file());
80+
81+
if(file.empty() || is_built_in(file))
82+
return {};
83+
84+
return concat_dir_file(id2string(get_working_directory()), file);
85+
}
86+
7487
std::ostream &operator << (
7588
std::ostream &out,
7689
const source_locationt &source_location)

src/util/source_location.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212

1313
#include "invariant.h"
1414
#include "irep.h"
15+
#include "optional.h"
1516
#include "prefix.h"
1617

1718
#include <string>
@@ -185,6 +186,8 @@ class source_locationt:public irept
185186
return static_cast<const source_locationt &>(get_nil_irep());
186187
}
187188

189+
optionalt<std::string> full_path() const;
190+
188191
protected:
189192
std::string as_string(bool print_cwd) const;
190193
};

0 commit comments

Comments
 (0)