2018-10-03 09:14:23 -07:00

397 lines
9.8 KiB
Rust

use ast;
use proc_macro2::Ident;
use syn;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImportedTypeKind {
/// The definition of an imported type.
Definition,
/// A reference to an imported type.
Reference,
}
impl<T> ImportedTypes for Option<T>
where
T: ImportedTypes,
{
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
if let Some(inner) = self {
inner.imported_types(f);
}
}
}
/// Iterate over definitions of and references to imported types in the AST.
pub trait ImportedTypes {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind);
}
/// Iterate over definitions of imported types in the AST.
pub trait ImportedTypeDefinitions {
fn imported_type_definitions<F>(&self, f: &mut F)
where
F: FnMut(&Ident);
}
impl<T> ImportedTypeDefinitions for T
where
T: ImportedTypes,
{
fn imported_type_definitions<F>(&self, f: &mut F)
where
F: FnMut(&Ident),
{
self.imported_types(&mut |id, kind| {
if let ImportedTypeKind::Definition = kind {
f(id);
}
});
}
}
/// Iterate over references to imported types in the AST.
pub trait ImportedTypeReferences {
fn imported_type_references<F>(&self, f: &mut F)
where
F: FnMut(&Ident);
}
impl<T> ImportedTypeReferences for T
where
T: ImportedTypes,
{
fn imported_type_references<F>(&self, f: &mut F)
where
F: FnMut(&Ident),
{
self.imported_types(&mut |id, kind| {
if let ImportedTypeKind::Reference = kind {
f(id);
}
});
}
}
impl<'a, T: ImportedTypes> ImportedTypes for &'a T {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
(*self).imported_types(f)
}
}
impl ImportedTypes for ast::Program {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.imports.imported_types(f);
self.consts.imported_types(f);
self.dictionaries.imported_types(f);
}
}
impl<T> ImportedTypes for Vec<T>
where
T: ImportedTypes,
{
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
for x in self {
x.imported_types(f);
}
}
}
impl ImportedTypes for ast::Import {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.kind.imported_types(f)
}
}
impl ImportedTypes for ast::ImportKind {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
ast::ImportKind::Static(s) => s.imported_types(f),
ast::ImportKind::Function(fun) => fun.imported_types(f),
ast::ImportKind::Type(ty) => ty.imported_types(f),
ast::ImportKind::Enum(enm) => enm.imported_types(f),
}
}
}
impl ImportedTypes for ast::ImportStatic {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.ty.imported_types(f);
}
}
impl ImportedTypes for syn::Type {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
syn::Type::Reference(ref r) => r.imported_types(f),
syn::Type::Path(ref p) => p.imported_types(f),
_ => {}
}
}
}
impl ImportedTypes for syn::TypeReference {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.elem.imported_types(f);
}
}
impl ImportedTypes for syn::TypePath {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.qself.imported_types(f);
self.path.imported_types(f);
}
}
impl ImportedTypes for syn::QSelf {
fn imported_types<F>(&self, _: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
// TODO
}
}
impl ImportedTypes for syn::Path {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
for seg in self.segments.iter() {
seg.arguments.imported_types(f);
}
f(
&self.segments.last().unwrap().value().ident,
ImportedTypeKind::Reference,
);
}
}
impl ImportedTypes for syn::PathArguments {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
syn::PathArguments::AngleBracketed(data) => {
for arg in data.args.iter() {
arg.imported_types(f);
}
}
//TOCHECK
syn::PathArguments::Parenthesized(data) => {
for input in data.inputs.iter() {
input.imported_types(f);
}
// TODO do we need to handle output here?
// https://docs.rs/syn/0.14.0/syn/struct.ParenthesizedGenericArguments.html
}
syn::PathArguments::None => {}
}
}
}
impl ImportedTypes for syn::GenericArgument {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
syn::GenericArgument::Lifetime(_) => {}
syn::GenericArgument::Type(ty) => ty.imported_types(f),
syn::GenericArgument::Binding(_) => {} // TODO
syn::GenericArgument::Const(_) => {} // TODO
syn::GenericArgument::Constraint(_) => {} // TODO
}
}
}
impl ImportedTypes for ast::ImportFunction {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.function.imported_types(f);
self.kind.imported_types(f);
}
}
impl ImportedTypes for ast::ImportFunctionKind {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
ast::ImportFunctionKind::Normal => {}
}
}
}
impl ImportedTypes for ast::Function {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.arguments.imported_types(f);
if let Some(ref r) = self.ret {
r.imported_types(f);
}
}
}
impl ImportedTypes for syn::ArgCaptured {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.ty.imported_types(f);
}
}
impl ImportedTypes for ast::ImportType {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
f(&self.rust_name, ImportedTypeKind::Definition);
for class in self.extends.iter() {
class.imported_types(f);
}
}
}
impl ImportedTypes for ast::ImportEnum {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
f(&self.name, ImportedTypeKind::Definition);
}
}
impl ImportedTypes for ast::Const {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.ty.imported_types(f);
}
}
impl ImportedTypes for ast::Dictionary {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
f(&self.name, ImportedTypeKind::Definition);
for field in self.fields.iter() {
field.imported_types(f);
}
}
}
impl ImportedTypes for ast::DictionaryField {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.ty.imported_types(f);
}
}
/// Remove any methods, statics, &c, that reference types that are *not*
/// defined.
pub trait RemoveUndefinedImports {
fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
where
F: Fn(&Ident) -> bool;
}
impl RemoveUndefinedImports for ast::Program {
fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
where
F: Fn(&Ident) -> bool,
{
let mut changed = self.imports.remove_undefined_imports(is_defined);
changed = self.consts.remove_undefined_imports(is_defined) || changed;
let mut dictionaries_to_remove = Vec::new();
for (i, dictionary) in self.dictionaries.iter_mut().enumerate() {
let num_required =
|dict: &ast::Dictionary| dict.fields.iter().filter(|f| f.required).count();
let before = num_required(dictionary);
changed = dictionary.fields.remove_undefined_imports(is_defined) || changed;
if before != num_required(dictionary) {
warn!(
"removing {} due to a required field being removed",
dictionary.name
);
dictionaries_to_remove.push(i);
}
}
for i in dictionaries_to_remove.iter().rev() {
self.dictionaries.swap_remove(*i);
}
changed || dictionaries_to_remove.len() > 0
}
}
impl<T> RemoveUndefinedImports for Vec<T>
where
T: ImportedTypeReferences,
{
fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
where
F: Fn(&Ident) -> bool,
{
let before = self.len();
self.retain(|x| {
let mut all_defined = true;
x.imported_type_references(&mut |id| {
if all_defined {
if !is_defined(id) {
info!("removing due to {} not being defined", id);
all_defined = false;
}
}
});
all_defined
});
before != self.len()
}
}