Skip to content

Commit 9c7366e

Browse files
committed
improve scope-based diagnostics and quickfixes
1 parent 8e02a40 commit 9c7366e

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

crates/analyzer/src/analysis/diagnostics/utils.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1497,7 +1497,19 @@ pub fn ensure_valid_quasi_direct_ink_descendants<T, F>(
14971497
| InkAttributeKind::Arg(InkArgKind::Unknown)
14981498
)
14991499
}) {
1500-
if !is_valid_quasi_direct_descendant(&attr) {
1500+
// Only show ink! scope diagnostics for the "primary" ink! attribute for it's parent item.
1501+
let is_primary_attribute = [attr.clone()]
1502+
.into_iter()
1503+
.chain(attr.siblings())
1504+
// Sort in order of appearance first.
1505+
.sorted_by_key(|attr| attr.syntax().text_range().start())
1506+
// Then sort in order of attribute kind ranking.
1507+
.sorted()
1508+
.next()
1509+
.map_or(false, |primary_attr| {
1510+
primary_attr.syntax().text_range() == attr.syntax().text_range()
1511+
});
1512+
if is_primary_attribute && !is_valid_quasi_direct_descendant(&attr) {
15011513
results.push(Diagnostic {
15021514
message: format!("Invalid scope for an `{}` item.", attr.syntax()),
15031515
range: attr.syntax().text_range(),

crates/ir/src/attrs.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use ink_analyzer_macro::FromAST;
44
use itertools::Itertools;
5-
use ra_ap_syntax::{ast, AstNode, SyntaxNode};
5+
use ra_ap_syntax::{ast, AstNode, Direction, SyntaxNode};
66
use std::cmp::Ordering;
77
use std::fmt;
88

@@ -119,6 +119,16 @@ impl InkAttribute {
119119
pub fn ink_arg_name(&self) -> Option<&MetaName> {
120120
self.ink_arg_name.as_ref()
121121
}
122+
123+
/// Returns sibling ink! attributes (if any).
124+
pub fn siblings(&self) -> impl Iterator<Item = Self> + '_ {
125+
self.syntax()
126+
.siblings(Direction::Prev)
127+
.chain(self.syntax().siblings(Direction::Next))
128+
.filter(|it| it.text_range() != self.syntax().text_range())
129+
.filter_map(ast::Attr::cast)
130+
.filter_map(Self::cast)
131+
}
122132
}
123133

124134
impl Ord for InkAttribute {

crates/test-utils/src/fixtures.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,6 +1897,65 @@ pub fn actions_fixtures() -> Vec<TestGroup> {
18971897
},
18981898
]),
18991899
},
1900+
TestCase {
1901+
modifications: Some(vec![TestCaseModification {
1902+
start_pat: Some("<-#[ink::contract]"),
1903+
end_pat: Some("#[ink::contract]"),
1904+
replacement: "#[ink::contract]\n#[ink(env=crate::Environment)]",
1905+
}]),
1906+
params: Some(TestCaseParams::Action(TestParamsOffsetOnly {
1907+
pat: Some("<-mod erc20"),
1908+
})),
1909+
results: TestCaseResults::Action(vec![
1910+
TestResultAction {
1911+
label: "Add",
1912+
edits: vec![TestResultTextRange {
1913+
text: r#"(keep_attr = "")"#,
1914+
start_pat: Some("#[ink::contract"),
1915+
end_pat: Some("#[ink::contract"),
1916+
}],
1917+
},
1918+
TestResultAction {
1919+
label: "Flatten",
1920+
edits: vec![
1921+
TestResultTextRange {
1922+
text: "#[ink::contract(env = crate::Environment)]",
1923+
start_pat: Some("<-#[ink::contract]"),
1924+
end_pat: Some("#[ink::contract]"),
1925+
},
1926+
TestResultTextRange {
1927+
text: "",
1928+
start_pat: Some("<-#[ink(env=crate::Environment)]"),
1929+
end_pat: Some("#[ink(env=crate::Environment)]\n"),
1930+
},
1931+
],
1932+
},
1933+
TestResultAction {
1934+
label: "Add",
1935+
edits: vec![TestResultTextRange {
1936+
text: "#[ink(event)]",
1937+
start_pat: Some("<-\n\n /// The ERC-20 error types."),
1938+
end_pat: Some("<-\n\n /// The ERC-20 error types."),
1939+
}],
1940+
},
1941+
TestResultAction {
1942+
label: "Add",
1943+
edits: vec![TestResultTextRange {
1944+
text: "#[ink(constructor)]",
1945+
start_pat: Some("<-\n }\n\n #[cfg(test)]"),
1946+
end_pat: Some("<-\n }\n\n #[cfg(test)]"),
1947+
}],
1948+
},
1949+
TestResultAction {
1950+
label: "Add",
1951+
edits: vec![TestResultTextRange {
1952+
text: "#[ink(message)]",
1953+
start_pat: Some("<-\n }\n\n #[cfg(test)]"),
1954+
end_pat: Some("<-\n }\n\n #[cfg(test)]"),
1955+
}],
1956+
},
1957+
]),
1958+
},
19001959
TestCase {
19011960
modifications: Some(vec![TestCaseModification {
19021961
start_pat: Some("<-#[ink(storage)]"),
@@ -2006,6 +2065,41 @@ pub fn actions_fixtures() -> Vec<TestGroup> {
20062065
}],
20072066
}]),
20082067
},
2068+
TestCase {
2069+
modifications: Some(vec![TestCaseModification {
2070+
start_pat: Some("<-#[ink(event)]"),
2071+
end_pat: Some("#[ink(event)]"),
2072+
replacement: "#[ink(event)]\n #[ink(anonymous)]",
2073+
}]),
2074+
params: Some(TestCaseParams::Action(TestParamsOffsetOnly {
2075+
pat: Some("<-pub struct Transfer"),
2076+
})),
2077+
results: TestCaseResults::Action(vec![
2078+
TestResultAction {
2079+
label: "Flatten",
2080+
edits: vec![
2081+
TestResultTextRange {
2082+
text: "#[ink(event, anonymous)]",
2083+
start_pat: Some("<-#[ink(event)]"),
2084+
end_pat: Some("#[ink(event)]"),
2085+
},
2086+
TestResultTextRange {
2087+
text: "",
2088+
start_pat: Some("<-#[ink(anonymous)]"),
2089+
end_pat: Some("<-pub struct Transfer"),
2090+
},
2091+
],
2092+
},
2093+
TestResultAction {
2094+
label: "Add",
2095+
edits: vec![TestResultTextRange {
2096+
text: "#[ink(topic)]",
2097+
start_pat: Some("value: Balance,"),
2098+
end_pat: Some("value: Balance,"),
2099+
}],
2100+
},
2101+
]),
2102+
},
20092103
TestCase {
20102104
modifications: None,
20112105
params: Some(TestCaseParams::Action(TestParamsOffsetOnly {

0 commit comments

Comments
 (0)