Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve InvalidCastException on LC0039 #643

Merged
merged 1 commit into from
Jun 2, 2024
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
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>