blob: f2865eba9ae407cf364c8da9d4304107f5308bd2 [file] [log] [blame]
// Copyright (C) 2020-2024 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#ifndef RUST_CANONICAL_PATH
#define RUST_CANONICAL_PATH
#include "rust-system.h"
#include "rust-mapping-common.h"
namespace Rust {
namespace Resolver {
// https://doc.rust-lang.org/reference/paths.html#canonical-paths
//
// struct X - path X
// impl X { fn test - path X::test }
//
// struct X<T> - path X
//
// impl X<T> { fn test - path X::test}
// impl X<i32> { fn test - path X<i32>::test }
// impl X<f32> { fn test - path X<f32>::test }
//
// pub trait Trait { // ::a::Trait
// fn f(&self); // ::a::Trait::f
// }
//
// impl Trait for Struct {
// fn f(&self) {} // <::a::Struct as ::a::Trait>::f
// }
class CanonicalPath
{
public:
CanonicalPath (const CanonicalPath &other) : segs (other.segs) {}
CanonicalPath &operator= (const CanonicalPath &other)
{
segs = other.segs;
return *this;
}
static CanonicalPath new_seg (NodeId id, const std::string &path)
{
rust_assert (!path.empty ());
return CanonicalPath ({std::pair<NodeId, std::string> (id, path)},
UNKNOWN_CRATENUM);
}
static CanonicalPath
trait_impl_projection_seg (NodeId id, const CanonicalPath &trait_seg,
const CanonicalPath &impl_type_seg)
{
return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + " as "
+ trait_seg.get () + ">");
}
static CanonicalPath inherent_impl_seg (NodeId id,
const CanonicalPath &impl_type_seg)
{
return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + ">");
}
std::string get () const
{
std::string buf;
for (size_t i = 0; i < segs.size (); i++)
{
bool have_more = (i + 1) < segs.size ();
const std::string &seg = segs.at (i).second;
buf += seg + (have_more ? "::" : "");
}
return buf;
}
static CanonicalPath get_big_self (NodeId id)
{
return CanonicalPath::new_seg (id, "Self");
}
static CanonicalPath create_empty ()
{
return CanonicalPath ({}, UNKNOWN_CRATENUM);
}
bool is_empty () const { return segs.size () == 0; }
CanonicalPath append (const CanonicalPath &other) const
{
rust_assert (!other.is_empty ());
if (is_empty ())
return CanonicalPath (other.segs, crate_num);
std::vector<std::pair<NodeId, std::string>> copy (segs);
for (auto &s : other.segs)
copy.push_back (s);
return CanonicalPath (copy, crate_num);
}
// if we have the path A::B::C this will give a callback for each segment
// including the prefix, example:
//
// path:
// A::B::C
//
// iterate:
// A
// A::B
// A::B::C
void iterate (std::function<bool (const CanonicalPath &)> cb) const
{
std::vector<std::pair<NodeId, std::string>> buf;
for (auto &seg : segs)
{
buf.push_back (seg);
if (!cb (CanonicalPath (buf, crate_num)))
return;
}
}
// if we have the path A::B::C this will give a callback for each segment
// example:
//
// path:
// A::B::C
//
// iterate:
// A
// B
// C
void iterate_segs (std::function<bool (const CanonicalPath &)> cb) const
{
for (auto &seg : segs)
{
std::vector<std::pair<NodeId, std::string>> buf;
buf.push_back ({seg.first, seg.second});
if (!cb (CanonicalPath (buf, crate_num)))
return;
}
}
size_t size () const { return segs.size (); }
NodeId get_node_id () const
{
rust_assert (!segs.empty ());
return segs.back ().first;
}
const std::pair<NodeId, std::string> &get_seg_at (size_t index) const
{
rust_assert (index < size ());
return segs.at (index);
}
bool is_equal (const CanonicalPath &b) const
{
return get ().compare (b.get ()) == 0;
}
void set_crate_num (CrateNum n) { crate_num = n; }
CrateNum get_crate_num () const
{
rust_assert (crate_num != UNKNOWN_CRATENUM);
return crate_num;
}
bool operator== (const CanonicalPath &b) const { return is_equal (b); }
bool operator< (const CanonicalPath &b) const { return get () < b.get (); }
private:
explicit CanonicalPath (std::vector<std::pair<NodeId, std::string>> path,
CrateNum crate_num)
: segs (path), crate_num (crate_num)
{}
std::vector<std::pair<NodeId, std::string>> segs;
CrateNum crate_num;
};
} // namespace Resolver
} // namespace Rust
#endif // RUST_CANONICAL_PATH