about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authormcarton <cartonmartin+git@gmail.com>2016-01-18 13:10:13 +0100
committermcarton <cartonmartin+git@gmail.com>2016-01-18 13:10:26 +0100
commitfb6b3bed0fc5701287035fc9c445a202e492a0d8 (patch)
tree4fc2e79424c37347efbf8867dc65c12f33d50303 /src
parent90cbc858e983e302d97f2bd72be7af9a94def51a (diff)
downloadrust-fb6b3bed0fc5701287035fc9c445a202e492a0d8.tar.gz
rust-fb6b3bed0fc5701287035fc9c445a202e492a0d8.zip
Add utility functions to check for trait impl
Diffstat (limited to 'src')
-rw-r--r--src/utils.rs88
1 files changed, 78 insertions, 10 deletions
diff --git a/src/utils.rs b/src/utils.rs
index 4b144452063..c41c0a8681b 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,20 +1,20 @@
-use rustc::lint::*;
-use rustc_front::hir::*;
+use consts::constant;
 use reexport::*;
-use syntax::codemap::{ExpnInfo, Span, ExpnFormat};
 use rustc::front::map::Node::*;
+use rustc::lint::*;
 use rustc::middle::def_id::DefId;
-use rustc::middle::ty;
+use rustc::middle::{cstore, def, infer, ty, traits};
+use rustc::session::Session;
+use rustc_front::hir::*;
 use std::borrow::Cow;
+use std::mem;
+use std::ops::{Deref, DerefMut};
+use std::str::FromStr;
 use syntax::ast::Lit_::*;
 use syntax::ast;
+use syntax::codemap::{ExpnInfo, Span, ExpnFormat};
 use syntax::errors::DiagnosticBuilder;
 use syntax::ptr::P;
-use consts::constant;
-
-use rustc::session::Session;
-use std::str::FromStr;
-use std::ops::{Deref, DerefMut};
 
 pub type MethodArgs = HirVec<P<Expr>>;
 
@@ -23,6 +23,7 @@ pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"];
 pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
 pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"];
 pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"];
+pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"];
 pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
 pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
 pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
@@ -132,7 +133,7 @@ pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool {
     }
 }
 
-/// Check if the method call given in `expr` belongs to given trait.
+/// Check if the method call given in `expr` belongs to given type.
 pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool {
     let method_call = ty::MethodCall::expr(expr.id);
 
@@ -186,6 +187,73 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
     path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b)
 }
 
+/// Get the definition associated to a path.
+/// TODO: investigate if there is something more efficient for that.
+pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> {
+    let cstore = &cx.tcx.sess.cstore;
+
+    let crates = cstore.crates();
+    let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]);
+    if let Some(krate) = krate {
+        let mut items = cstore.crate_top_level_items(*krate);
+        let mut path_it = path.iter().skip(1).peekable();
+
+        loop {
+            let segment = match path_it.next() {
+                Some(segment) => segment,
+                None => return None
+            };
+
+            for item in &mem::replace(&mut items, vec![]) {
+                if item.name.as_str() == *segment {
+                    if path_it.peek().is_none() {
+                        return Some(item.def);
+                    }
+
+                    let def_id = match item.def {
+                        cstore::DefLike::DlDef(def) => def.def_id(),
+                        cstore::DefLike::DlImpl(def_id) => def_id,
+                        _ => panic!("Unexpected {:?}", item.def),
+                    };
+
+                    items = cstore.item_children(def_id);
+                    break;
+                }
+            }
+        }
+    }
+    else {
+        None
+    }
+}
+
+/// Convenience function to get the `DefId` of a trait by path.
+pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> {
+    let def = match path_to_def(cx, path) {
+        Some(def) => def,
+        None => return None,
+    };
+
+    match def {
+        cstore::DlDef(def::DefTrait(trait_id)) => Some(trait_id),
+        _ => None,
+    }
+}
+
+/// Check whether a type implements a trait.
+/// See also `get_trait_def_id`.
+pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId) -> bool {
+    cx.tcx.populate_implementations_for_trait_if_necessary(trait_id);
+
+    let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, true);
+    let obligation = traits::predicate_for_trait_def(cx.tcx,
+                                                     traits::ObligationCause::dummy(),
+                                                     trait_id, 0, ty,
+                                                     vec![]);
+
+    traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)
+}
+
 /// Match an `Expr` against a chain of methods, and return the matched `Expr`s.
 ///
 /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,