types. Example of built-in types are char, int, unsigned int,
etc.
+ .. _suppr_source_location_not_in_label:
+
+* ``source_location_not_in``
+
+ Usage:
+
+ ``source_location_not_in`` ``=`` <``list-of-file-paths``>
+
+ Suppresses change reports involving a type which is defined in a file
+ which path is *NOT* listed in the value ``list-of-file-paths``. Note
+ that the value is a comma-separated list of file paths e.g, this
+ property ::
+
+ source_location_not_in = libabigail/abg-ir.h, libabigail/abg-dwarf-reader.h
+
+ suppresses change reports about all the types that are *NOT* defined
+ in header files whose path end up with the strings
+ libabigail/abg-ir.h or libabigail/abg-dwarf-reader.h.
+
+ .. _suppr_source_location_not_regexp_label:
+
+* ``source_location_not_regexp``
+
+ Usage:
+
+ ``source_location_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
+
+ Suppresses change reports involving a type which is defined in a file
+ which path does *NOT* match the :ref:`regular expression
+ <suppr_regexp_label>` provided as value of the property. E.g, this
+ property ::
+
+ source_location_not_regexp = libabigail/abg-.*\\.h
+
+ suppresses change reports involving all the types that are *NOT*
+ defined in header files whose path match the regular expression
+ provided a value of the property.
+
.. _suppr_has_data_member_inserted_at_label:
* ``has_data_member_inserted_at``
insertion_ranges&
get_data_member_insertion_ranges();
+ const vector<string>&
+ get_source_locations_to_keep() const;
+
+ void
+ set_source_locations_to_keep(const vector<string>&);
+
+ const string&
+ get_source_location_to_keep_regex_str() const;
+
+ void
+ set_source_location_to_keep_regex_str(const string&);
+
virtual bool
suppresses_diff(const diff* diff) const;
{
ABSTRACT_PROPERTY_VALUE = 0,
STRING_PROPERTY_VALUE = 1,
- TUPLE_PROPERTY_VALUE = 2,
+ LIST_PROPERTY_VALUE = 2,
+ TUPLE_PROPERTY_VALUE = 3,
};
private:
string_property_value_sptr
is_string_property_value(const property_value_sptr);
+class list_property_value;
+
+/// A convenience typedef for a shared_ptr to @ref
+/// list_property_value.
+typedef shared_ptr<list_property_value> list_property_value_sptr;
+
+/// Abstracts the value of a property representing a list of strings.
+///
+/// It's the right hand side of the construct which syntax looks like:
+///
+/// name = val1, val2, val3
+///
+/// where val1, val2 and val3 are strings.
+///
+/// So this class abstracts the set [val1, val2, val3].
+class list_property_value : public property_value
+{
+ struct priv;
+ typedef shared_ptr<priv> priv_sptr;
+
+ priv_sptr priv_;
+
+public:
+ list_property_value();
+ list_property_value(const vector<string>& values);
+
+ const vector<string>&
+ get_content() const;
+
+ void
+ set_content(const vector<string>&);
+
+ virtual const string&
+ as_string() const;
+}; // end class list_property_value
+
+list_property_value*
+is_list_property_value(const property_value*);
+
+list_property_value_sptr
+is_list_property_value(const property_value_sptr&);
+
class tuple_property_value;
/// Convenience typedef for a shared_ptr to a @ref
simple_property_sptr
is_simple_property(const property_sptr p);
+class list_property;
+
+/// A convenience typedef for a shared_ptr to a @ref list_property.
+typedef shared_ptr<list_property> list_property_sptr;
+
+/// A class representing a list property.
+///
+/// It abstracts a construct which syntax looks like:
+///
+/// name = val1, val2, val3
+///
+/// The value of a list property is a @ref list_property_value, i.e, a
+/// list of strings.
+class list_property : public property
+{
+ struct priv;
+ typedef shared_ptr<priv> priv_sptr;
+
+ priv_sptr priv_;
+
+public:
+ list_property();
+
+ list_property(const string& name,
+ const list_property_value_sptr& value);
+
+ const list_property_value_sptr&
+ get_value() const;
+
+ void
+ set_value(const list_property_value_sptr& value);
+
+ virtual ~list_property();
+}; // end class list_property
+
+list_property*
+is_list_property(const property* p);
+
+list_property_sptr
+is_list_property(const property_sptr p);
+
class tuple_property;
/// Convenience typedef for a shared_ptr of @ref tuple_property.
typedef shared_ptr<tuple_property> tuple_property_sptr;
/// The private data for @ref type_suppression.
class type_suppression::priv
{
- string type_name_regex_str_;
- mutable sptr_utils::regex_t_sptr type_name_regex_;
- string type_name_;
- bool consider_type_kind_;
- type_suppression::type_kind type_kind_;
- bool consider_reach_kind_;
- type_suppression::reach_kind reach_kind_;
- type_suppression::insertion_ranges insertion_ranges_;
+ string type_name_regex_str_;
+ mutable sptr_utils::regex_t_sptr type_name_regex_;
+ string type_name_;
+ bool consider_type_kind_;
+ type_suppression::type_kind type_kind_;
+ bool consider_reach_kind_;
+ type_suppression::reach_kind reach_kind_;
+ type_suppression::insertion_ranges insertion_ranges_;
+ vector<string> source_locations_to_keep_;
+ string source_location_to_keep_regex_str_;
+ mutable sptr_utils::regex_t_sptr source_location_to_keep_regex_;
priv();
set_type_name_regex(sptr_utils::regex_t_sptr r)
{type_name_regex_ = r;}
+ /// Getter for the source_location_to_keep_regex object.
+ ///
+ /// This function builds the regex if it's not yet built.
+ const sptr_utils::regex_t_sptr
+ get_source_location_to_keep_regex() const
+ {
+ if (!source_location_to_keep_regex_)
+ {
+ if (!source_location_to_keep_regex_str_.empty())
+ {
+ sptr_utils::regex_t_sptr r(new regex_t);
+ if (regcomp(r.get(),
+ source_location_to_keep_regex_str_.c_str(),
+ REG_EXTENDED) == 0)
+ source_location_to_keep_regex_ = r;
+ }
+ }
+ return source_location_to_keep_regex_;
+ }
+
+ /// Setter for the source_location_to_keep_regex object.
+ ///
+ /// @param r the new regex object.
+ void
+ set_source_location_to_keep_regex(sptr_utils::regex_t_sptr r)
+ {source_location_to_keep_regex_ = r;}
+
friend class type_suppression;
}; // class type_suppression::priv
type_suppression::get_data_member_insertion_ranges()
{return priv_->insertion_ranges_;}
+/// Getter for the array of source location paths of types that should
+/// *NOT* be suppressed.
+///
+/// @return the array of source locations of types that should *NOT*
+/// be supressed.
+const vector<string>&
+type_suppression::get_source_locations_to_keep() const
+{return priv_->source_locations_to_keep_;}
+
+/// Setter for the array of source location paths of types that should
+/// *NOT* be suppressed.
+///
+/// @param l the new array.
+void
+type_suppression::set_source_locations_to_keep(const vector<string>& l)
+{priv_->source_locations_to_keep_ = l;}
+
+/// Getter of the regular expression string that designates the source
+/// location paths of types that should not be suppressed.
+///
+/// @return the regular expression string.
+const string&
+type_suppression::get_source_location_to_keep_regex_str() const
+{return priv_->source_location_to_keep_regex_str_;}
+
+/// Setter of the regular expression string that designates the source
+/// location paths of types that should not be suppressed.
+///
+/// @param r the new regular expression.
+void
+type_suppression::set_source_location_to_keep_regex_str(const string& r)
+{priv_->source_location_to_keep_regex_str_ = r;}
+
/// Evaluate this suppression specification on a given diff node and
/// say if the diff node should be suppressed or not.
///
return false;
}
+ // Check if there is a source location related match.
+ if (decl_base_sptr d = get_type_declaration(type))
+ {
+ location loc = d->get_location();
+ if (loc)
+ {
+ translation_unit* tu = get_translation_unit(d);
+ if (tu)
+ {
+ string loc_path, loc_path_base;
+ unsigned loc_line = 0, loc_column = 0;
+ tu->get_loc_mgr().expand_location(loc, loc_path,
+ loc_line, loc_column);
+
+ if (sptr_utils::regex_t_sptr regexp =
+ priv_->get_source_location_to_keep_regex())
+ if (regexec(regexp.get(), loc_path.c_str(), 0, NULL, 0) == 0)
+ return false;
+
+ tools_utils::base_name(loc_path, loc_path_base);
+ for (vector<string>::const_iterator s =
+ get_source_locations_to_keep().begin();
+ s != get_source_locations_to_keep().end();
+ ++s)
+ {
+ if (tools_utils::string_ends_with(*s, loc_path)
+ || tools_utils::string_ends_with(*s, loc_path_base))
+ return false;
+ }
+ }
+ else
+ {
+ if (!get_source_locations_to_keep().empty()
+ || priv_->get_source_location_to_keep_regex())
+ // The user provided a "source_location_not_regexp" or
+ // a "source_location_not_in" property that was not
+ // triggered. This means the current type suppression
+ // doesn't suppress the type given.
+ return false;
+ }
+ }
+ else
+ {
+ if (!get_source_locations_to_keep().empty()
+ || priv_->get_source_location_to_keep_regex())
+ // The user provided a "source_location_not_regexp" or
+ // a "source_location_not_in" property that was not
+ // triggered. This means the current type suppression
+ // doesn't suppress the type given.
+ return false;
+ }
+ }
+ else
+ {
+ if (!get_source_locations_to_keep().empty()
+ || priv_->get_source_location_to_keep_regex())
+ // The user provided a "source_location_not_regexp" or
+ // a "source_location_not_in" property that was not
+ // triggered. This means the current type suppression
+ // doesn't suppress the type given.
+ return false;
+ }
+
return true;
}
? name_prop->get_value()->as_string()
: "";
+ ini::property_sptr srcloc_not_in_prop =
+ section.find_property("source_location_not_in");
+ vector<string> srcloc_not_in;
+ if (srcloc_not_in_prop)
+ {
+ if (ini::simple_property_sptr p = is_simple_property(srcloc_not_in_prop))
+ srcloc_not_in.push_back(p->get_value()->as_string());
+ else
+ {
+ ini::list_property_sptr list_property =
+ is_list_property(srcloc_not_in_prop);
+ if (list_property)
+ srcloc_not_in = list_property->get_value()->get_content();
+ }
+ }
+
+ ini::simple_property_sptr srcloc_not_regexp_prop =
+ is_simple_property(section.find_property("source_location_not_regexp"));
+ string srcloc_not_regexp_str;
+ if (srcloc_not_regexp_prop)
+ srcloc_not_regexp_str = srcloc_not_regexp_prop->get_value()->as_string();
+
bool consider_type_kind = false;
type_suppression::type_kind type_kind = type_suppression::UNKNOWN_TYPE_KIND;
if (ini::simple_property_sptr type_kind_prop =
// has_data_member_inserted_between = {0 , end};
// and not (for instance):
// has_data_member_inserted_between = {{0 , end}, {1, foo}}
+ //
+ // This means that the tuple_property_value contains just one
+ // value, which is a list_property that itself contains 2
+ // values.
type_suppression::insertion_range::boundary_sptr begin, end;
- if (prop->get_value()->get_value_items().size() == 2
- && is_string_property_value(prop->get_value()->get_value_items()[0])
- && is_string_property_value(prop->get_value()->get_value_items()[1]))
+ ini::tuple_property_value_sptr v = prop->get_value();
+ if (v
+ && v->get_value_items().size() == 1
+ && is_list_property_value(v->get_value_items()[0])
+ && is_list_property_value(v->get_value_items()[0])->get_content().size() == 2)
{
- string str = prop->get_value()->get_value_items()[0]->as_string();
+ ini::list_property_value_sptr val =
+ is_list_property_value(v->get_value_items()[0]);
+ assert(val);
+ string str = val->get_content()[0];
if (str == "end")
begin =
type_suppression::insertion_range::create_integer_boundary(-1);
else
return nil;
- str = prop->get_value()->get_value_items()[1]->as_string();
+ str = val->get_content()[1];
if (str == "end")
end =
type_suppression::insertion_range::create_integer_boundary(-1);
}
// Support has_data_members_inserted_between
+ // The syntax looks like:
+ //
+ // has_data_members_inserted_between = {{8, 24}, {32, 64}, {128, end}}
+ //
+ // So we expect a tuple property, with potentially several pairs (as
+ // part of the value); each pair designating a range. Note that
+ // each pair (range) is a list property value.
if (ini::tuple_property_sptr prop =
is_tuple_property(section.find_property
("has_data_members_inserted_between")))
ini::tuple_property_value_sptr tuple_value =
is_tuple_property_value(*i);
if (!tuple_value
- || tuple_value->get_value_items().size() != 2
- || !is_string_property_value(tuple_value->get_value_items()[0])
- || !is_string_property_value(tuple_value->get_value_items()[1]))
- is_well_formed = false;
+ || tuple_value->get_value_items().size() != 1
+ || !is_list_property_value(tuple_value->get_value_items()[0]))
+ {
+ is_well_formed = false;
+ break;
+ }
+ ini::list_property_value_sptr list_value =
+ is_list_property_value(tuple_value->get_value_items()[0]);
+ if (list_value->get_content().size() != 2)
+ {
+ is_well_formed = false;
+ break;
+ }
type_suppression::insertion_range::boundary_sptr begin, end;
- string str = tuple_value->get_value_items()[0]->as_string();
+ string str = list_value->get_content()[0];
if (str == "end")
begin =
type_suppression::insertion_range::create_integer_boundary(-1);
else
return nil;
- str = tuple_value->get_value_items()[1]->as_string();
+ str = list_value->get_content()[1];
if (str == "end")
end =
type_suppression::insertion_range::create_integer_boundary(-1);
if ((!name_regex_prop || name_regex_prop->get_value()->as_string().empty())
&& (!name_prop || name_prop->get_value()->as_string().empty())
- && !consider_type_kind)
+ && !consider_type_kind
+ && srcloc_not_regexp_str.empty()
+ && srcloc_not_in.empty())
return nil;
type_suppression_sptr suppr(new type_suppression(label_str,
if (!soname_regex_str.empty())
suppr->set_soname_regex_str(soname_regex_str);
+ if (!srcloc_not_in.empty())
+ suppr->set_source_locations_to_keep(srcloc_not_in);
+
+ if (!srcloc_not_regexp_str.empty())
+ suppr->set_source_location_to_keep_regex_str(srcloc_not_regexp_str);
+
return suppr;
}
/// the libabigail library.
#include <cassert>
+#include <cstdlib>
#include <utility>
#include <memory>
#include <fstream>
string_property_value::~string_property_value()
{}
-// </string_property stuff>
+// </string_property_value stuff>
+
+// <list_property_value stuff>
+struct list_property_value::priv
+{
+ vector<string> values_;
+ string representation_;
+
+ priv()
+ {}
+
+ priv(const vector<string>& vals)
+ : values_(vals)
+ {}
+}; // end struct list_property_value::priv
+
+/// Default constructor of the @ref list_property_value type.
+list_property_value::list_property_value()
+ : property_value(property_value::LIST_PROPERTY_VALUE),
+ priv_(new priv)
+{}
+
+/// Copy constructor of the @ref list_property_value type.
+///
+/// @param values the instance of @ref list_property_value to copy from.
+list_property_value::list_property_value(const vector<string>& values)
+ : property_value(property_value::LIST_PROPERTY_VALUE),
+ priv_(new priv(values))
+{
+}
+
+/// Getter of the content of the @ref list_property_value.
+///
+/// The content of the @ref list_property_value is a vector of
+/// strings.
+///
+/// @return the vector of strings contained in the @ref
+/// list_property_value.
+const vector<string>&
+list_property_value::get_content() const
+{return priv_->values_;}
+
+/// Setter of the content of the @ref list_property_value.
+///
+/// @param values the new content, which is a vector of strings.
+void
+list_property_value::set_content(const vector<string>& values)
+{
+ priv_->values_ = values;
+ priv_->representation_.clear();
+}
+
+/// Return a string representation of the @list_property_value.
+///
+/// @return the string representation.
+const string&
+list_property_value::as_string() const
+{
+ if (priv_->representation_.empty())
+ {
+ for (vector<string>::const_iterator i = priv_->values_.begin();
+ i != priv_->values_.end();
+ ++i)
+ {
+ if (i != priv_->values_.begin())
+ priv_->representation_ += ",";
+ priv_->representation_ += *i;
+ }
+ }
+ return priv_->representation_;
+}
+
+/// Test if an instance of @property_value is a @ref list_property_value.
+///
+/// @param v the property_value to consider.
+///
+/// @return the @ref property_value converted into a @ref
+/// list_property_value if the @p v is a @ref list_property_value, nil
+/// otherwise.
+list_property_value*
+is_list_property_value(const property_value* v)
+{return dynamic_cast<list_property_value*>(const_cast<property_value*>(v));}
+
+/// Test if an instance of @property_value is a @ref list_property_value.
+///
+/// @param v the property_value to consider.
+///
+/// @return the @ref property_value converted into a @ref
+/// list_property_value if the @p v is a @ref list_property_value, nil
+/// otherwise.
+list_property_value_sptr
+is_list_property_value(const property_value_sptr&v)
+{return dynamic_pointer_cast<list_property_value>(v);}
+
+// </list_property_value stuff>
// <tuple_property_value>
// </simple_property stuff>
+// <list_property stuff>
+struct list_property::priv
+{
+ list_property_value_sptr value_;
+
+ priv()
+ {}
+
+ priv(const list_property_value_sptr value)
+ : value_(value)
+ {}
+}; //end struct list_property
+
+/// Default constructor for @ref list_property.
+list_property::list_property()
+ : priv_(new priv)
+{}
+
+/// Constructor for @ref list_property.
+///
+/// @param name the name of the property.
+///
+/// @param value the value of the property.
+list_property::list_property(const string& name,
+ const list_property_value_sptr& value)
+ : property(name),
+ priv_(new priv(value))
+{}
+
+/// Getter for the value of the @ref list_property_value
+const list_property_value_sptr&
+list_property::get_value() const
+{return priv_->value_;}
+
+/// Setter for the value of the @ref list_property.
+///
+/// @param value the new value.
+void
+list_property::set_value(const list_property_value_sptr& value)
+{priv_->value_ = value;}
+
+/// Destructor of the @ref list_property type.
+list_property::~list_property()
+{}
+
+/// Test if an instance of a @ref property is actually an instance of
+/// @ref list_property.
+///
+/// @param p the @ref property to test.
+///
+/// @return the @p p converted into a @ref list_property if it's of
+/// type @ref list_property, or nil otherwise.
+list_property*
+is_list_property(const property* p)
+{return dynamic_cast<list_property*>(const_cast<property*>(p));}
+
+/// Test if an instance of a @ref property is actually an instance of
+/// @ref list_property.
+///
+/// @param p the @ref property to test.
+///
+/// @return the @p p converted into a @ref list_property if it's of
+/// type @ref list_property, or nil otherwise.
+list_property_sptr
+is_list_property(const property_sptr p)
+{return dynamic_pointer_cast<list_property>(p);}
+// </list_property stuff>
+
// <tuple_property stuff>
struct tuple_property::priv
{
unsigned cur_line_;
/// The current column on the current line.
unsigned cur_column_;
+ vector<char> buf_;
// Forbid this;
read_context();
public:
+ /// The constructor of @ref read_context.
+ ///
/// @param in the input stream to parse from.
read_context(istream& in)
: in_(in),
cur_column_(0)
{}
- /// Read the next character from the input stream.
+ /// @return the character that is going to be read by the next
+ /// invocation of read_next_char().
///
- /// This method updates the current line/column number after looking
- /// at the actual char that got read. It also handle escaped
- /// characters.
+ /// Note that this function doesn't alter the input stream.
///
- /// @param c output parameter. This is set by this function to the
- /// character that was read. It's set iff the function returned
- /// true.
+ /// Also note that this function handles escaping using the '\'
+ /// (backslash) character.
///
- /// @return true if the reading went well and if the input stream is
- /// in a non-erratic state.
+ /// @return peeked character.
+ char
+ peek()
+ {
+ if (!buf_.empty())
+ return buf_.back();
+
+ char c = in_.peek();
+ if (handle_escape(c, /*peek=*/true))
+ put_back(c);
+ return c;
+ }
+
+ /// Get the next character of the input stream.
+ ///
+ /// This function knows how to handles escaped characters from the
+ /// input stream.
+ ///
+ /// @param do_handle_escape if yes, this function handles escaped
+ /// characters from the input stream.
+ ///
+ /// @return the next character of the input stream.
+ char
+ get(bool do_handle_escape = true)
+ {
+ char result = 0;
+ if (!buf_.empty())
+ {
+ result = buf_.back();
+ buf_.pop_back();
+ }
+ else
+ {
+ result = in_.get();
+ if (do_handle_escape)
+ handle_escape(result);
+ }
+ return result;
+ }
+
+ /// Put a character that was read from the input stream, back into
+ /// that input stream, so that a subsequent call to
+ /// read_context::get() returns that same character.
+ ///
+ /// @param c the character to put back into the stream.
+ void
+ put_back(char c)
+ {buf_.push_back(c);}
+
+ /// Test if the status of the input stream is good.
+ ///
+ /// @return true iff the status of the input stream is good.
bool
- read_next_char(char& c)
+ good() const
+ {
+ if (!buf_.empty())
+ return true;
+ return in_.good();
+ }
+
+ /// Tests if the input stream has reached end of file.
+ ///
+ /// @return true iff the input stream has reached end of file.
+ bool
+ eof() const
{
- char b = in_.get();
- if (!in_.good())
+ if (!buf_.empty())
return false;
+ return in_.eof();
+ }
- bool escaping = false;
- if (b == '\\')
- escaping = true;
+ /// Handles the escaping of a character.
+ ///
+ /// This function must be called whenever the low level character
+ /// reading function encountered a backslash character ('\'). In
+ /// that case, this function reads the subsequent characters from
+ /// the input stream, sees if it needs to espace those and then
+ /// handles the escaping if need be. Otherwise, it does nothing.
+ ///
+ /// This is a subroutine of the read_context::get() and
+ /// read_context::peek() functions.
+ ///
+ /// @param peek if true, it means this function was called after the
+ /// caller issued a read_context::peek() call, rather than a
+ /// read_context::get() call.
+ ///
+ /// @return true if an escaping took place.
+ bool
+ handle_escape(char& c, bool peek = false)
+ {
+ bool escaped = false;
+ char b = c;
- // Handle escape
- if (escaping)
+ if (b == '\\')
{
- b = in_.get();
- if (!in_.good())
- return false;
+ escaped = true;
+ b = get(/*escape=*/false);
+ if (!good())
+ return escaped;
+ if (peek)
+ {
+ assert(b == c);
+ b = get(/*escape=*/false);
+ if (!good())
+ return escaped;
+ }
switch (b)
{
// character and this end-of-line character on the floor
// just like if they never existed.
++cur_column_;
- b = in_.get();
- if (!in_.good())
- return false;
+ b = get(/*escape=*/false);
+ if (!good())
+ return escaped;
+ c = b;
break;
case '\\':
case ';':
c = b;
break;
}
- ++cur_column_;
}
else
c = b;
+ return escaped;
+ }
+
+ /// Read the next character from the input stream.
+ ///
+ /// This method updates the current line/column number after looking
+ /// at the actual char that got read. Note that escaped characters
+ /// are handled transparently at this point.
+ ///
+ /// @param c output parameter. This is set by this function to the
+ /// character that was read. It's set iff the function returned
+ /// true.
+ ///
+ /// @return true if the reading went well and if the input stream is
+ /// in a non-erratic state.
+ bool
+ read_next_char(char& c)
+ {
+ char b = get();
+ if (!good())
+ return false;
+
+ c = b;
+
if (cur_line_ == 0)
cur_line_ = 1;
if (c == '\n')
break;
- return (c == '\n' || in_.eof());
+ return (c == '\n' || eof());
}
/// If the current character is a white space, skip it and all the
bool
skip_white_spaces()
{
- for (char c = in_.peek(); in_.good(); c = in_.peek())
+ for (char c = peek(); good(); c = peek())
if (char_is_white_space(c))
assert(read_next_char(c));
else
break;
- return in_.good() || in_.eof();
+ return good() || eof();
}
/// If the current character is the beginning of a comment, skip
bool
skip_comments()
{
- for (char c = in_.peek(); in_.good(); c = in_.peek())
+ for (char c = peek(); good(); c = peek())
if (char_is_comment_start(c))
skip_line();
else
break;
- return in_.good() || in_.eof();
+ return good() || eof();
}
/// If the current character is either the beginning of a comment or
skip_white_spaces_or_comments()
{
int b = 0;
- while (in_.good())
+ while (good())
{
- b = in_.peek();
+ b = peek();
if (char_is_white_space(b))
skip_white_spaces();
else if (char_is_comment_start(b))
else
break;
}
- return in_.good() || in_.eof();
+ return good() || eof();
}
/// Read a property name.
bool
read_property_name(string& name)
{
- char c = in_.peek();
- if (!in_.good() || !char_is_property_name_char(c))
+ char c = peek();
+ if (!good() || !char_is_property_name_char(c))
return false;
assert(read_next_char(c));
name += c;
- for (c = in_.peek(); in_.good(); c = in_.peek())
+ for (c = peek(); good(); c = peek())
{
if (!char_is_property_name_char(c))
break;
bool
read_function_name(string& name)
{
- char c = in_.peek();
- if (!in_.good() || !char_is_function_name_char(c))
+ char c = peek();
+ if (!good() || !char_is_function_name_char(c))
return false;
assert(read_next_char(c));
name += c;
- for (c = in_.peek(); in_.good(); c = in_.peek())
+ for (c = peek(); good(); c = peek())
{
if (!char_is_function_name_char(c))
break;
bool
read_function_argument(string& argument)
{
- char c = in_.peek();
- if (!in_.good() || !char_is_function_argument_char(c))
+ char c = peek();
+ if (!good() || !char_is_function_argument_char(c))
return false;
assert(read_next_char(c));
argument += c;
- for (c = in_.peek(); in_.good(); c = in_.peek())
+ for (c = peek(); good(); c = peek())
{
if (!char_is_function_argument_char(c))
break;
bool
read_function_call_expr(function_call_expr_sptr& expr)
{
- if (!in_.good())
+ if (!good())
return false;
skip_white_spaces_or_comments();
- if (!in_.good())
+ if (!good())
return false;
string name;
skip_white_spaces_or_comments();
- int b = in_.peek();
- if (!in_.good() || b != '(')
+ int b = peek();
+ if (!good() || b != '(')
return false;
char c = 0;
assert(c == '(');
skip_white_spaces_or_comments();
- if (!in_.good())
+ if (!good())
return false;
// Read function call arguments.
vector<string> arguments;
for (;;)
{
- if (in_.peek() == ')')
+ if (peek() == ')')
break;
string arg;
return true;
skip_white_spaces_or_comments();
- if (!in_.good())
+ if (!good())
return false;
- if (in_.peek() == ',')
+ if (peek() == ',')
{
c = 0;
assert(read_next_char(c) && c == ',');
skip_white_spaces_or_comments();
- if (!in_.good())
+ if (!good())
return false;
}
{
property_value_sptr nil, result;
- int b = in_.peek();
- if (!in_.good())
+ int b = peek();
+ if (!good())
return nil;
if (b == '{')
return t;
return nil;
}
- return read_string_property_value();
+
+ list_property_value_sptr list = read_list_property_value();
+ if (list->get_content().size() == 1)
+ result.reset(new string_property_value(list->get_content()[0]));
+ else
+ result = list;
+
+ return result;
+ }
+
+ /// Reads a string from the input stream.
+ ///
+ /// A string is just a contiguous set of characters that test
+ /// positive when passed to
+ /// read_context::char_is_property_name_char().
+ ///
+ /// @return the string read.
+ string
+ read_string()
+ {
+ int b = peek();
+ if (!good())
+ return "";
+
+ if (char_is_delimiter(b, /*include_white_space=*/false))
+ // Empty property value. This is accepted.
+ return "";
+
+ string v;
+ for (b = peek(); good();b = peek())
+ {
+ if (!char_is_property_value_char(b))
+ break;
+ char c = 0;
+ assert(read_next_char(c));
+ v += c;
+ }
+ string result = remove_trailing_white_spaces(v);
+ return result;
}
/// Read a string property value.
read_string_property_value()
{
string_property_value_sptr nil, result;
- int b = in_.peek();
- if (!in_.good())
+ if (!good())
return nil;
- if (char_is_delimiter(b, /*include_white_space=*/false))
- {
- // Empty property value. This is accepted.
- result.reset(new string_property_value);
- return result;
- }
+ string value = read_string();
+ result.reset(new string_property_value(value));
+ return result;
+ }
- string v;
- char c = 0;
- assert(read_next_char(c));
- v += c;
+ /// Read a @ref list_property_value.
+ ///
+ /// @return the instance of @ref list_property_value read, or nil if
+ /// none was read.
+ list_property_value_sptr
+ read_list_property_value()
+ {
+ list_property_value_sptr nil, result;
+ string str;
+ vector<string> content;
- for (b = in_.peek(); in_.good();b = in_.peek())
+ for (;;)
{
- if (!char_is_property_value_char(b))
+ str = read_string();
+ if (str.empty())
break;
- assert(read_next_char(c));
- v += c;
+ content.push_back(str);
+
+ skip_white_spaces();
+
+ int b = peek();
+ if (!good() || b != ',')
+ break;
+ skip_white_spaces();
+
+ char c = 0;
+ read_next_char(c);
+ assert(c == ',');
}
- string value = remove_trailing_white_spaces(v);
- result.reset(new string_property_value(value));
+
+ if (!content.empty())
+ result.reset(new list_property_value(content));
+
return result;
}
read_tuple_property_value()
{
tuple_property_value_sptr nil, result;
- int b = in_.peek();
- if (!in_.good())
+ int b = peek();
+ if (!good())
return nil;
if (b != '{')
property_value_sptr value;
vector<property_value_sptr> values;
- while (in_.good() && in_.peek() != '}')
+ while (good() && peek() != '}')
{
skip_white_spaces();
if ((value = read_property_value()))
values.push_back(value);
skip_white_spaces();
- if (in_.good() && in_.peek() == ',')
+ if (good() && peek() == ',')
{
c = 0;
read_next_char(c);
}
}
- b = in_.peek();
+ b = peek();
if (b != '}')
return nil;
+
c = 0;
read_next_char(c);
bool
read_section_name(string& name)
{
- int b = in_.peek();
- if (!in_.good() || !char_is_section_name_char(b))
+ int b = peek();
+ if (!good() || !char_is_section_name_char(b))
return false;
char c = 0;
assert(read_next_char(c) || char_is_section_name_char(b));
name += c;
- for (b = in_.peek(); in_.good(); b = in_.peek())
+ for (b = peek(); good(); b = peek())
{
if (!char_is_section_name_char(b))
break;
return nil;
skip_white_spaces();
- if (!in_.good())
+ if (!good())
return nil;
char c = 0;
return nil;
skip_white_spaces();
- if (!in_.good())
+ if (!good())
return nil;
property_value_sptr value = read_property_value();
property_sptr result;
if (tuple_property_value_sptr tv = is_tuple_property_value(value))
result.reset(new tuple_property(name, tv));
+ else if (list_property_value_sptr lv = is_list_property_value(value))
+ result.reset(new list_property(name, lv));
+ else if (string_property_value_sptr sv = is_string_property_value(value))
+ result.reset(new simple_property(name, sv));
else
- {
- string_property_value_sptr sv = is_string_property_value(value);
- assert(sv);
- result.reset(new simple_property(name, sv));
- }
+ // This new kind of property is not yet supported!
+ std::abort();
return result;
}
{
config::section_sptr nil;
- int b = in_.peek();
- if (!in_.good())
+ int b = peek();
+ if (!good())
return nil;
char c = 0;
string result;
if (simple_property_sptr simple_prop = is_simple_property(prop))
result = simple_prop->get_value()->as_string();
- else
- {
- tuple_property_sptr tuple_prop = is_tuple_property(prop);
- assert(tuple_prop);
+ else if (list_property_sptr list_prop = is_list_property(prop))
+ result = list_prop->get_value()->as_string();
+ else if (tuple_property_sptr tuple_prop = is_tuple_property(prop))
result = tuple_prop->get_value()->as_string();
- }
+ else
+ // This new kind of property is not yet supported!
+ abort();
return result;
}
test-diff-suppr/test25-typedef-report-1.txt\
test-diff-suppr/test25-typedef-v0.c \
test-diff-suppr/test25-typedef-v1.c \
+test-diff-suppr/libtest26-loc-suppr-v0.so \
+test-diff-suppr/libtest26-loc-suppr-v1.so \
+test-diff-suppr/test26-loc-suppr-0.suppr \
+test-diff-suppr/test26-loc-suppr-1.suppr \
+test-diff-suppr/test26-loc-suppr-2.suppr \
+test-diff-suppr/test26-loc-suppr-report-0.txt \
+test-diff-suppr/test26-loc-suppr-report-1.txt \
+test-diff-suppr/test26-loc-suppr-report-2.txt \
+test-diff-suppr/test26-loc-suppr-report-3.txt \
+test-diff-suppr/test26-loc-suppr-v0.cc \
+test-diff-suppr/test26-loc-suppr-v1.cc \
+test-diff-suppr/test26-loc-suppr.h \
\
test-lookup-syms/test0.cc \
test-lookup-syms/test0.o \
--- /dev/null
+[suppress_type]
+ source_location_not_in = test26-loc-suppr.h
--- /dev/null
+[suppress_type]
+ source_location_not_regexp = test26-loc.*\\.h
--- /dev/null
+[suppress_type]
+ source_location_not_regexp = test26-loc.*\\.cc
--- /dev/null
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+ [C]'function void func0(S*)' has some indirect sub-type changes:
+ parameter 1 of type 'S*' has sub-type changes:
+ in pointed to type 'struct S':
+ type size changed from 32 to 64 bits
+ 1 data member insertion:
+ 'char S::added_member', at offset 32 (in bits)
+
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
--- /dev/null
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+ [C]'function void func0(S*)' has some indirect sub-type changes:
+ parameter 1 of type 'S*' has sub-type changes:
+ in pointed to type 'struct S':
+ type size changed from 32 to 64 bits
+ 1 data member insertion:
+ 'char S::added_member', at offset 32 (in bits)
+
+
--- /dev/null
+// Compile this with:
+// g++ -g -Wall -shared -o libtest26-loc-suppr-v0.so test26-loc-suppr-v0.cc
+//
+
+#include "test26-loc-suppr.h"
+
+struct S
+{
+ int m0;
+};
+
+void
+func0(S*)
+{
+}
--- /dev/null
+// Compile this with:
+// g++ -g -Wall -shared -o libtest26-loc-suppr-v1.so test26-loc-suppr-v1.cc
+//
+
+#include "test26-loc-suppr.h"
+
+struct S
+{
+ int m0;
+ char added_member;
+};
+
+void
+func0(S*)
+{
+}
--- /dev/null
+struct S;
+
+void func0(S*);
"data/test-diff-suppr/test25-typedef-report-1.txt",
"output/test-diff-suppr/test25-typedef-report-1.txt"
},
+ {
+ "data/test-diff-suppr/libtest26-loc-suppr-v0.so",
+ "data/test-diff-suppr/libtest26-loc-suppr-v1.so",
+ "",
+ "--no-redundant",
+ "data/test-diff-suppr/test26-loc-suppr-report-0.txt",
+ "output/test-diff-suppr/test26-loc-suppr-report-0.txt"
+ },
+ {
+ "data/test-diff-suppr/libtest26-loc-suppr-v0.so",
+ "data/test-diff-suppr/libtest26-loc-suppr-v1.so",
+ "data/test-diff-suppr/test26-loc-suppr-0.suppr",
+ "--no-redundant",
+ "data/test-diff-suppr/test26-loc-suppr-report-1.txt",
+ "output/test-diff-suppr/test26-loc-suppr-report-1.txt"
+ },
+ {
+ "data/test-diff-suppr/libtest26-loc-suppr-v0.so",
+ "data/test-diff-suppr/libtest26-loc-suppr-v1.so",
+ "data/test-diff-suppr/test26-loc-suppr-1.suppr",
+ "--no-redundant",
+ "data/test-diff-suppr/test26-loc-suppr-report-2.txt",
+ "output/test-diff-suppr/test26-loc-suppr-report-2.txt"
+ },
+ {
+ "data/test-diff-suppr/libtest26-loc-suppr-v0.so",
+ "data/test-diff-suppr/libtest26-loc-suppr-v1.so",
+ "data/test-diff-suppr/test26-loc-suppr-2.suppr",
+ "--no-redundant",
+ "data/test-diff-suppr/test26-loc-suppr-report-3.txt",
+ "output/test-diff-suppr/test26-loc-suppr-report-3.txt"
+ },
// This should be the last entry
{NULL, NULL, NULL, NULL, NULL, NULL}
};