Add a (hint) diagnostic for unconfigured items

This commit is contained in:
Jonas Schievink 2020-10-20 17:49:21 +02:00
parent a54e481646
commit 80d2741401
6 changed files with 86 additions and 3 deletions

View File

@ -1,5 +1,5 @@
//! FIXME: write short doc here
pub use hir_def::diagnostics::UnresolvedModule;
pub use hir_def::diagnostics::{UnconfiguredCode, UnresolvedModule};
pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder};
pub use hir_ty::diagnostics::{
IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr,

View File

@ -86,3 +86,28 @@ impl Diagnostic for UnresolvedImport {
true
}
}
// Diagnostic: unconfigured-code
//
// This diagnostic is shown for code with inactive `#[cfg]` attributes.
#[derive(Debug)]
pub struct UnconfiguredCode {
pub file: HirFileId,
pub node: SyntaxNodePtr,
}
impl Diagnostic for UnconfiguredCode {
fn code(&self) -> DiagnosticCode {
DiagnosticCode("unconfigured-code")
}
fn message(&self) -> String {
// FIXME: say *why* it is configured out
"configured out".to_string()
}
fn display_source(&self) -> InFile<SyntaxNodePtr> {
InFile::new(self.file, self.node.clone())
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}

View File

@ -672,6 +672,24 @@ impl ModItem {
pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
N::id_from_mod_item(self)
}
pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
match self {
ModItem::Import(it) => tree[it.index].ast_id().upcast(),
ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(),
ModItem::Function(it) => tree[it.index].ast_id().upcast(),
ModItem::Struct(it) => tree[it.index].ast_id().upcast(),
ModItem::Union(it) => tree[it.index].ast_id().upcast(),
ModItem::Enum(it) => tree[it.index].ast_id().upcast(),
ModItem::Const(it) => tree[it.index].ast_id().upcast(),
ModItem::Static(it) => tree[it.index].ast_id().upcast(),
ModItem::Trait(it) => tree[it.index].ast_id().upcast(),
ModItem::Impl(it) => tree[it.index].ast_id().upcast(),
ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]

View File

@ -286,7 +286,7 @@ mod diagnostics {
use hir_expand::diagnostics::DiagnosticSink;
use hir_expand::hygiene::Hygiene;
use hir_expand::InFile;
use syntax::{ast, AstPtr};
use syntax::{ast, AstPtr, SyntaxNodePtr};
use crate::path::ModPath;
use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
@ -298,6 +298,8 @@ mod diagnostics {
UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
UnresolvedImport { ast: AstId<ast::Use>, index: usize },
UnconfiguredCode { ast: InFile<SyntaxNodePtr> },
}
#[derive(Debug, PartialEq, Eq)]
@ -336,6 +338,13 @@ mod diagnostics {
Self { in_module: container, kind: DiagnosticKind::UnresolvedImport { ast, index } }
}
pub(super) fn unconfigured_code(
container: LocalModuleId,
ast: InFile<SyntaxNodePtr>,
) -> Self {
Self { in_module: container, kind: DiagnosticKind::UnconfiguredCode { ast } }
}
pub(super) fn add_to(
&self,
db: &dyn DefDatabase,
@ -385,6 +394,10 @@ mod diagnostics {
sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
}
}
DiagnosticKind::UnconfiguredCode { ast } => {
sink.push(UnconfiguredCode { file: ast.file_id, node: ast.value.clone() });
}
}
}
}

View File

@ -913,6 +913,7 @@ impl ModCollector<'_, '_> {
for &item in items {
let attrs = self.item_tree.attrs(item.into());
if !self.is_cfg_enabled(attrs) {
self.emit_unconfigured_diagnostic(item);
continue;
}
let module =
@ -1323,6 +1324,18 @@ impl ModCollector<'_, '_> {
fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
attrs.is_cfg_enabled(self.def_collector.cfg_options)
}
fn emit_unconfigured_diagnostic(&mut self, item: ModItem) {
let ast_id = item.ast_id(self.item_tree);
let id_map = self.def_collector.db.ast_id_map(self.file_id);
let syntax_ptr = id_map.get(ast_id).syntax_node_ptr();
let ast_node = InFile::new(self.file_id, syntax_ptr);
self.def_collector
.def_map
.diagnostics
.push(DefDiagnostic::unconfigured_code(self.module_id, ast_node));
}
}
fn is_macro_rules(path: &ModPath) -> bool {

View File

@ -10,7 +10,10 @@ mod field_shorthand;
use std::cell::RefCell;
use base_db::SourceDatabase;
use hir::{diagnostics::DiagnosticSinkBuilder, Semantics};
use hir::{
diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
Semantics,
};
use ide_db::RootDatabase;
use itertools::Itertools;
use rustc_hash::FxHashSet;
@ -46,6 +49,10 @@ impl Diagnostic {
fn with_fix(self, fix: Option<Fix>) -> Self {
Self { fix, ..self }
}
fn with_unused(self, unused: bool) -> Self {
Self { unused, ..self }
}
}
#[derive(Debug)]
@ -115,6 +122,13 @@ pub(crate) fn diagnostics(
.on::<hir::diagnostics::IncorrectCase, _>(|d| {
res.borrow_mut().push(warning_with_fix(d, &sema));
})
.on::<hir::diagnostics::UnconfiguredCode, _>(|d| {
// Override severity and mark as unused.
res.borrow_mut().push(
Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
.with_unused(true),
);
})
// Only collect experimental diagnostics when they're enabled.
.filter(|diag| !(diag.is_experimental() && config.disable_experimental))
.filter(|diag| !config.disabled.contains(diag.code().as_str()));