Skip to content

Commit

Permalink
SonarAnalysisContextBase refactoring (#6915)
Browse files Browse the repository at this point in the history
  • Loading branch information
mary-georgiou-sonarsource committed Mar 15, 2023
1 parent f0553a7 commit 62efe30
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 31 deletions.
Expand Up @@ -53,9 +53,9 @@ protected SonarAnalysisContextBase(SonarAnalysisContext analysisContext, TContex
/// <param name="tree">Tree to decide on. Can be null for Symbol-based and Compilation-based scenarios. And we want to analyze those too.</param>
/// <param name="generatedCodeRecognizer">When set, generated trees are analyzed only when language-specific 'analyzeGeneratedCode' configuration property is also set.</param>
public bool ShouldAnalyzeTree(SyntaxTree tree, GeneratedCodeRecognizer generatedCodeRecognizer) =>
SonarLintFile() is var sonarLintReader
&& (generatedCodeRecognizer is null || sonarLintReader.AnalyzeGeneratedCode(Compilation.Language) || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
&& (tree is null || (!IsUnchanged(tree) && ShouldAnalyzeFile(sonarLintReader, tree.FilePath)));
SonarLintXml() is var sonarLintXml
&& (generatedCodeRecognizer is null || sonarLintXml.AnalyzeGeneratedCode(Compilation.Language) || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
&& (tree is null || (!IsUnchanged(tree) && !IsExcluded(sonarLintXml, tree.FilePath)));

/// <summary>
/// Reads configuration from SonarProjectConfig.xml file and caches the result for scope of this analysis.
Expand All @@ -79,7 +79,7 @@ public ProjectConfigReader ProjectConfiguration()
/// <summary>
/// Reads the properties from the SonarLint.xml file and caches the result for the scope of this analysis.
/// </summary>
public SonarLintXmlReader SonarLintFile()
public SonarLintXmlReader SonarLintXml()
{
if (Options.SonarLintXml() is { } sonarLintXml)
{
Expand Down Expand Up @@ -121,10 +121,12 @@ public bool HasMatchingScope(DiagnosticDescriptor descriptor)
descriptor.CustomTags.Contains(tag);
}

private bool ShouldAnalyzeFile(SonarLintXmlReader sonarLintXml, string filePath) =>
ProjectConfiguration().ProjectType != ProjectType.Unknown // Not SonarLint context, NuGet or Scanner <= 5.0
|| (FileInclusionCache.GetValue(Compilation, _ => new()) is var cache
&& cache.GetOrAdd(filePath, _ => IsFileIncluded(sonarLintXml, filePath)));
private bool IsExcluded(SonarLintXmlReader sonarLintXml, string filePath) =>
// If ProjectType is not 'Unknown' it means we are in S4NET context and all files are analyzed.
// If ProjectType is 'Unknown' then we are in SonarLint or NuGet context and we need to check if the file has been excluded from analysis through SonarLint.xml.
ProjectConfiguration().ProjectType == ProjectType.Unknown
&& FileInclusionCache.GetValue(Compilation, _ => new()) is var cache
&& !cache.GetOrAdd(filePath, _ => IsFileIncluded(sonarLintXml, filePath));

private ImmutableHashSet<string> CreateUnchangedFilesHashSet() =>
ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, ProjectConfiguration().AnalysisConfig?.UnchangedFiles() ?? Array.Empty<string>());
Expand Down
Expand Up @@ -32,7 +32,7 @@ protected sealed override void Initialize(SonarAnalysisContext context)
context.RegisterCompilationStartAction(
c =>
{
ParameterLoader.SetParameterValues(this, c.SonarLintFile());
ParameterLoader.SetParameterValues(this, c.SonarLintXml());
parameterContext.ExecutePostponedActions(c);
});
}
Expand Down
Expand Up @@ -100,8 +100,8 @@ private static SonarLintXml ParseContent(SourceText sonarLintXml)

private string ReadSettingsProperty(string property) =>
sonarLintXml is { Settings: { } settings }
? settings.Where(x => x.Key.Equals(property)).Select(x => x.Value).FirstOrDefault()
: string.Empty;
? settings.Where(x => x.Key.Equals(property)).Select(x => x.Value).FirstOrDefault()
: null;

private static string[] ReadCommaSeparatedArray(string str) =>
string.IsNullOrEmpty(str) ? Array.Empty<string>() : str.Split(',');
Expand Down
Expand Up @@ -60,7 +60,7 @@ protected void ReadParameters(SonarCompilationStartAnalysisContext context)
}
if (context.Options.SonarLintXml() != null && !string.IsNullOrEmpty(outPath))
{
var sonarLintXml = context.SonarLintFile();
var sonarLintXml = context.SonarLintXml();
IgnoreHeaderComments = sonarLintXml.IgnoreHeaderComments(context.Compilation.Language);
AnalyzeGeneratedCode = sonarLintXml.AnalyzeGeneratedCode(context.Compilation.Language);
OutPath = Path.Combine(outPath, context.Compilation.Language == LanguageNames.CSharp ? "output-cs" : "output-vbnet");
Expand Down
Expand Up @@ -179,7 +179,7 @@ public void SonarLintFile_LoadsExpectedValues(string language)
var analyzerLanguage = language == "cs" ? AnalyzerLanguage.CSharp : AnalyzerLanguage.VisualBasic;
var (compilation, _) = CreateDummyCompilation(analyzerLanguage, "ExtraEmptyFile");
var options = AnalysisScaffolding.CreateOptions($"ResourceTests\\SonarLintXml\\All_properties_{language}\\SonarLint.xml");
var sut = CreateSut(compilation, options).SonarLintFile();
var sut = CreateSut(compilation, options).SonarLintXml();

sut.IgnoreHeaderComments(analyzerLanguage.LanguageName).Should().BeTrue();
sut.AnalyzeGeneratedCode(analyzerLanguage.LanguageName).Should().BeFalse();
Expand All @@ -204,8 +204,8 @@ public void SonarLintFile_UsesCachedValue()
var options = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var firstSut = CreateSut(options);
var secondSut = CreateSut(options);
var firstFile = firstSut.SonarLintFile();
var secondFile = secondSut.SonarLintFile();
var firstFile = firstSut.SonarLintXml();
var secondFile = secondSut.SonarLintXml();

secondFile.Should().BeSameAs(firstFile);
}
Expand All @@ -215,8 +215,8 @@ public void SonarLintFile_WhenFileChanges_RebuildsCache()
{
var firstOptions = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var secondOptions = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_vbnet\\SonarLint.xml");
var firstFile = CreateSut(firstOptions).SonarLintFile();
var secondFile = CreateSut(secondOptions).SonarLintFile();
var firstFile = CreateSut(firstOptions).SonarLintXml();
var secondFile = CreateSut(secondOptions).SonarLintXml();

secondFile.Should().NotBeSameAs(firstFile);
}
Expand All @@ -229,14 +229,14 @@ public void SonarLintFile_WhenFileChanges_RebuildsCache()
[DataRow("path//SonarLint.xmla")] // different extension
public void SonarLintFile_WhenAdditionalFileNotPresent_ReturnsDefaultValues(string folder)
{
var sut = CreateSut(AnalysisScaffolding.CreateOptions(folder)).SonarLintFile();
var sut = CreateSut(AnalysisScaffolding.CreateOptions(folder)).SonarLintXml();
CheckSonarLintXmlDefaultValues(sut);
}

[TestMethod]
public void SonarLintFile_WhenInvalidXml_ReturnsDefaultValues()
{
var sut = CreateSut(AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\Invalid_Xml\\SonarLint.xml")).SonarLintFile();
var sut = CreateSut(AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\Invalid_Xml\\SonarLint.xml")).SonarLintXml();
CheckSonarLintXmlDefaultValues(sut);
}

Expand All @@ -245,7 +245,7 @@ public void SonarLintFile_WhenFileIsMissing_ThrowException()
{
var sut = CreateSut(AnalysisScaffolding.CreateOptions("ThisPathDoesNotExist\\SonarLint.xml"));

sut.Invoking(x => x.SonarLintFile())
sut.Invoking(x => x.SonarLintXml())
.Should()
.Throw<InvalidOperationException>()
.WithMessage("File 'SonarLint.xml' has been added as an AdditionalFile but could not be read and parsed.");
Expand Down
Expand Up @@ -41,7 +41,7 @@ public void SetParameterValues_WithInvalidSonarLintPath_DoesNotPopulateParameter
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.Maximum.Should().Be(3); // Default value
Expand All @@ -57,7 +57,7 @@ public void SetParameterValues_WithValidSonarLintPath_PopulatesProperties(string
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.Maximum.Should().Be(1); // Value from the xml file
Expand All @@ -71,7 +71,7 @@ public void SetParameterValues_SonarLintFileWithIntParameterType_PopulatesProper
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.Maximum.Should().Be(1); // Value from the xml file
Expand All @@ -87,7 +87,7 @@ public void SetParameterValues_SonarLintFileWithStringParameterType_PopulatesPro
var analyzer = new EnumNameShouldFollowRegex(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.FlagsEnumNamePattern.Should().Be(parameterValue); // value from XML file
Expand All @@ -103,7 +103,7 @@ public void SetParameterValues_SonarLintFileWithBooleanParameterType_PopulatesPr
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.IsRegularExpression.Should().Be(parameterValue); // value from XML file
Expand All @@ -117,7 +117,7 @@ public void SetParameterValues_SonarLintFileWithoutRuleParameters_DoesNotPopulat
var analyzer = new LineLength(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.Maximum.Should().Be(200); // Default value
Expand Down Expand Up @@ -149,7 +149,7 @@ public void SetParameterValues_CalledTwiceAfterChangeInConfigFile_UpdatesPropert
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
analyzer.Maximum.Should().Be(maxValue);

// Modify the in-memory additional file
Expand All @@ -159,7 +159,7 @@ public void SetParameterValues_CalledTwiceAfterChangeInConfigFile_UpdatesPropert
var modifiedFilePath = TestHelper.WriteFile(TestContext, "SonarLint.xml", modifiedSonarLintXml);
compilation = CreateCompilationWithOption(modifiedFilePath);

ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
analyzer.Maximum.Should().Be(maxValue);
}

Expand All @@ -174,7 +174,7 @@ public void SetParameterValues_WithMalformedXml_DoesNotPopulateProperties(string
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.Maximum.Should().Be(3); // Default value
Expand All @@ -190,7 +190,7 @@ public void SetParameterValues_SonarLintFileWithStringInsteadOfIntParameterType_
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.Maximum.Should().Be(3); // Default value
Expand All @@ -206,7 +206,7 @@ public void SetParameterValues_SonarLintFileWithStringInsteadOfBooleanParameterT
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.

// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());

// Assert
analyzer.IsRegularExpression.Should().BeFalse(); // Default value
Expand Down

0 comments on commit 62efe30

Please sign in to comment.