mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
feat: Tag macro calls as unsafe if they expand to unsafe expressions
This commit is contained in:
parent
5a87f09a71
commit
68de7b30e0
25 changed files with 208 additions and 68 deletions
|
@ -358,6 +358,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
self.imp.resolve_macro_call(macro_call)
|
self.imp.resolve_macro_call(macro_call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
|
||||||
|
self.imp.is_unsafe_macro_call(macro_call)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
|
pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
|
||||||
self.imp.resolve_attr_macro_call(item)
|
self.imp.resolve_attr_macro_call(item)
|
||||||
}
|
}
|
||||||
|
@ -961,6 +965,12 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
sa.resolve_macro_call(self.db, macro_call)
|
sa.resolve_macro_call(self.db, macro_call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
|
||||||
|
let sa = self.analyze(macro_call.syntax());
|
||||||
|
let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
|
||||||
|
sa.is_unsafe_macro_call(self.db, macro_call)
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
|
fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
|
||||||
let item_in_file = self.wrap_node_infile(item.clone());
|
let item_in_file = self.wrap_node_infile(item.clone());
|
||||||
let id = self.with_ctx(|ctx| {
|
let id = self.with_ctx(|ctx| {
|
||||||
|
|
|
@ -25,7 +25,10 @@ use hir_def::{
|
||||||
};
|
};
|
||||||
use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
|
use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
|
||||||
use hir_ty::{
|
use hir_ty::{
|
||||||
diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
|
diagnostics::{
|
||||||
|
record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
|
||||||
|
UnsafeExpr,
|
||||||
|
},
|
||||||
Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
|
Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
|
||||||
TyLoweringContext,
|
TyLoweringContext,
|
||||||
};
|
};
|
||||||
|
@ -46,8 +49,7 @@ use base_db::CrateId;
|
||||||
pub(crate) struct SourceAnalyzer {
|
pub(crate) struct SourceAnalyzer {
|
||||||
pub(crate) file_id: HirFileId,
|
pub(crate) file_id: HirFileId,
|
||||||
pub(crate) resolver: Resolver,
|
pub(crate) resolver: Resolver,
|
||||||
body: Option<Arc<Body>>,
|
def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
|
||||||
body_source_map: Option<Arc<BodySourceMap>>,
|
|
||||||
infer: Option<Arc<InferenceResult>>,
|
infer: Option<Arc<InferenceResult>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +69,7 @@ impl SourceAnalyzer {
|
||||||
let resolver = resolver_for_scope(db.upcast(), def, scope);
|
let resolver = resolver_for_scope(db.upcast(), def, scope);
|
||||||
SourceAnalyzer {
|
SourceAnalyzer {
|
||||||
resolver,
|
resolver,
|
||||||
body: Some(body),
|
def: Some((def, body, source_map)),
|
||||||
body_source_map: Some(source_map),
|
|
||||||
infer: Some(db.infer(def)),
|
infer: Some(db.infer(def)),
|
||||||
file_id,
|
file_id,
|
||||||
}
|
}
|
||||||
|
@ -87,26 +88,21 @@ impl SourceAnalyzer {
|
||||||
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.with_value(offset)),
|
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.with_value(offset)),
|
||||||
};
|
};
|
||||||
let resolver = resolver_for_scope(db.upcast(), def, scope);
|
let resolver = resolver_for_scope(db.upcast(), def, scope);
|
||||||
SourceAnalyzer {
|
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
|
||||||
resolver,
|
|
||||||
body: Some(body),
|
|
||||||
body_source_map: Some(source_map),
|
|
||||||
infer: None,
|
|
||||||
file_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_for_resolver(
|
pub(crate) fn new_for_resolver(
|
||||||
resolver: Resolver,
|
resolver: Resolver,
|
||||||
node: InFile<&SyntaxNode>,
|
node: InFile<&SyntaxNode>,
|
||||||
) -> SourceAnalyzer {
|
) -> SourceAnalyzer {
|
||||||
SourceAnalyzer {
|
SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
|
||||||
resolver,
|
}
|
||||||
body: None,
|
|
||||||
body_source_map: None,
|
fn body_source_map(&self) -> Option<&BodySourceMap> {
|
||||||
infer: None,
|
self.def.as_ref().map(|(.., source_map)| &**source_map)
|
||||||
file_id: node.file_id,
|
}
|
||||||
}
|
fn body(&self) -> Option<&Body> {
|
||||||
|
self.def.as_ref().map(|(_, body, _)| &**body)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
|
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
|
||||||
|
@ -116,14 +112,14 @@ impl SourceAnalyzer {
|
||||||
}
|
}
|
||||||
_ => InFile::new(self.file_id, expr.clone()),
|
_ => InFile::new(self.file_id, expr.clone()),
|
||||||
};
|
};
|
||||||
let sm = self.body_source_map.as_ref()?;
|
let sm = self.body_source_map()?;
|
||||||
sm.node_expr(src.as_ref())
|
sm.node_expr(src.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
|
fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
|
||||||
// FIXME: macros, see `expr_id`
|
// FIXME: macros, see `expr_id`
|
||||||
let src = InFile { file_id: self.file_id, value: pat };
|
let src = InFile { file_id: self.file_id, value: pat };
|
||||||
self.body_source_map.as_ref()?.node_pat(src)
|
self.body_source_map()?.node_pat(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_expr(
|
fn expand_expr(
|
||||||
|
@ -131,7 +127,7 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
expr: InFile<ast::MacroCall>,
|
expr: InFile<ast::MacroCall>,
|
||||||
) -> Option<InFile<ast::Expr>> {
|
) -> Option<InFile<ast::Expr>> {
|
||||||
let macro_file = self.body_source_map.as_ref()?.node_macro_file(expr.as_ref())?;
|
let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
|
||||||
let expanded = db.parse_or_expand(macro_file)?;
|
let expanded = db.parse_or_expand(macro_file)?;
|
||||||
|
|
||||||
let res = match ast::MacroCall::cast(expanded.clone()) {
|
let res = match ast::MacroCall::cast(expanded.clone()) {
|
||||||
|
@ -196,7 +192,7 @@ impl SourceAnalyzer {
|
||||||
param: &ast::SelfParam,
|
param: &ast::SelfParam,
|
||||||
) -> Option<Type> {
|
) -> Option<Type> {
|
||||||
let src = InFile { file_id: self.file_id, value: param };
|
let src = InFile { file_id: self.file_id, value: param };
|
||||||
let pat_id = self.body_source_map.as_ref()?.node_self_param(src)?;
|
let pat_id = self.body_source_map()?.node_self_param(src)?;
|
||||||
let ty = self.infer.as_ref()?[pat_id].clone();
|
let ty = self.infer.as_ref()?[pat_id].clone();
|
||||||
Type::new_with_resolver(db, &self.resolver, ty)
|
Type::new_with_resolver(db, &self.resolver, ty)
|
||||||
}
|
}
|
||||||
|
@ -226,7 +222,7 @@ impl SourceAnalyzer {
|
||||||
) -> Option<(Field, Option<Local>, Type)> {
|
) -> Option<(Field, Option<Local>, Type)> {
|
||||||
let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
|
let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
|
||||||
let expr = ast::Expr::from(record_expr);
|
let expr = ast::Expr::from(record_expr);
|
||||||
let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
|
let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
|
||||||
|
|
||||||
let local_name = field.field_name()?.as_name();
|
let local_name = field.field_name()?.as_name();
|
||||||
let local = if field.name_ref().is_some() {
|
let local = if field.name_ref().is_some() {
|
||||||
|
@ -279,7 +275,7 @@ impl SourceAnalyzer {
|
||||||
pat: &ast::IdentPat,
|
pat: &ast::IdentPat,
|
||||||
) -> Option<ModuleDef> {
|
) -> Option<ModuleDef> {
|
||||||
let pat_id = self.pat_id(&pat.clone().into())?;
|
let pat_id = self.pat_id(&pat.clone().into())?;
|
||||||
let body = self.body.as_ref()?;
|
let body = self.body()?;
|
||||||
let path = match &body[pat_id] {
|
let path = match &body[pat_id] {
|
||||||
Pat::Path(path) => path,
|
Pat::Path(path) => path,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
@ -415,7 +411,7 @@ impl SourceAnalyzer {
|
||||||
literal: &ast::RecordExpr,
|
literal: &ast::RecordExpr,
|
||||||
) -> Option<Vec<(Field, Type)>> {
|
) -> Option<Vec<(Field, Type)>> {
|
||||||
let krate = self.resolver.krate()?;
|
let krate = self.resolver.krate()?;
|
||||||
let body = self.body.as_ref()?;
|
let body = self.body()?;
|
||||||
let infer = self.infer.as_ref()?;
|
let infer = self.infer.as_ref()?;
|
||||||
|
|
||||||
let expr_id = self.expr_id(db, &literal.clone().into())?;
|
let expr_id = self.expr_id(db, &literal.clone().into())?;
|
||||||
|
@ -433,7 +429,7 @@ impl SourceAnalyzer {
|
||||||
pattern: &ast::RecordPat,
|
pattern: &ast::RecordPat,
|
||||||
) -> Option<Vec<(Field, Type)>> {
|
) -> Option<Vec<(Field, Type)>> {
|
||||||
let krate = self.resolver.krate()?;
|
let krate = self.resolver.krate()?;
|
||||||
let body = self.body.as_ref()?;
|
let body = self.body()?;
|
||||||
let infer = self.infer.as_ref()?;
|
let infer = self.infer.as_ref()?;
|
||||||
|
|
||||||
let pat_id = self.pat_id(&pattern.clone().into())?;
|
let pat_id = self.pat_id(&pattern.clone().into())?;
|
||||||
|
@ -488,6 +484,34 @@ impl SourceAnalyzer {
|
||||||
let expr_id = self.expr_id(db, &record_lit.into())?;
|
let expr_id = self.expr_id(db, &record_lit.into())?;
|
||||||
infer.variant_resolution_for_expr(expr_id)
|
infer.variant_resolution_for_expr(expr_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_unsafe_macro_call(
|
||||||
|
&self,
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
macro_call: InFile<&ast::MacroCall>,
|
||||||
|
) -> bool {
|
||||||
|
if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
|
||||||
|
if let Some(expr_ids) = sm.macro_expansion_expr(macro_call) {
|
||||||
|
let mut is_unsafe = false;
|
||||||
|
for &expr_id in expr_ids {
|
||||||
|
unsafe_expressions(
|
||||||
|
db,
|
||||||
|
infer,
|
||||||
|
*def,
|
||||||
|
body,
|
||||||
|
expr_id,
|
||||||
|
&mut |UnsafeExpr { inside_unsafe_block, .. }| {
|
||||||
|
is_unsafe |= !inside_unsafe_block
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if is_unsafe {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scope_for(
|
fn scope_for(
|
||||||
|
|
|
@ -19,6 +19,7 @@ use la_arena::{Arena, ArenaMap};
|
||||||
use limit::Limit;
|
use limit::Limit;
|
||||||
use profile::Count;
|
use profile::Count;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
|
use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -293,6 +294,10 @@ pub struct BodySourceMap {
|
||||||
field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
|
field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
|
||||||
field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
|
field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
|
||||||
|
|
||||||
|
/// Maps a macro call to its lowered expressions, a single one if it expands to an expression,
|
||||||
|
/// or multiple if it expands to MacroStmts.
|
||||||
|
macro_call_to_exprs: FxHashMap<InFile<AstPtr<ast::MacroCall>>, SmallVec<[ExprId; 1]>>,
|
||||||
|
|
||||||
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
|
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
|
||||||
|
|
||||||
/// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
|
/// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
|
||||||
|
@ -461,6 +466,11 @@ impl BodySourceMap {
|
||||||
self.field_map.get(&src).cloned()
|
self.field_map.get(&src).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroCall>) -> Option<&[ExprId]> {
|
||||||
|
let src = node.map(AstPtr::new);
|
||||||
|
self.macro_call_to_exprs.get(&src).map(|it| &**it)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the body source map's diagnostics.
|
/// Get a reference to the body source map's diagnostics.
|
||||||
pub fn diagnostics(&self) -> &[BodyDiagnostic] {
|
pub fn diagnostics(&self) -> &[BodyDiagnostic] {
|
||||||
&self.diagnostics
|
&self.diagnostics
|
||||||
|
|
|
@ -13,6 +13,7 @@ use hir_expand::{
|
||||||
use la_arena::Arena;
|
use la_arena::Arena;
|
||||||
use profile::Count;
|
use profile::Count;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use smallvec::smallvec;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
|
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
|
||||||
|
@ -507,14 +508,21 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
ast::Expr::MacroCall(e) => {
|
ast::Expr::MacroCall(e) => {
|
||||||
let macro_ptr = AstPtr::new(&e);
|
let macro_ptr = AstPtr::new(&e);
|
||||||
let mut ids = None;
|
let mut id = None;
|
||||||
self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
|
self.collect_macro_call(e, macro_ptr.clone(), true, |this, expansion| {
|
||||||
ids.get_or_insert(match expansion {
|
if let Some(it) = expansion {
|
||||||
Some(it) => this.collect_expr(it),
|
id.get_or_insert(this.collect_expr(it));
|
||||||
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
ids.unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()))
|
match id {
|
||||||
|
Some(id) => {
|
||||||
|
self.source_map
|
||||||
|
.macro_call_to_exprs
|
||||||
|
.insert(self.expander.to_source(macro_ptr), smallvec![id]);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
None => self.alloc_expr(Expr::Missing, syntax_ptr.clone()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast::Expr::MacroStmts(e) => {
|
ast::Expr::MacroStmts(e) => {
|
||||||
e.statements().for_each(|s| self.collect_stmt(s));
|
e.statements().for_each(|s| self.collect_stmt(s));
|
||||||
|
@ -529,12 +537,12 @@ impl ExprCollector<'_> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
|
fn collect_macro_call<F: FnOnce(&mut Self, Option<T>), T: ast::AstNode>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mcall: ast::MacroCall,
|
mcall: ast::MacroCall,
|
||||||
syntax_ptr: AstPtr<ast::MacroCall>,
|
syntax_ptr: AstPtr<ast::MacroCall>,
|
||||||
record_diagnostics: bool,
|
record_diagnostics: bool,
|
||||||
mut collector: F,
|
collector: F,
|
||||||
) {
|
) {
|
||||||
// File containing the macro call. Expansion errors will be attached here.
|
// File containing the macro call. Expansion errors will be attached here.
|
||||||
let outer_file = self.expander.current_file_id;
|
let outer_file = self.expander.current_file_id;
|
||||||
|
@ -625,17 +633,17 @@ impl ExprCollector<'_> {
|
||||||
let macro_ptr = AstPtr::new(&m);
|
let macro_ptr = AstPtr::new(&m);
|
||||||
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
||||||
|
|
||||||
self.collect_macro_call(
|
let prev_stmt = self.statements_in_scope.len();
|
||||||
m,
|
let mut tail = None;
|
||||||
macro_ptr,
|
self.collect_macro_call(m, macro_ptr.clone(), false, |this, expansion| {
|
||||||
false,
|
match expansion {
|
||||||
|this, expansion| match expansion {
|
|
||||||
Some(expansion) => {
|
Some(expansion) => {
|
||||||
let statements: ast::MacroStmts = expansion;
|
let statements: ast::MacroStmts = expansion;
|
||||||
|
|
||||||
statements.statements().for_each(|stmt| this.collect_stmt(stmt));
|
statements.statements().for_each(|stmt| this.collect_stmt(stmt));
|
||||||
if let Some(expr) = statements.expr() {
|
if let Some(expr) = statements.expr() {
|
||||||
let expr = this.collect_expr(expr);
|
let expr = this.collect_expr(expr);
|
||||||
|
tail = Some(expr);
|
||||||
this.statements_in_scope
|
this.statements_in_scope
|
||||||
.push(Statement::Expr { expr, has_semi });
|
.push(Statement::Expr { expr, has_semi });
|
||||||
}
|
}
|
||||||
|
@ -644,8 +652,24 @@ impl ExprCollector<'_> {
|
||||||
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
||||||
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
});
|
||||||
|
let mut macro_exprs = smallvec![];
|
||||||
|
for stmt in &self.statements_in_scope[prev_stmt..] {
|
||||||
|
match *stmt {
|
||||||
|
Statement::Let { initializer, else_branch, .. } => {
|
||||||
|
macro_exprs.extend(initializer);
|
||||||
|
macro_exprs.extend(else_branch);
|
||||||
|
}
|
||||||
|
Statement::Expr { expr, .. } => macro_exprs.push(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
macro_exprs.extend(tail);
|
||||||
|
if !macro_exprs.is_empty() {
|
||||||
|
self.source_map
|
||||||
|
.macro_call_to_exprs
|
||||||
|
.insert(self.expander.to_source(macro_ptr), macro_exprs);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let expr = self.collect_expr_opt(stmt.expr());
|
let expr = self.collect_expr_opt(stmt.expr());
|
||||||
self.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
self.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
||||||
|
|
|
@ -9,5 +9,5 @@ pub use crate::diagnostics::{
|
||||||
expr::{
|
expr::{
|
||||||
record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
|
record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
|
||||||
},
|
},
|
||||||
unsafe_check::missing_unsafe,
|
unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,54 +12,57 @@ use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind};
|
||||||
|
|
||||||
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
||||||
let infer = db.infer(def);
|
let infer = db.infer(def);
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
let is_unsafe = match def {
|
let is_unsafe = match def {
|
||||||
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
|
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
|
||||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
||||||
};
|
};
|
||||||
if is_unsafe {
|
if is_unsafe {
|
||||||
return Vec::new();
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_expressions(db, &infer, def)
|
let body = db.body(def);
|
||||||
.into_iter()
|
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
|
||||||
.filter(|it| !it.inside_unsafe_block)
|
if !expr.inside_unsafe_block {
|
||||||
.map(|it| it.expr)
|
res.push(expr.expr);
|
||||||
.collect()
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UnsafeExpr {
|
pub struct UnsafeExpr {
|
||||||
pub(crate) expr: ExprId,
|
pub expr: ExprId,
|
||||||
pub(crate) inside_unsafe_block: bool,
|
pub inside_unsafe_block: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unsafe_expressions(
|
pub fn unsafe_expressions(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
infer: &InferenceResult,
|
infer: &InferenceResult,
|
||||||
def: DefWithBodyId,
|
def: DefWithBodyId,
|
||||||
) -> Vec<UnsafeExpr> {
|
body: &Body,
|
||||||
let mut unsafe_exprs = vec![];
|
current: ExprId,
|
||||||
let body = db.body(def);
|
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
||||||
walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false);
|
) {
|
||||||
|
walk_unsafe(db, infer, def, body, current, false, unsafe_expr_cb)
|
||||||
unsafe_exprs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_unsafe(
|
fn walk_unsafe(
|
||||||
unsafe_exprs: &mut Vec<UnsafeExpr>,
|
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
infer: &InferenceResult,
|
infer: &InferenceResult,
|
||||||
def: DefWithBodyId,
|
def: DefWithBodyId,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
current: ExprId,
|
current: ExprId,
|
||||||
inside_unsafe_block: bool,
|
inside_unsafe_block: bool,
|
||||||
|
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
||||||
) {
|
) {
|
||||||
let expr = &body.exprs[current];
|
let expr = &body.exprs[current];
|
||||||
match expr {
|
match expr {
|
||||||
&Expr::Call { callee, .. } => {
|
&Expr::Call { callee, .. } => {
|
||||||
if let Some(func) = infer[callee].as_fn_def(db) {
|
if let Some(func) = infer[callee].as_fn_def(db) {
|
||||||
if db.function_data(func).is_unsafe() {
|
if db.function_data(func).is_unsafe() {
|
||||||
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
|
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +71,7 @@ fn walk_unsafe(
|
||||||
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
|
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
|
||||||
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
|
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
|
||||||
if db.static_data(id).mutable {
|
if db.static_data(id).mutable {
|
||||||
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
|
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,21 +81,21 @@ fn walk_unsafe(
|
||||||
.map(|(func, _)| db.function_data(func).is_unsafe())
|
.map(|(func, _)| db.function_data(func).is_unsafe())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
|
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
|
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
|
||||||
if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
|
if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
|
||||||
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
|
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Unsafe { body: child } => {
|
Expr::Unsafe { body: child } => {
|
||||||
return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true);
|
return walk_unsafe(db, infer, def, body, *child, true, unsafe_expr_cb);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr.walk_child_exprs(|child| {
|
expr.walk_child_exprs(|child| {
|
||||||
walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
|
walk_unsafe(db, infer, def, body, child, inside_unsafe_block, unsafe_expr_cb);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,6 +248,16 @@ fn highlight_name_ref(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Definition::Macro(_) => {
|
||||||
|
if let Some(macro_call) =
|
||||||
|
ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref)
|
||||||
|
.and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast))
|
||||||
|
{
|
||||||
|
if sema.is_unsafe_macro_call(¯o_call) {
|
||||||
|
h |= HlMod::Unsafe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.operator.unsafe { color: #BC8383; }
|
.operator.unsafe { color: #BC8383; }
|
||||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.macro.unsafe { color: #BC8383; }
|
||||||
.parameter { color: #94BFF3; }
|
.parameter { color: #94BFF3; }
|
||||||
.text { color: #DCDCCC; }
|
.text { color: #DCDCCC; }
|
||||||
.type { color: #7CB8BB; }
|
.type { color: #7CB8BB; }
|
||||||
|
@ -41,7 +42,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
|
|
||||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||||
</style>
|
</style>
|
||||||
<pre><code><span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
|
<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
|
||||||
|
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span>
|
||||||
|
<span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
|
||||||
|
<span class="brace">}</span><span class="semicolon">;</span>
|
||||||
|
<span class="brace">}</span>
|
||||||
|
<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span>
|
||||||
|
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span>
|
||||||
|
<span class="punctuation">*</span><span class="parenthesis">(</span><span class="operator">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
|
||||||
|
<span class="brace">}</span><span class="semicolon">;</span>
|
||||||
|
<span class="brace">}</span>
|
||||||
|
<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
|
||||||
<span class="keyword">static</span> <span class="static declaration">GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
|
<span class="keyword">static</span> <span class="static declaration">GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
|
||||||
<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
|
<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
|
||||||
|
|
||||||
|
@ -77,7 +88,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
|
<span class="macro">id</span><span class="macro_bang">!</span> <span class="brace">{</span>
|
||||||
|
<span class="keyword unsafe">unsafe</span> <span class="brace">{</span> <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">}</span>
|
||||||
|
<span class="brace">}</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
|
<span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
|
||||||
|
<span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||||
|
<span class="macro unsafe">id</span><span class="macro_bang">!</span> <span class="brace">{</span> <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="comment">// unsafe fn and method calls</span>
|
<span class="comment">// unsafe fn and method calls</span>
|
||||||
<span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
<span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
|
||||||
|
|
|
@ -483,6 +483,16 @@ fn main() {
|
||||||
fn test_unsafe_highlighting() {
|
fn test_unsafe_highlighting() {
|
||||||
check_highlighting(
|
check_highlighting(
|
||||||
r#"
|
r#"
|
||||||
|
macro_rules! id {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
$($tt)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! unsafe_deref {
|
||||||
|
() => {
|
||||||
|
*(&() as *const ())
|
||||||
|
};
|
||||||
|
}
|
||||||
static mut MUT_GLOBAL: Struct = Struct { field: 0 };
|
static mut MUT_GLOBAL: Struct = Struct { field: 0 };
|
||||||
static GLOBAL: Struct = Struct { field: 0 };
|
static GLOBAL: Struct = Struct { field: 0 };
|
||||||
unsafe fn unsafe_fn() {}
|
unsafe fn unsafe_fn() {}
|
||||||
|
@ -519,7 +529,15 @@ impl DoTheAutoref for u16 {
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = &5 as *const _ as *const usize;
|
let x = &5 as *const _ as *const usize;
|
||||||
let u = Union { b: 0 };
|
let u = Union { b: 0 };
|
||||||
|
|
||||||
|
id! {
|
||||||
|
unsafe { unsafe_deref!() }
|
||||||
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
unsafe_deref!();
|
||||||
|
id! { unsafe_deref!() };
|
||||||
|
|
||||||
// unsafe fn and method calls
|
// unsafe fn and method calls
|
||||||
unsafe_fn();
|
unsafe_fn();
|
||||||
let b = u.b;
|
let b = u.b;
|
||||||
|
|
|
@ -15,6 +15,13 @@ pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn full_path_of_name_ref(name_ref: &ast::NameRef) -> Option<ast::Path> {
|
||||||
|
let mut ancestors = name_ref.syntax().ancestors();
|
||||||
|
let _ = ancestors.next()?; // skip self
|
||||||
|
let _ = ancestors.next().filter(|it| ast::PathSegment::can_cast(it.kind()))?; // skip self
|
||||||
|
ancestors.take_while(|it| ast::Path::can_cast(it.kind())).last().and_then(ast::Path::cast)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn block_as_lone_tail(block: &ast::BlockExpr) -> Option<ast::Expr> {
|
pub fn block_as_lone_tail(block: &ast::BlockExpr) -> Option<ast::Expr> {
|
||||||
block.statements().next().is_none().then(|| block.tail_expr()).flatten()
|
block.statements().next().is_none().then(|| block.tail_expr()).flatten()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue