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
2 changes: 1 addition & 1 deletion src/CustomCode-Analyzer.Vsix/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="CustomCode_Analyzer.Vsix.e1c79fe3-d19f-4bf9-9c0c-57ba1f95b494" Version="0.2.0" Language="en-US" Publisher="Jonathan Algar"/>
<Identity Id="CustomCode_Analyzer.Vsix.e1c79fe3-d19f-4bf9-9c0c-57ba1f95b494" Version="0.2.1" Language="en-US" Publisher="Jonathan Algar"/>
<DisplayName>ODC Custom Code Analyzer</DisplayName>
<Description xml:space="preserve">Get feedback on your OutSytems Developer Cloud (ODC) custom C# code as you code.</Description>
<MoreInfo>https://github.com/jonathanalgar/CustomCode-Analyzer</MoreInfo>
Expand Down
35 changes: 17 additions & 18 deletions src/CustomCode-Analyzer/Analyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using CustomCode_Analyzer.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using static CustomCode_Analyzer.AttributeNames;
using static CustomCode_Analyzer.Helpers.AttributeNames;

namespace CustomCode_Analyzer
{
Expand Down Expand Up @@ -349,7 +350,7 @@ public static class Categories
/// Returns the full set of DiagnosticDescriptors that this analyzer is capable of producing.
/// </summary>
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(
[
NonPublicInterfaceRule,
NoSingleInterfaceRule,
ManyInterfacesRule,
Expand All @@ -373,8 +374,8 @@ public static class Categories
UnsupportedParameterTypeRule,
UnsupportedDefaultValueRule,
PotentialStatefulImplementationRule,
InputSizeLimitRule
);
InputSizeLimitRule,
];

/// <summary>
/// Entry point for the analyzer. Initializes analysis by setting up compilation-level
Expand Down Expand Up @@ -1151,12 +1152,12 @@ is InterfaceDeclarationSyntax ifDecl
// Create a comma-separated list of interface names
var interfaceNames = string.Join(", ", osInterfaces.Keys.OrderBy(n => n));
// Report diagnostic indicating multiple OSInterfaces
foreach (var osInterface in osInterfaces.Values)
foreach (var (Syntax, Symbol) in osInterfaces.Values)
{
context.ReportDiagnostic(
Diagnostic.Create(
ManyInterfacesRule,
osInterface.Syntax.Identifier.GetLocation(),
Syntax.Identifier.GetLocation(),
interfaceNames
)
);
Expand Down Expand Up @@ -1216,9 +1217,7 @@ is InterfaceDeclarationSyntax ifDecl
t => t.TypeKind == TypeKind.Struct && HasAttribute(t, OSStructureAttributeNames)
);

#pragma warning disable RS1024
var duplicates = allStructures.GroupBy(x => x.Name).Where(g => g.Count() > 1);
#pragma warning restore RS1024

foreach (var duplicate in duplicates)
{
Expand Down Expand Up @@ -1296,16 +1295,16 @@ Func<INamedTypeSymbol, bool> predicate
/// Anything not in this set (and is not null for reference types) is considered invalid.
/// </summary>
private static readonly ImmutableHashSet<SpecialType> ValidParameterSpecialTypes =
ImmutableHashSet.Create(
SpecialType.System_String,
SpecialType.System_Int32,
SpecialType.System_Int64,
SpecialType.System_Single,
SpecialType.System_Double,
SpecialType.System_Decimal,
SpecialType.System_Boolean,
SpecialType.System_DateTime
);
[
SpecialType.System_String,
SpecialType.System_Int32,
SpecialType.System_Int64,
SpecialType.System_Single,
SpecialType.System_Double,
SpecialType.System_Decimal,
SpecialType.System_Boolean,
SpecialType.System_DateTime,
];

/// <summary>
/// Checks whether a parameter's default value is a compile-time constant of a supported type.
Expand Down
17 changes: 10 additions & 7 deletions src/CustomCode-Analyzer/CodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CustomCode_Analyzer.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using static CustomCode_Analyzer.AttributeNames;
using static CustomCode_Analyzer.Helpers.AttributeNames;

namespace CustomCode_Analyzer
{
Expand All @@ -29,15 +30,15 @@ public class Fixer : CodeFixProvider
/// Code fixes will only be offered for diagnostics with these IDs.
/// </summary>
public override ImmutableArray<string> FixableDiagnosticIds =>
ImmutableArray.Create(
[
Analyzer.DiagnosticIds.NameBeginsWithUnderscore,
Analyzer.DiagnosticIds.NonPublicInterface,
Analyzer.DiagnosticIds.UnsupportedTypeMapping,
Analyzer.DiagnosticIds.NonPublicStruct,
Analyzer.DiagnosticIds.NonPublicStructureField,
Analyzer.DiagnosticIds.NonPublicIgnored,
Analyzer.DiagnosticIds.MissingStructureDecoration
);
Analyzer.DiagnosticIds.MissingStructureDecoration,
];

/// <summary>
/// Returns a <see cref="FixAllProvider"/> that can handle applying fixes across an entire solution,
Expand Down Expand Up @@ -240,8 +241,10 @@ CancellationToken cancellationToken
return document;

var typeInfo = semanticModel.GetTypeInfo(parameterSyntax.Type, cancellationToken);
var structSymbol = typeInfo.Type as INamedTypeSymbol;
if (structSymbol is null || structSymbol.DeclaringSyntaxReferences.Length == 0)
if (
typeInfo.Type is not INamedTypeSymbol structSymbol
|| structSymbol.DeclaringSyntaxReferences.Length == 0
)
return document;

// Get the StructDeclarationSyntax for the referenced struct
Expand Down Expand Up @@ -276,7 +279,7 @@ CancellationToken cancellationToken
{
// Otherwise, prepend this attribute before the first existing list
var firstList = structDecl.AttributeLists.First();
newStructDecl = structDecl.InsertNodesBefore(firstList, new[] { attributeList });
newStructDecl = structDecl.InsertNodesBefore(firstList, [attributeList]);
}

// Use a DocumentEditor to replace the old struct node with the new one containing[OSStructure]
Expand Down
6 changes: 3 additions & 3 deletions src/CustomCode-Analyzer/CustomCode-Analyzer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
<LangVersion>latest</LangVersion>
<RootNamespace>CustomCode_Analyzer</RootNamespace>
<PackageId>CustomCode.Analyzer</PackageId>
<Version>0.2.0</Version>
<AssemblyVersion>0.2.0</AssemblyVersion>
<FileVersion>0.2.0</FileVersion>
<Version>0.2.1</Version>
<AssemblyVersion>0.2.1</AssemblyVersion>
<FileVersion>0.2.1</FileVersion>
<Authors>Jonathan Algar</Authors>
<Product>OutSystems Developer Cloud (ODC) Custom Code Analyzer</Product>
<Description>Get feedback on your OutSytems Developer Cloud (ODC) custom C# code as you code.</Description>
Expand Down
26 changes: 13 additions & 13 deletions src/CustomCode-Analyzer/Helpers/AttributeNames.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
using System.Collections.Generic;

namespace CustomCode_Analyzer
namespace CustomCode_Analyzer.Helpers
{
public static class AttributeNames
{
/// <summary>
/// Valid names for the OSInterface attribute.
/// </summary>
internal static readonly HashSet<string> OSInterfaceAttributeNames = new()
{
internal static readonly HashSet<string> OSInterfaceAttributeNames =
[
"OSInterfaceAttribute",
"OSInterface",
};
];

/// <summary>
/// Valid names for the OSStructure attribute.
/// </summary>
internal static readonly HashSet<string> OSStructureAttributeNames = new()
{
internal static readonly HashSet<string> OSStructureAttributeNames =
[
"OSStructureAttribute",
"OSStructure",
};
];

/// <summary>
/// Valid names for the OSStructureField attribute.
/// </summary>
internal static readonly HashSet<string> OSStructureFieldAttributeNames = new()
{
internal static readonly HashSet<string> OSStructureFieldAttributeNames =
[
"OSStructureFieldAttribute",
"OSStructureField",
};
];

/// <summary>
/// Valid names for the OSIgnore attribute.
/// </summary>
internal static readonly HashSet<string> OSIgnoreAttributeNames = new()
{
internal static readonly HashSet<string> OSIgnoreAttributeNames =
[
"OSIgnoreAttribute",
"OSIgnore",
};
];
}
}
2 changes: 1 addition & 1 deletion src/CustomCode-Analyzer/Helpers/TypeMappingHelper.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;

namespace CustomCode_Analyzer
namespace CustomCode_Analyzer.Helpers
{
/// <summary>
/// Provides a centralized mapping between OutSystems <c>OSDataType</c> enum names
Expand Down
5 changes: 2 additions & 3 deletions tests/CustomCode-Analyzer.Tests/CSharpVerifierHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ public static ImmutableDictionary<string, ReportDiagnostic> NullableWarnings
get
{
return ImmutableDictionary.CreateRange(
new[]
{
[
// Configure specific nullable warning codes as errors
new KeyValuePair<string, ReportDiagnostic>(
"CS8632",
Expand All @@ -23,7 +22,7 @@ public static ImmutableDictionary<string, ReportDiagnostic> NullableWarnings
"CS8669",
ReportDiagnostic.Error
),
}
]
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<RootNamespace>CustomCode_Analyzer.Tests</RootNamespace>
<ParallelizeTestCollections>true</ParallelizeTestCollections>
</PropertyGroup>

<ItemGroup>
Expand Down
9 changes: 2 additions & 7 deletions tests/CustomCode-Analyzer.Tests/DetailedTestLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,11 @@ namespace CustomCode_Analyzer.Tests
/// Provides detailed logging capabilities for analyzer tests.
/// Implements ITestOutputHelper to capture and display test execution details.
/// </summary>
public class DetailedTestLogger : ITestOutputHelper
public class DetailedTestLogger(TestContext testContext) : ITestOutputHelper
{
private readonly TestContext TestContext;
private readonly TestContext TestContext = testContext;
private readonly StringBuilder _output = new();

public DetailedTestLogger(TestContext testContext)
{
TestContext = testContext;
}

public void WriteLine(string message)
{
_output.AppendLine(message);
Expand Down