<commit_before>use rusqlite::{Connection, Result};
use tagged_rusqlite::tagged_sql;

fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;

    tagged_sql!(
        CreateTable,
        "CREATE TABLE person (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  data            BLOB
                  );"
    );

    CreateTable::prepare(&conn).execute()?;

    tagged_sql!(
        InsertPerson,
        r#"INSERT INTO
                person (name, data)
                VALUES (
                    ?1 /*:name:String*/,
                    ?2 /*:data:Option<Vec<u8>>*/
                );
                "#
    );

    let mut insert = InsertPerson::prepare(&conn);
    insert.execute_bind(&InsertPersonParams {
        name: "Steven".to_string(),
        data: Some(vec![1u8, 2u8]),
    })?;
    insert.execute_bind(&InsertPersonParams {
        name: "John".to_string(),
        data: None,
    })?;
    insert.execute_bind(&InsertPersonParams {
        name: "Bill".to_string(),
        data: None,
    })?;

    tagged_sql!(
        SelectPerson,
        r#"SELECT
                            id   /*:i64*/,
                            name /*:String*/,
                            data /*:Option<Vec<u8>>*/
                            FROM person;
                            "#
    );

    let mut stmt = SelectPerson::prepare(&conn);
    let person_iterator = stmt.query()?;

    for person in person_iterator {
        println!("Found person {:?}", &person.unwrap());
    }

    tagged_sql!(
        SearchByName,
        r#"SELECT
                            id   /*:i64*/,
                            name /*:String*/,
                            data /*:Option<Vec<u8>>*/
                            FROM person
                            WHERE name = ? /*:name:String*/;
                            "#
    );
    let search_params = SearchByNameParams {
        name: "John".into(),
    };
    for person in SearchByName::prepare(&conn).query_bind(&search_params)? {
        println!(
            "Found person with name {}  {:?}",
            &search_params.name,
            &person.unwrap()
        );
    }

    let mut stmt = SelectPerson::prepare(&conn);
    println!("Found single person {:?} ", stmt.query_row()?);

    let mut stmt = SearchByName::prepare(&conn);
    let search_params = SearchByNameParams {
        name: "Bill".into(),
    };
    println!(
        "Found single person with name {}, {:?} ",
        &search_params.name,
        stmt.query_row_bind(&search_params)?
    );

    Ok(())
}
<commit_msg>Added output to end as comment to tagged_rusqlite_example<commit_after>use rusqlite::{Connection, Result};
use tagged_rusqlite::tagged_sql;

fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;

    tagged_sql!(
        CreateTable,
        "CREATE TABLE person (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  data            BLOB
                  );"
    );

    CreateTable::prepare(&conn).execute()?;

    tagged_sql!(
    tagged_sql!(
        InsertPerson,
        r#"INSERT INTO
                person (name, data)
                VALUES (
                    ?1 /*:name:String*/,
                    ?2 /*:data:Option<Vec<u8>>*/
                );
                "#
    );

    let mut insert = InsertPerson::prepare(&conn);
    insert.execute_bind(&InsertPersonParams {
        name: "Steven".to_string(),
        data: Some(vec![1u8, 2u8]),
    })?;
    insert.execute_bind(&InsertPersonParams {
        name: "John".to_string(),
        data: None,
    })?;
    insert.execute_bind(&InsertPersonParams {
        name: "Bill".to_string(),
        data: None,
    })?;

    tagged_sql!(
        SelectPerson,
        r#"SELECT
                            id   /*:i64*/,
                            name /*:String*/,
                            data /*:Option<Vec<u8>>*/
                            FROM person;
                            "#
    );

    let mut stmt = SelectPerson::prepare(&conn);
    let person_iterator = stmt.query()?;

    for person in person_iterator {
        println!("Found person {:?}", &person.unwrap());
    }

    tagged_sql!(
        SearchByName,
        r#"SELECT
                            id   /*:i64*/,
                            name /*:String*/,
                            data /*:Option<Vec<u8>>*/
                            FROM person
                            WHERE name = ? /*:name:String*/;
                            "#
    );
    let search_params = SearchByNameParams {
        name: "John".into(),
    };
    for person in SearchByName::prepare(&conn).query_bind(&search_params)? {
        println!(
            "Found person with name {}  {:?}",
            &search_params.name,
            &person.unwrap()
        );
    }

    let mut stmt = SelectPerson::prepare(&conn);
    println!("Found single person {:?} ", stmt.query_row()?);

    let mut stmt = SearchByName::prepare(&conn);
    let search_params = SearchByNameParams {
        name: "Bill".into(),
    };
    println!(
        "Found single person with name {}, {:?} ",
        &search_params.name,
        stmt.query_row_bind(&search_params)?
    );

    Ok(())
}

/* Output
Found person SelectPersonRow { id: 1, name: "Steven", data: Some([1, 2]) }
Found person SelectPersonRow { id: 2, name: "John", data: None }
Found person SelectPersonRow { id: 3, name: "Bill", data: None }
Found person with name John  SearchByNameRow { id: 2, name: "John", data: None }
Found single person SelectPersonRow { id: 1, name: "Steven", data: Some([1, 2]) }
Found single person with name Bill, SearchByNameRow { id: 3, name: "Bill", data: None }
 */
<|endoftext|>


<commit_before>//! Tests specific to declarative macros, aka macros by example. This covers
//! both stable `macro_rules!` macros as well as unstable `macro` macros.

mod tt_conversion;
mod matching;
mod meta_syntax;

use expect_test::expect;

use crate::macro_expansion_tests::check;

#[test]
fn expansion_does_not_parse_as_expression() {
    check(
        r#"
macro_rules! stmts {
    () => { let _ = 0; }
}

fn f() { let _ = stmts!(); }
"#,
        expect![[r#"
macro_rules! stmts {
    () => { let _ = 0; }
}

fn f() { let _ = /* error: could not convert tokens */; }
"#]],
    )
}

#[test]
fn wrong_nesting_level() {
    check(
        r#"
macro_rules! m {
    ($($i:ident);*) => ($i)
}
m!{a}
"#,
        expect![[r#"
macro_rules! m {
    ($($i:ident);*) => ($i)
}
/* error: expected simple binding, found nested binding `i` */
"#]],
    );
}

#[test]
fn match_by_first_token_literally() {
    check(
        r#"
macro_rules! m {
    ($ i:ident) => ( mod $ i {} );
    (= $ i:ident) => ( fn $ i() {} );
    (+ $ i:ident) => ( struct $ i; )
}
m! { foo }
m! { = bar }
m! { + Baz }
"#,
        expect![[r#"
macro_rules! m {
    ($ i:ident) => ( mod $ i {} );
    (= $ i:ident) => ( fn $ i() {} );
    (+ $ i:ident) => ( struct $ i; )
}
mod foo {}
fn bar() {}
struct Baz;
"#]],
    );
}

#[test]
fn match_by_last_token_literally() {
    check(
        r#"
macro_rules! m {
    ($ i:ident) => ( mod $ i {} );
    ($ i:ident =) => ( fn $ i() {} );
    ($ i:ident +) => ( struct $ i; )
}
m! { foo }
m! { bar = }
m! { Baz + }
"#,
        expect![[r#"
macro_rules! m {
    ($ i:ident) => ( mod $ i {} );
    ($ i:ident =) => ( fn $ i() {} );
    ($ i:ident +) => ( struct $ i; )
}
mod foo {}
fn bar() {}
struct Baz;
"#]],
    );
}

#[test]
fn match_by_ident() {
    check(
        r#"
macro_rules! m {
    ($ i:ident) => ( mod $ i {} );
    (spam $ i:ident) => ( fn $ i() {} );
    (eggs $ i:ident) => ( struct $ i; )
}
m! { foo }
m! { spam bar }
m! { eggs Baz }
"#,
        expect![[r#"
macro_rules! m {
    ($ i:ident) => ( mod $ i {} );
    (spam $ i:ident) => ( fn $ i() {} );
    (eggs $ i:ident) => ( struct $ i; )
}
mod foo {}
fn bar() {}
struct Baz;
"#]],
    );
}

#[test]
fn match_by_separator_token() {
    check(
        r#"
macro_rules! m {
    ($ ($ i:ident),*) => ($ ( mod $ i {} )*);
    ($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
    ($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
}

m! { foo, bar }

m! { foo# bar }

m! { Foo,# Bar }
"#,
        expect![[r##"
macro_rules! m {
    ($ ($ i:ident),*) => ($ ( mod $ i {} )*);
    ($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
    ($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
}

mod foo {}
mod bar {}

fn foo() {}
fn bar() {}

struct Foo;
struct Bar;
"##]],
    );
}

#[test]
fn test_match_group_pattern_with_multiple_defs() {
    check(
        r#"
macro_rules! m {
    ($ ($ i:ident),*) => ( impl Bar { $ ( fn $ i {} )*} );
}
m! { foo, bar }
"#,
        expect![[r#"
macro_rules! m {
    ($ ($ i:ident),*) => ( impl Bar { $ ( fn $ i {} )*} );
}
impl Bar {
fn foo {}
fn bar {}
}
"#]],
    );
}

#[test]
fn test_match_group_pattern_with_multiple_statement() {
    check(
        r#"
macro_rules! m {
    ($ ($ i:ident),*) => ( fn baz { $ ( $ i (); )*} );
}
m! { foo, bar }
"#,
        expect![[r#"
macro_rules! m {
    ($ ($ i:ident),*) => ( fn baz { $ ( $ i (); )*} );
}
fn baz {
foo();
bar();
}
"#]],
    )
}

#[test]
fn test_match_group_pattern_with_multiple_statement_without_semi() {
    check(
        r#"
macro_rules! m {
    ($ ($ i:ident),*) => ( fn baz { $ ( $i() );*} );
}
m! { foo, bar }
"#,
        expect![[r#"
macro_rules! m {
    ($ ($ i:ident),*) => ( fn baz { $ ( $i() );*} );
}
fn baz {
foo();
bar()
}
"#]],
    )
}
<commit_msg>align tests to code style<commit_after>//! Tests specific to declarative macros, aka macros by example. This covers
//! both stable `macro_rules!` macros as well as unstable `macro` macros.

mod tt_conversion;
mod matching;
mod meta_syntax;

use expect_test::expect;

use crate::macro_expansion_tests::check;

#[test]
fn expansion_does_not_parse_as_expression() {
    check(
        r#"
macro_rules! stmts {
    () => { let _ = 0; }
}

fn f() { let _ = stmts!(); }
"#,
        expect![[r#"
macro_rules! stmts {
    () => { let _ = 0; }
}

fn f() { let _ = /* error: could not convert tokens */; }
"#]],
    )
}

#[test]
fn wrong_nesting_level() {
    check(
        r#"
macro_rules! m {
    ($($i:ident);*) => ($i)
}
m!{a}
"#,
        expect![[r#"
macro_rules! m {
    ($($i:ident);*) => ($i)
}
/* error: expected simple binding, found nested binding `i` */
"#]],
    );
}

#[test]
fn match_by_first_token_literally() {
    check(
        r#"
macro_rules! m {
    ($i:ident) => ( mod $i {} );
    (= $i:ident) => ( fn $i() {} );
    (+ $i:ident) => ( struct $i; )
}
m! { foo }
m! { = bar }
m! { + Baz }
"#,
        expect![[r#"
macro_rules! m {
    ($i:ident) => ( mod $i {} );
    (= $i:ident) => ( fn $i() {} );
    (+ $i:ident) => ( struct $i; )
}
mod foo {}
fn bar() {}
struct Baz;
"#]],
    );
}

#[test]
fn match_by_last_token_literally() {
    check(
        r#"
macro_rules! m {
    ($i:ident) => ( mod $i {} );
    ($i:ident =) => ( fn $i() {} );
    ($i:ident +) => ( struct $i; )
}
m! { foo }
m! { bar = }
m! { Baz + }
"#,
        expect![[r#"
macro_rules! m {
    ($i:ident) => ( mod $i {} );
    ($i:ident =) => ( fn $i() {} );
    ($i:ident +) => ( struct $i; )
}
mod foo {}
fn bar() {}
struct Baz;
"#]],
    );
}

#[test]
fn match_by_ident() {
    check(
        r#"
macro_rules! m {
    ($i:ident) => ( mod $i {} );
    (spam $i:ident) => ( fn $i() {} );
    (eggs $i:ident) => ( struct $i; )
}
m! { foo }
m! { spam bar }
m! { eggs Baz }
"#,
        expect![[r#"
macro_rules! m {
    ($i:ident) => ( mod $i {} );
    (spam $i:ident) => ( fn $i() {} );
    (eggs $i:ident) => ( struct $i; )
}
mod foo {}
fn bar() {}
struct Baz;
"#]],
    );
}

#[test]
fn match_by_separator_token() {
    check(
        r#"
macro_rules! m {
    ($($i:ident),*) => ($(mod $i {} )*);
    ($($i:ident)#*) => ($(fn $i() {} )*);
    ($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
}

m! { foo, bar }

m! { foo# bar }

m! { Foo,# Bar }
"#,
        expect![[r##"
macro_rules! m {
    ($($i:ident),*) => ($(mod $i {} )*);
    ($($i:ident)#*) => ($(fn $i() {} )*);
    ($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
}

mod foo {}
mod bar {}

fn foo() {}
fn bar() {}

struct Foo;
struct Bar;
"##]],
    );
}

#[test]
fn test_match_group_pattern_with_multiple_defs() {
    check(
        r#"
macro_rules! m {
    ($($i:ident),*) => ( impl Bar { $(fn $i {})* } );
}
m! { foo, bar }
"#,
        expect![[r#"
macro_rules! m {
    ($($i:ident),*) => ( impl Bar { $(fn $i {})* } );
}
impl Bar {
fn foo {}
fn bar {}
}
"#]],
    );
}

#[test]
fn test_match_group_pattern_with_multiple_statement() {
    check(
        r#"
macro_rules! m {
    ($($i:ident),*) => ( fn baz { $($i ();)* } );
}
m! { foo, bar }
"#,
        expect![[r#"
macro_rules! m {
    ($($i:ident),*) => ( fn baz { $($i ();)* } );
}
fn baz {
foo();
bar();
}
"#]],
    )
}

#[test]
fn test_match_group_pattern_with_multiple_statement_without_semi() {
    check(
        r#"
macro_rules! m {
    ($($i:ident),*) => ( fn baz { $($i() );* } );
}
m! { foo, bar }
"#,
        expect![[r#"
macro_rules! m {
    ($($i:ident),*) => ( fn baz { $($i() );* } );
}
fn baz {
foo();
bar()
}
"#]],
    )
}
<|endoftext|>


<commit_before>#![warn(clippy::unnecessary_wrap)]
#![allow(clippy::no_effect)]
#![allow(clippy::needless_return)]
#![allow(clippy::if_same_then_else)]
#![allow(dead_code)]

// should be linted
fn func1(a: bool, b: bool) -> Option<i32> {
    if a && b {
        return Some(42);
    }
    if a {
        Some(-1);
        Some(2)
    } else {
        return Some(1337);
    }
}

// should be linted
fn func2(a: bool, b: bool) -> Option<i32> {
    if a && b {
        return Some(10);
    }
    if a {
        Some(20)
    } else {
        Some(30)
    }
}

// public fns should not be linted
pub fn func3(a: bool) -> Option<i32> {
    if a {
        Some(1)
    } else {
        Some(1)
    }
}

// should not be linted
fn func4(a: bool) -> Option<i32> {
    if a {
        Some(1)
    } else {
        None
    }
}

// should be linted
fn func5() -> Option<i32> {
    Some(1)
}

// should not be linted
fn func6() -> Option<i32> {
    None
}

// should be linted
fn func7() -> Result<i32, ()> {
    Ok(1)
}

// should not be linted
fn func8(a: bool) -> Result<i32, ()> {
    if a {
        Ok(1)
    } else {
        Err(())
    }
}

// should not be linted
fn func9(a: bool) -> Result<i32, ()> {
    Err(())
}

// should not be linted
fn func10() -> Option<()> {
    unimplemented!()
}

struct A;

impl A {
    // should not be linted
    pub fn func11() -> Option<i32> {
        Some(1)
    }

    // should be linted
    fn func12() -> Option<i32> {
        Some(1)
    }
}

trait B {
    // trait impls are not linted
    fn func13() -> Option<i32> {
        Some(1)
    }
}

impl A for B {
    // trait impls are not linted
    fn func13() -> Option<i32> {
        Some(0)
    }
}

fn main() {
    // method calls are not linted
    func1(true, true);
    func2(true, true);
}
<commit_msg>Fix embarrassing grammatical error<commit_after>#![warn(clippy::unnecessary_wrap)]
#![allow(clippy::no_effect)]
#![allow(clippy::needless_return)]
#![allow(clippy::if_same_then_else)]
#![allow(dead_code)]

// should be linted
fn func1(a: bool, b: bool) -> Option<i32> {
    if a && b {
        return Some(42);
    }
    if a {
        Some(-1);
        Some(2)
    } else {
        return Some(1337);
    }
}

// should be linted
fn func2(a: bool, b: bool) -> Option<i32> {
    if a && b {
        return Some(10);
    }
    if a {
        Some(20)
    } else {
        Some(30)
    }
}

// public fns should not be linted
pub fn func3(a: bool) -> Option<i32> {
    if a {
        Some(1)
    } else {
        Some(1)
    }
}

// should not be linted
fn func4(a: bool) -> Option<i32> {
    if a {
        Some(1)
    } else {
        None
    }
}

// should be linted
fn func5() -> Option<i32> {
    Some(1)
}

// should not be linted
fn func6() -> Option<i32> {
    None
}

// should be linted
fn func7() -> Result<i32, ()> {
    Ok(1)
}

// should not be linted
fn func8(a: bool) -> Result<i32, ()> {
    if a {
        Ok(1)
    } else {
        Err(())
    }
}

// should not be linted
fn func9(a: bool) -> Result<i32, ()> {
    Err(())
}

// should not be linted
fn func10() -> Option<()> {
    unimplemented!()
}

struct A;

impl A {
    // should not be linted
    pub fn func11() -> Option<i32> {
        Some(1)
    }

    // should be linted
    fn func12() -> Option<i32> {
        Some(1)
    }
}

trait B {
    // trait impls are not linted
    fn func13() -> Option<i32> {
        Some(1)
    }
}

impl B for A {
    // trait impls are not linted
    fn func13() -> Option<i32> {
        Some(0)
    }
}

fn main() {
    // method calls are not linted
    func1(true, true);
    func2(true, true);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for reporting errors to an LSP client
use crate::lsp::{
    publish_diagnostic, Diagnostic, DiagnosticSeverity, Position, PublishDiagnosticsParams, Range,
    Url,
};
use common::{Diagnostic as CompilerDiagnostic, Location};
use crossbeam::crossbeam_channel::Sender;
use lsp_server::Message;
use relay_compiler::{
    errors::{BuildProjectError, Error},
    source_for_location, FsSourceReader, SourceReader,
};
use std::{
    collections::{hash_map::Entry, HashMap},
    path::PathBuf,
    sync::{Arc, RwLock},
};

/// Converts a Location to a Url pointing to the canonical path based on the root_dir provided.
/// Returns None if we are unable to do the conversion
fn url_from_location(location: Location, root_dir: &PathBuf) -> Option<Url> {
    let file_path = location.source_location().path();
    let canonical_path = std::fs::canonicalize(root_dir.join(file_path)).ok()?;
    Url::from_file_path(canonical_path).ok()
}

#[derive(Default)]
struct DiagnosticSet {
    /// Stores the diagnostics from IDE source, which will be updated on any text change
    quick_diagnostics: Vec<Diagnostic>,
    /// Stores the diagnostics from watchman source, which will be updated on file save
    regular_diagnostics: Vec<Diagnostic>,
}

pub struct DiagnosticReporter {
    active_diagnostics: Arc<RwLock<HashMap<Url, DiagnosticSet>>>,
    sender: Sender<Message>,
    root_dir: PathBuf,
    source_reader: Box<dyn SourceReader + Send + Sync>,
}

impl DiagnosticReporter {
    pub fn new(root_dir: PathBuf, sender: Sender<Message>) -> Self {
        Self {
            active_diagnostics: Default::default(),
            sender,
            root_dir,
            source_reader: Box::new(FsSourceReader),
        }
    }

    pub fn clear_regular_diagnostics(&self) {
        let mut active_diagnostics = self
            .active_diagnostics
            .write()
            .expect("build_finishes: could not acquire write lock for self.active_diagnostics");
        for diagnostics in active_diagnostics.values_mut() {
            diagnostics.regular_diagnostics.clear();
        }
        active_diagnostics.retain(|_, diagnostics| {
            !diagnostics.regular_diagnostics.is_empty() || !diagnostics.quick_diagnostics.is_empty()
        })
    }

    pub fn report_error(&self, error: &Error) {
        match error {
            Error::DiagnosticsError { errors } => {
                for diagnostic in errors {
                    self.report_diagnostic(diagnostic);
                }
            }
            Error::BuildProjectsErrors { errors } => {
                for error in errors {
                    self.print_project_error(error);
                }
            }
            Error::Cancelled => {
                // Ignore the cancellation
            }
            error => {
                self.print_generic_error(format!("{}", error));
            }
        }
    }

    pub fn commit_diagnostics(&self) {
        for (url, diagnostics) in self
            .active_diagnostics
            .read()
            .expect("commit_diagnostic: could not acquire read lock for self.active_diagnostics")
            .iter()
        {
            self.publish_diangostics_set(url, diagnostics)
        }
    }

    fn add_diagnostic(&self, url: Url, diagnostic: Diagnostic) {
        self.active_diagnostics
            .write()
            .expect("add_diagnostic: could not acquire write lock for self.active_diagnostics")
            .entry(url)
            .or_default()
            .regular_diagnostics
            .push(diagnostic);
    }

    pub fn update_quick_diagnostics_for_url(&self, url: Url, diagnostics: Vec<Diagnostic>) {
        match self.active_diagnostics
            .write()
            .expect("update_quick_diagnostics_for_url: could not acquire write lock for self.active_diagnostics")
            .entry(url.clone()) {
                Entry::Occupied(mut e) => {
                    let data = e.get_mut();
                    if data.quick_diagnostics != diagnostics {
                        data.quick_diagnostics = diagnostics;
                        self.publish_diangostics_set(&url, data);
                    }
                }
                Entry::Vacant(e) => {
                    if !diagnostics.is_empty() {
                        let data = DiagnosticSet {
                            regular_diagnostics: vec![],
                            quick_diagnostics: diagnostics
                        };
                        self.publish_diangostics_set(&url, &data);
                        e.insert(data);
                    }
                }
            }
    }

    pub fn clear_quick_diagnostics_for_url(&self, url: &Url) {
        if let Some(diagnostics) = self.active_diagnostics
            .write()
            .expect("update_quick_diagnostics_for_url: could not acquire write lock for self.active_diagnostics")
            .get_mut(url) {
                if !diagnostics.quick_diagnostics.is_empty() {
                    diagnostics.quick_diagnostics.clear();
                    self.publish_diangostics_set(url, diagnostics)
                }
            }
    }

    fn publish_diangostics_set(&self, url: &Url, diagnostics: &DiagnosticSet) {
        let mut next_diagnostics = diagnostics.quick_diagnostics.clone();
        for diagnostic in &diagnostics.regular_diagnostics {
            if !next_diagnostics
                .iter()
                .any(|prev_diag| prev_diag.eq(&diagnostic))
            {
                next_diagnostics.push(diagnostic.clone());
            }
        }
        let params = PublishDiagnosticsParams {
            diagnostics: next_diagnostics,
            uri: url.clone(),
            version: None,
        };
        publish_diagnostic(params, &self.sender).ok();
    }

    #[cfg(test)]
    fn set_source_reader(&mut self, source_reader: Box<dyn SourceReader + Send + Sync>) {
        self.source_reader = source_reader;
    }

    fn report_diagnostic(&self, diagnostic: &CompilerDiagnostic) {
        let message = diagnostic.message().to_string();

        let location = diagnostic.location();

        let url = match url_from_location(location, &self.root_dir) {
            Some(url) => url,
            None => {
                // TODO(brandondail) we should always be able to parse as a Url, so log here when we don't
                if let Ok(root) = Url::from_directory_path(&self.root_dir) {
                    root
                } else {
                    return;
                }
            }
        };

        let source = if let Some(source) = source_for_location(
            &self.root_dir,
            location.source_location(),
            self.source_reader.as_ref(),
        ) {
            source
        } else {
            return;
        };

        let range = location
            .span()
            .to_range(&source.text, source.line_index, source.column_index);

        let diagnostic = Diagnostic {
            code: None,
            message,
            range,
            related_information: None,
            severity: Some(DiagnosticSeverity::Error),
            source: None,
            tags: None,
        };
        self.add_diagnostic(url, diagnostic);
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        match error {
            BuildProjectError::ValidationErrors { errors } => {
                for diagnostic in errors {
                    self.report_diagnostic(diagnostic);
                }
            }
            BuildProjectError::PersistErrors { errors } => {
                for error in errors {
                    self.print_generic_error(format!("{}", error));
                }
            }
            _ => {
                self.print_generic_error(format!("{}", error));
            }
        }
    }

    fn print_generic_error(&self, message: String) {
        let diagnostic = Diagnostic {
            code: None,
            message,
            range: Range::new(Position::new(0, 0), Position::new(0, 0)),
            related_information: None,
            severity: Some(DiagnosticSeverity::Error),
            source: None,
            tags: None,
        };
        let url = Url::from_directory_path(&self.root_dir)
            .expect("print_generic_error: Could not convert self.root_dir to Url");
        self.add_diagnostic(url, diagnostic);
    }
}

#[cfg(test)]
mod tests {
    use super::DiagnosticReporter;
    use common::{Diagnostic, Location, SourceLocationKey, Span};
    use crossbeam::crossbeam_channel;
    use interner::Intern;
    use relay_compiler::SourceReader;
    use std::path::PathBuf;

    struct MockSourceReader(String);

    impl SourceReader for MockSourceReader {
        fn read_to_string(&self, _path: &PathBuf) -> std::io::Result<String> {
            Ok(self.0.to_string())
        }
    }

    #[test]
    fn report_diagnostic_test() {
        let root_dir = PathBuf::from("/tmp");
        let (sender, _) = crossbeam_channel::unbounded();
        let mut reporter = DiagnosticReporter::new(root_dir, sender);
        reporter.set_source_reader(Box::new(MockSourceReader("Content".to_string())));
        let source_location = SourceLocationKey::Standalone {
            path: "foo.txt".intern(),
        };
        assert_eq!(reporter.active_diagnostics.read().unwrap().len(), 0);
        reporter.report_diagnostic(&Diagnostic::error(
            "test message",
            Location::new(source_location, Span { start: 0, end: 1 }),
        ));
        assert_eq!(reporter.active_diagnostics.read().unwrap().len(), 1);
    }

    /// This test will assert that the message without URL (with generated source) won't be reported by LSPStatusReporter
    /// I'm not sure if this is the right behavior, but lets capture it here.
    #[test]
    fn do_not_report_diagnostic_without_url_test() {
        let root_dir = PathBuf::from("/tmp");
        let (sender, _) = crossbeam_channel::unbounded();

        let mut reporter = DiagnosticReporter::new(root_dir, sender);
        reporter.set_source_reader(Box::new(MockSourceReader("".to_string())));

        reporter.report_diagnostic(&Diagnostic::error("-", Location::generated()));
        assert_eq!(reporter.active_diagnostics.read().unwrap().len(), 0);
    }
}
<commit_msg>Fix clearing regular diagnostics<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for reporting errors to an LSP client
use crate::lsp::{
    publish_diagnostic, Diagnostic, DiagnosticSeverity, Position, PublishDiagnosticsParams, Range,
    Url,
};
use common::{Diagnostic as CompilerDiagnostic, Location};
use crossbeam::crossbeam_channel::Sender;
use lsp_server::Message;
use relay_compiler::{
    errors::{BuildProjectError, Error},
    source_for_location, FsSourceReader, SourceReader,
};
use std::{
    collections::{hash_map::Entry, HashMap},
    path::PathBuf,
    sync::{Arc, RwLock},
};

/// Converts a Location to a Url pointing to the canonical path based on the root_dir provided.
/// Returns None if we are unable to do the conversion
fn url_from_location(location: Location, root_dir: &PathBuf) -> Option<Url> {
    let file_path = location.source_location().path();
    let canonical_path = std::fs::canonicalize(root_dir.join(file_path)).ok()?;
    Url::from_file_path(canonical_path).ok()
}

#[derive(Default)]
struct DiagnosticSet {
    /// Stores the diagnostics from IDE source, which will be updated on any text change
    quick_diagnostics: Vec<Diagnostic>,
    /// Stores the diagnostics from watchman source, which will be updated on file save
    regular_diagnostics: Vec<Diagnostic>,
}

pub struct DiagnosticReporter {
    active_diagnostics: Arc<RwLock<HashMap<Url, DiagnosticSet>>>,
    sender: Sender<Message>,
    root_dir: PathBuf,
    source_reader: Box<dyn SourceReader + Send + Sync>,
}

impl DiagnosticReporter {
    pub fn new(root_dir: PathBuf, sender: Sender<Message>) -> Self {
        Self {
            active_diagnostics: Default::default(),
            sender,
            root_dir,
            source_reader: Box::new(FsSourceReader),
        }
    }

    pub fn clear_regular_diagnostics(&self) {
        let mut active_diagnostics = self
            .active_diagnostics
            .write()
            .expect("build_finishes: could not acquire write lock for self.active_diagnostics");
        for (url, diagnostics) in active_diagnostics.iter_mut() {
            diagnostics.regular_diagnostics.clear();
            self.publish_diangostics_set(url, diagnostics)
        }
        active_diagnostics.retain(|_, diagnostics| {
            !diagnostics.regular_diagnostics.is_empty() || !diagnostics.quick_diagnostics.is_empty()
        })
    }

    pub fn report_error(&self, error: &Error) {
        match error {
            Error::DiagnosticsError { errors } => {
                for diagnostic in errors {
                    self.report_diagnostic(diagnostic);
                }
            }
            Error::BuildProjectsErrors { errors } => {
                for error in errors {
                    self.print_project_error(error);
                }
            }
            Error::Cancelled => {
                // Ignore the cancellation
            }
            error => {
                self.print_generic_error(format!("{}", error));
            }
        }
    }

    pub fn commit_diagnostics(&self) {
        for (url, diagnostics) in self
            .active_diagnostics
            .read()
            .expect("commit_diagnostic: could not acquire read lock for self.active_diagnostics")
            .iter()
        {
            self.publish_diangostics_set(url, diagnostics)
        }
    }

    fn add_diagnostic(&self, url: Url, diagnostic: Diagnostic) {
        self.active_diagnostics
            .write()
            .expect("add_diagnostic: could not acquire write lock for self.active_diagnostics")
            .entry(url)
            .or_default()
            .regular_diagnostics
            .push(diagnostic);
    }

    pub fn update_quick_diagnostics_for_url(&self, url: Url, diagnostics: Vec<Diagnostic>) {
        match self.active_diagnostics
            .write()
            .expect("update_quick_diagnostics_for_url: could not acquire write lock for self.active_diagnostics")
            .entry(url.clone()) {
                Entry::Occupied(mut e) => {
                    let data = e.get_mut();
                    if data.quick_diagnostics != diagnostics {
                        data.quick_diagnostics = diagnostics;
                        self.publish_diangostics_set(&url, data);
                    }
                }
                Entry::Vacant(e) => {
                    if !diagnostics.is_empty() {
                        let data = DiagnosticSet {
                            regular_diagnostics: vec![],
                            quick_diagnostics: diagnostics
                        };
                        self.publish_diangostics_set(&url, &data);
                        e.insert(data);
                    }
                }
            }
    }

    pub fn clear_quick_diagnostics_for_url(&self, url: &Url) {
        if let Some(diagnostics) = self.active_diagnostics
            .write()
            .expect("update_quick_diagnostics_for_url: could not acquire write lock for self.active_diagnostics")
            .get_mut(url) {
                if !diagnostics.quick_diagnostics.is_empty() {
                    diagnostics.quick_diagnostics.clear();
                    self.publish_diangostics_set(url, diagnostics)
                }
            }
    }

    fn publish_diangostics_set(&self, url: &Url, diagnostics: &DiagnosticSet) {
        let mut next_diagnostics = diagnostics.quick_diagnostics.clone();
        for diagnostic in &diagnostics.regular_diagnostics {
            if !next_diagnostics
                .iter()
                .any(|prev_diag| prev_diag.eq(&diagnostic))
            {
                next_diagnostics.push(diagnostic.clone());
            }
        }
        let params = PublishDiagnosticsParams {
            diagnostics: next_diagnostics,
            uri: url.clone(),
            version: None,
        };
        publish_diagnostic(params, &self.sender).ok();
    }

    #[cfg(test)]
    fn set_source_reader(&mut self, source_reader: Box<dyn SourceReader + Send + Sync>) {
        self.source_reader = source_reader;
    }

    fn report_diagnostic(&self, diagnostic: &CompilerDiagnostic) {
        let message = diagnostic.message().to_string();

        let location = diagnostic.location();

        let url = match url_from_location(location, &self.root_dir) {
            Some(url) => url,
            None => {
                // TODO(brandondail) we should always be able to parse as a Url, so log here when we don't
                if let Ok(root) = Url::from_directory_path(&self.root_dir) {
                    root
                } else {
                    return;
                }
            }
        };

        let source = if let Some(source) = source_for_location(
            &self.root_dir,
            location.source_location(),
            self.source_reader.as_ref(),
        ) {
            source
        } else {
            return;
        };

        let range = location
            .span()
            .to_range(&source.text, source.line_index, source.column_index);

        let diagnostic = Diagnostic {
            code: None,
            message,
            range,
            related_information: None,
            severity: Some(DiagnosticSeverity::Error),
            source: None,
            tags: None,
        };
        self.add_diagnostic(url, diagnostic);
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        match error {
            BuildProjectError::ValidationErrors { errors } => {
                for diagnostic in errors {
                    self.report_diagnostic(diagnostic);
                }
            }
            BuildProjectError::PersistErrors { errors } => {
                for error in errors {
                    self.print_generic_error(format!("{}", error));
                }
            }
            _ => {
                self.print_generic_error(format!("{}", error));
            }
        }
    }

    fn print_generic_error(&self, message: String) {
        let diagnostic = Diagnostic {
            code: None,
            message,
            range: Range::new(Position::new(0, 0), Position::new(0, 0)),
            related_information: None,
            severity: Some(DiagnosticSeverity::Error),
            source: None,
            tags: None,
        };
        let url = Url::from_directory_path(&self.root_dir)
            .expect("print_generic_error: Could not convert self.root_dir to Url");
        self.add_diagnostic(url, diagnostic);
    }
}

#[cfg(test)]
mod tests {
    use super::DiagnosticReporter;
    use common::{Diagnostic, Location, SourceLocationKey, Span};
    use crossbeam::crossbeam_channel;
    use interner::Intern;
    use relay_compiler::SourceReader;
    use std::path::PathBuf;

    struct MockSourceReader(String);

    impl SourceReader for MockSourceReader {
        fn read_to_string(&self, _path: &PathBuf) -> std::io::Result<String> {
            Ok(self.0.to_string())
        }
    }

    #[test]
    fn report_diagnostic_test() {
        let root_dir = PathBuf::from("/tmp");
        let (sender, _) = crossbeam_channel::unbounded();
        let mut reporter = DiagnosticReporter::new(root_dir, sender);
        reporter.set_source_reader(Box::new(MockSourceReader("Content".to_string())));
        let source_location = SourceLocationKey::Standalone {
            path: "foo.txt".intern(),
        };
        assert_eq!(reporter.active_diagnostics.read().unwrap().len(), 0);
        reporter.report_diagnostic(&Diagnostic::error(
            "test message",
            Location::new(source_location, Span { start: 0, end: 1 }),
        ));
        assert_eq!(reporter.active_diagnostics.read().unwrap().len(), 1);
    }

    /// This test will assert that the message without URL (with generated source) won't be reported by LSPStatusReporter
    /// I'm not sure if this is the right behavior, but lets capture it here.
    #[test]
    fn do_not_report_diagnostic_without_url_test() {
        let root_dir = PathBuf::from("/tmp");
        let (sender, _) = crossbeam_channel::unbounded();

        let mut reporter = DiagnosticReporter::new(root_dir, sender);
        reporter.set_source_reader(Box::new(MockSourceReader("".to_string())));

        reporter.report_diagnostic(&Diagnostic::error("-", Location::generated()));
        assert_eq!(reporter.active_diagnostics.read().unwrap().len(), 0);
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
#[macro_use] extern crate version;

use clap::Shell;
use libimagrt::runtime::Runtime;

/// This macro generates mods with the given '$modulename',
/// whose content is the file given with `$path`.
/// In this case, It is used specifically to include the
/// `ui.rs` files of the imag binaries.
/// The imag project (accidentally?) followed the convention
/// to write a `ui.rs` containing the function
/// `fn build_ui(app : App) -> App`.
/// This macro allows us to use the same named functions by
/// putting them each into their own module.
macro_rules! gen_mods_buildui {
    ($(($path:expr, $modulename:ident)$(,)*)*) => (
        $(
            mod $modulename {
                include!($path);
            }
         )*
        )
}

/// This macro reduces boilerplate code.
///
/// For example: `build_subcommand!("counter", imagcounter)`
/// will result in the following code:
/// ```ignore
/// imagcounter::build_ui(Runtime::get_default_cli_builder(
///     "counter",
///     &version!()[..],
///     "counter"))
/// ```
/// As for the `&version!()[..]` part, it does not matter
/// which version the subcommand is getting here, as the
/// output of this script is a completion script, which
/// does not contain information about the version at all.
macro_rules! build_subcommand {
    ($name:expr, $module:ident) => (
        $module::build_ui(Runtime::get_default_cli_builder(
                $name,
                &version!()[..],
                $name))
    )
}

// Actually generates the module.
gen_mods_buildui!(
    ("../imag-link/src/ui.rs",      imaglink),
    ("../imag-notes/src/ui.rs",     imagnotes),
    ("../imag-ref/src/ui.rs",       imagref),
    ("../imag-store/src/ui.rs",     imagstore),
    ("../imag-tag/src/ui.rs",       imagtag),
    ("../imag-view/src/ui.rs",      imagview)
);

fn main() {
    // Make the `imag`-App...
    let mut app = Runtime::get_default_cli_builder(
        "imag",
        &version!()[..],
        "imag")
        // and add all the subapps as subcommands.
        .subcommand(build_subcommand!("link",       imaglink))
        .subcommand(build_subcommand!("notes",      imagnotes))
        .subcommand(build_subcommand!("ref",        imagref))
        .subcommand(build_subcommand!("store",      imagstore))
        .subcommand(build_subcommand!("tag",        imagtag))
        .subcommand(build_subcommand!("view",       imagview));

    let outdir = std::env::var("OUT_DIR").unwrap();

    // Actually generates the completion files
    app.gen_completions("imag", Shell::Bash, outdir);
    app.gen_completions("imag", Shell::Fish, outdir);
    app.gen_completions("imag", Shell::Zsh,  outdir);

}

<commit_msg>Fix build script once more<commit_after>extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
#[macro_use] extern crate version;

use clap::Shell;
use libimagrt::runtime::Runtime;

/// This macro generates mods with the given '$modulename',
/// whose content is the file given with `$path`.
/// In this case, It is used specifically to include the
/// `ui.rs` files of the imag binaries.
/// The imag project (accidentally?) followed the convention
/// to write a `ui.rs` containing the function
/// `fn build_ui(app : App) -> App`.
/// This macro allows us to use the same named functions by
/// putting them each into their own module.
macro_rules! gen_mods_buildui {
    ($(($path:expr, $modulename:ident)$(,)*)*) => (
        $(
            mod $modulename {
                include!($path);
            }
         )*
        )
}

/// This macro reduces boilerplate code.
///
/// For example: `build_subcommand!("counter", imagcounter)`
/// will result in the following code:
/// ```ignore
/// imagcounter::build_ui(Runtime::get_default_cli_builder(
///     "counter",
///     &version!()[..],
///     "counter"))
/// ```
/// As for the `&version!()[..]` part, it does not matter
/// which version the subcommand is getting here, as the
/// output of this script is a completion script, which
/// does not contain information about the version at all.
macro_rules! build_subcommand {
    ($name:expr, $module:ident) => (
        $module::build_ui(Runtime::get_default_cli_builder(
                $name,
                &version!()[..],
                $name))
    )
}

// Actually generates the module.
gen_mods_buildui!(
    ("../imag-link/src/ui.rs",      imaglink),
    ("../imag-notes/src/ui.rs",     imagnotes),
    ("../imag-ref/src/ui.rs",       imagref),
    ("../imag-store/src/ui.rs",     imagstore),
    ("../imag-tag/src/ui.rs",       imagtag),
    ("../imag-view/src/ui.rs",      imagview)
);

fn main() {
    // Make the `imag`-App...
    let mut app = Runtime::get_default_cli_builder(
        "imag",
        &version!()[..],
        "imag")
        // and add all the subapps as subcommands.
        .subcommand(build_subcommand!("link",       imaglink))
        .subcommand(build_subcommand!("notes",      imagnotes))
        .subcommand(build_subcommand!("ref",        imagref))
        .subcommand(build_subcommand!("store",      imagstore))
        .subcommand(build_subcommand!("tag",        imagtag))
        .subcommand(build_subcommand!("view",       imagview));

    let outdir = std::env::var("OUT_DIR").unwrap();

    // Actually generates the completion files
    app.gen_completions("imag", Shell::Bash, outdir.clone());
    app.gen_completions("imag", Shell::Fish, outdir.clone());
    app.gen_completions("imag", Shell::Zsh,  outdir);

}

<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::same_type_and_consts;
use clippy_utils::{in_macro, meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
    self as hir,
    def::{CtorOf, DefKind, Res},
    def_id::LocalDefId,
    intravisit::{walk_ty, NestedVisitorMap, Visitor},
    Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, QPath, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::{AssocKind, Ty};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
use rustc_typeck::hir_ty_to_ty;

declare_clippy_lint! {
    /// **What it does:** Checks for unnecessary repetition of structure name when a
    /// replacement with `Self` is applicable.
    ///
    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
    /// name
    /// feels inconsistent.
    ///
    /// **Known problems:**
    /// - Unaddressed false negative in fn bodies of trait implementations
    /// - False positive with assotiated types in traits (#4140)
    ///
    /// **Example:**
    ///
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Foo {
    ///         Foo {}
    ///     }
    /// }
    /// ```
    /// could be
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Self {}
    ///     }
    /// }
    /// ```
    pub USE_SELF,
    nursery,
    "unnecessary structure name repetition whereas `Self` is applicable"
}

#[derive(Default)]
pub struct UseSelf {
    msrv: Option<RustcVersion>,
    stack: Vec<StackItem>,
}

impl UseSelf {
    #[must_use]
    pub fn new(msrv: Option<RustcVersion>) -> Self {
        Self {
            msrv,
            ..Self::default()
        }
    }
}

#[derive(Debug)]
enum StackItem {
    Check {
        hir_id: HirId,
        impl_trait_ref_def_id: Option<LocalDefId>,
        types_to_skip: Vec<HirId>,
        types_to_lint: Vec<HirId>,
    },
    NoCheck,
}

impl_lint_pass!(UseSelf => [USE_SELF]);

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

impl<'tcx> LateLintPass<'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
        // We push the self types of `impl`s on a stack here. Only the top type on the stack is
        // relevant for linting, since this is the self type of the `impl` we're currently in. To
        // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
        // we're in an `impl` or nested item, that we don't want to lint
        //
        // NB: If you push something on the stack in this method, remember to also pop it in the
        // `check_item_post` method.
        match &item.kind {
            ItemKind::Impl(Impl {
                self_ty: hir_self_ty,
                of_trait,
                ..
            }) => {
                let should_check = if let TyKind::Path(QPath::Resolved(_, item_path)) = hir_self_ty.kind {
                    let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                    parameters.as_ref().map_or(true, |params| {
                        !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
                    })
                } else {
                    false
                };
                let impl_trait_ref_def_id = of_trait.as_ref().map(|_| cx.tcx.hir().local_def_id(item.hir_id()));
                if should_check {
                    self.stack.push(StackItem::Check {
                        hir_id: hir_self_ty.hir_id,
                        impl_trait_ref_def_id,
                        types_to_lint: Vec::new(),
                        types_to_skip: Vec::new(),
                    });
                } else {
                    self.stack.push(StackItem::NoCheck);
                }
            },
            ItemKind::Static(..)
            | ItemKind::Const(..)
            | ItemKind::Fn(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Trait(..) => {
                self.stack.push(StackItem::NoCheck);
            },
            _ => (),
        }
    }

    fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) {
        use ItemKind::{Const, Enum, Fn, Impl, Static, Struct, Trait, Union};
        match item.kind {
            Impl { .. } | Static(..) | Const(..) | Fn(..) | Enum(..) | Struct(..) | Union(..) | Trait(..) => {
                self.stack.pop();
            },
            _ => (),
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
        // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
        // declaration. The collection of those types is all this method implementation does.
        if_chain! {
            if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind;
            if let Some(&mut StackItem::Check {
                impl_trait_ref_def_id: Some(def_id),
                ref mut types_to_skip,
                ..
            }) = self.stack.last_mut();
            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(def_id);
            then {
                // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
                // `Self`.
                let self_ty = impl_trait_ref.self_ty();

                // `trait_method_sig` is the signature of the function, how it is declared in the
                // trait, not in the impl of the trait.
                let trait_method = cx
                    .tcx
                    .associated_items(impl_trait_ref.def_id)
                    .find_by_name_and_kind(cx.tcx, impl_item.ident, AssocKind::Fn, impl_trait_ref.def_id)
                    .expect("impl method matches a trait method");
                let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
                let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);

                // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
                // implementation of the trait.
                let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output {
                    Some(&**ty)
                } else {
                    None
                };
                let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty);

                // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
                //
                // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
                // trait declaration. This is used to check if `Self` was used in the trait
                // declaration.
                //
                // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
                // to `Self`), we want to skip linting that type and all subtypes of it. This
                // avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
                // for u8`, when the trait always uses `Vec<u8>`.
                //
                // See also https://github.com/rust-lang/rust-clippy/issues/2894.
                for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
                    if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
                        let mut visitor = SkipTyCollector::default();
                        visitor.visit_ty(impl_hir_ty);
                        types_to_skip.extend(visitor.types_to_skip);
                    }
                }
            }
        }
    }

    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) {
        // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
        // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
        // However the `node_type()` method can *only* be called in bodies.
        //
        // This method implementation determines which types should get linted in a `Body` and
        // which shouldn't, with a visitor. We could directly lint in the visitor, but then we
        // could only allow this lint on item scope. And we would have to check if those types are
        // already dealt with in `check_ty` anyway.
        if let Some(StackItem::Check {
            hir_id,
            types_to_lint,
            types_to_skip,
            ..
        }) = self.stack.last_mut()
        {
            let self_ty = ty_from_hir_id(cx, *hir_id);

            let mut visitor = LintTyCollector {
                cx,
                self_ty,
                types_to_lint: vec![],
                types_to_skip: vec![],
            };
            visitor.visit_expr(&body.value);
            types_to_lint.extend(visitor.types_to_lint);
            types_to_skip.extend(visitor.types_to_skip);
        }
    }

    fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
        if_chain! {
            if !in_macro(hir_ty.span) && !in_impl(cx, hir_ty);
            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
            if let Some(StackItem::Check {
                hir_id,
                types_to_lint,
                types_to_skip,
                ..
            }) = self.stack.last();
            if !types_to_skip.contains(&hir_ty.hir_id);
            if types_to_lint.contains(&hir_ty.hir_id)
                || {
                    let self_ty = ty_from_hir_id(cx, *hir_id);
                    should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
                };
            let hir = cx.tcx.hir();
            let id = hir.get_parent_node(hir_ty.hir_id);
            if !hir.opt_span(id).map_or(false, in_macro);
            then {
                span_lint(cx, hir_ty.span);
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if_chain! {
            if !in_macro(expr.span);
            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
            if let Some(StackItem::Check { hir_id, .. }) = self.stack.last();
            if cx.typeck_results().expr_ty(expr) == ty_from_hir_id(cx, *hir_id);
            then {} else { return; }
        }
        match expr.kind {
            ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
                Res::SelfTy(..) => (),
                Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
                _ => span_lint(cx, path.span),
            },
            // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
            ExprKind::Call(fun, _) => {
                if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
                    if let Res::Def(DefKind::Ctor(ctor_of, _), ..) = path.res {
                        match ctor_of {
                            CtorOf::Variant => lint_path_to_variant(cx, path),
                            CtorOf::Struct => span_lint(cx, path.span),
                        }
                    }
                }
            },
            // unit enum variants (`Enum::A`)
            ExprKind::Path(QPath::Resolved(_, path)) => lint_path_to_variant(cx, path),
            _ => (),
        }
    }

    extract_msrv_attr!(LateContext);
}

#[derive(Default)]
struct SkipTyCollector {
    types_to_skip: Vec<HirId>,
}

impl<'tcx> Visitor<'tcx> for SkipTyCollector {
    type Map = Map<'tcx>;

    fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
        self.types_to_skip.push(hir_ty.hir_id);

        walk_ty(self, hir_ty);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

struct LintTyCollector<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    self_ty: Ty<'tcx>,
    types_to_lint: Vec<HirId>,
    types_to_skip: Vec<HirId>,
}

impl<'a, 'tcx> Visitor<'tcx> for LintTyCollector<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) {
        if_chain! {
            if let Some(ty) = self.cx.typeck_results().node_type_opt(hir_ty.hir_id);
            if should_lint_ty(hir_ty, ty, self.self_ty);
            then {
                self.types_to_lint.push(hir_ty.hir_id);
            } else {
                self.types_to_skip.push(hir_ty.hir_id);
            }
        }

        walk_ty(self, hir_ty);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

fn span_lint(cx: &LateContext<'_>, span: Span) {
    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
    if let [.., self_seg, _variant] = path.segments {
        let span = path
            .span
            .with_hi(self_seg.args().span_ext().unwrap_or(self_seg.ident.span).hi());
        span_lint(cx, span);
    }
}

fn ty_from_hir_id<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Ty<'tcx> {
    if let Some(Node::Ty(hir_ty)) = cx.tcx.hir().find(hir_id) {
        hir_ty_to_ty(cx.tcx, hir_ty)
    } else {
        unreachable!("This function should only be called with `HirId`s that are for sure `Node::Ty`")
    }
}

fn in_impl(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> bool {
    let map = cx.tcx.hir();
    let parent = map.get_parent_node(hir_ty.hir_id);
    if_chain! {
        if let Some(Node::Item(item)) = map.find(parent);
        if let ItemKind::Impl { .. } = item.kind;
        then {
            true
        } else {
            false
        }
    }
}

fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool {
    if_chain! {
        if same_type_and_consts(ty, self_ty);
        if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
        then {
            !matches!(path.res, Res::SelfTy(..) | Res::Def(DefKind::TyParam, _))
        } else {
            false
        }
    }
}
<commit_msg>Auto merge of #7411 - camsteffen:use-self-visitor, r=flip1995<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::same_type_and_consts;
use clippy_utils::{in_macro, meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::{
    self as hir,
    def::{CtorOf, DefKind, Res},
    def_id::LocalDefId,
    intravisit::{walk_ty, NestedVisitorMap, Visitor},
    Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::AssocKind;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
use rustc_typeck::hir_ty_to_ty;

declare_clippy_lint! {
    /// **What it does:** Checks for unnecessary repetition of structure name when a
    /// replacement with `Self` is applicable.
    ///
    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
    /// name
    /// feels inconsistent.
    ///
    /// **Known problems:**
    /// - Unaddressed false negative in fn bodies of trait implementations
    /// - False positive with assotiated types in traits (#4140)
    ///
    /// **Example:**
    ///
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Foo {
    ///         Foo {}
    ///     }
    /// }
    /// ```
    /// could be
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Self {}
    ///     }
    /// }
    /// ```
    pub USE_SELF,
    nursery,
    "unnecessary structure name repetition whereas `Self` is applicable"
}

#[derive(Default)]
pub struct UseSelf {
    msrv: Option<RustcVersion>,
    stack: Vec<StackItem>,
}

impl UseSelf {
    #[must_use]
    pub fn new(msrv: Option<RustcVersion>) -> Self {
        Self {
            msrv,
            ..Self::default()
        }
    }
}

#[derive(Debug)]
enum StackItem {
    Check {
        impl_id: LocalDefId,
        in_body: u32,
        types_to_skip: FxHashSet<HirId>,
    },
    NoCheck,
}

impl_lint_pass!(UseSelf => [USE_SELF]);

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

impl<'tcx> LateLintPass<'tcx> for UseSelf {
    fn check_item(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
        if !is_item_interesting(item) {
            // This does two things:
            //  1) Reduce needless churn on `self.stack`
            //  2) Don't push `StackItem::NoCheck` when entering `ItemKind::OpaqueTy`,
            //     in order to lint `foo() -> impl <..>`
            return;
        }
        // We push the self types of `impl`s on a stack here. Only the top type on the stack is
        // relevant for linting, since this is the self type of the `impl` we're currently in. To
        // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
        // we're in an `impl` or nested item, that we don't want to lint
        let stack_item = if_chain! {
            if let ItemKind::Impl(Impl { self_ty, .. }) = item.kind;
            if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind;
            let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
            if parameters.as_ref().map_or(true, |params| {
                !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
            });
            then {
                StackItem::Check {
                    impl_id: item.def_id,
                    in_body: 0,
                    types_to_skip: std::iter::once(self_ty.hir_id).collect(),
                }
            } else {
                StackItem::NoCheck
            }
        };
        self.stack.push(stack_item);
    }

    fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) {
        if is_item_interesting(item) {
            self.stack.pop();
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
        // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
        // declaration. The collection of those types is all this method implementation does.
        if_chain! {
            if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind;
            if let Some(&mut StackItem::Check {
                impl_id,
                ref mut types_to_skip,
                ..
            }) = self.stack.last_mut();
            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id);
            then {
                // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
                // `Self`.
                let self_ty = impl_trait_ref.self_ty();

                // `trait_method_sig` is the signature of the function, how it is declared in the
                // trait, not in the impl of the trait.
                let trait_method = cx
                    .tcx
                    .associated_items(impl_trait_ref.def_id)
                    .find_by_name_and_kind(cx.tcx, impl_item.ident, AssocKind::Fn, impl_trait_ref.def_id)
                    .expect("impl method matches a trait method");
                let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
                let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);

                // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
                // implementation of the trait.
                let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output {
                    Some(&**ty)
                } else {
                    None
                };
                let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty);

                // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
                //
                // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
                // trait declaration. This is used to check if `Self` was used in the trait
                // declaration.
                //
                // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
                // to `Self`), we want to skip linting that type and all subtypes of it. This
                // avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
                // for u8`, when the trait always uses `Vec<u8>`.
                //
                // See also https://github.com/rust-lang/rust-clippy/issues/2894.
                for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
                    if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
                        let mut visitor = SkipTyCollector::default();
                        visitor.visit_ty(impl_hir_ty);
                        types_to_skip.extend(visitor.types_to_skip);
                    }
                }
            }
        }
    }

    fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
        // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
        // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
        // However the `node_type()` method can *only* be called in bodies.
        if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
            *in_body = in_body.saturating_add(1);
        }
    }

    fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
        if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
            *in_body = in_body.saturating_sub(1);
        }
    }

    fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
        if_chain! {
            if !in_macro(hir_ty.span);
            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
            if let Some(&StackItem::Check {
                impl_id,
                in_body,
                ref types_to_skip,
            }) = self.stack.last();
            if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
            if !matches!(path.res, Res::SelfTy(..) | Res::Def(DefKind::TyParam, _));
            if !types_to_skip.contains(&hir_ty.hir_id);
            let ty = if in_body > 0 {
                cx.typeck_results().node_type(hir_ty.hir_id)
            } else {
                hir_ty_to_ty(cx.tcx, hir_ty)
            };
            if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
            let hir = cx.tcx.hir();
            let id = hir.get_parent_node(hir_ty.hir_id);
            if !hir.opt_span(id).map_or(false, in_macro);
            then {
                span_lint(cx, hir_ty.span);
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if_chain! {
            if !in_macro(expr.span);
            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
            if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
            if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
            then {} else { return; }
        }
        match expr.kind {
            ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
                Res::SelfTy(..) => (),
                Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
                _ => span_lint(cx, path.span),
            },
            // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
            ExprKind::Call(fun, _) => {
                if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
                    if let Res::Def(DefKind::Ctor(ctor_of, _), ..) = path.res {
                        match ctor_of {
                            CtorOf::Variant => lint_path_to_variant(cx, path),
                            CtorOf::Struct => span_lint(cx, path.span),
                        }
                    }
                }
            },
            // unit enum variants (`Enum::A`)
            ExprKind::Path(QPath::Resolved(_, path)) => lint_path_to_variant(cx, path),
            _ => (),
        }
    }

    extract_msrv_attr!(LateContext);
}

#[derive(Default)]
struct SkipTyCollector {
    types_to_skip: Vec<HirId>,
}

impl<'tcx> Visitor<'tcx> for SkipTyCollector {
    type Map = Map<'tcx>;

    fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
        self.types_to_skip.push(hir_ty.hir_id);

        walk_ty(self, hir_ty);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

fn span_lint(cx: &LateContext<'_>, span: Span) {
    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
    if let [.., self_seg, _variant] = path.segments {
        let span = path
            .span
            .with_hi(self_seg.args().span_ext().unwrap_or(self_seg.ident.span).hi());
        span_lint(cx, span);
    }
}

fn is_item_interesting(item: &Item<'_>) -> bool {
    use rustc_hir::ItemKind::{Const, Enum, Fn, Impl, Static, Struct, Trait, Union};
    matches!(
        item.kind,
        Impl { .. } | Static(..) | Const(..) | Fn(..) | Enum(..) | Struct(..) | Union(..) | Trait(..)
    )
}
<|endoftext|>


<commit_before>use std::str::FromStr;

use cargo_edit::VersionExt;

use crate::{Error, ErrorKind};

#[derive(Clone, Debug)]
pub enum TargetVersion {
    Relative(BumpLevel),
    Absolute(semver::Version),
}

impl TargetVersion {
    pub fn bump(
        &self,
        current: &semver::Version,
        metadata: Option<&str>,
    ) -> Result<Option<semver::Version>, Error> {
        match self {
            TargetVersion::Relative(bump_level) => {
                let mut potential_version = current.to_owned();
                bump_level.bump_version(&mut potential_version, metadata)?;
                if potential_version != *current {
                    let version = potential_version;
                    Ok(Some(version))
                } else {
                    Ok(None)
                }
            }
            TargetVersion::Absolute(version) => {
                if current < version {
                    Ok(Some(version.clone()))
                } else if current == version {
                    Ok(None)
                } else {
                    Err(ErrorKind::VersionDowngreade(current.clone(), version.clone()).into())
                }
            }
        }
    }
}

impl Default for TargetVersion {
    fn default() -> Self {
        TargetVersion::Relative(BumpLevel::Release)
    }
}

#[derive(Debug, Clone, Copy)]
pub enum BumpLevel {
    Major,
    Minor,
    Patch,
    /// Strip all pre-release flags
    Release,
    Rc,
    Beta,
    Alpha,
}

impl BumpLevel {
    pub fn variants() -> &'static [&'static str] {
        &["major", "minor", "patch", "release", "rc", "beta", "alpha"]
    }
}

impl FromStr for BumpLevel {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "major" => Ok(BumpLevel::Major),
            "minor" => Ok(BumpLevel::Minor),
            "patch" => Ok(BumpLevel::Patch),
            "release" => Ok(BumpLevel::Release),
            "rc" => Ok(BumpLevel::Rc),
            "beta" => Ok(BumpLevel::Beta),
            "alpha" => Ok(BumpLevel::Alpha),
            _ => Err(String::from(
                "[valid values: major, minor, patch, rc, beta, alpha]",
            )),
        }
    }
}

impl BumpLevel {
    pub fn bump_version(
        self,
        version: &mut semver::Version,
        metadata: Option<&str>,
    ) -> Result<(), Error> {
        match self {
            BumpLevel::Major => {
                version.increment_major();
            }
            BumpLevel::Minor => {
                version.increment_minor();
            }
            BumpLevel::Patch => {
                if !version.is_prerelease() {
                    version.increment_patch();
                } else {
                    version.pre = semver::Prerelease::EMPTY;
                }
            }
            BumpLevel::Release => {
                if version.is_prerelease() {
                    version.pre = semver::Prerelease::EMPTY;
                }
            }
            BumpLevel::Rc => {
                version.increment_rc()?;
            }
            BumpLevel::Beta => {
                version.increment_beta()?;
            }
            BumpLevel::Alpha => {
                version.increment_alpha()?;
            }
        };

        if let Some(metadata) = metadata {
            version.metadata(metadata)?;
        }

        Ok(())
    }
}
<commit_msg>fix(version): Handle build metadata for absolute versions (#556)<commit_after>use std::str::FromStr;

use cargo_edit::VersionExt;

use crate::{Error, ErrorKind};

#[derive(Clone, Debug)]
pub enum TargetVersion {
    Relative(BumpLevel),
    Absolute(semver::Version),
}

impl TargetVersion {
    pub fn bump(
        &self,
        current: &semver::Version,
        metadata: Option<&str>,
    ) -> Result<Option<semver::Version>, Error> {
        match self {
            TargetVersion::Relative(bump_level) => {
                let mut potential_version = current.to_owned();
                bump_level.bump_version(&mut potential_version, metadata)?;
                if potential_version != *current {
                    let version = potential_version;
                    Ok(Some(version))
                } else {
                    Ok(None)
                }
            }
            TargetVersion::Absolute(version) => {
                if current < version {
                    let mut version = version.clone();
                    if version.build.is_empty() {
                        if let Some(metadata) = metadata {
                            version.build = semver::BuildMetadata::new(metadata)?;
                        } else {
                            version.build = current.build.clone();
                        }
                    }

                    Ok(Some(version))
                } else if current == version {
                    Ok(None)
                } else {
                    Err(ErrorKind::VersionDowngreade(current.clone(), version.clone()).into())
                }
            }
        }
    }
}

impl Default for TargetVersion {
    fn default() -> Self {
        TargetVersion::Relative(BumpLevel::Release)
    }
}

#[derive(Debug, Clone, Copy)]
pub enum BumpLevel {
    Major,
    Minor,
    Patch,
    /// Strip all pre-release flags
    Release,
    Rc,
    Beta,
    Alpha,
}

impl BumpLevel {
    pub fn variants() -> &'static [&'static str] {
        &["major", "minor", "patch", "release", "rc", "beta", "alpha"]
    }
}

impl FromStr for BumpLevel {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "major" => Ok(BumpLevel::Major),
            "minor" => Ok(BumpLevel::Minor),
            "patch" => Ok(BumpLevel::Patch),
            "release" => Ok(BumpLevel::Release),
            "rc" => Ok(BumpLevel::Rc),
            "beta" => Ok(BumpLevel::Beta),
            "alpha" => Ok(BumpLevel::Alpha),
            _ => Err(String::from(
                "[valid values: major, minor, patch, rc, beta, alpha]",
            )),
        }
    }
}

impl BumpLevel {
    pub fn bump_version(
        self,
        version: &mut semver::Version,
        metadata: Option<&str>,
    ) -> Result<(), Error> {
        match self {
            BumpLevel::Major => {
                version.increment_major();
            }
            BumpLevel::Minor => {
                version.increment_minor();
            }
            BumpLevel::Patch => {
                if !version.is_prerelease() {
                    version.increment_patch();
                } else {
                    version.pre = semver::Prerelease::EMPTY;
                }
            }
            BumpLevel::Release => {
                if version.is_prerelease() {
                    version.pre = semver::Prerelease::EMPTY;
                }
            }
            BumpLevel::Rc => {
                version.increment_rc()?;
            }
            BumpLevel::Beta => {
                version.increment_beta()?;
            }
            BumpLevel::Alpha => {
                version.increment_alpha()?;
            }
        };

        if let Some(metadata) = metadata {
            version.metadata(metadata)?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::sync::RwLock;
use std::collections::HashSet;
use std::slice;
use std::str;
use std::mem;
use std::cmp::Ordering;
use std::ops::Deref;
use std::hash::{Hash, Hasher};

pub fn leek(s: String) -> &'static str {
    let boxed = s.into_boxed_str();
    let ptr = boxed.as_ptr();
    let len = boxed.len();
    mem::forget(boxed);
    unsafe {
        let slice = slice::from_raw_parts(ptr, len);
        str::from_utf8_unchecked(slice)
    }
}

lazy_static! {
    static ref STRING_CASHE: RwLock<HashSet<&'static str>> =
        RwLock::new(HashSet::new());
}

#[derive(Eq, PartialEq, Clone, Copy)]
pub struct InternedString {
    ptr: *const u8,
    len: usize,
}

impl InternedString {
    pub fn new(str: &str) -> InternedString {
        let mut cache = STRING_CASHE.write().unwrap();
        if let Some(&s) = cache.get(str) {
            return InternedString {
                ptr: s.as_ptr(),
                len: s.len(),
            };
        }
        let s = leek(str.to_string());
        cache.insert(s);
        InternedString {
            ptr: s.as_ptr(),
            len: s.len(),
        }
    }
    pub fn to_inner(&self) -> &'static str {
        unsafe {
            let slice = slice::from_raw_parts(self.ptr, self.len);
            &str::from_utf8_unchecked(slice)
        }
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &'static str {
        self.to_inner()
    }
}

impl Hash for InternedString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.to_inner().hash(state);
    }
}

impl fmt::Debug for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.to_inner(), f)
    }
}

impl fmt::Display for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.to_inner(), f)
    }
}

impl Ord for InternedString {
    fn cmp(&self, other: &InternedString) -> Ordering {
        self.to_inner().cmp(&*other)
    }
}

impl PartialOrd for InternedString {
    fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

unsafe impl Send for InternedString {}
unsafe impl Sync for InternedString {}
<commit_msg>Auto merge of #5271 - djc:interning-spelling, r=alexcrichton<commit_after>use std::fmt;
use std::sync::RwLock;
use std::collections::HashSet;
use std::slice;
use std::str;
use std::mem;
use std::cmp::Ordering;
use std::ops::Deref;
use std::hash::{Hash, Hasher};

pub fn leak(s: String) -> &'static str {
    let boxed = s.into_boxed_str();
    let ptr = boxed.as_ptr();
    let len = boxed.len();
    mem::forget(boxed);
    unsafe {
        let slice = slice::from_raw_parts(ptr, len);
        str::from_utf8_unchecked(slice)
    }
}

lazy_static! {
    static ref STRING_CACHE: RwLock<HashSet<&'static str>> =
        RwLock::new(HashSet::new());
}

#[derive(Eq, PartialEq, Clone, Copy)]
pub struct InternedString {
    ptr: *const u8,
    len: usize,
}

impl InternedString {
    pub fn new(str: &str) -> InternedString {
        let mut cache = STRING_CACHE.write().unwrap();
        if let Some(&s) = cache.get(str) {
            return InternedString {
                ptr: s.as_ptr(),
                len: s.len(),
            };
        }
        let s = leak(str.to_string());
        cache.insert(s);
        InternedString {
            ptr: s.as_ptr(),
            len: s.len(),
        }
    }
    pub fn to_inner(&self) -> &'static str {
        unsafe {
            let slice = slice::from_raw_parts(self.ptr, self.len);
            &str::from_utf8_unchecked(slice)
        }
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &'static str {
        self.to_inner()
    }
}

impl Hash for InternedString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.to_inner().hash(state);
    }
}

impl fmt::Debug for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.to_inner(), f)
    }
}

impl fmt::Display for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.to_inner(), f)
    }
}

impl Ord for InternedString {
    fn cmp(&self, other: &InternedString) -> Ordering {
        self.to_inner().cmp(&*other)
    }
}

impl PartialOrd for InternedString {
    fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

unsafe impl Send for InternedString {}
unsafe impl Sync for InternedString {}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(target_os = "windows")]
pub use self::windows::shell_escape;

#[cfg(any(test, target_os = "windows"))]
mod windows {
    use std::borrow::Cow;

    static NEED_QUOTING: &'static str = r#" ""#;
    const ESCAPE_CHAR: char = '\\';
    const QUOTE_CHAR: char = '"';
    const BACKSLASH: char = '\\';
    const SLASH: char = '/';

    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    ///
    /// Escape double quotes and spaces by wrapping the string in double quotes.
    ///
    /// Turn all backslashes into forward slashes.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        // check if string needs to be escaped
        let mut needs_quoting = false;
        let mut needs_slashes = false;
        for ch in s.chars() {
            if NEED_QUOTING.contains(ch) {
                needs_quoting = true;
            } else if ch == BACKSLASH {
                needs_slashes = true;
            }
        }
        if !needs_quoting && !needs_slashes {
            return s
        }
        let mut es = String::with_capacity(s.len());
        if needs_quoting {
            es.push(QUOTE_CHAR);
        }
        for ch in s.chars() {
            match ch {
                BACKSLASH => { es.push(SLASH); continue }
                QUOTE_CHAR => es.push(ESCAPE_CHAR),
                _ => {}
            }
            es.push(ch)
        }
        if needs_quoting {
            es.push(QUOTE_CHAR);
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#""linker=gcc -L/foo -Wl,bar""#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#""--features=\"default\"""#);
        assert_eq!(shell_escape(r#"\path\to\my documents\"#.into()),
                                r#""/path/to/my documents/""#);
    }
}

#[cfg(not(target_os = "windows"))]
pub use self::other::shell_escape;

#[cfg(any(test, not(target_os = "windows")))]
mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    #[cfg(not(target_os = "windows"))]
    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<commit_msg>shell_escape: Only add quotes if it contains spaces<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(target_os = "windows")]
pub use self::windows::shell_escape;

#[cfg(any(test, target_os = "windows"))]
mod windows {
    use std::borrow::Cow;

    const SPACE: char = ' ';
    const ESCAPE_CHAR: char = '\\';
    const QUOTE_CHAR: char = '"';
    const BACKSLASH: char = '\\';
    const SLASH: char = '/';

    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    ///
    /// Escape double quotes and spaces by wrapping the string in double quotes.
    ///
    /// Turn all backslashes into forward slashes.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        // check if string needs to be escaped
        let mut has_spaces = false;
        let mut has_backslashes = false;
        let mut has_quotes = false;
        for ch in s.chars() {
            match ch {
                QUOTE_CHAR => has_quotes = true,
                SPACE => has_spaces = true,
                BACKSLASH => has_backslashes = true,
                _ => {}
            }
        }
        if !has_spaces && !has_backslashes && !has_quotes {
            return s
        }
        let mut es = String::with_capacity(s.len());
        if has_spaces {
            es.push(QUOTE_CHAR);
        }
        for ch in s.chars() {
            match ch {
                BACKSLASH => { es.push(SLASH); continue }
                QUOTE_CHAR => es.push(ESCAPE_CHAR),
                _ => {}
            }
            es.push(ch)
        }
        if has_spaces {
            es.push(QUOTE_CHAR);
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#""linker=gcc -L/foo -Wl,bar""#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"\path\to\my documents\"#.into()),
                                r#""/path/to/my documents/""#);
    }
}

#[cfg(not(target_os = "windows"))]
pub use self::other::shell_escape;

#[cfg(any(test, not(target_os = "windows")))]
mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    #[cfg(not(target_os = "windows"))]
    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<|endoftext|>