let module = file.syntax().descendants().find_map(Module::cast).unwrap();
assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap());
}
+
+#[test]
+fn test_where_predicates() {
+ fn assert_bound(text: &str, bound: Option<&TypeBound>) {
+ assert_eq!(text, bound.unwrap().syntax().text().to_string());
+ }
+
+ let file = SourceFile::parse(
+ r#"
+fn foo()
+where
+ T: Clone + Copy + Debug + 'static,
+ 'a: 'b + 'c,
+ Iterator::Item: 'a + Debug,
+ Iterator::Item: Debug + 'a,
+ <T as Iterator>::Item: Debug + 'a,
+ for<'a> F: Fn(&'a str)
+{}
+ "#,
+ );
+ let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap();
+
+ let mut predicates = where_clause.predicates();
+
+ let pred = predicates.next().unwrap();
+ let mut bounds = pred.type_bound_list().unwrap().bounds();
+
+ assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string());
+ assert_bound("Clone", bounds.next());
+ assert_bound("Copy", bounds.next());
+ assert_bound("Debug", bounds.next());
+ assert_bound("'static", bounds.next());
+
+ let pred = predicates.next().unwrap();
+ let mut bounds = pred.type_bound_list().unwrap().bounds();
+
+ assert_eq!("'a", pred.lifetime().unwrap().syntax().text().to_string());
+
+ assert_bound("'b", bounds.next());
+ assert_bound("'c", bounds.next());
+
+ let pred = predicates.next().unwrap();
+ let mut bounds = pred.type_bound_list().unwrap().bounds();
+
+ assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
+ assert_bound("'a", bounds.next());
+
+ let pred = predicates.next().unwrap();
+ let mut bounds = pred.type_bound_list().unwrap().bounds();
+
+ assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
+ assert_bound("Debug", bounds.next());
+ assert_bound("'a", bounds.next());
+
+ let pred = predicates.next().unwrap();
+ let mut bounds = pred.type_bound_list().unwrap().bounds();
+
+ assert_eq!("<T as Iterator>::Item", pred.type_ref().unwrap().syntax().text().to_string());
+ assert_bound("Debug", bounds.next());
+ assert_bound("'a", bounds.next());
+
+ let pred = predicates.next().unwrap();
+ let mut bounds = pred.type_bound_list().unwrap().bounds();
+
+ assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string());
+ assert_bound("Fn(&'a str)", bounds.next());
+}
}
-impl WhereClause {}
+impl WhereClause {
+ pub fn predicates(&self) -> impl Iterator<Item = &WherePred> {
+ super::children(self)
+ }
+}
+
+// WherePred
+#[derive(Debug, PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct WherePred {
+ pub(crate) syntax: SyntaxNode,
+}
+unsafe impl TransparentNewType for WherePred {
+ type Repr = rowan::SyntaxNode<RaTypes>;
+}
+
+impl AstNode for WherePred {
+ fn cast(syntax: &SyntaxNode) -> Option<&Self> {
+ match syntax.kind() {
+ WHERE_PRED => Some(WherePred::from_repr(syntax.into_repr())),
+ _ => None,
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+
+impl ToOwned for WherePred {
+ type Owned = TreeArc<WherePred>;
+ fn to_owned(&self) -> TreeArc<WherePred> { TreeArc::cast(self.syntax.to_owned()) }
+}
+
+
+impl ast::TypeBoundsOwner for WherePred {}
+impl WherePred {
+ pub fn type_ref(&self) -> Option<&TypeRef> {
+ super::child_opt(self)
+ }
+
+ pub fn lifetime(&self) -> Option<&Lifetime> {
+ super::child_opt(self)
+ }
+}
// WhileExpr
#[derive(Debug, PartialEq, Eq, Hash)]