-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1b4a365
commit 23608f1
Showing
16 changed files
with
455 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "mun_diagnostics" | ||
version = "0.1.0" | ||
authors = ["The Mun Team <team@mun-lang.org>"] | ||
edition = "2018" | ||
description = "Provides in depth diagnostic information for compiler errors" | ||
documentation = "https://docs.mun-lang.org/v0.2" | ||
readme = "README.md" | ||
homepage = "https://mun-lang.org" | ||
repository = "https://github.com/mun-lang/mun" | ||
license = "MIT OR Apache-2.0" | ||
keywords = ["game", "hot-reloading", "language", "mun", "diagnostics"] | ||
categories = ["game-development", "mun"] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
hir = { version = "=0.2.0", path="../mun_hir", package="mun_hir" } | ||
mun_syntax = { version = "=0.2.0", path = "../mun_syntax" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
mod access_unknown_field; | ||
mod expected_function; | ||
mod mismatched_type; | ||
mod missing_fields; | ||
mod possibly_unitialized_variable; | ||
mod unresolved_type; | ||
mod unresolved_value; | ||
|
||
use crate::{Diagnostic, DiagnosticForWith, SourceAnnotation}; | ||
use hir::Diagnostic as HirDiagnostic; | ||
use mun_syntax::TextRange; | ||
|
||
// Provides conversion of a hir::Diagnostic to a crate::Diagnostic. This requires a database for | ||
// most operations. | ||
impl<DB: hir::HirDatabase> DiagnosticForWith<DB> for dyn hir::Diagnostic { | ||
fn with_diagnostic<R, F: FnMut(&dyn Diagnostic) -> R>(&self, with: &DB, mut f: F) -> R { | ||
if let Some(v) = self.downcast_ref::<hir::diagnostics::UnresolvedValue>() { | ||
f(&unresolved_value::UnresolvedValue::new(with, v)) | ||
} else if let Some(v) = self.downcast_ref::<hir::diagnostics::UnresolvedType>() { | ||
f(&unresolved_type::UnresolvedType::new(with, v)) | ||
} else if let Some(v) = self.downcast_ref::<hir::diagnostics::ExpectedFunction>() { | ||
f(&expected_function::ExpectedFunction::new(with, v)) | ||
} else if let Some(v) = self.downcast_ref::<hir::diagnostics::MismatchedType>() { | ||
f(&mismatched_type::MismatchedType::new(with, v)) | ||
} else if let Some(v) = | ||
self.downcast_ref::<hir::diagnostics::PossiblyUninitializedVariable>() | ||
{ | ||
f(&possibly_unitialized_variable::PossiblyUninitializedVariable::new(with, v)) | ||
} else if let Some(v) = self.downcast_ref::<hir::diagnostics::AccessUnknownField>() { | ||
f(&access_unknown_field::AccessUnknownField::new(with, v)) | ||
} else if let Some(v) = self.downcast_ref::<hir::diagnostics::MissingFields>() { | ||
f(&missing_fields::MissingFields::new(with, v)) | ||
} else { | ||
f(&GenericHirDiagnostic { diagnostic: self }) | ||
} | ||
} | ||
} | ||
|
||
/// Diagnostic handler for generic hir diagnostics | ||
struct GenericHirDiagnostic<'diag> { | ||
diagnostic: &'diag dyn hir::Diagnostic, | ||
} | ||
|
||
impl<'diag> Diagnostic for GenericHirDiagnostic<'diag> { | ||
fn range(&self) -> TextRange { | ||
self.diagnostic.highlight_range() | ||
} | ||
|
||
fn label(&self) -> String { | ||
self.diagnostic.message() | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
None | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use hir::HirDisplay; | ||
use mun_syntax::{ast, AstNode, TextRange}; | ||
|
||
pub struct AccessUnknownField<'db, 'diag, DB: hir::HirDatabase> { | ||
db: &'db DB, | ||
diag: &'diag hir::diagnostics::AccessUnknownField, | ||
location: TextRange, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic for AccessUnknownField<'db, 'diag, DB> { | ||
fn range(&self) -> TextRange { | ||
self.location | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!( | ||
"no field `{}` on type `{}`", | ||
self.diag.name, | ||
self.diag.receiver_ty.display(self.db), | ||
) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
Some(SourceAnnotation { | ||
range: self.location, | ||
message: "unknown field".to_string(), | ||
}) | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> AccessUnknownField<'db, 'diag, DB> { | ||
/// Constructs a new instance of `AccessUnknownField` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::AccessUnknownField) -> Self { | ||
let parse = db.parse(diag.file); | ||
|
||
let location = ast::FieldExpr::cast(diag.expr.to_node(&parse.syntax_node())) | ||
.map(|f| f.field_range()) | ||
.unwrap_or_else(|| diag.highlight_range()); | ||
|
||
AccessUnknownField { db, diag, location } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use hir::HirDisplay; | ||
use mun_syntax::TextRange; | ||
|
||
pub struct ExpectedFunction<'db, 'diag, DB: hir::HirDatabase> { | ||
db: &'db DB, | ||
diag: &'diag hir::diagnostics::ExpectedFunction, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic for ExpectedFunction<'db, 'diag, DB> { | ||
fn range(&self) -> TextRange { | ||
self.diag.highlight_range() | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!( | ||
"expected function, found `{}`", | ||
self.diag.found.display(self.db) | ||
) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
Some(SourceAnnotation { | ||
range: self.diag.highlight_range(), | ||
message: "not a function".to_owned(), | ||
}) | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> ExpectedFunction<'db, 'diag, DB> { | ||
/// Constructs a new instance of `ExpectedFunction` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::ExpectedFunction) -> Self { | ||
ExpectedFunction { db, diag } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use hir::HirDisplay; | ||
use mun_syntax::TextRange; | ||
|
||
pub struct MismatchedType<'db, 'diag, DB: hir::HirDatabase> { | ||
db: &'db DB, | ||
diag: &'diag hir::diagnostics::MismatchedType, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic for MismatchedType<'db, 'diag, DB> { | ||
fn range(&self) -> TextRange { | ||
self.diag.highlight_range() | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!( | ||
"expected `{}`, found `{}`", | ||
self.diag.expected.display(self.db), | ||
self.diag.found.display(self.db) | ||
) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
None | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> MismatchedType<'db, 'diag, DB> { | ||
/// Constructs a new instance of `MismatchedType` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::MismatchedType) -> Self { | ||
MismatchedType { db, diag } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use hir::HirDisplay; | ||
use mun_syntax::{ast, AstNode, TextRange}; | ||
|
||
pub struct MissingFields<'db, 'diag, DB: hir::HirDatabase> { | ||
db: &'db DB, | ||
diag: &'diag hir::diagnostics::MissingFields, | ||
location: TextRange, | ||
missing_fields: String, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic for MissingFields<'db, 'diag, DB> { | ||
fn range(&self) -> TextRange { | ||
self.location | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!( | ||
"missing fields {} in initializer of `{}`", | ||
self.missing_fields, | ||
self.diag.struct_ty.display(self.db) | ||
) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
Some(SourceAnnotation { | ||
range: self.location, | ||
message: self.missing_fields.clone(), | ||
}) | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> MissingFields<'db, 'diag, DB> { | ||
/// Constructs a new instance of `MissingFields` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::MissingFields) -> Self { | ||
let parse = db.parse(diag.file); | ||
let missing_fields = diag | ||
.field_names | ||
.iter() | ||
.map(|n| format!("`{}`", n)) | ||
.collect::<Vec<String>>() | ||
.join(", "); | ||
let location = ast::RecordLit::cast(diag.fields.to_node(&parse.syntax_node())) | ||
.and_then(|f| f.type_ref()) | ||
.map(|t| t.syntax().text_range()) | ||
.unwrap_or_else(|| diag.highlight_range()); | ||
|
||
MissingFields { | ||
db, | ||
diag, | ||
location, | ||
missing_fields, | ||
} | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
crates/mun_diagnostics/src/hir/possibly_unitialized_variable.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use mun_syntax::TextRange; | ||
|
||
pub struct PossiblyUninitializedVariable<'db, 'diag, DB: hir::HirDatabase> { | ||
_db: &'db DB, | ||
diag: &'diag hir::diagnostics::PossiblyUninitializedVariable, | ||
value_name: String, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic | ||
for PossiblyUninitializedVariable<'db, 'diag, DB> | ||
{ | ||
fn range(&self) -> TextRange { | ||
self.diag.highlight_range() | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!("use of possibly-uninitialized `{}`", self.value_name) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
None | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> PossiblyUninitializedVariable<'db, 'diag, DB> { | ||
/// Constructs a new instance of `PossiblyUninitializedVariable` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::PossiblyUninitializedVariable) -> Self { | ||
let parse = db.parse(diag.file); | ||
|
||
// Get the text of the value as a string | ||
let value_name = diag.pat.to_node(&parse.syntax_node()).text().to_string(); | ||
|
||
PossiblyUninitializedVariable { | ||
_db: db, | ||
diag, | ||
value_name, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use mun_syntax::{AstNode, TextRange}; | ||
|
||
pub struct UnresolvedType<'db, 'diag, DB: hir::HirDatabase> { | ||
_db: &'db DB, | ||
diag: &'diag hir::diagnostics::UnresolvedType, | ||
value_name: String, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic for UnresolvedType<'db, 'diag, DB> { | ||
fn range(&self) -> TextRange { | ||
self.diag.highlight_range() | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!("cannot find type `{}` in this scope", self.value_name) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
Some(SourceAnnotation { | ||
range: self.diag.highlight_range(), | ||
message: "not found in this scope".to_owned(), | ||
}) | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> UnresolvedType<'db, 'diag, DB> { | ||
/// Constructs a new instance of `UnresolvedType` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::UnresolvedType) -> Self { | ||
let parse = db.parse(diag.file); | ||
|
||
// Get the text of the value as a string | ||
let value_name = diag | ||
.type_ref | ||
.to_node(&parse.syntax_node()) | ||
.syntax() | ||
.text() | ||
.to_string(); | ||
|
||
UnresolvedType { | ||
_db: db, | ||
diag, | ||
value_name, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use super::HirDiagnostic; | ||
use crate::{Diagnostic, SourceAnnotation}; | ||
use mun_syntax::{AstNode, TextRange}; | ||
|
||
pub struct UnresolvedValue<'db, 'diag, DB: hir::HirDatabase> { | ||
_db: &'db DB, | ||
diag: &'diag hir::diagnostics::UnresolvedValue, | ||
value_name: String, | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> Diagnostic for UnresolvedValue<'db, 'diag, DB> { | ||
fn range(&self) -> TextRange { | ||
self.diag.highlight_range() | ||
} | ||
|
||
fn label(&self) -> String { | ||
format!("cannot find value `{}` in this scope", self.value_name) | ||
} | ||
|
||
fn primary_annotation(&self) -> Option<SourceAnnotation> { | ||
Some(SourceAnnotation { | ||
range: self.diag.highlight_range(), | ||
message: "not found in this scope".to_owned(), | ||
}) | ||
} | ||
} | ||
|
||
impl<'db, 'diag, DB: hir::HirDatabase> UnresolvedValue<'db, 'diag, DB> { | ||
/// Constructs a new instance of `UnresolvedValue` | ||
pub fn new(db: &'db DB, diag: &'diag hir::diagnostics::UnresolvedValue) -> Self { | ||
let parse = db.parse(diag.file); | ||
|
||
// Get the text of the value as a string | ||
let value_name = diag.expr.to_node(&parse.tree().syntax()).text().to_string(); | ||
|
||
UnresolvedValue { | ||
_db: db, | ||
diag, | ||
value_name, | ||
} | ||
} | ||
} |
Oops, something went wrong.