<commit_before>use crate::hir::def_id::DefId;
use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
use std::borrow::Cow;
use std::fmt;
use rustc_target::spec::abi;
use syntax::ast;
use errors::{Applicability, DiagnosticBuilder};
use syntax_pos::Span;

use crate::hir;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ExpectedFound<T> {
    pub expected: T,
    pub found: T,
}

// Data structures used in type unification
#[derive(Clone, Debug)]
pub enum TypeError<'tcx> {
    Mismatch,
    UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
    AbiMismatch(ExpectedFound<abi::Abi>),
    Mutability,
    TupleSize(ExpectedFound<usize>),
    FixedArraySize(ExpectedFound<u64>),
    ArgCount,

    RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
    RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
    RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
    RegionsPlaceholderMismatch,

    Sorts(ExpectedFound<Ty<'tcx>>),
    IntMismatch(ExpectedFound<ty::IntVarValue>),
    FloatMismatch(ExpectedFound<ast::FloatTy>),
    Traits(ExpectedFound<DefId>),
    VariadicMismatch(ExpectedFound<bool>),

    /// Instantiating a type variable with the given type would have
    /// created a cycle (because it appears somewhere within that
    /// type).
    CyclicTy(Ty<'tcx>),
    ProjectionMismatched(ExpectedFound<DefId>),
    ProjectionBoundsLength(ExpectedFound<usize>),
    ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),

    ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
}

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
pub enum UnconstrainedNumeric {
    UnconstrainedFloat,
    UnconstrainedInt,
    Neither,
}

/// Explains the source of a type err in a short, human readable way. This is meant to be placed
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
/// afterwards to present additional details, particularly when it comes to lifetime-related
/// errors.
impl<'tcx> fmt::Display for TypeError<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use self::TypeError::*;
        fn report_maybe_different(f: &mut fmt::Formatter<'_>,
                                  expected: &str, found: &str) -> fmt::Result {
            // A naive approach to making sure that we're not reporting silly errors such as:
            // (expected closure, found closure).
            if expected == found {
                write!(f, "expected {}, found a different {}", expected, found)
            } else {
                write!(f, "expected {}, found {}", expected, found)
            }
        }

        let br_string = |br: ty::BoundRegion| {
            match br {
                ty::BrNamed(_, name) => format!(" {}", name),
                _ => String::new(),
            }
        };

        macro_rules! pluralise {
            ($x:expr) => {
                if $x != 1 { "s" } else { "" }
            };
        }

        match *self {
            CyclicTy(_) => write!(f, "cyclic type of infinite size"),
            Mismatch => write!(f, "types differ"),
            UnsafetyMismatch(values) => {
                write!(f, "expected {} fn, found {} fn",
                       values.expected,
                       values.found)
            }
            AbiMismatch(values) => {
                write!(f, "expected {} fn, found {} fn",
                       values.expected,
                       values.found)
            }
            Mutability => write!(f, "types differ in mutability"),
            TupleSize(values) => {
                write!(f, "expected a tuple with {} element{}, \
                           found one with {} element{}",
                       values.expected,
                       pluralise!(values.expected),
                       values.found,
                       pluralise!(values.found))
            }
            FixedArraySize(values) => {
                write!(f, "expected an array with a fixed size of {} element{}, \
                           found one with {} element{}",
                       values.expected,
                       pluralise!(values.expected),
                       values.found,
                       pluralise!(values.found))
            }
            ArgCount => {
                write!(f, "incorrect number of function parameters")
            }
            RegionsDoesNotOutlive(..) => {
                write!(f, "lifetime mismatch")
            }
            RegionsInsufficientlyPolymorphic(br, _) => {
                write!(f,
                       "expected bound lifetime parameter{}, found concrete lifetime",
                       br_string(br))
            }
            RegionsOverlyPolymorphic(br, _) => {
                write!(f,
                       "expected concrete lifetime, found bound lifetime parameter{}",
                       br_string(br))
            }
            RegionsPlaceholderMismatch => {
                write!(f, "one type is more general than the other")
            }
            Sorts(values) => ty::tls::with(|tcx| {
                report_maybe_different(f, &values.expected.sort_string(tcx),
                                       &values.found.sort_string(tcx))
            }),
            Traits(values) => ty::tls::with(|tcx| {
                report_maybe_different(f,
                                       &format!("trait `{}`",
                                                tcx.def_path_str(values.expected)),
                                       &format!("trait `{}`",
                                                tcx.def_path_str(values.found)))
            }),
            IntMismatch(ref values) => {
                write!(f, "expected `{:?}`, found `{:?}`",
                       values.expected,
                       values.found)
            }
            FloatMismatch(ref values) => {
                write!(f, "expected `{:?}`, found `{:?}`",
                       values.expected,
                       values.found)
            }
            VariadicMismatch(ref values) => {
                write!(f, "expected {} fn, found {} function",
                       if values.expected { "variadic" } else { "non-variadic" },
                       if values.found { "variadic" } else { "non-variadic" })
            }
            ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
                write!(f, "expected {}, found {}",
                       tcx.def_path_str(values.expected),
                       tcx.def_path_str(values.found))
            }),
            ProjectionBoundsLength(ref values) => {
                write!(f, "expected {} associated type binding{}, found {}",
                       values.expected,
                       pluralise!(values.expected),
                       values.found)
            },
            ExistentialMismatch(ref values) => {
                report_maybe_different(f, &format!("trait `{}`", values.expected),
                                       &format!("trait `{}`", values.found))
            }
            ConstMismatch(ref values) => {
                write!(f, "expected `{}`, found `{}`", values.expected, values.found)
            }
        }
    }
}

impl<'tcx> ty::TyS<'tcx> {
    pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
        match self.sty {
            ty::Bool | ty::Char | ty::Int(_) |
            ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(),
            ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(),

            ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
            ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
            ty::Array(_, n) => {
                let n = tcx.lift_to_global(&n).unwrap();
                match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                    Some(n) => format!("array of {} elements", n).into(),
                    None => "array".into(),
                }
            }
            ty::Slice(_) => "slice".into(),
            ty::RawPtr(_) => "*-ptr".into(),
            ty::Ref(region, ty, mutbl) => {
                let tymut = ty::TypeAndMut { ty, mutbl };
                let tymut_string = tymut.to_string();
                if tymut_string == "_" ||         //unknown type name,
                   tymut_string.len() > 10 ||     //name longer than saying "reference",
                   region.to_string() != "'_"     //... or a complex type
                {
                    format!("{}reference", match mutbl {
                        hir::Mutability::MutMutable => "mutable ",
                        _ => ""
                    }).into()
                } else {
                    format!("&{}", tymut_string).into()
                }
            }
            ty::FnDef(..) => "fn item".into(),
            ty::FnPtr(_) => "fn pointer".into(),
            ty::Dynamic(ref inner, ..) => {
                if let Some(principal) = inner.principal() {
                    format!("trait {}", tcx.def_path_str(principal.def_id())).into()
                } else {
                    "trait".into()
                }
            }
            ty::Closure(..) => "closure".into(),
            ty::Generator(..) => "generator".into(),
            ty::GeneratorWitness(..) => "generator witness".into(),
            ty::Tuple(..) => "tuple".into(),
            ty::Infer(ty::TyVar(_)) => "inferred type".into(),
            ty::Infer(ty::IntVar(_)) => "integer".into(),
            ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
            ty::Placeholder(..) => "placeholder type".into(),
            ty::Bound(..) => "bound type".into(),
            ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
            ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
            ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
            ty::Projection(_) => "associated type".into(),
            ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
            ty::Param(_) => "type parameter".into(),
            ty::Opaque(..) => "opaque type".into(),
            ty::Error => "type error".into(),
        }
    }
}

impl<'tcx> TyCtxt<'tcx> {
    pub fn note_and_explain_type_err(
        self,
        db: &mut DiagnosticBuilder<'_>,
        err: &TypeError<'tcx>,
        sp: Span,
    ) {
        use self::TypeError::*;

        match err {
            Sorts(values) => {
                let expected_str = values.expected.sort_string(self);
                let found_str = values.found.sort_string(self);
                if expected_str == found_str && expected_str == "closure" {
                    db.note("no two closures, even if identical, have the same type");
                    db.help("consider boxing your closure and/or using it as a trait object");
                }
                if expected_str == found_str && expected_str == "opaque type" { // Issue #63167
                    db.note("distinct uses of `impl Trait` result in different opaque types");
                    let e_str = values.expected.to_string();
                    let f_str = values.found.to_string();
                    if &e_str == &f_str && &e_str == "impl std::future::Future" {
                        db.help("if both futures resolve to the same type, consider `await`ing \
                                 on both of them");
                    }
                }
                if let (ty::Infer(ty::IntVar(_)), ty::Float(_)) =
                       (&values.found.sty, &values.expected.sty) // Issue #53280
                {
                    if let Ok(snippet) = self.sess.source_map().span_to_snippet(sp) {
                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
                            db.span_suggestion(
                                sp,
                                "use a float literal",
                                format!("{}.0", snippet),
                                Applicability::MachineApplicable
                            );
                        }
                    }
                }
            },
            CyclicTy(ty) => {
                // Watch out for various cases of cyclic types and try to explain.
                if ty.is_closure() || ty.is_generator() {
                    db.note("closures cannot capture themselves or take themselves as argument;\n\
                             this error may be the result of a recent compiler bug-fix,\n\
                             see https://github.com/rust-lang/rust/issues/46062 for more details");
                }
            }
            _ => {}
        }
    }
}
<commit_msg>Add clarification on E0308 about opaque types<commit_after>use crate::hir::def_id::DefId;
use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
use std::borrow::Cow;
use std::fmt;
use rustc_target::spec::abi;
use syntax::ast;
use errors::{Applicability, DiagnosticBuilder};
use syntax_pos::Span;

use crate::hir;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ExpectedFound<T> {
    pub expected: T,
    pub found: T,
}

// Data structures used in type unification
#[derive(Clone, Debug)]
pub enum TypeError<'tcx> {
    Mismatch,
    UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
    AbiMismatch(ExpectedFound<abi::Abi>),
    Mutability,
    TupleSize(ExpectedFound<usize>),
    FixedArraySize(ExpectedFound<u64>),
    ArgCount,

    RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
    RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
    RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
    RegionsPlaceholderMismatch,

    Sorts(ExpectedFound<Ty<'tcx>>),
    IntMismatch(ExpectedFound<ty::IntVarValue>),
    FloatMismatch(ExpectedFound<ast::FloatTy>),
    Traits(ExpectedFound<DefId>),
    VariadicMismatch(ExpectedFound<bool>),

    /// Instantiating a type variable with the given type would have
    /// created a cycle (because it appears somewhere within that
    /// type).
    CyclicTy(Ty<'tcx>),
    ProjectionMismatched(ExpectedFound<DefId>),
    ProjectionBoundsLength(ExpectedFound<usize>),
    ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),

    ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
}

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
pub enum UnconstrainedNumeric {
    UnconstrainedFloat,
    UnconstrainedInt,
    Neither,
}

/// Explains the source of a type err in a short, human readable way. This is meant to be placed
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
/// afterwards to present additional details, particularly when it comes to lifetime-related
/// errors.
impl<'tcx> fmt::Display for TypeError<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use self::TypeError::*;
        fn report_maybe_different(f: &mut fmt::Formatter<'_>,
                                  expected: &str, found: &str) -> fmt::Result {
            // A naive approach to making sure that we're not reporting silly errors such as:
            // (expected closure, found closure).
            if expected == found {
                write!(f, "expected {}, found a different {}", expected, found)
            } else {
                write!(f, "expected {}, found {}", expected, found)
            }
        }

        let br_string = |br: ty::BoundRegion| {
            match br {
                ty::BrNamed(_, name) => format!(" {}", name),
                _ => String::new(),
            }
        };

        macro_rules! pluralise {
            ($x:expr) => {
                if $x != 1 { "s" } else { "" }
            };
        }

        match *self {
            CyclicTy(_) => write!(f, "cyclic type of infinite size"),
            Mismatch => write!(f, "types differ"),
            UnsafetyMismatch(values) => {
                write!(f, "expected {} fn, found {} fn",
                       values.expected,
                       values.found)
            }
            AbiMismatch(values) => {
                write!(f, "expected {} fn, found {} fn",
                       values.expected,
                       values.found)
            }
            Mutability => write!(f, "types differ in mutability"),
            TupleSize(values) => {
                write!(f, "expected a tuple with {} element{}, \
                           found one with {} element{}",
                       values.expected,
                       pluralise!(values.expected),
                       values.found,
                       pluralise!(values.found))
            }
            FixedArraySize(values) => {
                write!(f, "expected an array with a fixed size of {} element{}, \
                           found one with {} element{}",
                       values.expected,
                       pluralise!(values.expected),
                       values.found,
                       pluralise!(values.found))
            }
            ArgCount => {
                write!(f, "incorrect number of function parameters")
            }
            RegionsDoesNotOutlive(..) => {
                write!(f, "lifetime mismatch")
            }
            RegionsInsufficientlyPolymorphic(br, _) => {
                write!(f,
                       "expected bound lifetime parameter{}, found concrete lifetime",
                       br_string(br))
            }
            RegionsOverlyPolymorphic(br, _) => {
                write!(f,
                       "expected concrete lifetime, found bound lifetime parameter{}",
                       br_string(br))
            }
            RegionsPlaceholderMismatch => {
                write!(f, "one type is more general than the other")
            }
            Sorts(values) => ty::tls::with(|tcx| {
                report_maybe_different(f, &values.expected.sort_string(tcx),
                                       &values.found.sort_string(tcx))
            }),
            Traits(values) => ty::tls::with(|tcx| {
                report_maybe_different(f,
                                       &format!("trait `{}`",
                                                tcx.def_path_str(values.expected)),
                                       &format!("trait `{}`",
                                                tcx.def_path_str(values.found)))
            }),
            IntMismatch(ref values) => {
                write!(f, "expected `{:?}`, found `{:?}`",
                       values.expected,
                       values.found)
            }
            FloatMismatch(ref values) => {
                write!(f, "expected `{:?}`, found `{:?}`",
                       values.expected,
                       values.found)
            }
            VariadicMismatch(ref values) => {
                write!(f, "expected {} fn, found {} function",
                       if values.expected { "variadic" } else { "non-variadic" },
                       if values.found { "variadic" } else { "non-variadic" })
            }
            ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
                write!(f, "expected {}, found {}",
                       tcx.def_path_str(values.expected),
                       tcx.def_path_str(values.found))
            }),
            ProjectionBoundsLength(ref values) => {
                write!(f, "expected {} associated type binding{}, found {}",
                       values.expected,
                       pluralise!(values.expected),
                       values.found)
            },
            ExistentialMismatch(ref values) => {
                report_maybe_different(f, &format!("trait `{}`", values.expected),
                                       &format!("trait `{}`", values.found))
            }
            ConstMismatch(ref values) => {
                write!(f, "expected `{}`, found `{}`", values.expected, values.found)
            }
        }
    }
}

impl<'tcx> ty::TyS<'tcx> {
    pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
        match self.sty {
            ty::Bool | ty::Char | ty::Int(_) |
            ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(),
            ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(),

            ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
            ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
            ty::Array(_, n) => {
                let n = tcx.lift_to_global(&n).unwrap();
                match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                    Some(n) => format!("array of {} elements", n).into(),
                    None => "array".into(),
                }
            }
            ty::Slice(_) => "slice".into(),
            ty::RawPtr(_) => "*-ptr".into(),
            ty::Ref(region, ty, mutbl) => {
                let tymut = ty::TypeAndMut { ty, mutbl };
                let tymut_string = tymut.to_string();
                if tymut_string == "_" ||         //unknown type name,
                   tymut_string.len() > 10 ||     //name longer than saying "reference",
                   region.to_string() != "'_"     //... or a complex type
                {
                    format!("{}reference", match mutbl {
                        hir::Mutability::MutMutable => "mutable ",
                        _ => ""
                    }).into()
                } else {
                    format!("&{}", tymut_string).into()
                }
            }
            ty::FnDef(..) => "fn item".into(),
            ty::FnPtr(_) => "fn pointer".into(),
            ty::Dynamic(ref inner, ..) => {
                if let Some(principal) = inner.principal() {
                    format!("trait {}", tcx.def_path_str(principal.def_id())).into()
                } else {
                    "trait".into()
                }
            }
            ty::Closure(..) => "closure".into(),
            ty::Generator(..) => "generator".into(),
            ty::GeneratorWitness(..) => "generator witness".into(),
            ty::Tuple(..) => "tuple".into(),
            ty::Infer(ty::TyVar(_)) => "inferred type".into(),
            ty::Infer(ty::IntVar(_)) => "integer".into(),
            ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
            ty::Placeholder(..) => "placeholder type".into(),
            ty::Bound(..) => "bound type".into(),
            ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
            ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
            ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
            ty::Projection(_) => "associated type".into(),
            ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
            ty::Param(_) => "type parameter".into(),
            ty::Opaque(..) => "opaque type".into(),
            ty::Error => "type error".into(),
        }
    }
}

impl<'tcx> TyCtxt<'tcx> {
    pub fn note_and_explain_type_err(
        self,
        db: &mut DiagnosticBuilder<'_>,
        err: &TypeError<'tcx>,
        sp: Span,
    ) {
        use self::TypeError::*;

        match err {
            Sorts(values) => {
                let expected_str = values.expected.sort_string(self);
                let found_str = values.found.sort_string(self);
                if expected_str == found_str && expected_str == "closure" {
                    db.note("no two closures, even if identical, have the same type");
                    db.help("consider boxing your closure and/or using it as a trait object");
                }
                if expected_str == found_str && expected_str == "opaque type" { // Issue #63167
                    db.note("distinct uses of `impl Trait` result in different opaque types");
                    let e_str = values.expected.to_string();
                    let f_str = values.found.to_string();
                    if &e_str == &f_str && &e_str == "impl std::future::Future" {
                        // FIXME: use non-string based check.
                        db.help("if both futures resolve to the same type, consider `await`ing \
                                 on both of them");
                    }
                }
                if let (ty::Infer(ty::IntVar(_)), ty::Float(_)) =
                       (&values.found.sty, &values.expected.sty) // Issue #53280
                {
                    if let Ok(snippet) = self.sess.source_map().span_to_snippet(sp) {
                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
                            db.span_suggestion(
                                sp,
                                "use a float literal",
                                format!("{}.0", snippet),
                                Applicability::MachineApplicable
                            );
                        }
                    }
                }
            },
            CyclicTy(ty) => {
                // Watch out for various cases of cyclic types and try to explain.
                if ty.is_closure() || ty.is_generator() {
                    db.note("closures cannot capture themselves or take themselves as argument;\n\
                             this error may be the result of a recent compiler bug-fix,\n\
                             see https://github.com/rust-lang/rust/issues/46062 for more details");
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>//! # Lints in the Rust compiler
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
//!
//! ## Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

#![cfg_attr(test, feature(test))]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(nll)]
#![feature(matches_macro)]

#![recursion_limit="256"]

#[macro_use]
extern crate rustc;
#[macro_use]
extern crate rustc_session;

mod array_into_iter;
mod nonstandard_style;
mod redundant_semicolon;
pub mod builtin;
mod types;
mod unused;
mod non_ascii_idents;

use rustc::lint;
use rustc::lint::{EarlyContext, LateContext, LateLintPass, EarlyLintPass, LintPass, LintArray};
use rustc::lint::builtin::{
    BARE_TRAIT_OBJECTS,
    ELIDED_LIFETIMES_IN_PATHS,
    EXPLICIT_OUTLIVES_REQUIREMENTS,
    INTRA_DOC_LINK_RESOLUTION_FAILURE,
    MISSING_DOC_CODE_EXAMPLES,
    PRIVATE_DOC_TESTS,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;

use syntax::ast;
use syntax_pos::Span;

use lint::LintId;

use redundant_semicolon::*;
use nonstandard_style::*;
use builtin::*;
use types::*;
use unused::*;
use non_ascii_idents::*;
use rustc::lint::internal::*;
use array_into_iter::ArrayIntoIter;

/// Useful for other parts of the compiler.
pub use builtin::SoftLints;

pub fn provide(providers: &mut Providers<'_>) {
    *providers = Providers {
        lint_mod,
        ..*providers
    };
}

fn lint_mod(tcx: TyCtxt<'_>, module_def_id: DefId) {
    lint::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
}

macro_rules! pre_expansion_lint_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            KeywordIdents: KeywordIdents,
            UnusedDocComment: UnusedDocComment,
        ]);
    )
}

macro_rules! early_lint_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            UnusedParens: UnusedParens,
            UnusedImportBraces: UnusedImportBraces,
            UnsafeCode: UnsafeCode,
            AnonymousParameters: AnonymousParameters,
            EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
            NonCamelCaseTypes: NonCamelCaseTypes,
            DeprecatedAttr: DeprecatedAttr::new(),
            WhileTrue: WhileTrue,
            NonAsciiIdents: NonAsciiIdents,
            IncompleteFeatures: IncompleteFeatures,
            RedundantSemicolon: RedundantSemicolon,
        ]);
    )
}

macro_rules! declare_combined_early_pass {
    ([$name:ident], $passes:tt) => (
        early_lint_methods!(declare_combined_early_lint_pass, [pub $name, $passes]);
    )
}

pre_expansion_lint_passes!(declare_combined_early_pass, [BuiltinCombinedPreExpansionLintPass]);
early_lint_passes!(declare_combined_early_pass, [BuiltinCombinedEarlyLintPass]);

macro_rules! late_lint_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            // FIXME: Look into regression when this is used as a module lint
            // May Depend on constants elsewhere
            UnusedBrokenConst: UnusedBrokenConst,

            // Uses attr::is_used which is untracked, can't be an incremental module pass.
            UnusedAttributes: UnusedAttributes::new(),

            // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
            UnstableFeatures: UnstableFeatures,

            // Tracks state across modules
            UnnameableTestItems: UnnameableTestItems::new(),

            // Tracks attributes of parents
            MissingDoc: MissingDoc::new(),

            // Depends on access levels
            // FIXME: Turn the computation of types which implement Debug into a query
            // and change this to a module lint pass
            MissingDebugImplementations: MissingDebugImplementations::default(),

            ArrayIntoIter: ArrayIntoIter,
        ]);
    )
}

macro_rules! late_lint_mod_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            HardwiredLints: HardwiredLints,
            ImproperCTypes: ImproperCTypes,
            VariantSizeDifferences: VariantSizeDifferences,
            BoxPointers: BoxPointers,
            PathStatements: PathStatements,

            // Depends on referenced function signatures in expressions
            UnusedResults: UnusedResults,

            NonUpperCaseGlobals: NonUpperCaseGlobals,
            NonShorthandFieldPatterns: NonShorthandFieldPatterns,
            UnusedAllocation: UnusedAllocation,

            // Depends on types used in type definitions
            MissingCopyImplementations: MissingCopyImplementations,

            // Depends on referenced function signatures in expressions
            MutableTransmutes: MutableTransmutes,

            TypeAliasBounds: TypeAliasBounds,

            TrivialConstraints: TrivialConstraints,
            TypeLimits: TypeLimits::new(),

            NonSnakeCase: NonSnakeCase,
            InvalidNoMangleItems: InvalidNoMangleItems,

            // Depends on access levels
            UnreachablePub: UnreachablePub,

            ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
            InvalidValue: InvalidValue,
        ]);
    )
}

macro_rules! declare_combined_late_pass {
    ([$v:vis $name:ident], $passes:tt) => (
        late_lint_methods!(declare_combined_late_lint_pass, [$v $name, $passes], ['tcx]);
    )
}

// FIXME: Make a separate lint type which do not require typeck tables
late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]);

late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);

pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore {
    let mut lint_store = lint::LintStore::new();

    register_builtins(&mut lint_store, no_interleave_lints);
    if internal_lints {
        register_internals(&mut lint_store);
    }

    lint_store
}

/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
    macro_rules! add_lint_group {
        ($name:expr, $($lint:ident),*) => (
            store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
        )
    }

    macro_rules! register_pass {
        ($method:ident, $ty:ident, $constructor:expr) => (
            store.register_lints(&$ty::get_lints());
            store.$method(|| box $constructor);
        )
    }

    macro_rules! register_passes {
        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
            $(
                register_pass!($method, $passes, $constructor);
            )*
        )
    }

    if no_interleave_lints {
        pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass);
        early_lint_passes!(register_passes, register_early_pass);
        late_lint_passes!(register_passes, register_late_pass);
        late_lint_mod_passes!(register_passes, register_late_mod_pass);
    } else {
        store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
        store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
        store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
        store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
    }

    add_lint_group!("nonstandard_style",
                    NON_CAMEL_CASE_TYPES,
                    NON_SNAKE_CASE,
                    NON_UPPER_CASE_GLOBALS);

    add_lint_group!("unused",
                    UNUSED_IMPORTS,
                    UNUSED_VARIABLES,
                    UNUSED_ASSIGNMENTS,
                    DEAD_CODE,
                    UNUSED_MUT,
                    UNREACHABLE_CODE,
                    UNREACHABLE_PATTERNS,
                    OVERLAPPING_PATTERNS,
                    UNUSED_MUST_USE,
                    UNUSED_UNSAFE,
                    PATH_STATEMENTS,
                    UNUSED_ATTRIBUTES,
                    UNUSED_MACROS,
                    UNUSED_ALLOCATION,
                    UNUSED_DOC_COMMENTS,
                    UNUSED_EXTERN_CRATES,
                    UNUSED_FEATURES,
                    UNUSED_LABELS,
                    UNUSED_PARENS);

    add_lint_group!("rust_2018_idioms",
                    BARE_TRAIT_OBJECTS,
                    UNUSED_EXTERN_CRATES,
                    ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
                    ELIDED_LIFETIMES_IN_PATHS,
                    EXPLICIT_OUTLIVES_REQUIREMENTS

                    // FIXME(#52665, #47816) not always applicable and not all
                    // macros are ready for this yet.
                    // UNREACHABLE_PUB,

                    // FIXME macro crates are not up for this yet, too much
                    // breakage is seen if we try to encourage this lint.
                    // MACRO_USE_EXTERN_CRATE,
                    );

    add_lint_group!("rustdoc",
                    INTRA_DOC_LINK_RESOLUTION_FAILURE,
                    MISSING_DOC_CODE_EXAMPLES,
                    PRIVATE_DOC_TESTS);

    // Register renamed and removed lints.
    store.register_renamed("single_use_lifetime", "single_use_lifetimes");
    store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");
    store.register_renamed("bare_trait_object", "bare_trait_objects");
    store.register_renamed("unstable_name_collision", "unstable_name_collisions");
    store.register_renamed("unused_doc_comment", "unused_doc_comments");
    store.register_renamed("async_idents", "keyword_idents");
    store.register_removed("unknown_features", "replaced by an error");
    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
    store.register_removed("negate_unsigned", "cast a signed value instead");
    store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
    // Register lint group aliases.
    store.register_group_alias("nonstandard_style", "bad_style");
    // This was renamed to `raw_pointer_derive`, which was then removed,
    // so it is also considered removed.
    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
    store.register_removed("drop_with_repr_extern", "drop flags have been removed");
    store.register_removed("fat_ptr_transmutes", "was accidentally removed back in 2014");
    store.register_removed("deprecated_attr", "use `deprecated` instead");
    store.register_removed("transmute_from_fn_item_types",
        "always cast functions before transmuting them");
    store.register_removed("hr_lifetime_in_assoc_type",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/33685");
    store.register_removed("inaccessible_extern_crate",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36886");
    store.register_removed("super_or_self_in_global_path",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36888");
    store.register_removed("overlapping_inherent_impls",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36889");
    store.register_removed("illegal_floating_point_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36890");
    store.register_removed("illegal_struct_or_enum_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36891");
    store.register_removed("lifetime_underscore",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
    store.register_removed("extra_requirement_in_impl",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
    store.register_removed("legacy_imports",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/38260");
    store.register_removed("coerce_never",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
    store.register_removed("resolve_trait_on_defaulted_unit",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
    store.register_removed("private_no_mangle_fns",
        "no longer a warning, `#[no_mangle]` functions always exported");
    store.register_removed("private_no_mangle_statics",
        "no longer a warning, `#[no_mangle]` statics always exported");
    store.register_removed("bad_repr",
        "replaced with a generic attribute input check");
    store.register_removed("duplicate_matcher_binding_name",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/57742");
    store.register_removed("incoherent_fundamental_impls",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/46205");
    store.register_removed("legacy_constructor_visibility",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/39207");
    store.register_removed("legacy_disrectory_ownership",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/37872");
    store.register_removed("safe_extern_statics",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36247");
    store.register_removed("parenthesized_params_in_types_and_modules",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/42238");
    store.register_removed("duplicate_macro_exports",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/35896");
    store.register_removed("nested_impl_trait",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/59014");
    store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
}

fn register_internals(store: &mut lint::LintStore) {
    store.register_lints(&DefaultHashTypes::get_lints());
    store.register_early_pass(|| box DefaultHashTypes::new());
    store.register_lints(&LintPassImpl::get_lints());
    store.register_early_pass(|| box LintPassImpl);
    store.register_lints(&TyTyKind::get_lints());
    store.register_late_pass(|| box TyTyKind);
    store.register_group(
        false,
        "rustc::internal",
        None,
        vec![
            LintId::of(DEFAULT_HASH_TYPES),
            LintId::of(USAGE_OF_TY_TYKIND),
            LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
            LintId::of(TY_PASS_BY_REFERENCE),
            LintId::of(USAGE_OF_QUALIFIED_TY),
        ],
    );
}
<commit_msg>Fixes typo<commit_after>//! # Lints in the Rust compiler
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
//!
//! ## Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

#![cfg_attr(test, feature(test))]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(nll)]
#![feature(matches_macro)]

#![recursion_limit="256"]

#[macro_use]
extern crate rustc;
#[macro_use]
extern crate rustc_session;

mod array_into_iter;
mod nonstandard_style;
mod redundant_semicolon;
pub mod builtin;
mod types;
mod unused;
mod non_ascii_idents;

use rustc::lint;
use rustc::lint::{EarlyContext, LateContext, LateLintPass, EarlyLintPass, LintPass, LintArray};
use rustc::lint::builtin::{
    BARE_TRAIT_OBJECTS,
    ELIDED_LIFETIMES_IN_PATHS,
    EXPLICIT_OUTLIVES_REQUIREMENTS,
    INTRA_DOC_LINK_RESOLUTION_FAILURE,
    MISSING_DOC_CODE_EXAMPLES,
    PRIVATE_DOC_TESTS,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;

use syntax::ast;
use syntax_pos::Span;

use lint::LintId;

use redundant_semicolon::*;
use nonstandard_style::*;
use builtin::*;
use types::*;
use unused::*;
use non_ascii_idents::*;
use rustc::lint::internal::*;
use array_into_iter::ArrayIntoIter;

/// Useful for other parts of the compiler.
pub use builtin::SoftLints;

pub fn provide(providers: &mut Providers<'_>) {
    *providers = Providers {
        lint_mod,
        ..*providers
    };
}

fn lint_mod(tcx: TyCtxt<'_>, module_def_id: DefId) {
    lint::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
}

macro_rules! pre_expansion_lint_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            KeywordIdents: KeywordIdents,
            UnusedDocComment: UnusedDocComment,
        ]);
    )
}

macro_rules! early_lint_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            UnusedParens: UnusedParens,
            UnusedImportBraces: UnusedImportBraces,
            UnsafeCode: UnsafeCode,
            AnonymousParameters: AnonymousParameters,
            EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
            NonCamelCaseTypes: NonCamelCaseTypes,
            DeprecatedAttr: DeprecatedAttr::new(),
            WhileTrue: WhileTrue,
            NonAsciiIdents: NonAsciiIdents,
            IncompleteFeatures: IncompleteFeatures,
            RedundantSemicolon: RedundantSemicolon,
        ]);
    )
}

macro_rules! declare_combined_early_pass {
    ([$name:ident], $passes:tt) => (
        early_lint_methods!(declare_combined_early_lint_pass, [pub $name, $passes]);
    )
}

pre_expansion_lint_passes!(declare_combined_early_pass, [BuiltinCombinedPreExpansionLintPass]);
early_lint_passes!(declare_combined_early_pass, [BuiltinCombinedEarlyLintPass]);

macro_rules! late_lint_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            // FIXME: Look into regression when this is used as a module lint
            // May Depend on constants elsewhere
            UnusedBrokenConst: UnusedBrokenConst,

            // Uses attr::is_used which is untracked, can't be an incremental module pass.
            UnusedAttributes: UnusedAttributes::new(),

            // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
            UnstableFeatures: UnstableFeatures,

            // Tracks state across modules
            UnnameableTestItems: UnnameableTestItems::new(),

            // Tracks attributes of parents
            MissingDoc: MissingDoc::new(),

            // Depends on access levels
            // FIXME: Turn the computation of types which implement Debug into a query
            // and change this to a module lint pass
            MissingDebugImplementations: MissingDebugImplementations::default(),

            ArrayIntoIter: ArrayIntoIter,
        ]);
    )
}

macro_rules! late_lint_mod_passes {
    ($macro:path, $args:tt) => (
        $macro!($args, [
            HardwiredLints: HardwiredLints,
            ImproperCTypes: ImproperCTypes,
            VariantSizeDifferences: VariantSizeDifferences,
            BoxPointers: BoxPointers,
            PathStatements: PathStatements,

            // Depends on referenced function signatures in expressions
            UnusedResults: UnusedResults,

            NonUpperCaseGlobals: NonUpperCaseGlobals,
            NonShorthandFieldPatterns: NonShorthandFieldPatterns,
            UnusedAllocation: UnusedAllocation,

            // Depends on types used in type definitions
            MissingCopyImplementations: MissingCopyImplementations,

            // Depends on referenced function signatures in expressions
            MutableTransmutes: MutableTransmutes,

            TypeAliasBounds: TypeAliasBounds,

            TrivialConstraints: TrivialConstraints,
            TypeLimits: TypeLimits::new(),

            NonSnakeCase: NonSnakeCase,
            InvalidNoMangleItems: InvalidNoMangleItems,

            // Depends on access levels
            UnreachablePub: UnreachablePub,

            ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
            InvalidValue: InvalidValue,
        ]);
    )
}

macro_rules! declare_combined_late_pass {
    ([$v:vis $name:ident], $passes:tt) => (
        late_lint_methods!(declare_combined_late_lint_pass, [$v $name, $passes], ['tcx]);
    )
}

// FIXME: Make a separate lint type which do not require typeck tables
late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]);

late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);

pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore {
    let mut lint_store = lint::LintStore::new();

    register_builtins(&mut lint_store, no_interleave_lints);
    if internal_lints {
        register_internals(&mut lint_store);
    }

    lint_store
}

/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
    macro_rules! add_lint_group {
        ($name:expr, $($lint:ident),*) => (
            store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
        )
    }

    macro_rules! register_pass {
        ($method:ident, $ty:ident, $constructor:expr) => (
            store.register_lints(&$ty::get_lints());
            store.$method(|| box $constructor);
        )
    }

    macro_rules! register_passes {
        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
            $(
                register_pass!($method, $passes, $constructor);
            )*
        )
    }

    if no_interleave_lints {
        pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass);
        early_lint_passes!(register_passes, register_early_pass);
        late_lint_passes!(register_passes, register_late_pass);
        late_lint_mod_passes!(register_passes, register_late_mod_pass);
    } else {
        store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
        store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
        store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
        store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
    }

    add_lint_group!("nonstandard_style",
                    NON_CAMEL_CASE_TYPES,
                    NON_SNAKE_CASE,
                    NON_UPPER_CASE_GLOBALS);

    add_lint_group!("unused",
                    UNUSED_IMPORTS,
                    UNUSED_VARIABLES,
                    UNUSED_ASSIGNMENTS,
                    DEAD_CODE,
                    UNUSED_MUT,
                    UNREACHABLE_CODE,
                    UNREACHABLE_PATTERNS,
                    OVERLAPPING_PATTERNS,
                    UNUSED_MUST_USE,
                    UNUSED_UNSAFE,
                    PATH_STATEMENTS,
                    UNUSED_ATTRIBUTES,
                    UNUSED_MACROS,
                    UNUSED_ALLOCATION,
                    UNUSED_DOC_COMMENTS,
                    UNUSED_EXTERN_CRATES,
                    UNUSED_FEATURES,
                    UNUSED_LABELS,
                    UNUSED_PARENS);

    add_lint_group!("rust_2018_idioms",
                    BARE_TRAIT_OBJECTS,
                    UNUSED_EXTERN_CRATES,
                    ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
                    ELIDED_LIFETIMES_IN_PATHS,
                    EXPLICIT_OUTLIVES_REQUIREMENTS

                    // FIXME(#52665, #47816) not always applicable and not all
                    // macros are ready for this yet.
                    // UNREACHABLE_PUB,

                    // FIXME macro crates are not up for this yet, too much
                    // breakage is seen if we try to encourage this lint.
                    // MACRO_USE_EXTERN_CRATE,
                    );

    add_lint_group!("rustdoc",
                    INTRA_DOC_LINK_RESOLUTION_FAILURE,
                    MISSING_DOC_CODE_EXAMPLES,
                    PRIVATE_DOC_TESTS);

    // Register renamed and removed lints.
    store.register_renamed("single_use_lifetime", "single_use_lifetimes");
    store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");
    store.register_renamed("bare_trait_object", "bare_trait_objects");
    store.register_renamed("unstable_name_collision", "unstable_name_collisions");
    store.register_renamed("unused_doc_comment", "unused_doc_comments");
    store.register_renamed("async_idents", "keyword_idents");
    store.register_removed("unknown_features", "replaced by an error");
    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
    store.register_removed("negate_unsigned", "cast a signed value instead");
    store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
    // Register lint group aliases.
    store.register_group_alias("nonstandard_style", "bad_style");
    // This was renamed to `raw_pointer_derive`, which was then removed,
    // so it is also considered removed.
    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
    store.register_removed("drop_with_repr_extern", "drop flags have been removed");
    store.register_removed("fat_ptr_transmutes", "was accidentally removed back in 2014");
    store.register_removed("deprecated_attr", "use `deprecated` instead");
    store.register_removed("transmute_from_fn_item_types",
        "always cast functions before transmuting them");
    store.register_removed("hr_lifetime_in_assoc_type",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/33685");
    store.register_removed("inaccessible_extern_crate",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36886");
    store.register_removed("super_or_self_in_global_path",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36888");
    store.register_removed("overlapping_inherent_impls",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36889");
    store.register_removed("illegal_floating_point_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36890");
    store.register_removed("illegal_struct_or_enum_constant_pattern",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36891");
    store.register_removed("lifetime_underscore",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
    store.register_removed("extra_requirement_in_impl",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
    store.register_removed("legacy_imports",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/38260");
    store.register_removed("coerce_never",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
    store.register_removed("resolve_trait_on_defaulted_unit",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
    store.register_removed("private_no_mangle_fns",
        "no longer a warning, `#[no_mangle]` functions always exported");
    store.register_removed("private_no_mangle_statics",
        "no longer a warning, `#[no_mangle]` statics always exported");
    store.register_removed("bad_repr",
        "replaced with a generic attribute input check");
    store.register_removed("duplicate_matcher_binding_name",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/57742");
    store.register_removed("incoherent_fundamental_impls",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/46205");
    store.register_removed("legacy_constructor_visibility",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/39207");
    store.register_removed("legacy_directory_ownership",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/37872");
    store.register_removed("safe_extern_statics",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/36247");
    store.register_removed("parenthesized_params_in_types_and_modules",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/42238");
    store.register_removed("duplicate_macro_exports",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/35896");
    store.register_removed("nested_impl_trait",
        "converted into hard error, see https://github.com/rust-lang/rust/issues/59014");
    store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
}

fn register_internals(store: &mut lint::LintStore) {
    store.register_lints(&DefaultHashTypes::get_lints());
    store.register_early_pass(|| box DefaultHashTypes::new());
    store.register_lints(&LintPassImpl::get_lints());
    store.register_early_pass(|| box LintPassImpl);
    store.register_lints(&TyTyKind::get_lints());
    store.register_late_pass(|| box TyTyKind);
    store.register_group(
        false,
        "rustc::internal",
        None,
        vec![
            LintId::of(DEFAULT_HASH_TYPES),
            LintId::of(USAGE_OF_TY_TYKIND),
            LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
            LintId::of(TY_PASS_BY_REFERENCE),
            LintId::of(USAGE_OF_QUALIFIED_TY),
        ],
    );
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

mod wiz;
mod constants;

use clap::{App, Arg};

arg_enum! {
    #[derive(Debug)]
    enum Method {
        Install,
        Remove
    }
}

fn main() {

/*
 * TODO: Eliminate hardcoded strings, instead
 * putting them in constants.rs or other places.
 */

    let arg_matches = App::new("wiz")
        .version("0.1.0")

        .arg(Arg::with_name("method")
             .help("Specify what to do with the specified package")
             .index(1)
             .possible_values(&Method::variants())
             .required(true))

        .arg(Arg::with_name("package")
             .help("Specify package")
             .index(2)
             .required(true))

        .get_matches();

    let method = value_t!(arg_matches.value_of("method"), Method).unwrap();
    let package = arg_matches.value_of("package").unwrap_or("invalid");

    match method {
        Method::Install => println!("install: {}", package),
        Method::Remove => println!("remove: {}", package)
    }
}
<commit_msg>Finishing todo #2<commit_after>#[macro_use]
extern crate clap;

mod wiz;
mod constants;

use clap::{App, Arg};

arg_enum! {
    #[derive(Debug)]
    enum Method {
        Install,
        Remove
    }
}

fn main() {

/*
 * TODO: Eliminate hardcoded strings, instead
 * putting them in constants.rs or other places.
 */

    let arg_matches = App::new(NAME)
        .version(VERSION)

        .arg(Arg::with_name("method")
             .help("Specify what to do with the specified package")
             .index(1)
             .possible_values(&Method::variants())
             .required(true))

        .arg(Arg::with_name("package")
             .help("Specify package")
             .index(2)
             .required(true))

        .get_matches();

    let method = value_t!(arg_matches.value_of("method"), Method).unwrap();
    let package = arg_matches.value_of("package").unwrap_or("invalid");

    match method {
        Method::Install => println!("install: {}", package),
        Method::Remove => println!("remove: {}", package)
    }
}
<|endoftext|>


<commit_before>// This file is part of sokoban-rs
// Copyright 2015 Sébastien Watteau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is an implementation of Sokoban in Rust.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate clap;
extern crate sdl2;
extern crate xml;

use clap::{App, ArgMatches};
use sdl2::event::Event;
use sdl2::image::LoadTexture;
use sdl2::image::INIT_PNG;
use sdl2::keyboard::Keycode;
use sdl2::render::TextureCreator;
use sdl2::video::{Window, WindowContext};
use sdl2::Sdl;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::str::FromStr;
use xml::reader::EventReader;
use xml::reader::XmlEvent;

pub mod error;
pub mod game;
pub mod painter;
pub mod shadow;
pub mod tileset;

use game::Level;
use painter::Painter;
use tileset::Tileset;

pub fn main() {
    let yml = load_yaml!("clap.yml");
    let matches = App::from_yaml(yml).get_matches();

    let slc_file = matches.value_of("slc_file").unwrap();

    let sdl_context =
        sdl2::init().unwrap_or_else(|err| panic!("Failed to initialize an SDL context: {}", err));

    let window = get_window(&sdl_context, &matches);

    let mut canvas = window
        .into_canvas()
        .build()
        .unwrap_or_else(|err| panic!("Failed to get an SDL canvas for the main window: {}", err));

    let creator = canvas.texture_creator();

    let _image_context = sdl2::image::init(INIT_PNG).unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();

    let mut painter = {
        let big_set = load_tileset(&creator, "assets/image/tileset.png", 101, 171, 83, 40);
        let small_set = load_tileset(&creator, "assets/image/tileset-small.png", 50, 85, 41, 20);
        Painter::new(&mut canvas, big_set, small_set, &ttf_context)
    };

    let mut collection = load_slc_file(Path::new(&slc_file))
        .unwrap_or_else(|err| panic!("{}", err))
        .into_iter();
    let mut reference_level = collection.next().unwrap();
    let mut level = reference_level.clone();

    let mut running = true;
    let mut event_pump = sdl_context.event_pump().unwrap();
    let mut skip = false;
    while running {
        if level.is_completed() || skip {
            match collection.next() {
                Some(l) => {
                    level = l;
                    reference_level = level.clone();
                    skip = false;
                }
                None => {
                    break;
                }
            }
        }
        painter.paint(&mut canvas, &level);

        match event_pump.wait_event() {
            Event::Quit { .. }
            | Event::KeyDown {
                keycode: Some(Keycode::Escape),
                ..
            } => running = false,
            Event::KeyDown {
                keycode: Some(Keycode::Left),
                ..
            } => {
                level.step(game::Direction::Left);
            }
            Event::KeyDown {
                keycode: Some(Keycode::Right),
                ..
            } => {
                level.step(game::Direction::Right);
            }
            Event::KeyDown {
                keycode: Some(Keycode::Up),
                ..
            } => {
                level.step(game::Direction::Up);
            }
            Event::KeyDown {
                keycode: Some(Keycode::Down),
                ..
            } => {
                level.step(game::Direction::Down);
            }
            Event::KeyDown {
                keycode: Some(Keycode::R),
                ..
            } => {
                level = reference_level.clone();
            }
            Event::KeyDown {
                keycode: Some(Keycode::N),
                ..
            } => {
                skip = true;
            }
            _ => {}
        }
    }
}

fn get_window(sdl_context: &Sdl, matches: &ArgMatches) -> Window {
    let width = value_t!(matches.value_of("width"), u32).unwrap_or(1024);
    let height = value_t!(matches.value_of("height"), u32).unwrap_or(768);

    let video_subsystem = sdl_context
        .video()
        .unwrap_or_else(|err| panic!("Failed to initialize the video subsystem: {}", err));

    let mut window_builder = video_subsystem.window("sokoban-rs", width, height);
    if matches.is_present("fullscreen") {
        window_builder.fullscreen();
    } else {
        window_builder.position_centered();
    }

    let window = window_builder
        .opengl()
        .build()
        .unwrap_or_else(|err| panic!("Failed to create the window: {}", err));

    window
}

fn load_tileset<P: AsRef<Path>>(texture_creator: &TextureCreator<WindowContext>, path: P, width: u32, height: u32, effective_height: u32, offset: i32) -> Tileset {
    let texture = texture_creator
        .load_texture(path.as_ref())
        .unwrap();
    Tileset::new(texture, width, height, effective_height, offset)
}

/// Builds levels from a level collection file in the SLC format.
fn load_slc_file(path: &Path) -> Result<Vec<Level>, error::SokobanError> {
    let mut collection = Vec::new();
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    let parser = EventReader::new(reader);

    let mut level_title = String::new();
    let mut level_str = String::new();
    let mut reading_level = false;
    for e in parser {
        match e {
            Ok(XmlEvent::StartElement {
                ref name,
                ref attributes,
                ..
            }) => {
                if name.local_name == "L" {
                    reading_level = true;
                } else if name.local_name == "Level" {
                    if let Some(id) = attributes.iter().find(|&attr| attr.name.local_name == "Id") {
                        level_title = id.value.clone();
                    }
                }
            }
            Ok(XmlEvent::EndElement { name }) => {
                if name.local_name == "Level" {
                    let mut level = try!(Level::from_str(&level_str));
                    level.set_title(level_title.clone());
                    collection.push(level);
                    level_str.clear();
                }
            }
            Ok(XmlEvent::Characters(ref data)) => {
                if reading_level {
                    level_str.push_str(data);
                    level_str.push('\n');
                }
            }
            _ => {}
        }
    }

    Ok(collection)
}
<commit_msg>Minor changes<commit_after>// This file is part of sokoban-rs
// Copyright 2015 Sébastien Watteau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is an implementation of Sokoban in Rust.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate clap;
extern crate sdl2;
extern crate xml;

use clap::{App, ArgMatches};
use sdl2::event::Event;
use sdl2::image::LoadTexture;
use sdl2::image::INIT_PNG;
use sdl2::keyboard::Keycode;
use sdl2::render::TextureCreator;
use sdl2::video::{Window, WindowContext};
use sdl2::Sdl;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::str::FromStr;
use xml::reader::EventReader;
use xml::reader::XmlEvent;

pub mod error;
pub mod game;
pub mod painter;
pub mod shadow;
pub mod tileset;

use game::Level;
use painter::Painter;
use tileset::Tileset;

pub fn main() {
    let yml = load_yaml!("clap.yml");
    let matches = App::from_yaml(yml).get_matches();

    let slc_file = matches.value_of("slc_file").unwrap();
    let mut collection = load_slc_file(Path::new(&slc_file))
        .unwrap_or_else(|err| panic!("{}", err))
        .into_iter();
    let mut reference_level = collection.next().unwrap();
    let mut level = reference_level.clone();

    let sdl_context =
        sdl2::init().unwrap_or_else(|err| panic!("Failed to initialize an SDL context: {}", err));

    let _ = sdl2::image::init(INIT_PNG).unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();

    let window = get_window(&sdl_context, &matches);

    let mut canvas = window
        .into_canvas()
        .build()
        .unwrap_or_else(|err| panic!("Failed to get an SDL canvas for the main window: {}", err));

    let texture_creator = canvas.texture_creator();

    let mut painter = {
        let big_set = load_tileset(&texture_creator, "assets/image/tileset.png", 101, 171, 83, 40);
        let small_set = load_tileset(&texture_creator, "assets/image/tileset-small.png", 50, 85, 41, 20);
        Painter::new(&mut canvas, big_set, small_set, &ttf_context)
    };

    let mut running = true;
    let mut event_pump = sdl_context.event_pump().unwrap();
    let mut skip = false;
    while running {
        if level.is_completed() || skip {
            match collection.next() {
                Some(l) => {
                    level = l;
                    reference_level = level.clone();
                    skip = false;
                }
                None => {
                    break;
                }
            }
        }
        painter.paint(&mut canvas, &level);

        match event_pump.wait_event() {
            Event::Quit { .. }
            | Event::KeyDown {
                keycode: Some(Keycode::Escape),
                ..
            } => running = false,
            Event::KeyDown {
                keycode: Some(Keycode::Left),
                ..
            } => {
                level.step(game::Direction::Left);
            }
            Event::KeyDown {
                keycode: Some(Keycode::Right),
                ..
            } => {
                level.step(game::Direction::Right);
            }
            Event::KeyDown {
                keycode: Some(Keycode::Up),
                ..
            } => {
                level.step(game::Direction::Up);
            }
            Event::KeyDown {
                keycode: Some(Keycode::Down),
                ..
            } => {
                level.step(game::Direction::Down);
            }
            Event::KeyDown {
                keycode: Some(Keycode::R),
                ..
            } => {
                level = reference_level.clone();
            }
            Event::KeyDown {
                keycode: Some(Keycode::N),
                ..
            } => {
                skip = true;
            }
            _ => {}
        }
    }
}

fn get_window(sdl_context: &Sdl, matches: &ArgMatches) -> Window {
    let width = value_t!(matches.value_of("width"), u32).unwrap_or(1024);
    let height = value_t!(matches.value_of("height"), u32).unwrap_or(768);

    let video_subsystem = sdl_context
        .video()
        .unwrap_or_else(|err| panic!("Failed to initialize the video subsystem: {}", err));

    let mut window_builder = video_subsystem.window("sokoban-rs", width, height);
    if matches.is_present("fullscreen") {
        window_builder.fullscreen();
    } else {
        window_builder.position_centered();
    }

    let window = window_builder
        .opengl()
        .build()
        .unwrap_or_else(|err| panic!("Failed to create the window: {}", err));

    window
}

fn load_tileset<P: AsRef<Path>>(texture_creator: &TextureCreator<WindowContext>, path: P, width: u32, height: u32, effective_height: u32, offset: i32) -> Tileset {
    let texture = texture_creator
        .load_texture(path.as_ref())
        .unwrap();
    Tileset::new(texture, width, height, effective_height, offset)
}

/// Builds levels from a level collection file in the SLC format.
fn load_slc_file(path: &Path) -> Result<Vec<Level>, error::SokobanError> {
    let mut collection = Vec::new();
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    let parser = EventReader::new(reader);

    let mut level_title = String::new();
    let mut level_str = String::new();
    let mut reading_level = false;
    for e in parser {
        match e {
            Ok(XmlEvent::StartElement {
                ref name,
                ref attributes,
                ..
            }) => {
                if name.local_name == "L" {
                    reading_level = true;
                } else if name.local_name == "Level" {
                    if let Some(id) = attributes.iter().find(|&attr| attr.name.local_name == "Id") {
                        level_title = id.value.clone();
                    }
                }
            }
            Ok(XmlEvent::EndElement { name }) => {
                if name.local_name == "Level" {
                    let mut level = try!(Level::from_str(&level_str));
                    level.set_title(level_title.clone());
                    collection.push(level);
                    level_str.clear();
                }
            }
            Ok(XmlEvent::Characters(ref data)) => {
                if reading_level {
                    level_str.push_str(data);
                    level_str.push('\n');
                }
            }
            _ => {}
        }
    }

    Ok(collection)
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! update-ssh-keys
//!
//! this command allows users of container linux to administer ssh keys

#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate users;

extern crate update_ssh_keys;

use clap::{Arg, App};
use users::get_current_username;

use std::fs::File;

use update_ssh_keys::*;
use update_ssh_keys::errors::*;

#[derive(Clone, Debug)]
struct Config {
    user: String,
    command: Command,
}
#[derive(Clone, Debug)]
enum Command {
    Add {
        name: String,
        force: bool,
        replace: bool,
        stdin: bool,
        keyfiles: Vec<String>,
    },
    Delete { name: String },
    Disable { name: String },
    List,
    Sync,
}

quick_main!(run);

fn run() -> Result<()> {
    let config = config()
        .chain_err(|| format!("command line configuration"))?;

    let user = users::get_user_by_name(&config.user)
        .ok_or(format!("failed to find user with name '{}'", config.user))?;

    let mut aks =  AuthorizedKeys::open(user, true)
        .chain_err(|| format!("failed to open authorized keys directory for user '{}'", config.user))?;

    match config.command {
        Command::Add{name, force, replace, stdin, keyfiles} => {
            let keys = if stdin {
                // read the keys from stdin
                AuthorizedKeys::read_keys(std::io::stdin())?
            } else {
                // keys are in provided files
                let mut keys = vec![];
                for keyfile in keyfiles {
                    let file = File::open(&keyfile)
                        .chain_err(|| format!("failed to open keyfile '{:?}'", keyfile))?;
                    keys.append(&mut AuthorizedKeys::read_keys(file)?);
                }
                keys
            };
            let res = aks.add_keys(&name, keys, replace, force);
            match res {
                Err(Error(ErrorKind::KeysDisabled(name), _)) => println!("Skipping add {} for {}, disabled.", name, config.user),
                Err(Error(ErrorKind::KeysExist(_), _)) => println!("Skipping add {} for {}, already exists.", name, config.user),
                _ => res.chain_err(|| "failed to add keys")?,
            }
        },
        Command::Delete{name} => aks.remove_keys(&name),
        Command::Disable{name} => aks.disable_keys(&name),
        Command::List => {
            let keys = aks.get_all_keys();
            println!("All keys for {}:", config.user);
            for (name, keyset) in keys {
                println!("{}:", name);
                for key in &keyset.keys {
                    println!("{}", key.to_fingerprint_string())
                }
            }
        },
        Command::Sync => {},
    }

    aks.write()
        .chain_err(|| format!("failed to update authorized keys directory"))?;
    aks.sync()
        .chain_err(|| format!("failed to update authorized keys"))?;

    println!("Updated {:?}", aks.file);

    Ok(())
}

fn config() -> Result<Config> {
    // get the default user by figuring out the current user if the current user
    // is root (or doesn't exist) then use core
    let default_user = get_current_username().map_or("core".into(), |u| {
        if u == "root" {
            "core".into()
        } else {
            u
        }
    });

    // setup cli
    // TODO(sdemos): help should print out the default user
    // tried format! but it doesn't seem to like multi-line strings?
    let matches = App::new("update-ssh-keys")
        .version(crate_version!())
        .help("Usage: update-ssh-keys [-l] [-u user] [-a name file1... | -d name]
Options:
    -u USER     Update the given user's authorized_keys file [{}]
    -a NAME     Add the given keys, using the given name to identify them.
    -A NAME     Add the given keys, even if it was disabled with '-D'
    -n          When adding, don't replace an existing key with the given name.
    -d NAME     Delete keys identified by the given name.
    -D NAME     Disable the given set from being added with '-a'
    -l          List the names and number of keys currently installed.
    -h          This ;-)

This tool provides a consistent way for different systems to add ssh public
keys to a given user account, usually the default '${UPDATE_USER}' user.
If -a, -A, -d, nor -D are provided then the authorized_keys file is simply
regenerated using the existing keys.

With the -a option keys may be provided as files on the command line. If no
files are provided with the -a option the keys will be read from stdin.")
        .arg(Arg::with_name("user")
             .short("u")
             .help("Update the given user's authorized_keys file.")
             .takes_value(true))
        .arg(Arg::with_name("no-replace")
             .short("n")
             .help("When adding, don't replace an existing key with the given name."))
        .arg(Arg::with_name("list")
             .short("l")
             .help("List the names and number of keys currently installed."))
        .arg(Arg::with_name("add")
             .short("a")
             .help("Add the given keys, using the given name to identify them.")
             .takes_value(true))
        .arg(Arg::with_name("add-force")
             .short("A")
             .help("Add the given keys, even if it was disabled with '-D'.")
             .takes_value(true))
        .arg(Arg::with_name("delete")
             .short("d")
             .help("Delete keys identified by the given name.")
             .takes_value(true))
        .arg(Arg::with_name("disable")
             .short("D")
             .help("Disable the given set from being added with '-a'.")
             .takes_value(true))
        .arg(Arg::with_name("keys")
             .multiple(true))
        .get_matches();

    let command = matches.value_of("add").map(|name| Command::Add{
            name: name.into(),
            force: false,
            replace: !matches.is_present("no-replace"),
            stdin: !matches.is_present("keys"),
            keyfiles: matches.values_of("keys").map(|vals| vals.map(|s| s.into()).collect::<Vec<_>>()).unwrap_or_default(),
        })
        .or(matches.value_of("add-force").map(|name| Command::Add{
            name: name.into(),
            force: true,
            replace: !matches.is_present("no-replace"),
            stdin: !matches.is_present("keys"),
            keyfiles: matches.values_of("keys").map(|vals| vals.map(|s| s.into()).collect::<Vec<_>>()).unwrap_or_default(),
        }))
        .or(matches.value_of("delete").map(|name| Command::Delete{name: name.into()}))
        .or(matches.value_of("disable").map(|name| Command::Disable{name: name.into()}))
        .unwrap_or(if matches.is_present("list") { Command::List } else { Command::Sync });

    let user = matches.value_of("user")
        .map_or(default_user, String::from);

    Ok(Config {
        user: user,
        command: command,
    })
}
<commit_msg>bin: clippy cleanup<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! update-ssh-keys
//!
//! this command allows users of container linux to administer ssh keys

#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate users;

extern crate update_ssh_keys;

use clap::{Arg, App};
use users::get_current_username;

use std::fs::File;

use update_ssh_keys::*;
use update_ssh_keys::errors::*;

#[derive(Clone, Debug)]
struct Config {
    user: String,
    command: Command,
}
#[derive(Clone, Debug)]
enum Command {
    Add {
        name: String,
        force: bool,
        replace: bool,
        stdin: bool,
        keyfiles: Vec<String>,
    },
    Delete { name: String },
    Disable { name: String },
    List,
    Sync,
}

quick_main!(run);

fn run() -> Result<()> {
    let config = config()
        .chain_err(|| "command line configuration")?;

    let user = users::get_user_by_name(&config.user)
        .ok_or_else(|| format!("failed to find user with name '{}'", config.user))?;

    let mut aks =  AuthorizedKeys::open(user, true)
        .chain_err(|| format!("failed to open authorized keys directory for user '{}'", config.user))?;

    match config.command {
        Command::Add{name, force, replace, stdin, keyfiles} => {
            let keys = if stdin {
                // read the keys from stdin
                AuthorizedKeys::read_keys(std::io::stdin())?
            } else {
                // keys are in provided files
                let mut keys = vec![];
                for keyfile in keyfiles {
                    let file = File::open(&keyfile)
                        .chain_err(|| format!("failed to open keyfile '{:?}'", keyfile))?;
                    keys.append(&mut AuthorizedKeys::read_keys(file)?);
                }
                keys
            };
            let res = aks.add_keys(&name, keys, replace, force);
            match res {
                Err(Error(ErrorKind::KeysDisabled(name), _)) => println!("Skipping add {} for {}, disabled.", name, config.user),
                Err(Error(ErrorKind::KeysExist(_), _)) => println!("Skipping add {} for {}, already exists.", name, config.user),
                _ => res.chain_err(|| "failed to add keys")?,
            }
        },
        Command::Delete{name} => aks.remove_keys(&name),
        Command::Disable{name} => aks.disable_keys(&name),
        Command::List => {
            let keys = aks.get_all_keys();
            println!("All keys for {}:", config.user);
            for (name, keyset) in keys {
                println!("{}:", name);
                for key in &keyset.keys {
                    println!("{}", key.to_fingerprint_string())
                }
            }
        },
        Command::Sync => {},
    }

    aks.write()
        .chain_err(|| "failed to update authorized keys directory")?;
    aks.sync()
        .chain_err(|| "failed to update authorized keys")?;

    println!("Updated {:?}", aks.file);

    Ok(())
}

fn config() -> Result<Config> {
    // get the default user by figuring out the current user if the current user
    // is root (or doesn't exist) then use core
    let default_user = get_current_username().map_or("core".into(), |u| {
        if u == "root" {
            "core".into()
        } else {
            u
        }
    });

    // setup cli
    // TODO(sdemos): help should print out the default user
    // tried format! but it doesn't seem to like multi-line strings?
    let matches = App::new("update-ssh-keys")
        .version(crate_version!())
        .help("Usage: update-ssh-keys [-l] [-u user] [-a name file1... | -d name]
Options:
    -u USER     Update the given user's authorized_keys file [{}]
    -a NAME     Add the given keys, using the given name to identify them.
    -A NAME     Add the given keys, even if it was disabled with '-D'
    -n          When adding, don't replace an existing key with the given name.
    -d NAME     Delete keys identified by the given name.
    -D NAME     Disable the given set from being added with '-a'
    -l          List the names and number of keys currently installed.
    -h          This ;-)

This tool provides a consistent way for different systems to add ssh public
keys to a given user account, usually the default '${UPDATE_USER}' user.
If -a, -A, -d, nor -D are provided then the authorized_keys file is simply
regenerated using the existing keys.

With the -a option keys may be provided as files on the command line. If no
files are provided with the -a option the keys will be read from stdin.")
        .arg(Arg::with_name("user")
             .short("u")
             .help("Update the given user's authorized_keys file.")
             .takes_value(true))
        .arg(Arg::with_name("no-replace")
             .short("n")
             .help("When adding, don't replace an existing key with the given name."))
        .arg(Arg::with_name("list")
             .short("l")
             .help("List the names and number of keys currently installed."))
        .arg(Arg::with_name("add")
             .short("a")
             .help("Add the given keys, using the given name to identify them.")
             .takes_value(true))
        .arg(Arg::with_name("add-force")
             .short("A")
             .help("Add the given keys, even if it was disabled with '-D'.")
             .takes_value(true))
        .arg(Arg::with_name("delete")
             .short("d")
             .help("Delete keys identified by the given name.")
             .takes_value(true))
        .arg(Arg::with_name("disable")
             .short("D")
             .help("Disable the given set from being added with '-a'.")
             .takes_value(true))
        .arg(Arg::with_name("keys")
             .multiple(true))
        .get_matches();

    let command = matches.value_of("add").map(|name| Command::Add{
            name: name.into(),
            force: false,
            replace: !matches.is_present("no-replace"),
            stdin: !matches.is_present("keys"),
            keyfiles: matches.values_of("keys").map(|vals| vals.map(|s| s.into()).collect::<Vec<_>>()).unwrap_or_default(),
        })
        .or_else(|| matches.value_of("add-force").map(|name| Command::Add{
            name: name.into(),
            force: true,
            replace: !matches.is_present("no-replace"),
            stdin: !matches.is_present("keys"),
            keyfiles: matches.values_of("keys").map(|vals| vals.map(|s| s.into()).collect::<Vec<_>>()).unwrap_or_default(),
        }))
        .or_else(|| matches.value_of("delete").map(|name| Command::Delete{name: name.into()}))
        .or_else(|| matches.value_of("disable").map(|name| Command::Disable{name: name.into()}))
        .unwrap_or(if matches.is_present("list") { Command::List } else { Command::Sync });

    let user = matches.value_of("user")
        .map_or(default_user, String::from);

    Ok(Config {
        user: user,
        command: command,
    })
}
<|endoftext|>


<commit_before>//! Client for tldr-pages writting in Rust

#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate hyper;
extern crate clap;
#[macro_use]
extern crate quick_error;

use std::io::{stderr, stdout, Read, Write};
use clap::{Arg, App};
use hyper::client::response::Response as HttpResponse;

#[cfg(target_os = "macos")]
const PLATFORM: &'static str = "osx";
#[cfg(not(target_os = "macos"))]
const PLATFORM: &'static str = "linux";

fn fetch_tldr(command: &str, platform: &str) -> Result<HttpResponse, Error> {
    let client = hyper::Client::new();
    let url = format!("http://raw.github.com/rprieto/tldr/master/pages/{platform}/{page}.md",
                      platform = platform,
                      page = command);

    let res = try!(client.get(&url)
                         .header(hyper::header::Connection::close())
                         .header(hyper::header::ContentType::plaintext())
                         .send()
                         .map_err(|err| Error::HttpRequest(command.to_owned(), err)));

    if res.status.is_success() {
        Ok(res)
    } else {
        Err(Error::HttpReponse(command.to_owned(), res.status))
    }
}

fn render_tldr<R: Read>(text: &mut R) -> Result<(), Error> {
    pipe(text, &mut stdout())
}

fn pipe<R: Read, W: Write>(input: &mut R, output: &mut W) -> Result<(), Error> {
    let mut buffer = [0; 1024];

    loop {
        let written = try!(input.read(&mut buffer));
        if written == 0 { break; }
        try!(output.write_all(&buffer[0..written]));
        buffer = [0; 1024];
    }

    Ok(())
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        HttpRequest(command: String, err: hyper::Error) {
            from(err)
            cause(err)
            description("Error fetching page")
            display("Error fetching description for `{}`: {}", command, err)
        }
        HttpReponse(command: String, status: hyper::status::StatusCode) {
            description("Could not fetch description for command")
            display("Could not fetch description for command `{}`: {}", command, status)
        }
        Io(err: std::io::Error) {
            from()
            cause(err)
            description(err.description())
            display("Couldn't read stream")
        }
    }
}

fn main() {
    let matches = App::new("tldr")
                      .version(env!("CARGO_PKG_VERSION"))
                      .author("Pascal Hertleif <killercup@gmail.com>")
                      .about("Simplified and community-driven man pages")
                      .arg(Arg::with_name("command")
                               .help("Fetch the docs for command and render them to the \
                                      terminal.")
                               .required(true)
                               .index(1))
                      .get_matches();

    let command = matches.value_of("command").unwrap();

    fetch_tldr(command, "common")
        .or_else(|_| fetch_tldr(command, PLATFORM))
        .and_then(|mut res| render_tldr(&mut res))
        .unwrap_or_else(|err| {
            writeln!(stderr(), "{}", err).unwrap();
            std::process::exit(1);
        });
}
<commit_msg>feat(fetch): Accept Header<commit_after>//! Client for tldr-pages writting in Rust

#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate hyper;
extern crate clap;
#[macro_use]
extern crate quick_error;

use std::io::{stderr, stdout, Read, Write};
use clap::{Arg, App};
use hyper::client::response::Response as HttpResponse;
use hyper::header::{Connection, Accept, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

#[cfg(target_os = "macos")]
const PLATFORM: &'static str = "osx";
#[cfg(not(target_os = "macos"))]
const PLATFORM: &'static str = "linux";

fn fetch_tldr(command: &str, platform: &str) -> Result<HttpResponse, Error> {
    let client = hyper::Client::new();
    let url = format!("http://raw.github.com/rprieto/tldr/master/pages/{platform}/{page}.md",
                      platform = platform,
                      page = command);

    let res = try!(client.get(&url)
                         .header(Connection::close())
                         .header(Accept(vec![
                            qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![])),
                         ]))
                         .send()
                         .map_err(|err| Error::HttpRequest(command.to_owned(), err)));

    if res.status.is_success() {
        Ok(res)
    } else {
        Err(Error::HttpReponse(command.to_owned(), res.status))
    }
}

fn render_tldr<R: Read>(text: &mut R) -> Result<(), Error> {
    pipe(text, &mut stdout())
}

fn pipe<R: Read, W: Write>(input: &mut R, output: &mut W) -> Result<(), Error> {
    let mut buffer = [0; 1024];

    loop {
        let written = try!(input.read(&mut buffer));
        if written == 0 { break; }
        try!(output.write_all(&buffer[0..written]));
        buffer = [0; 1024];
    }

    Ok(())
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        HttpRequest(command: String, err: hyper::Error) {
            from(err)
            cause(err)
            description("Error fetching page")
            display("Error fetching description for `{}`: {}", command, err)
        }
        HttpReponse(command: String, status: hyper::status::StatusCode) {
            description("Could not fetch description for command")
            display("Could not fetch description for command `{}`: {}", command, status)
        }
        Io(err: std::io::Error) {
            from()
            cause(err)
            description(err.description())
            display("Couldn't read stream")
        }
    }
}

fn main() {
    let matches = App::new("tldr")
                      .version(env!("CARGO_PKG_VERSION"))
                      .author("Pascal Hertleif <killercup@gmail.com>")
                      .about("Simplified and community-driven man pages")
                      .arg(Arg::with_name("command")
                               .help("Fetch the docs for command and render them to the \
                                      terminal.")
                               .required(true)
                               .index(1))
                      .get_matches();

    let command = matches.value_of("command").unwrap();

    fetch_tldr(command, "common")
        .or_else(|_| fetch_tldr(command, PLATFORM))
        .and_then(|mut res| render_tldr(&mut res))
        .unwrap_or_else(|err| {
            writeln!(stderr(), "{}", err).unwrap();
            std::process::exit(1);
        });
}
<|endoftext|>