<commit_before>// Copyright 2012-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.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(custom_attribute)]
#![cfg_attr(not(stage0), feature(nll))]
#![allow(unused_attributes)]

#![recursion_limit="256"]

#[macro_use]
extern crate rustc;

#[macro_use]
extern crate log;
extern crate rustc_data_structures;
extern crate rustc_serialize;
extern crate rustc_target;
extern crate rustc_typeck;
#[macro_use]
extern crate syntax;
extern crate syntax_pos;

extern crate rls_data;
extern crate rls_span;


mod json_dumper;
mod dump_visitor;
#[macro_use]
mod span_utils;
mod sig;

use rustc::hir;
use rustc::hir::def::Def as HirDef;
use rustc::hir::map::{Node, NodeTraitItem, NodeImplItem};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::cstore::ExternCrate;
use rustc::session::config::CrateType;
use rustc::ty::{self, TyCtxt};
use rustc_typeck::hir_ty_to_ty;

use std::cell::Cell;
use std::default::Default;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};

use syntax::ast::{self, Attribute, NodeId, PatKind};
use syntax::source_map::Spanned;
use syntax::parse::lexer::comments::strip_doc_comment_decoration;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{arg_to_string, ty_to_string};
use syntax::source_map::MacroAttribute;
use syntax_pos::*;

use json_dumper::JsonDumper;
use dump_visitor::DumpVisitor;
use span_utils::SpanUtils;

use rls_data::{Def, DefKind, ExternalCrateData, GlobalCrateId, MacroRef, Ref, RefKind, Relation,
               RelationKind, SpanData, Impl, ImplKind};
use rls_data::config::Config;


pub struct SaveContext<'l, 'tcx: 'l> {
    tcx: TyCtxt<'l, 'tcx, 'tcx>,
    tables: &'l ty::TypeckTables<'tcx>,
    analysis: &'l ty::CrateAnalysis,
    span_utils: SpanUtils<'tcx>,
    config: Config,
    impl_counter: Cell<u32>,
}

#[derive(Debug)]
pub enum Data {
    RefData(Ref),
    DefData(Def),
    RelationData(Relation, Impl),
}

impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
    fn span_from_span(&self, span: Span) -> SpanData {
        use rls_span::{Column, Row};

        let cm = self.tcx.sess.source_map();
        let start = cm.lookup_char_pos(span.lo());
        let end = cm.lookup_char_pos(span.hi());

        SpanData {
            file_name: start.file.name.clone().to_string().into(),
            byte_start: span.lo().0,
            byte_end: span.hi().0,
            line_start: Row::new_one_indexed(start.line as u32),
            line_end: Row::new_one_indexed(end.line as u32),
            column_start: Column::new_one_indexed(start.col.0 as u32 + 1),
            column_end: Column::new_one_indexed(end.col.0 as u32 + 1),
        }
    }

    // List external crates used by the current crate.
    pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
        let mut result = Vec::new();

        for &n in self.tcx.crates().iter() {
            let span = match *self.tcx.extern_crate(n.as_def_id()) {
                Some(ExternCrate { span, .. }) => span,
                None => {
                    debug!("Skipping crate {}, no data", n);
                    continue;
                }
            };
            let lo_loc = self.span_utils.sess.source_map().lookup_char_pos(span.lo());
            result.push(ExternalCrateData {
                // FIXME: change file_name field to PathBuf in rls-data
                // https://github.com/nrc/rls-data/issues/7
                file_name: self.span_utils.make_path_string(&lo_loc.file.name),
                num: n.as_u32(),
                id: GlobalCrateId {
                    name: self.tcx.crate_name(n).to_string(),
                    disambiguator: self.tcx.crate_disambiguator(n).to_fingerprint().as_value(),
                },
            });
        }

        result
    }

    pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> {
        let qualname = format!("::{}", self.tcx.node_path_str(item.id));
        match item.node {
            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
                let sub_span = self.span_utils
                    .sub_span_after_keyword(item.span, keywords::Fn);
                filter!(self.span_utils, sub_span, item.span, None);

                Some(Data::DefData(Def {
                    kind: DefKind::Function,
                    id: id_from_node_id(item.id, self),
                    span: self.span_from_span(sub_span.unwrap()),
                    name: item.ident.to_string(),
                    qualname,
                    value: make_signature(decl, generics),
                    parent: None,
                    children: vec![],
                    decl_id: None,
                    docs: self.docs_for_attrs(&item.attrs),
                    sig: sig::foreign_item_signature(item, self),
                    attributes: lower_attributes(item.attrs.clone(), self),
                }))
            }
            ast::ForeignItemKind::Static(ref ty, m) => {
                let keyword = if m { keywords::Mut } else { keywords::Static };
                let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
                filter!(self.span_utils, sub_span, item.span, None);

                let id = ::id_from_node_id(item.id, self);
                let span = self.span_from_span(sub_span.unwrap());

                Some(Data::DefData(Def {
                    kind: DefKind::Static,
                    id,
                    span,
                    name: item.ident.to_string(),
                    qualname,
                    value: ty_to_string(ty),
                    parent: None,
                    children: vec![],
                    decl_id: None,
                    docs: self.docs_for_attrs(&item.attrs),
                    sig: sig::foreign_item_signature(item, self),
                    attributes: lower_attributes(item.attrs.clone(), self),
                }))
            }<commit_msg>save-analysis: Differentiate foreign functions and statics.<commit_after>// Copyright 2012-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.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(custom_attribute)]
#![cfg_attr(not(stage0), feature(nll))]
#![allow(unused_attributes)]

#![recursion_limit="256"]

#[macro_use]
extern crate rustc;

#[macro_use]
extern crate log;
extern crate rustc_data_structures;
extern crate rustc_serialize;
extern crate rustc_target;
extern crate rustc_typeck;
#[macro_use]
extern crate syntax;
extern crate syntax_pos;

extern crate rls_data;
extern crate rls_span;


mod json_dumper;
mod dump_visitor;
#[macro_use]
mod span_utils;
mod sig;

use rustc::hir;
use rustc::hir::def::Def as HirDef;
use rustc::hir::map::{Node, NodeTraitItem, NodeImplItem};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::cstore::ExternCrate;
use rustc::session::config::CrateType;
use rustc::ty::{self, TyCtxt};
use rustc_typeck::hir_ty_to_ty;

use std::cell::Cell;
use std::default::Default;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};

use syntax::ast::{self, Attribute, NodeId, PatKind};
use syntax::source_map::Spanned;
use syntax::parse::lexer::comments::strip_doc_comment_decoration;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{arg_to_string, ty_to_string};
use syntax::source_map::MacroAttribute;
use syntax_pos::*;

use json_dumper::JsonDumper;
use dump_visitor::DumpVisitor;
use span_utils::SpanUtils;

use rls_data::{Def, DefKind, ExternalCrateData, GlobalCrateId, MacroRef, Ref, RefKind, Relation,
               RelationKind, SpanData, Impl, ImplKind};
use rls_data::config::Config;


pub struct SaveContext<'l, 'tcx: 'l> {
    tcx: TyCtxt<'l, 'tcx, 'tcx>,
    tables: &'l ty::TypeckTables<'tcx>,
    analysis: &'l ty::CrateAnalysis,
    span_utils: SpanUtils<'tcx>,
    config: Config,
    impl_counter: Cell<u32>,
}

#[derive(Debug)]
pub enum Data {
    RefData(Ref),
    DefData(Def),
    RelationData(Relation, Impl),
}

impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
    fn span_from_span(&self, span: Span) -> SpanData {
        use rls_span::{Column, Row};

        let cm = self.tcx.sess.source_map();
        let start = cm.lookup_char_pos(span.lo());
        let end = cm.lookup_char_pos(span.hi());

        SpanData {
            file_name: start.file.name.clone().to_string().into(),
            byte_start: span.lo().0,
            byte_end: span.hi().0,
            line_start: Row::new_one_indexed(start.line as u32),
            line_end: Row::new_one_indexed(end.line as u32),
            column_start: Column::new_one_indexed(start.col.0 as u32 + 1),
            column_end: Column::new_one_indexed(end.col.0 as u32 + 1),
        }
    }

    // List external crates used by the current crate.
    pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
        let mut result = Vec::new();

        for &n in self.tcx.crates().iter() {
            let span = match *self.tcx.extern_crate(n.as_def_id()) {
                Some(ExternCrate { span, .. }) => span,
                None => {
                    debug!("Skipping crate {}, no data", n);
                    continue;
                }
            };
            let lo_loc = self.span_utils.sess.source_map().lookup_char_pos(span.lo());
            result.push(ExternalCrateData {
                // FIXME: change file_name field to PathBuf in rls-data
                // https://github.com/nrc/rls-data/issues/7
                file_name: self.span_utils.make_path_string(&lo_loc.file.name),
                num: n.as_u32(),
                id: GlobalCrateId {
                    name: self.tcx.crate_name(n).to_string(),
                    disambiguator: self.tcx.crate_disambiguator(n).to_fingerprint().as_value(),
                },
            });
        }

        result
    }

    pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> {
        let qualname = format!("::{}", self.tcx.node_path_str(item.id));
        match item.node {
            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
                let sub_span = self.span_utils
                    .sub_span_after_keyword(item.span, keywords::Fn);
                filter!(self.span_utils, sub_span, item.span, None);

                Some(Data::DefData(Def {
                    kind: DefKind::ForeignFunction,
                    id: id_from_node_id(item.id, self),
                    span: self.span_from_span(sub_span.unwrap()),
                    name: item.ident.to_string(),
                    qualname,
                    value: make_signature(decl, generics),
                    parent: None,
                    children: vec![],
                    decl_id: None,
                    docs: self.docs_for_attrs(&item.attrs),
                    sig: sig::foreign_item_signature(item, self),
                    attributes: lower_attributes(item.attrs.clone(), self),
                }))
            }
            ast::ForeignItemKind::Static(ref ty, m) => {
                let keyword = if m { keywords::Mut } else { keywords::Static };
                let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
                filter!(self.span_utils, sub_span, item.span, None);

                let id = ::id_from_node_id(item.id, self);
                let span = self.span_from_span(sub_span.unwrap());

                Some(Data::DefData(Def {
                    kind: DefKind::ForeignStatic,
                    id,
                    span,
                    name: item.ident.to_string(),
                    qualname,
                    value: ty_to_string(ty),
                    parent: None,
                    children: vec![],
                    decl_id: None,
                    docs: self.docs_for_attrs(&item.attrs),
                    sig: sig::foreign_item_signature(item, self),
                    attributes: lower_attributes(item.attrs.clone(), self),
                }))
            }
{'fraction_non_alphanumeric': 0.13421052631578947, 'fraction_numerical': 0.00631578947368421, 'mean_word_length': 2.3724645030425964, 'pattern_counts': {'":': 2, '<': 25, '<?xml version=': 0, '>': 39, 'https://': 8, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6119673', 'n_tokens_mistral': 4275, 'n_tokens_neox': 4144, 'n_words': 851}