Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .SONAR_VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9.32.0.97167
10 changes: 0 additions & 10 deletions docs/description/description.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions docs/multiple-tests/default-rules/results.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<checkstyle version="4.3">
<file name="example.cs">
<error source="S3904" line="1" message="Provide an 'AssemblyVersion' attribute for assembly 'srcassembly.dll'." severity="error" />
<error source="S3990" line="1" message="Provide a 'CLSCompliant' attribute for assembly 'srcassembly.dll'." severity="warning" />
<error source="S1451" line="1" message="Add or update the header of this file." severity="error" />
<error source="S3992" line="1" message="Provide a 'ComVisible' attribute for assembly 'srcassembly.dll'." severity="warning" />
<error source="S3903" line="3" message="Move 'Foobar' into a named namespace." severity="warning" />
<error source="S2933" line="5" message="Make 'bar' 'readonly'." severity="warning" />
</file>
Expand Down
6 changes: 6 additions & 0 deletions docs/multiple-tests/s1125-unresolved-types/patterns.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<module name="root">
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="SonarLint\.xml"/>
</module>
</module>
6 changes: 6 additions & 0 deletions docs/multiple-tests/s1125-unresolved-types/results.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<checkstyle version="4.3">
<file name="S1125.cs">
<error source="S1125" line="10" message="Remove the unnecessary Boolean literal(s)." severity="info" />
</file>
</checkstyle>
5 changes: 5 additions & 0 deletions docs/multiple-tests/s1125-unresolved-types/src/Course.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class Course
{
public bool? Enabled { get; set; }
public bool? Visible { get; set; }
}
12 changes: 12 additions & 0 deletions docs/multiple-tests/s1125-unresolved-types/src/S1125.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
public class Example
{
public bool Check(Course course, bool flag, bool? nullableFlag)
{
if (course.Enabled == true && !course.Visible.HasValue)
{
return nullableFlag == true;
}

return flag == true;
}
}
8 changes: 8 additions & 0 deletions docs/multiple-tests/s1125-unresolved-types/src/SonarLint.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<AnalysisInput>
<Rules>
<Rule>
<Key>S1125</Key>
</Rule>
</Rules>
</AnalysisInput>
6 changes: 6 additions & 0 deletions docs/multiple-tests/s1128-framework-usings/patterns.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<module name="root">
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="SonarLint\.xml"/>
</module>
</module>
6 changes: 6 additions & 0 deletions docs/multiple-tests/s1128-framework-usings/results.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<checkstyle version="4.3">
<file name="S1128.cs">
<error source="S1128" line="3" message="Remove this unnecessary 'using'." severity="info" />
</file>
</checkstyle>
13 changes: 13 additions & 0 deletions docs/multiple-tests/s1128-framework-usings/src/S1128.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Net;
using System.Text;
using System.Collections.Generic;

public class Example
{
public HttpStatusCode Status { get; set; }

public string Build()
{
return new StringBuilder().Append(Status).ToString();
}
}
8 changes: 8 additions & 0 deletions docs/multiple-tests/s1128-framework-usings/src/SonarLint.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<AnalysisInput>
<Rules>
<Rule>
<Key>S1128</Key>
</Rule>
</Rules>
</AnalysisInput>
12 changes: 0 additions & 12 deletions docs/patterns.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/Analyzer/CodeAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class CodeAnalyzer : Codacy.Engine.Seed.CodeAnalyzer, IDisposable
private readonly ImmutableArray<DiagnosticAnalyzer> availableAnalyzers;
private readonly DiagnosticsRunner diagnosticsRunner;
private readonly string tmpSonarLintFolder;
private static HashSet<string> blacklist = new HashSet<string> { "S1144", "S2325", "S2077", "AD0001" };
private static HashSet<string> blacklist = new HashSet<string> { "S1144", "S2325", "S2077", "AD0001", "S3992", "S3904" };

public static bool IsInBlacklist(string id)
{
Expand Down
28 changes: 25 additions & 3 deletions src/Analyzer/Runner/CompilationHelper.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace CodacyCSharp.Analyzer.Runner
{
public static class CompilationHelper
{
private static readonly MetadataReference systemMetadataReference =
MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
// Reference the whole runtime framework (not only System.Private.CoreLib),
// so types like System.Net.HttpStatusCode resolve and rules relying on
// the semantic model (e.g. S1128) don't report false positives.
private static readonly IReadOnlyList<MetadataReference> frameworkMetadataReferences =
GetFrameworkMetadataReferences();

private static IReadOnlyList<MetadataReference> GetFrameworkMetadataReferences()
{
var trustedAssemblies = AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") as string;
var paths = string.IsNullOrEmpty(trustedAssemblies)
? new[] { typeof(object).Assembly.Location }
: trustedAssemblies.Split(Path.PathSeparator);

var frameworkDirectory = Path.GetDirectoryName(typeof(object).Assembly.Location);

return paths
// keep only framework assemblies, not the analyzer's own dependencies
.Where(path => Path.GetDirectoryName(path) == frameworkDirectory)
.Select(path => (MetadataReference)MetadataReference.CreateFromFile(path))
.ToList();
}

public static Solution GetSolutionFromFile(string filePath)
{
Expand All @@ -16,7 +38,7 @@ public static Solution GetSolutionFromFile(string filePath)
var file = new FileInfo(filePath);
var project = workspace.CurrentSolution
.AddProject("srcassembly", "srcassembly.dll", LanguageNames.CSharp)
.AddMetadataReference(systemMetadataReference);
.AddMetadataReferences(frameworkMetadataReferences);

using (var fileStream = File.Open(file.FullName, FileMode.Open, FileAccess.Read))
{
Expand Down
47 changes: 46 additions & 1 deletion src/Analyzer/Runner/DiagnosticsRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using SonarAnalyzer.Common;

Expand Down Expand Up @@ -56,7 +57,51 @@ public Task<ImmutableArray<Diagnostic>> GetDiagnostics(Compilation compilation,
options,
cancellationToken);

return compilationWithAnalyzer.GetAnalyzerDiagnosticsAsync(cancellationToken);
return FilterDiagnostics(modifiedCompilation, compilationWithAnalyzer, cancellationToken);
}

private static async Task<ImmutableArray<Diagnostic>> FilterDiagnostics(
Compilation compilation,
CompilationWithAnalyzers compilationWithAnalyzer,
CancellationToken cancellationToken)
{
var diagnostics = await compilationWithAnalyzer.GetAnalyzerDiagnosticsAsync(cancellationToken);

return diagnostics
.Where(diagnostic => !IsS1125OnUnresolvedType(compilation, diagnostic, cancellationToken))
.ToImmutableArray();
}

// S1125 can only tell `x == true` apart from a valid `bool?` comparison when the
// type of `x` is known. Files are compiled in isolation, so types declared in other
// files or packages are unresolved and the rule reports false positives on them.
private static bool IsS1125OnUnresolvedType(
Compilation compilation,
Diagnostic diagnostic,
CancellationToken cancellationToken)
{
var tree = diagnostic.Location.SourceTree;
if (diagnostic.Id != "S1125" || tree is null)
{
return false;
}

var binaryExpression = tree.GetRoot(cancellationToken)
.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true)
.AncestorsAndSelf()
.OfType<BinaryExpressionSyntax>()
.FirstOrDefault();

if (binaryExpression is null)
{
return false;
}

var semanticModel = compilation.GetSemanticModel(tree);

return new[] { binaryExpression.Left, binaryExpression.Right }
.Select(operand => semanticModel.GetTypeInfo(operand, cancellationToken).Type)
.Any(type => type is null || type.TypeKind == TypeKind.Error);
}

private ReportDiagnostic GetReportDiagnosticForPattern(string diagnosticId)
Expand Down