mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-14 17:07:26 +00:00
Move semantic logic into Semantics, fix missing tag for safe amp operator, using functional methods rather than clunky inline closure
This commit is contained in:
parent
87cb09365c
commit
a6af0272f7
6 changed files with 112 additions and 105 deletions
|
@ -25,7 +25,8 @@ use crate::{
|
|||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||
source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
|
||||
AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
|
||||
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
||||
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef,
|
||||
VariantDef,
|
||||
};
|
||||
use resolver::TypeNs;
|
||||
|
||||
|
@ -280,45 +281,84 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
self.imp.assert_contains_node(node)
|
||||
}
|
||||
|
||||
pub fn is_unsafe_pat(&self, pat: &ast::Pat) -> bool {
|
||||
let ty = (|| {
|
||||
let parent = match pat {
|
||||
ast::Pat::BindPat(bind_pat) => bind_pat.syntax().parent()?,
|
||||
_ => return None,
|
||||
};
|
||||
pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> Option<()> {
|
||||
let expr = method_call_expr.expr()?;
|
||||
let field_expr =
|
||||
if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None };
|
||||
let ty = self.type_of_expr(&field_expr.expr()?)?;
|
||||
if !ty.is_packed(self.db) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
|
||||
// `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
|
||||
// so this tries to lookup the `BindPat` anywhere along that structure to the
|
||||
// `RecordPat` so we can get the containing type.
|
||||
let record_pat = ast::RecordFieldPat::cast(parent.clone())
|
||||
.and_then(|record_pat| record_pat.syntax().parent())
|
||||
.or_else(|| Some(parent.clone()))
|
||||
.and_then(|parent| {
|
||||
ast::RecordFieldPatList::cast(parent)?
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::RecordPat::cast)
|
||||
});
|
||||
|
||||
// If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
|
||||
// this is initialized from a `FieldExpr`.
|
||||
if let Some(record_pat) = record_pat {
|
||||
self.type_of_pat(&ast::Pat::RecordPat(record_pat))
|
||||
} else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
|
||||
let field_expr = match let_stmt.initializer()? {
|
||||
ast::Expr::FieldExpr(field_expr) => field_expr,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
self.type_of_expr(&field_expr.expr()?)
|
||||
let func = self.resolve_method_call(&method_call_expr)?;
|
||||
if func.has_self_param(self.db) {
|
||||
let params = func.params(self.db);
|
||||
if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})();
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Binding a reference to a packed type is possibly unsafe.
|
||||
ty.map(|ty| ty.is_packed(self.db)).unwrap_or(false)
|
||||
pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
|
||||
ref_expr
|
||||
.expr()
|
||||
.and_then(|expr| {
|
||||
let field_expr = match expr {
|
||||
ast::Expr::FieldExpr(field_expr) => field_expr,
|
||||
_ => return None,
|
||||
};
|
||||
let expr = field_expr.expr()?;
|
||||
self.type_of_expr(&expr)
|
||||
})
|
||||
// Binding a reference to a packed type is possibly unsafe.
|
||||
.map(|ty| ty.is_packed(self.db))
|
||||
.unwrap_or(false)
|
||||
|
||||
// FIXME This needs layout computation to be correct. It will highlight
|
||||
// more than it should with the current implementation.
|
||||
}
|
||||
|
||||
pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool {
|
||||
bind_pat
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(|parent| {
|
||||
// `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
|
||||
// `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
|
||||
// so this tries to lookup the `BindPat` anywhere along that structure to the
|
||||
// `RecordPat` so we can get the containing type.
|
||||
let record_pat = ast::RecordFieldPat::cast(parent.clone())
|
||||
.and_then(|record_pat| record_pat.syntax().parent())
|
||||
.or_else(|| Some(parent.clone()))
|
||||
.and_then(|parent| {
|
||||
ast::RecordFieldPatList::cast(parent)?
|
||||
.syntax()
|
||||
.parent()
|
||||
.and_then(ast::RecordPat::cast)
|
||||
});
|
||||
|
||||
// If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
|
||||
// this is initialized from a `FieldExpr`.
|
||||
if let Some(record_pat) = record_pat {
|
||||
self.type_of_pat(&ast::Pat::RecordPat(record_pat))
|
||||
} else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
|
||||
let field_expr = match let_stmt.initializer()? {
|
||||
ast::Expr::FieldExpr(field_expr) => field_expr,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
self.type_of_expr(&field_expr.expr()?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
// Binding a reference to a packed type is possibly unsafe.
|
||||
.map(|ty| ty.is_packed(self.db))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -565,29 +565,21 @@ fn highlight_element(
|
|||
_ => h,
|
||||
}
|
||||
}
|
||||
T![&] => {
|
||||
let ref_expr = element.parent().and_then(ast::RefExpr::cast)?;
|
||||
let expr = ref_expr.expr()?;
|
||||
let field_expr = match expr {
|
||||
ast::Expr::FieldExpr(fe) => fe,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let expr = field_expr.expr()?;
|
||||
let ty = sema.type_of_expr(&expr)?;
|
||||
if !ty.is_packed(db) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// FIXME This needs layout computation to be correct. It will highlight
|
||||
// more than it should with the current implementation.
|
||||
|
||||
HighlightTag::Operator | HighlightModifier::Unsafe
|
||||
}
|
||||
p if p.is_punct() => match p {
|
||||
T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => {
|
||||
HighlightTag::Operator.into()
|
||||
T![&] => {
|
||||
let h = HighlightTag::Operator.into();
|
||||
let is_unsafe = element
|
||||
.parent()
|
||||
.and_then(ast::RefExpr::cast)
|
||||
.map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
|
||||
.unwrap_or(false);
|
||||
if is_unsafe {
|
||||
h | HighlightModifier::Unsafe
|
||||
} else {
|
||||
h
|
||||
}
|
||||
}
|
||||
T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] => HighlightTag::Operator.into(),
|
||||
T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
|
||||
HighlightTag::Macro.into()
|
||||
}
|
||||
|
@ -668,22 +660,18 @@ fn highlight_element(
|
|||
HighlightTag::SelfKeyword.into()
|
||||
}
|
||||
}
|
||||
T![ref] => {
|
||||
let modifier: Option<HighlightModifier> = (|| {
|
||||
let bind_pat = element.parent().and_then(ast::BindPat::cast)?;
|
||||
if sema.is_unsafe_pat(&ast::Pat::BindPat(bind_pat)) {
|
||||
T![ref] => element
|
||||
.parent()
|
||||
.and_then(ast::BindPat::cast)
|
||||
.and_then(|bind_pat| {
|
||||
if sema.is_unsafe_bind_pat(&bind_pat) {
|
||||
Some(HighlightModifier::Unsafe)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})();
|
||||
|
||||
if let Some(modifier) = modifier {
|
||||
h | modifier
|
||||
} else {
|
||||
h
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|modifier| h | modifier)
|
||||
.unwrap_or(h),
|
||||
_ => h,
|
||||
}
|
||||
}
|
||||
|
@ -713,31 +701,6 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_method_call_unsafe(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
method_call_expr: ast::MethodCallExpr,
|
||||
) -> Option<()> {
|
||||
let expr = method_call_expr.expr()?;
|
||||
let field_expr =
|
||||
if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None };
|
||||
let ty = sema.type_of_expr(&field_expr.expr()?)?;
|
||||
if !ty.is_packed(sema.db) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let func = sema.resolve_method_call(&method_call_expr)?;
|
||||
if func.has_self_param(sema.db) {
|
||||
let params = func.params(sema.db);
|
||||
if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_name(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
db: &RootDatabase,
|
||||
|
@ -767,7 +730,7 @@ fn highlight_name(
|
|||
let is_unsafe = name_ref
|
||||
.and_then(|name_ref| name_ref.syntax().parent())
|
||||
.and_then(ast::MethodCallExpr::cast)
|
||||
.and_then(|method_call_expr| is_method_call_unsafe(sema, method_call_expr));
|
||||
.and_then(|method_call_expr| sema.is_unsafe_method_call(method_call_expr));
|
||||
if is_unsafe.is_some() {
|
||||
h |= HighlightModifier::Unsafe;
|
||||
}
|
||||
|
@ -846,7 +809,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
|
|||
METHOD_CALL_EXPR => {
|
||||
let mut h = Highlight::new(HighlightTag::Function);
|
||||
let is_unsafe = ast::MethodCallExpr::cast(parent)
|
||||
.and_then(|method_call_expr| is_method_call_unsafe(sema, method_call_expr));
|
||||
.and_then(|method_call_expr| sema.is_unsafe_method_call(method_call_expr));
|
||||
|
||||
if is_unsafe.is_some() {
|
||||
h |= HighlightModifier::Unsafe;
|
||||
|
@ -866,7 +829,11 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
|
|||
})
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if is_union { h | HighlightModifier::Unsafe } else { h.into() }
|
||||
if is_union {
|
||||
h | HighlightModifier::Unsafe
|
||||
} else {
|
||||
h.into()
|
||||
}
|
||||
}
|
||||
PATH_SEGMENT => {
|
||||
let path = match parent.parent().and_then(ast::Path::cast) {
|
||||
|
|
|
@ -87,7 +87,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="comment documentation">/// ```sh</span>
|
||||
<span class="comment documentation">/// echo 1</span>
|
||||
<span class="comment documentation">/// ```</span>
|
||||
<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span>&<span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">bool</span> <span class="punctuation">{</span>
|
||||
<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">bool</span> <span class="punctuation">{</span>
|
||||
<span class="bool_literal">true</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
|
|
@ -35,7 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> &<span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||
<span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span>
|
||||
|
|
|
@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span>
|
||||
<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span>&<span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||
<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span>
|
||||
|
@ -55,7 +55,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">x</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="punctuation">;</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="punctuation">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
|
||||
<span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
|
||||
<span class="comment">// unsafe fn and method calls</span>
|
||||
|
|
|
@ -45,11 +45,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span>
|
||||
<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span>&<span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="punctuation">;</span>
|
||||
<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
|
||||
<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span>&<span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span>
|
||||
<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span>
|
||||
<span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
@ -59,7 +59,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span>&<span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||
<span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||
<span class="self_keyword mutable">self</span><span class="punctuation">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
@ -107,8 +107,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="macro">noop!</span><span class="punctuation">(</span><span class="macro">noop</span><span class="macro">!</span><span class="punctuation">(</span><span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="punctuation">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> &<span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> &<span class="variable mutable">y</span><span class="punctuation">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">let</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable declaration">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span><span class="punctuation">;</span>
|
||||
|
||||
|
|
Loading…
Reference in a new issue