parent
fe00358888
commit
0b3d0cde8b
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -487,6 +487,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"la-arena",
|
||||
"limit",
|
||||
"log",
|
||||
"mbe",
|
||||
"once_cell",
|
||||
@ -508,6 +509,7 @@ dependencies = [
|
||||
"either",
|
||||
"expect-test",
|
||||
"la-arena",
|
||||
"limit",
|
||||
"log",
|
||||
"mbe",
|
||||
"parser",
|
||||
@ -534,6 +536,7 @@ dependencies = [
|
||||
"hir_expand",
|
||||
"itertools",
|
||||
"la-arena",
|
||||
"limit",
|
||||
"log",
|
||||
"once_cell",
|
||||
"profile",
|
||||
@ -640,6 +643,7 @@ dependencies = [
|
||||
"fst",
|
||||
"hir",
|
||||
"itertools",
|
||||
"limit",
|
||||
"log",
|
||||
"once_cell",
|
||||
"profile",
|
||||
@ -792,6 +796,10 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "limit"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
|
@ -31,6 +31,7 @@ hir_expand = { path = "../hir_expand", version = "0.0.0" }
|
||||
mbe = { path = "../mbe", version = "0.0.0" }
|
||||
cfg = { path = "../cfg", version = "0.0.0" }
|
||||
tt = { path = "../tt", version = "0.0.0" }
|
||||
limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
|
@ -15,6 +15,7 @@
|
||||
ast_id_map::AstIdMap, hygiene::Hygiene, AstId, ExpandResult, HirFileId, InFile, MacroDefId,
|
||||
};
|
||||
use la_arena::{Arena, ArenaMap};
|
||||
use limit::Limit;
|
||||
use profile::Count;
|
||||
use rustc_hash::FxHashMap;
|
||||
use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
|
||||
@ -53,10 +54,10 @@ pub struct Expander {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
const EXPANSION_RECURSION_LIMIT: usize = 32;
|
||||
const EXPANSION_RECURSION_LIMIT: Limit = Limit::new(32);
|
||||
|
||||
#[cfg(not(test))]
|
||||
const EXPANSION_RECURSION_LIMIT: usize = 128;
|
||||
const EXPANSION_RECURSION_LIMIT: Limit = Limit::new(128);
|
||||
|
||||
impl CfgExpander {
|
||||
pub(crate) fn new(
|
||||
@ -99,7 +100,7 @@ pub fn enter_expand<T: ast::AstNode>(
|
||||
db: &dyn DefDatabase,
|
||||
macro_call: ast::MacroCall,
|
||||
) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
|
||||
if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
|
||||
if EXPANSION_RECURSION_LIMIT.check(self.recursion_limit + 1).is_err() {
|
||||
cov_mark::hit!(your_stack_belongs_to_me);
|
||||
return Ok(ExpandResult::str_err(
|
||||
"reached recursion limit during macro expansion".into(),
|
||||
|
@ -19,6 +19,7 @@
|
||||
use hir_expand::{InFile, MacroCallLoc};
|
||||
use itertools::Itertools;
|
||||
use la_arena::Idx;
|
||||
use limit::Limit;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use syntax::ast;
|
||||
|
||||
@ -49,9 +50,9 @@
|
||||
UnresolvedMacro,
|
||||
};
|
||||
|
||||
const GLOB_RECURSION_LIMIT: usize = 100;
|
||||
const EXPANSION_DEPTH_LIMIT: usize = 128;
|
||||
const FIXED_POINT_LIMIT: usize = 8192;
|
||||
const GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
|
||||
const EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128);
|
||||
const FIXED_POINT_LIMIT: Limit = Limit::new(8192);
|
||||
|
||||
pub(super) fn collect_defs(
|
||||
db: &dyn DefDatabase,
|
||||
@ -357,7 +358,7 @@ fn collect(&mut self) {
|
||||
}
|
||||
|
||||
i += 1;
|
||||
if i == FIXED_POINT_LIMIT {
|
||||
if FIXED_POINT_LIMIT.check(i).is_err() {
|
||||
log::error!("name resolution is stuck");
|
||||
break 'outer;
|
||||
}
|
||||
@ -924,7 +925,7 @@ fn update_recursive(
|
||||
import_type: ImportType,
|
||||
depth: usize,
|
||||
) {
|
||||
if depth > GLOB_RECURSION_LIMIT {
|
||||
if GLOB_RECURSION_LIMIT.check(depth).is_err() {
|
||||
// prevent stack overflows (but this shouldn't be possible)
|
||||
panic!("infinite recursion in glob imports!");
|
||||
}
|
||||
@ -1157,7 +1158,7 @@ fn collect_macro_expansion(
|
||||
macro_call_id: MacroCallId,
|
||||
depth: usize,
|
||||
) {
|
||||
if depth > EXPANSION_DEPTH_LIMIT {
|
||||
if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
|
||||
cov_mark::hit!(macro_expansion_overflow);
|
||||
log::warn!("macro expansion is too deep");
|
||||
return;
|
||||
|
@ -1,11 +1,12 @@
|
||||
//! This module resolves `mod foo;` declaration to file.
|
||||
use base_db::{AnchoredPath, FileId};
|
||||
use hir_expand::name::Name;
|
||||
use limit::Limit;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{db::DefDatabase, HirFileId};
|
||||
|
||||
const MOD_DEPTH_LIMIT: u32 = 32;
|
||||
const MOD_DEPTH_LIMIT: Limit = Limit::new(32);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) struct ModDir {
|
||||
@ -25,7 +26,7 @@ pub(super) fn root() -> ModDir {
|
||||
}
|
||||
fn child(&self, dir_path: DirPath, root_non_dir_owner: bool) -> Option<ModDir> {
|
||||
let depth = self.depth + 1;
|
||||
if depth > MOD_DEPTH_LIMIT {
|
||||
if MOD_DEPTH_LIMIT.check(depth as usize).is_err() {
|
||||
log::error!("MOD_DEPTH_LIMIT exceeded");
|
||||
cov_mark::hit!(circular_mods);
|
||||
return None;
|
||||
|
@ -21,6 +21,7 @@ parser = { path = "../parser", version = "0.0.0" }
|
||||
profile = { path = "../profile", version = "0.0.0" }
|
||||
tt = { path = "../tt", version = "0.0.0" }
|
||||
mbe = { path = "../mbe", version = "0.0.0" }
|
||||
limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
|
@ -3,6 +3,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use base_db::{salsa, SourceDatabase};
|
||||
use limit::Limit;
|
||||
use mbe::{ExpandError, ExpandResult};
|
||||
use parser::FragmentKind;
|
||||
use syntax::{
|
||||
@ -21,7 +22,7 @@
|
||||
///
|
||||
/// If an invocation produces more tokens than this limit, it will not be stored in the database and
|
||||
/// an error will be emitted.
|
||||
const TOKEN_LIMIT: usize = 524288;
|
||||
const TOKEN_LIMIT: Limit = Limit::new(524288);
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum TokenExpander {
|
||||
@ -356,10 +357,12 @@ fn macro_expand_with_arg(
|
||||
let ExpandResult { value: tt, err } = macro_rules.expand(db, id, ¯o_arg.0);
|
||||
// Set a hard limit for the expanded tt
|
||||
let count = tt.count();
|
||||
if count > TOKEN_LIMIT {
|
||||
// XXX: Make ExpandResult a real error and use .map_err instead?
|
||||
if TOKEN_LIMIT.check(count).is_err() {
|
||||
return ExpandResult::str_err(format!(
|
||||
"macro invocation exceeds token limit: produced {} tokens, limit is {}",
|
||||
count, TOKEN_LIMIT,
|
||||
count,
|
||||
TOKEN_LIMIT.inner(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ hir_expand = { path = "../hir_expand", version = "0.0.0" }
|
||||
base_db = { path = "../base_db", version = "0.0.0" }
|
||||
profile = { path = "../profile", version = "0.0.0" }
|
||||
syntax = { path = "../syntax", version = "0.0.0" }
|
||||
limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
|
@ -9,6 +9,7 @@
|
||||
use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
|
||||
use hir_def::lang_item::LangItemTarget;
|
||||
use hir_expand::name::name;
|
||||
use limit::Limit;
|
||||
use log::{info, warn};
|
||||
|
||||
use crate::{
|
||||
@ -17,6 +18,8 @@
|
||||
Ty, TyBuilder, TyKind,
|
||||
};
|
||||
|
||||
const AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
|
||||
|
||||
pub(crate) enum AutoderefKind {
|
||||
Builtin,
|
||||
Overloaded,
|
||||
@ -63,7 +66,7 @@ fn next(&mut self) -> Option<Self::Item> {
|
||||
return Some((self.ty.clone(), 0));
|
||||
}
|
||||
|
||||
if self.steps.len() >= AUTODEREF_RECURSION_LIMIT {
|
||||
if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -87,8 +90,6 @@ fn next(&mut self) -> Option<Self::Item> {
|
||||
}
|
||||
}
|
||||
|
||||
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
||||
|
||||
// FIXME: replace uses of this with Autoderef above
|
||||
pub fn autoderef<'a>(
|
||||
db: &'a dyn HirDatabase,
|
||||
@ -99,7 +100,7 @@ pub fn autoderef<'a>(
|
||||
successors(Some(ty), move |ty| {
|
||||
deref(db, krate?, InEnvironment { goal: ty, environment: environment.clone() })
|
||||
})
|
||||
.take(AUTODEREF_RECURSION_LIMIT)
|
||||
.take(AUTODEREF_RECURSION_LIMIT.inner())
|
||||
}
|
||||
|
||||
pub(crate) fn deref(
|
||||
|
@ -65,7 +65,7 @@ pub(crate) fn replace_derive_with_manual_impl(
|
||||
current_crate,
|
||||
NameToImport::Exact(trait_name.to_string()),
|
||||
items_locator::AssocItemSearch::Exclude,
|
||||
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
|
||||
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
|
||||
ModuleDef::Trait(trait_) => Some(trait_),
|
||||
|
@ -187,7 +187,7 @@ pub fn resolve_completion_edits(
|
||||
current_crate,
|
||||
NameToImport::Exact(imported_name),
|
||||
items_locator::AssocItemSearch::Include,
|
||||
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
|
||||
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|candidate| {
|
||||
current_module
|
||||
|
@ -26,6 +26,7 @@ profile = { path = "../profile", version = "0.0.0" }
|
||||
# ide should depend only on the top-level `hir` package. if you need
|
||||
# something from some `hir_xxx` subpackage, reexport the API via `hir`.
|
||||
hir = { path = "../hir", version = "0.0.0" }
|
||||
limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
|
@ -282,7 +282,7 @@ fn path_applicable_imports(
|
||||
//
|
||||
// see also an ignored test under FIXME comment in the qualify_path.rs module
|
||||
AssocItemSearch::Exclude,
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT),
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|item| {
|
||||
let mod_path = mod_path(item)?;
|
||||
@ -299,7 +299,7 @@ fn path_applicable_imports(
|
||||
current_crate,
|
||||
path_candidate.name.clone(),
|
||||
AssocItemSearch::Include,
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT),
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|item| {
|
||||
import_for_item(
|
||||
@ -445,7 +445,7 @@ fn trait_applicable_items(
|
||||
current_crate,
|
||||
trait_candidate.assoc_item_name.clone(),
|
||||
AssocItemSearch::AssocItemsOnly,
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT),
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|input| item_as_assoc(db, input))
|
||||
.filter_map(|assoc| {
|
||||
|
@ -7,6 +7,7 @@
|
||||
import_map::{self, ImportKind},
|
||||
AsAssocItem, Crate, ItemInNs, ModuleDef, Semantics,
|
||||
};
|
||||
use limit::Limit;
|
||||
use syntax::{ast, AstNode, SyntaxKind::NAME};
|
||||
|
||||
use crate::{
|
||||
@ -17,7 +18,7 @@
|
||||
};
|
||||
|
||||
/// A value to use, when uncertain which limit to pick.
|
||||
pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40;
|
||||
pub const DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(40);
|
||||
|
||||
/// Three possible ways to search for the name in associated and/or other items.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
9
crates/limit/Cargo.toml
Normal file
9
crates/limit/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "limit"
|
||||
version = "0.0.0"
|
||||
description = "TBD"
|
||||
license = "MIT OR Apache-2.0"
|
||||
authors = ["rust-analyzer developers"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
31
crates/limit/src/lib.rs
Normal file
31
crates/limit/src/lib.rs
Normal file
@ -0,0 +1,31 @@
|
||||
//! limit defines a struct to enforce limits.
|
||||
|
||||
/// Represents a struct used to enforce a numerical limit.
|
||||
pub struct Limit {
|
||||
upper_bound: usize,
|
||||
}
|
||||
|
||||
impl Limit {
|
||||
/// Creates a new limit.
|
||||
#[inline]
|
||||
pub const fn new(upper_bound: usize) -> Self {
|
||||
Self { upper_bound }
|
||||
}
|
||||
|
||||
/// Gets the underlying numeric limit.
|
||||
#[inline]
|
||||
pub const fn inner(&self) -> usize {
|
||||
self.upper_bound
|
||||
}
|
||||
|
||||
/// Checks whether the given value is below the limit.
|
||||
/// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
|
||||
#[inline]
|
||||
pub const fn check(&self, other: usize) -> Result<(), ()> {
|
||||
if other > self.upper_bound {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user