Skip to content

Commit

Permalink
Merge pull request #643 from StefanMaron/InvalidCastExceptionOnRule0039
Browse files Browse the repository at this point in the history
Resolve InvalidCastException on LC0039
  • Loading branch information
Arthurvdv authored Jun 2, 2024
2 parents f7f3fff + 3f1c1d1 commit 9a2125e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 43 deletions.
78 changes: 38 additions & 40 deletions Design/Rule0039ArgumentDifferentTypeThenExpected.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using Microsoft.Dynamics.Nav.CodeAnalysis.Symbols;
using Microsoft.Dynamics.Nav.CodeAnalysis.Utilities;
using System.Collections.Immutable;

namespace BusinessCentral.LinterCop.Design
{
[DiagnosticAnalyzer]
public class Rule0039ArgumentDifferentTypeThenExpected : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, DiagnosticDescriptors.Rule0049PageWithoutSourceTable, DiagnosticDescriptors.Rule0000ErrorInRule);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, DiagnosticDescriptors.Rule0049PageWithoutSourceTable);

private static readonly List<PropertyKind> referencePageProviders = new List<PropertyKind>
{
Expand Down Expand Up @@ -54,43 +55,40 @@ private void AnalyzeRunPageArguments(OperationAnalysisContext ctx)

private void AnalyzeSetRecordArgument(OperationAnalysisContext ctx)
{
try
{
if (ctx.IsObsoletePendingOrRemoved()) return;

IInvocationExpression operation = (IInvocationExpression)ctx.Operation;
if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return;

if (operation.TargetMethod.ContainingType.GetTypeSymbol().GetNavTypeKindSafe() != NavTypeKind.Page) return;
string[] procedureNames = { "GetRecord", "SetRecord", "SetSelectionFilter", "SetTableView" };
if (!procedureNames.Contains(operation.TargetMethod.Name)) return;
if (operation.Arguments.Count() != 1) return;

if (operation.Arguments[0].Syntax.Kind != SyntaxKind.IdentifierName || operation.Arguments[0].Value.Kind != OperationKind.ConversionExpression) return;

IOperation pageReference = ctx.Operation.DescendantsAndSelf().Where(x => x.GetSymbol() != null)
.Where(x => x.Type.GetNavTypeKindSafe() == NavTypeKind.Page)
.SingleOrDefault();
if (pageReference == null) return;
ISymbol variableSymbol = pageReference.GetSymbol().OriginalDefinition;
IPageTypeSymbol pageTypeSymbol = (IPageTypeSymbol)variableSymbol.GetTypeSymbol().OriginalDefinition;
if (pageTypeSymbol.RelatedTable == null)
{
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0049PageWithoutSourceTable, ctx.Operation.Syntax.GetLocation(), new object[] { NavTypeKind.Page, GetFullyQualifiedObjectName(pageTypeSymbol) }));
return;
}
ITableTypeSymbol pageSourceTable = pageTypeSymbol.RelatedTable;

IOperation operand = ((IConversionExpression)operation.Arguments[0].Value).Operand;
ITableTypeSymbol recordArgument = ((IRecordTypeSymbol)operand.GetSymbol().GetTypeSymbol()).BaseTable;

if (!AreTheSameNavObjects(recordArgument, pageSourceTable))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, ctx.Operation.Syntax.GetLocation(), new object[] { 1, operand.GetSymbol().GetTypeSymbol().ToString(), pageSourceTable.GetNavTypeKindSafe() + " \"" + pageSourceTable.Name + "\"" }));
}
catch (InvalidCastException)
if (ctx.IsObsoletePendingOrRemoved()) return;

IInvocationExpression operation = (IInvocationExpression)ctx.Operation;
if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return;

if (operation.TargetMethod.ContainingType.GetTypeSymbol().GetNavTypeKindSafe() != NavTypeKind.Page) return;
string[] procedureNames = { "GetRecord", "SetRecord", "SetSelectionFilter", "SetTableView" };
if (!procedureNames.Contains(operation.TargetMethod.Name)) return;
if (operation.Arguments.Count() != 1) return;

if (operation.Arguments[0].Syntax.Kind != SyntaxKind.IdentifierName || operation.Arguments[0].Value.Kind != OperationKind.ConversionExpression) return;

IOperation pageReference = ctx.Operation.DescendantsAndSelf().Where(x => x.GetSymbol() != null)
.Where(x => x.Type.GetNavTypeKindSafe() == NavTypeKind.Page)
.SingleOrDefault();
if (pageReference == null) return;
ISymbol variableSymbol = pageReference.GetSymbol().OriginalDefinition;
IPageTypeSymbol pageTypeSymbol = (IPageTypeSymbol)variableSymbol.GetTypeSymbol().OriginalDefinition;
if (pageTypeSymbol.RelatedTable == null)
{
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0000ErrorInRule, ctx.Operation.Syntax.GetLocation(), new Object[] { "Rule0039", "Exception", "" }));
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0049PageWithoutSourceTable, ctx.Operation.Syntax.GetLocation(), new object[] { NavTypeKind.Page, GetFullyQualifiedObjectName(pageTypeSymbol) }));
return;
}
ITableTypeSymbol pageSourceTable = pageTypeSymbol.RelatedTable;

IOperation operand = ((IConversionExpression)operation.Arguments[0].Value).Operand;
ITypeSymbol typeSymbol = operand.GetSymbol().GetTypeSymbol();
if (typeSymbol.GetNavTypeKindSafe() != NavTypeKind.Record)
return;

ITableTypeSymbol recordArgument = ((IRecordTypeSymbol)typeSymbol).BaseTable;

if (!AreTheSameNavObjects(recordArgument, pageSourceTable))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, ctx.Operation.Syntax.GetLocation(), new object[] { 1, operand.GetSymbol().GetTypeSymbol().ToString(), pageSourceTable.GetNavTypeKindSafe().ToString() + ' ' + pageSourceTable.Name.QuoteIdentifierIfNeeded() }));
}

private void AnalyzeTableReferencePageProvider(SymbolAnalysisContext ctx)
Expand All @@ -108,7 +106,7 @@ private void AnalyzeTableReferencePageProvider(SymbolAnalysisContext ctx)
if (pageSourceTable == null) continue;

if (!AreTheSameNavObjects(table, pageSourceTable))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, pageReference.GetLocation(), new object[] { 1, table.GetTypeSymbol().GetNavTypeKindSafe() + " \"" + table.Name + "\"", pageSourceTable.GetNavTypeKindSafe() + " \"" + pageSourceTable.Name + "\"" }));
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, pageReference.GetLocation(), new object[] { 1, table.GetTypeSymbol().GetNavTypeKindSafe() + ' ' + table.Name.QuoteIdentifierIfNeeded(), pageSourceTable.GetNavTypeKindSafe().ToString() + ' ' + pageSourceTable.Name.QuoteIdentifierIfNeeded() }));
}
}

Expand All @@ -127,7 +125,7 @@ private void AnalyzeTableExtensionReferencePageProvider(SymbolAnalysisContext ct
if (pageSourceTable == null) continue;

if (!AreTheSameNavObjects(table, pageSourceTable))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, pageReference.GetLocation(), new object[] { 1, table.GetTypeSymbol().GetNavTypeKindSafe() + " \"" + table.Name + "\"", pageSourceTable.GetNavTypeKindSafe() + " \"" + pageSourceTable.Name + "\"" }));
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, pageReference.GetLocation(), new object[] { 1, table.GetTypeSymbol().GetNavTypeKindSafe() + ' ' + table.Name.QuoteIdentifierIfNeeded(), pageSourceTable.GetNavTypeKindSafe() + ' ' + pageSourceTable.Name.QuoteIdentifierIfNeeded() }));
}
}

Expand All @@ -145,9 +143,9 @@ private static string GetFullyQualifiedObjectName(IPageTypeSymbol page)
{
#if Fall2023RV1
if (page.ContainingNamespace.QualifiedName != "")
return page.ContainingNamespace.QualifiedName + "." + "\"" + page.Name + "\"";
return page.ContainingNamespace.QualifiedName + "." + page.Name.QuoteIdentifierIfNeeded();
#endif
return page.Name;
return page.Name.QuoteIdentifierIfNeeded();
}
}
}
15 changes: 12 additions & 3 deletions LinterCopAnalyzers.resx
Original file line number Diff line number Diff line change
Expand Up @@ -448,13 +448,13 @@
<value>Try to not exceed 200 characters (including spaces).</value>
</data>
<data name="Rule0039ArgumentDifferentTypeThenExpectedDescription" xml:space="preserve">
<value>Argument {0}: cannot convert from '{1}' to '{2}'.</value>
<value>Argument {0}: cannot convert from {1} to {2}.</value>
</data>
<data name="Rule0039ArgumentDifferentTypeThenExpectedFormat" xml:space="preserve">
<value>Argument {0}: cannot convert from '{1}' to '{2}'.</value>
<value>Argument {0}: cannot convert from {1} to {2}.</value>
</data>
<data name="Rule0039ArgumentDifferentTypeThenExpectedTitle" xml:space="preserve">
<value>Argument {0}: cannot convert from '{1}' to '{2}'.</value>
<value>Argument {0}: cannot convert from {1} to {2}.</value>
</data>
<data name="Rule0040ExplicitlySetRunTriggerTitle" xml:space="preserve">
<value>Explicitly set the RunTrigger parameter on build-in methods.</value>
Expand Down Expand Up @@ -618,4 +618,13 @@
<data name="Rule0057EnumValueWithEmptyCaptionDescription" xml:space="preserve">
<value>Enum values must have non-empty a Caption to be selectable in the client.</value>
</data>
<data name="Rule0058PageVariableMethodOnTemporaryTableTitle" xml:space="preserve">
<value>You cannot use a temporary record for the Record parameter on {0}.{1}."</value>
</data>
<data name="Rule0058PageVariableMethodOnTemporaryTableFormat" xml:space="preserve">
<value>You cannot use a temporary record for the Record parameter on {0}.{1}."</value>
</data>
<data name="Rule0058PageVariableMethodOnTemporaryTableDescription" xml:space="preserve">
<value>You cannot use a temporary record for the Record parameter on {0}.{1}."</value>
</data>
</root>

0 comments on commit 9a2125e

Please sign in to comment.