Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ rpds = { version = "*", features = ["serde"] }
rustc_tools_util = "*"
petgraph = "*"
shellwords = "*"

[package.metadata.rust-analyzer]
rustc_private = true
33 changes: 18 additions & 15 deletions src/mir/analysis_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use std::rc::Rc;

use crate::mir::function::{FuncId, FunctionReference, GenericArgE};
use crate::mir::known_names::{KnownNames, KnownNamesCache};
use crate::mir::visibility::lib_entry_funcs;
use crate::mir::path::Path;
use crate::util;
use crate::util::options::AnalysisOptions;
Expand All @@ -33,7 +34,7 @@ pub struct AnalysisContext<'tcx, 'compilation> {
pub session: &'compilation Session,

/// The entry function of the analysis.
pub entry_point: DefId,
pub entry_points: HashSet<DefId>,

/// Options of the analysis.
pub analysis_options: AnalysisOptions,
Expand Down Expand Up @@ -80,7 +81,7 @@ impl<'tcx, 'compilation> AnalysisContext<'tcx, 'compilation> {
analysis_options: AnalysisOptions,
) -> Option<Self> {
info!("Initializing AnalysisContext");
let mut entry_fn_def_id: Option<DefId> = None;
let mut entry_fn_def_ids = HashSet::new();

// Find the DefId for the entry point according to the function name
if !analysis_options.entry_func.is_empty() {
Expand All @@ -90,33 +91,37 @@ impl<'tcx, 'compilation> AnalysisContext<'tcx, 'compilation> {
if def_kind == DefKind::Fn || def_kind == DefKind::AssocFn {
let item_name = tcx.item_name(local_def_id.to_def_id());
if item_name.to_string() == *entr_func {
entry_fn_def_id = Some(local_def_id.to_def_id());
entry_fn_def_ids.insert(local_def_id.to_def_id());
}
}
}
} else {
// If `entry_func` is not specified and the local crate is a library,
// then we add all effectively public (i.e. can be called by library users)
// functions to the `entry_funcs`.
entry_fn_def_ids.extend(&lib_entry_funcs(tcx));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entry point for the analysis can be specified using either the entry_func or entry_def_id option. I think the entry_fn_def_ids should include all the library entry functions when neither option is set.

We need to check if the local crate is a library.

}

if entry_fn_def_id.is_none() {
if entry_fn_def_ids.is_empty() {
// If `entry_def_id` flag is provided, find entry point according to the index
entry_fn_def_id = if let Some(entry_def_id) = analysis_options.entry_def_id {
Some(DefId::local(DefIndex::from_u32(entry_def_id)))
if let Some(entry_def_id) = analysis_options.entry_def_id {
entry_fn_def_ids.insert(DefId::local(DefIndex::from_u32(entry_def_id)));
} else {
// If no entry point specified, use the default entry
if let Some((def_id, _)) = tcx.entry_fn(()) {
Some(def_id)
} else {
None
entry_fn_def_ids.insert(def_id);
}
}
}

if let Some(entry_def_id) = entry_fn_def_id {
let entry_name = tcx.item_name(entry_def_id);
info!("Entry Point: {:?}, DefId: {:?}", entry_name, entry_def_id);
if !entry_fn_def_ids.is_empty() {
entry_fn_def_ids
.iter()
.for_each(|def_id| info!("Entry Point: {:?}, DefId: {:?}", tcx.item_name(*def_id), def_id));
Some(Self {
tcx,
session,
entry_point: entry_def_id,
entry_points: entry_fn_def_ids,
analysis_options,
functions: IndexVec::new(),
func_id_map: HashMap::new(),
Expand Down Expand Up @@ -323,6 +328,4 @@ impl<'tcx, 'compilation> AnalysisContext<'tcx, 'compilation> {
self.aux_local_indexer.insert(func_id, aux_local_index + 1);
aux
}

}

1 change: 1 addition & 0 deletions src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ pub mod context;
pub mod function;
pub mod analysis_context;
pub mod known_names;
mod visibility;
pub mod path;
30 changes: 30 additions & 0 deletions src/mir/visibility.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! Utilities of resolving visibility issues.

use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::TyCtxt;
use std::collections::HashSet;

pub(crate) fn is_reachable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
match def_id.as_local() {
Some(def_id) => tcx.effective_visibilities(()).is_reachable(def_id),
None => false,
}
}

pub(crate) fn lib_entry_funcs<'tcx>(tcx: TyCtxt<'tcx>) -> HashSet<DefId> {
let mut set = HashSet::new();
for item in tcx.hir_crate_items(()).items() {
let def_id = item.owner_id.def_id.to_def_id();
match tcx.def_kind(def_id) {
// XXX: make sure those cover all possible entries for call graph construction
DefKind::AssocFn | DefKind::Fn => {
if is_reachable(tcx, def_id) {
set.insert(def_id);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to skip generic functions, constant functions and higher order function.

}
}
_ => {}
}
}
set
}
9 changes: 6 additions & 3 deletions src/pta/andersen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,12 @@ impl<'pta, 'tcx, 'compilation> AndersenPTA<'pta, 'tcx, 'compilation> {
/// Initialize the analysis.
pub fn initialize(&mut self) {
// add the entry point to the call graph
let entry_point = self.acx.entry_point;
let entry_func_id = self.acx.get_func_id(entry_point, self.tcx().mk_args(&[]));
self.call_graph.add_node(entry_func_id);
let entry_points = self.acx.entry_points.clone();

for entry_point in entry_points {
let entry_func_id = self.acx.get_func_id(entry_point, self.tcx().mk_args(&[]));
self.call_graph.add_node(entry_func_id);
}

// process statements of reachable functions
self.process_reach_funcs();
Expand Down
9 changes: 6 additions & 3 deletions src/pta/context_sensitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,13 @@ impl<'pta, 'tcx, 'compilation, S: ContextStrategy> ContextSensitivePTA<'pta, 'tc
/// Initialize the analysis.
pub fn initialize(&mut self) {
// add the entry point to the call graph
let entry_point = self.acx.entry_point;
let empty_context_id = self.get_empty_context_id();
let entry_func_id = self.acx.get_func_id(entry_point, self.tcx().mk_args(&[]));
self.call_graph.add_node(CSFuncId::new(empty_context_id, entry_func_id));
let entry_points = self.acx.entry_points.clone();
for entry_point in entry_points {
let entry_func_id = self.acx.get_func_id(entry_point, self.tcx().mk_args(&[]));
self.call_graph
.add_node(CSFuncId::new(empty_context_id, entry_func_id));
}

// process statements of reachable functions
self.process_reach_funcs();
Expand Down