3367: Fix highlighting of const patterns r=matklad a=matklad



bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-02-28 15:56:07 +00:00 committed by GitHub
commit c692e07b4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 143 additions and 70 deletions

View file

@ -17,8 +17,8 @@ use crate::{
db::HirDatabase,
source_analyzer::{resolve_hir_path, ReferenceDescriptor, SourceAnalyzer},
source_binder::{ChildContainer, SourceBinder},
Function, HirFileId, InFile, Local, MacroDef, Module, Name, Origin, Path, PathResolution,
ScopeDef, StructField, Trait, Type, TypeParam, VariantDef,
Function, HirFileId, InFile, Local, MacroDef, Module, ModuleDef, Name, Origin, Path,
PathResolution, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef,
};
use hir_expand::ExpansionInfo;
use ra_prof::profile;
@ -129,6 +129,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.analyze(path.syntax()).resolve_path(self.db, path)
}
pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
}
// FIXME: use this instead?
// pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;

View file

@ -11,9 +11,9 @@ use either::Either;
use hir_def::{
body::{
scope::{ExprScopes, ScopeId},
BodySourceMap,
Body, BodySourceMap,
},
expr::{ExprId, PatId},
expr::{ExprId, Pat, PatId},
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
AsMacroCall, DefWithBodyId,
};
@ -25,8 +25,8 @@ use ra_syntax::{
};
use crate::{
db::HirDatabase, Adt, Const, EnumVariant, Function, Local, MacroDef, Path, Static, Struct,
Trait, Type, TypeAlias, TypeParam,
db::HirDatabase, Adt, Const, EnumVariant, Function, Local, MacroDef, ModuleDef, Path, Static,
Struct, Trait, Type, TypeAlias, TypeParam,
};
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@ -35,6 +35,7 @@ use crate::{
pub(crate) struct SourceAnalyzer {
file_id: HirFileId,
pub(crate) resolver: Resolver,
body: Option<Arc<Body>>,
body_source_map: Option<Arc<BodySourceMap>>,
infer: Option<Arc<InferenceResult>>,
scopes: Option<Arc<ExprScopes>>,
@ -66,7 +67,7 @@ impl SourceAnalyzer {
node: InFile<&SyntaxNode>,
offset: Option<TextUnit>,
) -> SourceAnalyzer {
let (_body, source_map) = db.body_with_source_map(def);
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
let scope = match offset {
None => scope_for(&scopes, &source_map, node),
@ -75,6 +76,7 @@ impl SourceAnalyzer {
let resolver = resolver_for_scope(db, def, scope);
SourceAnalyzer {
resolver,
body: Some(body),
body_source_map: Some(source_map),
infer: Some(db.infer(def)),
scopes: Some(scopes),
@ -88,6 +90,7 @@ impl SourceAnalyzer {
) -> SourceAnalyzer {
SourceAnalyzer {
resolver,
body: None,
body_source_map: None,
infer: None,
scopes: None,
@ -197,6 +200,24 @@ impl SourceAnalyzer {
self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into())
}
pub(crate) fn resolve_bind_pat_to_const(
&self,
db: &impl HirDatabase,
pat: &ast::BindPat,
) -> Option<ModuleDef> {
let pat_id = self.pat_id(&pat.clone().into())?;
let body = self.body.as_ref()?;
let path = match &body[pat_id] {
Pat::Path(path) => path,
_ => return None,
};
let res = resolve_hir_path(db, &self.resolver, &path)?;
match res {
PathResolution::Def(def) => Some(def),
_ => None,
}
}
pub(crate) fn resolve_path(
&self,
db: &impl HirDatabase,

View file

@ -30,7 +30,9 @@ pub(crate) fn goto_definition(
reference_definition(&sema, &name_ref).to_vec()
},
ast::Name(name) => {
name_definition(&sema, &name)?
let def = classify_name(&sema, &name)?.definition();
let nav = def.try_to_nav(sema.db)?;
vec![nav]
},
_ => return None,
}
@ -88,15 +90,6 @@ pub(crate) fn reference_definition(
Approximate(navs)
}
fn name_definition(
sema: &Semantics<RootDatabase>,
name: &ast::Name,
) -> Option<Vec<NavigationTarget>> {
let def = classify_name(sema, name)?;
let nav = def.try_to_nav(sema.db)?;
Some(vec![nav])
}
#[cfg(test)]
mod tests {
use test_utils::{assert_eq_text, covers};

View file

@ -156,7 +156,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
classify_name_ref(&sema, &name_ref).map(|d| (name_ref.syntax().clone(), d))
},
ast::Name(name) => {
classify_name(&sema, &name).map(|d| (name.syntax().clone(), d))
classify_name(&sema, &name).map(|d| (name.syntax().clone(), d.definition()))
},
_ => None,
}

View file

@ -155,7 +155,7 @@ fn find_name(
opt_name: Option<ast::Name>,
) -> Option<RangeInfo<(String, NameDefinition)>> {
if let Some(name) = opt_name {
let def = classify_name(sema, &name)?;
let def = classify_name(sema, &name)?.definition();
let range = name.syntax().text_range();
return Some(RangeInfo::new(range, (name.text().to_string(), def)));
}

View file

@ -3,7 +3,7 @@
body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.struct, .enum { color: #7CB8BB; }
.enum_variant { color: #BDE0F3; }
@ -27,14 +27,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
</style>
<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span>
<span class="keyword">struct</span> <span class="struct">Foo</span> {
<span class="keyword">pub</span> <span class="field">x</span>: <span class="builtin_type">i32</span>,
<span class="keyword">pub</span> <span class="field">y</span>: <span class="builtin_type">i32</span>,
<span class="keyword">struct</span> <span class="struct declaration">Foo</span> {
<span class="keyword">pub</span> <span class="field declaration">x</span>: <span class="builtin_type">i32</span>,
<span class="keyword">pub</span> <span class="field declaration">y</span>: <span class="builtin_type">i32</span>,
}
<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type_param">T</span>&gt;() -&gt; <span class="type_param">T</span> {
<span class="macro">unimplemented</span><span class="macro">!</span>();
<span class="function">foo</span>::&lt;<span class="builtin_type">i32</span>&gt;();
<span class="keyword">fn</span> <span class="function declaration">foo</span>&lt;<span class="lifetime declaration">'a</span>, <span class="type_param declaration">T</span>&gt;() -&gt; <span class="type_param">T</span> {
<span class="function">foo</span>::&lt;<span class="lifetime">'a</span>, <span class="builtin_type">i32</span>&gt;()
}
<span class="macro">macro_rules</span><span class="macro">!</span> def_fn {
@ -42,33 +41,40 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
}
<span class="macro">def_fn</span><span class="macro">!</span> {
<span class="keyword">fn</span> <span class="function">bar</span>() -&gt; <span class="builtin_type">u32</span> {
<span class="keyword">fn</span> <span class="function declaration">bar</span>() -&gt; <span class="builtin_type">u32</span> {
<span class="numeric_literal">100</span>
}
}
<span class="comment">// comment</span>
<span class="keyword">fn</span> <span class="function">main</span>() {
<span class="keyword">fn</span> <span class="function declaration">main</span>() {
<span class="macro">println</span><span class="macro">!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>);
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable mutable">vec</span> = Vec::new();
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> = Vec::new();
<span class="keyword control">if</span> <span class="keyword">true</span> {
<span class="keyword">let</span> <span class="variable">x</span> = <span class="numeric_literal">92</span>;
<span class="keyword">let</span> <span class="variable declaration">x</span> = <span class="numeric_literal">92</span>;
<span class="variable mutable">vec</span>.push(<span class="struct">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="numeric_literal">1</span> });
}
<span class="keyword unsafe">unsafe</span> { <span class="variable mutable">vec</span>.set_len(<span class="numeric_literal">0</span>); }
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable mutable">x</span> = <span class="numeric_literal">42</span>;
<span class="keyword">let</span> <span class="variable mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>;
<span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable mutable">y</span>;
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> = <span class="numeric_literal">42</span>;
<span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>;
<span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>;
<span class="variable mutable">y</span>;
}
<span class="keyword">enum</span> <span class="enum">E</span>&lt;<span class="type_param">X</span>&gt; {
<span class="enum_variant">V</span>(<span class="type_param">X</span>)
<span class="keyword">enum</span> <span class="enum declaration">Option</span>&lt;<span class="type_param declaration">T</span>&gt; {
<span class="enum_variant declaration">Some</span>(<span class="type_param">T</span>),
<span class="enum_variant declaration">None</span>,
}
<span class="keyword">use</span> <span class="enum">Option</span>::*;
<span class="keyword">impl</span>&lt;<span class="type_param">X</span>&gt; <span class="enum">E</span>&lt;<span class="type_param">X</span>&gt; {
<span class="keyword">fn</span> <span class="function">new</span>&lt;<span class="type_param">T</span>&gt;() -&gt; <span class="enum">E</span>&lt;<span class="type_param">T</span>&gt; {}
<span class="keyword">impl</span>&lt;<span class="type_param declaration">T</span>&gt; <span class="enum">Option</span>&lt;<span class="type_param">T</span>&gt; {
<span class="keyword">fn</span> <span class="function declaration">and</span>&lt;<span class="type_param declaration">U</span>&gt;(<span class="keyword">self</span>, <span class="variable declaration">other</span>: <span class="enum">Option</span>&lt;<span class="type_param">U</span>&gt;) -&gt; <span class="enum">Option</span>&lt;(<span class="type_param">T</span>, <span class="type_param">U</span>)&gt; {
<span class="keyword control">match</span> <span class="variable">other</span> {
<span class="enum_variant">None</span> =&gt; <span class="macro">unimplemented</span><span class="macro">!</span>(),
<span class="variable declaration">Nope</span> =&gt; <span class="variable">Nope</span>,
}
}
}</code></pre>

View file

@ -3,7 +3,7 @@
body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.struct, .enum { color: #7CB8BB; }
.enum_variant { color: #BDE0F3; }
@ -26,15 +26,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.keyword.unsafe { color: #BC8383; font-weight: bold; }
.control { font-style: italic; }
</style>
<pre><code><span class="keyword">fn</span> <span class="function">main</span>() {
<span class="keyword">let</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span> = <span class="string_literal">"hello"</span>;
<span class="keyword">let</span> <span class="variable" data-binding-hash="2705725358298919760" style="color: hsl(17,51%,74%);">x</span> = <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span>.to_string();
<span class="keyword">let</span> <span class="variable" data-binding-hash="3365759661443752373" style="color: hsl(127,76%,66%);">y</span> = <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span>.to_string();
<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span>() {
<span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span> = <span class="string_literal">"hello"</span>;
<span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(17,51%,74%);">x</span> = <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span>.to_string();
<span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(127,76%,66%);">y</span> = <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span>.to_string();
<span class="keyword">let</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(19,74%,76%);">x</span> = <span class="string_literal">"other color please!"</span>;
<span class="keyword">let</span> <span class="variable" data-binding-hash="6717528807933952652" style="color: hsl(85,49%,84%);">y</span> = <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(19,74%,76%);">x</span>.to_string();
<span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(19,74%,76%);">x</span> = <span class="string_literal">"other color please!"</span>;
<span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(85,49%,84%);">y</span> = <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(19,74%,76%);">x</span>.to_string();
}
<span class="keyword">fn</span> <span class="function">bar</span>() {
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable mutable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span> = <span class="string_literal">"hello"</span>;
<span class="keyword">fn</span> <span class="function declaration">bar</span>() {
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span> = <span class="string_literal">"hello"</span>;
}</code></pre>

View file

@ -7,7 +7,7 @@ mod tests;
use hir::{Name, Semantics};
use ra_ide_db::{
defs::{classify_name, NameDefinition},
defs::{classify_name, NameClass, NameDefinition},
RootDatabase,
};
use ra_prof::profile;
@ -169,7 +169,7 @@ fn highlight_element(
let name = element.into_node().and_then(ast::Name::cast).unwrap();
let name_kind = classify_name(sema, &name);
if let Some(NameDefinition::Local(local)) = &name_kind {
if let Some(NameClass::NameDefinition(NameDefinition::Local(local))) = &name_kind {
if let Some(name) = local.name(db) {
let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
*shadow_count += 1;
@ -177,11 +177,13 @@ fn highlight_element(
}
};
let h = match name_kind {
Some(name_kind) => highlight_name(db, name_kind),
None => highlight_name_by_syntax(name),
};
h | HighlightModifier::Definition
match name_kind {
Some(NameClass::NameDefinition(def)) => {
highlight_name(db, def) | HighlightModifier::Definition
}
Some(NameClass::ConstReference(def)) => highlight_name(db, def),
None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
}
}
// Highlight references like the definitions they resolve to
@ -212,8 +214,13 @@ fn highlight_element(
INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(),
BYTE => HighlightTag::ByteLiteral.into(),
CHAR => HighlightTag::CharLiteral.into(),
// FIXME: set Declaration for decls
LIFETIME => HighlightTag::Lifetime.into(),
LIFETIME => {
let h = Highlight::new(HighlightTag::Lifetime);
dbg!(match element.parent().map(|it| it.kind()) {
Some(LIFETIME_PARAM) | Some(LABEL) => h | HighlightModifier::Definition,
_ => h,
})
}
k if k.is_keyword() => {
let h = Highlight::new(HighlightTag::Keyword);

View file

@ -80,7 +80,7 @@ const STYLE: &str = "
body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.struct, .enum { color: #7CB8BB; }
.enum_variant { color: #BDE0F3; }

View file

@ -90,8 +90,12 @@ impl fmt::Display for HighlightTag {
}
impl HighlightModifier {
const ALL: &'static [HighlightModifier] =
&[HighlightModifier::Mutable, HighlightModifier::Unsafe, HighlightModifier::Control];
const ALL: &'static [HighlightModifier] = &[
HighlightModifier::Control,
HighlightModifier::Definition,
HighlightModifier::Mutable,
HighlightModifier::Unsafe,
];
fn as_str(self) -> &'static str {
match self {

View file

@ -17,9 +17,8 @@ struct Foo {
pub y: i32,
}
fn foo<T>() -> T {
unimplemented!();
foo::<i32>();
fn foo<'a, T>() -> T {
foo::<'a, i32>()
}
macro_rules! def_fn {
@ -50,12 +49,19 @@ fn main() {
y;
}
enum E<X> {
V(X)
enum Option<T> {
Some(T),
None,
}
use Option::*;
impl<X> E<X> {
fn new<T>() -> E<T> {}
impl<T> Option<T> {
fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
match other {
None => unimplemented!(),
Nope => Nope,
}
}
}
"#
.trim(),
@ -123,5 +129,5 @@ fn test_ranges() {
.highlight_range(FileRange { file_id, range: TextRange::offset_len(82.into(), 1.into()) })
.unwrap();
assert_eq!(&highlights[0].highlight.to_string(), "field");
assert_eq!(&highlights[0].highlight.to_string(), "field.declaration");
}

View file

@ -68,7 +68,38 @@ impl NameDefinition {
}
}
pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameDefinition> {
pub enum NameClass {
NameDefinition(NameDefinition),
/// `None` in `if let None = Some(82) {}`
ConstReference(NameDefinition),
}
impl NameClass {
pub fn into_definition(self) -> Option<NameDefinition> {
match self {
NameClass::NameDefinition(it) => Some(it),
NameClass::ConstReference(_) => None,
}
}
pub fn definition(self) -> NameDefinition {
match self {
NameClass::NameDefinition(it) | NameClass::ConstReference(it) => it,
}
}
}
pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) {
if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
return Some(NameClass::ConstReference(NameDefinition::ModuleDef(def)));
}
}
classify_name_inner(sema, name).map(NameClass::NameDefinition)
}
fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameDefinition> {
let _p = profile("classify_name");
let parent = name.syntax().parent()?;

View file

@ -59,6 +59,7 @@ impl<'a> ImportsLocator<'a> {
} else {
candidate_node
};
classify_name(&self.sema, &ast::Name::cast(candidate_name_node)?)
let name = ast::Name::cast(candidate_name_node)?;
classify_name(&self.sema, &name)?.into_definition()
}
}