Repository: intellij-rust/intellij-rust
Issue: Wrong detected error "Possibly uninitialized variable"

<!--
Hello and thank you for the issue!
If you would like to report a bug, we have added some points below that you can fill out.
Feel free to remove all the irrelevant text to request a new feature.
-->

## Environment

* **Intellij-Rust plugin v0.2.99.2126-191:**
* **Rust toolchain rustup 1.16.0 (beab5ac2b 2018-12-06)**
* **IDE name and clion 2019.1:**
* **Operating system: linux**

## Problem description
Wrong detected error "Possibly uninitialized variable". Plugin not consider cases: "unimplemented", "unreachable", etc.

## Steps to reproduce


```rust
    let value;
    match &enum_item {
        ItemType::Element1(f_data) => {
            value = 123;
        },
        ItemType::Element2(_,f_data)=>{

            value = 23;
        }
        _ => unimplemented!(),
    }
    return value  // Use of posibly uninitialized variable  
```



Changed files:
src/test/kotlin/org/rust/lang/core/cfg/RsControlFlowGraphTest.kt
src/test/kotlin/org/rust/ide/inspections/borrowck/RsBorrowCheckerUninitializedTest.kt
src/main/kotlin/org/rust/lang/core/cfg/CFGBuilder.kt

diff --git a/src/main/kotlin/org/rust/lang/core/cfg/CFGBuilder.kt b/src/main/kotlin/org/rust/lang/core/cfg/CFGBuilder.kt
index dfa8db135..057b15c5b 100644
--- a/src/main/kotlin/org/rust/lang/core/cfg/CFGBuilder.kt
+++ b/src/main/kotlin/org/rust/lang/core/cfg/CFGBuilder.kt
@@ -109,23 +109,20 @@ class CFGBuilder(val graph: Graph<CFGNodeData, CFGEdgeData>, val entry: CFGNode,
 
     private fun processCall(callExpr: RsExpr, funcOrReceiver: RsExpr?, args: List<RsExpr?>): CFGNode {
         val funcOrReceiverExit = process(funcOrReceiver, pred)
-        return straightLine(callExpr, funcOrReceiverExit, args)
-    }
-
-    private fun processExpr(expr: RsExpr, parent: RsElement, pred: CFGNode) {
-        val exprExit = process(expr, pred)
-        if (expr.type is TyNever) {
-            addReturningEdge(exprExit)
-            finishWith { addUnreachableNode() }
+        val callExit = straightLine(callExpr, funcOrReceiverExit, args)
+        return if (callExpr.type is TyNever) {
+            addUnreachableNode()
         } else {
-            finishWithAstNode(parent, exprExit)
+            callExit
         }
     }
 
     override fun visitBlock(block: RsBlock) {
         val stmtsExit = block.stmtList.fold(pred) { pred, stmt -> process(stmt, pred) }
         val blockExpr = block.expr ?: return finishWithAstNode(block, stmtsExit)
-        processExpr(blockExpr, block, stmtsExit)
+        val exprExit = process(blockExpr, stmtsExit)
+
+        finishWithAstNode(block, exprExit)
     }
 
     override fun visitLetDecl(letDecl: RsLetDecl) {
@@ -139,8 +136,10 @@ class CFGBuilder(val graph: Graph<CFGNodeData, CFGEdgeData>, val entry: CFGNode,
 
     override fun visitLabelDecl(labelDecl: RsLabelDecl) = finishWith(pred)
 
-    override fun visitExprStmt(exprStmt: RsExprStmt) =
-        processExpr(exprStmt.expr, exprStmt, pred)
+    override fun visitExprStmt(exprStmt: RsExprStmt) {
+        val exprExit = process(exprStmt.expr, pred)
+        finishWithAstNode(exprStmt, exprExit)
+    }
 
     override fun visitPatIdent(patIdent: RsPatIdent) {
         val subPatExit = process(patIdent.pat, pred)
@@ -163,6 +162,14 @@ class CFGBuilder(val graph: Graph<CFGNodeData, CFGEdgeData>, val entry: CFGNode,
     override fun visitPathExpr(pathExpr: RsPathExpr) =
         finishWithAstNode(pathExpr, pred)
 
+    override fun visitMacroExpr(macroExpr: RsMacroExpr) {
+        if (macroExpr.type is TyNever) {
+            finishWith { addUnreachableNode() }
+        } else {
+            finishWithAstNode(macroExpr, pred)
+        }
+    }
+
     override fun visitRangeExpr(rangeExpr: RsRangeExpr) =
         finishWith { straightLine(rangeExpr, pred, rangeExpr.exprList) }
 
diff --git a/src/test/kotlin/org/rust/ide/inspections/borrowck/RsBorrowCheckerUninitializedTest.kt b/src/test/kotlin/org/rust/ide/inspections/borrowck/RsBorrowCheckerUninitializedTest.kt
index e3c93a706..4c285d450 100644
--- a/src/test/kotlin/org/rust/ide/inspections/borrowck/RsBorrowCheckerUninitializedTest.kt
+++ b/src/test/kotlin/org/rust/ide/inspections/borrowck/RsBorrowCheckerUninitializedTest.kt
@@ -216,4 +216,16 @@ class RsBorrowCheckerUninitializedTest : RsInspectionsTestBase(RsBorrowCheckerIn
             <error descr="Use of possibly uninitialized variable">x</error>;
         }
     """, checkWarn = false)
+
+    /** Issue [#4008](https://github.com/intellij-rust/intellij-rust/issues/4008) */
+    fun `test no E0381 never type`() = checkByText("""
+        fn foo(flag: bool) -> i32 {
+            let value: i32;
+            match flag {
+                true => { value = 1 }
+                false => panic!()
+            };
+            value
+        }
+    """, checkWarn = false)
 }
diff --git a/src/test/kotlin/org/rust/lang/core/cfg/RsControlFlowGraphTest.kt b/src/test/kotlin/org/rust/lang/core/cfg/RsControlFlowGraphTest.kt
index 5b67a6fcb..3f1720241 100644
--- a/src/test/kotlin/org/rust/lang/core/cfg/RsControlFlowGraphTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/cfg/RsControlFlowGraphTest.kt
@@ -534,7 +534,7 @@ class RsControlFlowGraphTest : RsTestBase() {
         Exit
     """)
 
-    fun `test noreturn`() = testCFG("""
+    fun `test noreturn simple`() = testCFG("""
         fn main() {
             if true {
                 noreturn();
@@ -548,15 +548,39 @@ class RsControlFlowGraphTest : RsTestBase() {
         true
         noreturn
         noreturn()
+        IF
+        IF;
+        42
+        42;
+        BLOCK
         Exit
+    """)
+
+    fun `test noreturn complex expr`() = testCFG("""
+        fn main() {
+            if true {
+                foo.bar(1, noreturn());
+            }
+            42;
+        }
+
+        fn noreturn() -> ! { panic!() }
+    """, """
+        Entry
+        true
+        foo
+        1
+        noreturn
+        noreturn()
         IF
         IF;
         42
         42;
         BLOCK
+        Exit
     """)
 
-    fun `test panic macro call`() = testCFG("""
+    fun `test panic macro call inside stmt`() = testCFG("""
         fn main() {
             1;
             if true { 2; } else { panic!(); }
@@ -578,6 +602,49 @@ class RsControlFlowGraphTest : RsTestBase() {
         Exit
     """)
 
+    fun `test panic macro call outside stmt`() = testCFG("""
+        fn main() {
+            match x {
+                true => 2,
+                false => panic!()
+            };
+        }
+    """, """
+        Entry
+        x
+        true
+        Dummy
+        2
+        MATCH
+        MATCH;
+        BLOCK
+        Exit
+        false
+        Dummy
+    """)
+
+    fun `test macro call outside stmt`() = testCFG("""
+        fn main() {
+            match e {
+                E::A => 2,
+                E::B => some_macro!()
+            };
+        }
+    """, """
+        Entry
+        e
+        E::A
+        Dummy
+        2
+        MATCH
+        MATCH;
+        BLOCK
+        Exit
+        E::B
+        Dummy
+        some_macro!()
+    """)
+
     private fun testCFG(@Language("Rust") code: String, expectedIndented: String) {
         InlineFile(code)
         val block = myFixture.file.descendantsOfType<RsBlock>().firstOrNull() ?: return