+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum PpSourceMode {
+ PpmNormal,
+ PpmEveryBodyLoops,
+ PpmExpanded,
+ PpmIdentified,
+ PpmExpandedIdentified,
+ PpmExpandedHygiene,
+ PpmTyped,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum PpMode {
+ PpmSource(PpSourceMode),
+ PpmHir(PpSourceMode),
+ PpmHirTree(PpSourceMode),
+ PpmMir,
+ PpmMirCFG,
+}
+
+impl PpMode {
+ pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool {
+ use PpMode::*;
+ use PpSourceMode::*;
+ match *self {
+ PpmSource(PpmNormal) |
+ PpmSource(PpmEveryBodyLoops) |
+ PpmSource(PpmIdentified) => opt_uii.is_some(),
+
+ PpmSource(PpmExpanded) |
+ PpmSource(PpmExpandedIdentified) |
+ PpmSource(PpmExpandedHygiene) |
+ PpmHir(_) |
+ PpmHirTree(_) |
+ PpmMir |
+ PpmMirCFG => true,
+ PpmSource(PpmTyped) => panic!("invalid state"),
+ }
+ }
+
+ pub fn needs_analysis(&self) -> bool {
+ use PpMode::*;
+ match *self {
+ PpmMir | PpmMirCFG => true,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum UserIdentifiedItem {
+ ItemViaNode(ast::NodeId),
+ ItemViaPath(Vec<String>),
+}
+
+impl FromStr for UserIdentifiedItem {
+ type Err = ();
+ fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
+ use UserIdentifiedItem::*;
+ Ok(s.parse()
+ .map(ast::NodeId::from_u32)
+ .map(ItemViaNode)
+ .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
+ }
+}
+
+pub enum NodesMatchingUII<'a> {
+ NodesMatchingDirect(std::option::IntoIter<ast::NodeId>),
+ NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
+}
+
+impl<'a> Iterator for NodesMatchingUII<'a> {
+ type Item = ast::NodeId;
+
+ fn next(&mut self) -> Option<ast::NodeId> {
+ use NodesMatchingUII::*;
+ match self {
+ &mut NodesMatchingDirect(ref mut iter) => iter.next(),
+ &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ use NodesMatchingUII::*;
+ match self {
+ &NodesMatchingDirect(ref iter) => iter.size_hint(),
+ &NodesMatchingSuffix(ref iter) => iter.size_hint(),
+ }
+ }
+}
+
+impl UserIdentifiedItem {
+ pub fn reconstructed_input(&self) -> String {
+ use UserIdentifiedItem::*;
+ match *self {
+ ItemViaNode(node_id) => node_id.to_string(),
+ ItemViaPath(ref parts) => parts.join("::"),
+ }
+ }
+
+ pub fn all_matching_node_ids<'a, 'hir>(&'a self,
+ map: &'a hir_map::Map<'hir>)
+ -> NodesMatchingUII<'a> {
+ use UserIdentifiedItem::*;
+ use NodesMatchingUII::*;
+ match *self {
+ ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
+ ItemViaPath(ref parts) => {
+ NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
+ }
+ }
+ }
+
+ pub fn to_one_node_id(self,
+ user_option: &str,
+ sess: &Session,
+ map: &hir_map::Map<'_>)
+ -> ast::NodeId {
+ let fail_because = |is_wrong_because| -> ast::NodeId {
+ let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
+ {}, which {}",
+ user_option,
+ self.reconstructed_input(),
+ is_wrong_because);
+ sess.fatal(&message)
+ };
+
+ let mut saw_node = ast::DUMMY_NODE_ID;
+ let mut seen = 0;
+ for node in self.all_matching_node_ids(map) {
+ saw_node = node;
+ seen += 1;
+ if seen > 1 {
+ fail_because("does not resolve uniquely");
+ }
+ }
+ if seen == 0 {
+ fail_because("does not resolve to any item");
+ }
+
+ assert!(seen == 1);
+ return saw_node;
+ }
+}
+