Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add proper doc for new rules + add a few tests
  • Loading branch information
jairbubbles committed Sep 29, 2024
commit c890443c8069937eca190ad86193b67f58236eaa
25 changes: 3 additions & 22 deletions docs/Rules/MA0161.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,17 @@

Detects when `Process.Start` is called without specifying the value of `UseShellExecute`.

Specifying the value is important because:
- The default value for this property is `true` on .NET Framework apps and `false` on .NET Core apps. It's a common issue when migrating a desktop app from .NET Framework to .NET Core.
- It must be set to to `false` when redirecting I/O. Otherwise you'll get an issue at runtime.
Specifying the value is important because the default value for this property is `true` on .NET Framework apps and `false` on .NET Core apps. It's a common issue when migrating a desktop app from .NET Framework to .NET Core.


````c#
using System.Diasgnostics;

// Non compliant

Process.Start("cmd"); // Intent is not clear if you want to use ShellExecute or not
Process.Start(new ProcessStartInfo("cmd")); // Intent is not clear if you want to use ShellExecute or not

Process.Start("https://www.meziantou.net/"); // Will fail on .NET Core apps

Process.Start(new ProcessStartInfo("cmd")
{
RedirectStandardOutput = true,
UseShellExecute = true,
}); // It will throw with error "UseShellExecute must be set to false when redirecting I/O"

Process.Start(new ProcessStartInfo("cmd")
{
RedirectStandardOutput = true,
}); // It will throw with error "UseShellExecute must be set to false when redirecting I/O" on .NET Framework apps
Process.Start(new ProcessStartInfo("https://www.meziantou.net/")); // Will fail on .NET Core apps

// Compliant

Expand All @@ -34,10 +21,4 @@ Process.Start(new ProcessStartInfo("https://www.meziantou.net/")
UseShellExecute = true,
});

Process.Start(new ProcessStartInfo("cmd")
{
RedirectStandardOutput = true,
UseShellExecute = false,
});

````
22 changes: 22 additions & 0 deletions docs/Rules/MA0162.md
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
# MA0162 - Use Process.Start overload with ProcessStartInfo

Detects when `Process.Start` is called without the `ProcessStartInfo` parameter.

Specifying a `ProcessStartInfo` allows to specify the `UseShellExecute` property. This value is important because the default value for this property is `true` on .NET Framework apps and `false` on .NET Core apps. It's a common issue when migrating a desktop app from .NET Framework to .NET Core.

````c#
using System.Diasgnostics;

// Non compliant

Process.Start("cmd"); // Intent is not clear if you want to use ShellExecute or not

Process.Start("https://www.meziantou.net/"); // Will fail on .NET Core apps

// Compliant

Process.Start(new ProcessStartInfo("https://www.meziantou.net/")
{
UseShellExecute = true,
});

````
42 changes: 42 additions & 0 deletions docs/Rules/MA0163.md
Original file line number Diff line number Diff line change
@@ -1 +1,43 @@
# MA0163 - UseShellExecute must be false when redirecting standard input or output

Detects when `Process.Start` is called without specifying the value of `UseShellExecute`.

Specifying the value is important because:
- The default value for this property is `true` on .NET Framework apps and `false` on .NET Core apps. It's a common issue when migrating a desktop app from .NET Framework to .NET Core.
- It must be set to to `false` when redirecting I/O. Otherwise you'll get an issue at runtime.


````c#
using System.Diasgnostics;

// Non compliant

Process.Start("cmd"); // Intent is not clear if you want to use ShellExecute or not

Process.Start("https://www.meziantou.net/"); // Will fail on .NET Core apps

Process.Start(new ProcessStartInfo("cmd")
{
RedirectStandardOutput = true,
UseShellExecute = true,
}); // It will throw with error "UseShellExecute must be set to false when redirecting I/O"

Process.Start(new ProcessStartInfo("cmd")
{
RedirectStandardOutput = true,
}); // It will throw with error "UseShellExecute must be set to false when redirecting I/O" on .NET Framework apps

// Compliant

Process.Start(new ProcessStartInfo("https://www.meziantou.net/")
{
UseShellExecute = true,
});

Process.Start(new ProcessStartInfo("cmd")
{
RedirectStandardOutput = true,
UseShellExecute = false,
});

````
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,47 @@ await CreateProjectBuilder("MA0161")
.ValidateAsync();
}

[Fact]
public async Task Process_start_should_report_when_use_shell_execute_is_not_set_3()
{
const string SourceCode = """
using System.Diagnostics;

class TypeName
{
public void Test()
{
var processStartInfo = [||]new ProcessStartInfo("notepad");
Process.Start(processStartInfo);
}
}
""";
await CreateProjectBuilder("MA0161")
.WithSourceCode(SourceCode)
.ShouldReportDiagnosticWithMessage("UseShellExecute must be explicitly set when initializing a ProcessStartInfo")
.ValidateAsync();
}

[Fact]
public async Task Process_start_should_report_when_use_shell_execute_is_not_set_4()
{
const string SourceCode = """
using System.Diagnostics;

class TypeName
{
public void Test()
{
var processStartInfo = [||]new ProcessStartInfo("notepad", string.Empty);
Process.Start(processStartInfo);
}
}
""";
await CreateProjectBuilder("MA0161")
.WithSourceCode(SourceCode)
.ShouldReportDiagnosticWithMessage("UseShellExecute must be explicitly set when initializing a ProcessStartInfo")
.ValidateAsync();
}

[Fact]
public async Task Process_start_should_report_when_using_overload_with_no_process_start_info()
Expand All @@ -233,5 +274,25 @@ await CreateProjectBuilder("MA0162")
.ValidateAsync();
}

[Fact]
public async Task Process_start_should_report_when_using_overload_with_no_process_start_info_2()
{
const string SourceCode = """
using System.Diagnostics;

class TypeName
{
public void Test()
{
[||]Process.Start("notepad", "file.txt");
}
}
""";
await CreateProjectBuilder("MA0162")
.WithSourceCode(SourceCode)
.ShouldReportDiagnosticWithMessage("Use an overload of Process.Start that has a ProcessStartInfo parameter")
.ValidateAsync();
}

private static ProjectBuilder CreateProjectBuilder(string id) => new ProjectBuilder().WithAnalyzer<ProcessStartAnalyzer>(id);
}