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

Null reference exception on Rule0068 #746

Merged
merged 2 commits into from
Aug 28, 2024
Merged
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
39 changes: 19 additions & 20 deletions BusinessCentral.LinterCop/Design/Rule0068CheckObjectPermission.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#nullable enable
using System.Collections.Immutable;
using System.Dynamic;
using BusinessCentral.LinterCop.AnalysisContextExtension;
using Microsoft.Dynamics.Nav.Analyzers.Common;
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using Microsoft.Dynamics.Nav.CodeAnalysis.Symbols;
using Microsoft.Dynamics.Nav.CodeAnalysis.Utilities;

namespace BusinessCentral.LinterCop.Design
{
Expand Down Expand Up @@ -54,7 +54,7 @@ private void CheckXmlportNodeObjectPermission(SymbolAnalysisContext ctx)

IXmlPortTypeSymbol xmlPort = (IXmlPortTypeSymbol)ctx.Symbol.GetContainingObjectTypeSymbol();

IPropertySymbol objectPermissions = xmlPort.GetProperty(PropertyKind.Permissions);
IPropertySymbol? objectPermissions = xmlPort.GetProperty(PropertyKind.Permissions);
ITypeSymbol targetSymbol = ((IXmlPortNodeSymbol)ctx.Symbol.OriginalDefinition).GetTypeSymbol();
var directionProperty = xmlPort.Properties.FirstOrDefault(property => property.Name == "Direction");

Expand All @@ -78,7 +78,7 @@ private void CheckQueryDataItemObjectPermission(SymbolAnalysisContext ctx)
{
if (ctx.IsObsoletePendingOrRemoved()) return;

IPropertySymbol objectPermissions = ctx.Symbol.GetContainingApplicationObjectTypeSymbol().GetProperty(PropertyKind.Permissions);
IPropertySymbol? objectPermissions = ctx.Symbol.GetContainingApplicationObjectTypeSymbol()?.GetProperty(PropertyKind.Permissions);
ITypeSymbol targetSymbol = ((IQueryDataItemSymbol)ctx.Symbol).GetTypeSymbol();
CheckProcedureInvocation(objectPermissions, targetSymbol, 'r', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition);
}
Expand All @@ -89,7 +89,7 @@ private void CheckReportDataItemObjectPermission(SymbolAnalysisContext ctx)
if (ctx.Symbol.GetBooleanPropertyValue(PropertyKind.UseTemporary) == true) return;
if (((ITableTypeSymbol)((IRecordTypeSymbol)((IReportDataItemSymbol)ctx.Symbol).GetTypeSymbol()).OriginalDefinition).TableType == TableTypeKind.Temporary) return;

IPropertySymbol objectPermissions = ctx.Symbol.GetContainingApplicationObjectTypeSymbol().GetProperty(PropertyKind.Permissions);
IPropertySymbol? objectPermissions = ctx.Symbol.GetContainingApplicationObjectTypeSymbol()?.GetProperty(PropertyKind.Permissions);
ITypeSymbol targetSymbol = ((IReportDataItemSymbol)ctx.Symbol).GetTypeSymbol();
CheckProcedureInvocation(objectPermissions, targetSymbol, 'r', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition);
}
Expand All @@ -101,14 +101,14 @@ private void CheckObjectPermission(OperationAnalysisContext ctx)
IInvocationExpression operation = (IInvocationExpression)ctx.Operation;
if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return;

ITypeSymbol variableType = operation.Instance?.GetSymbol().GetTypeSymbol();
if (variableType.GetNavTypeKindSafe() != NavTypeKind.Record) return;
ITypeSymbol? variableType = operation.Instance?.GetSymbol()?.GetTypeSymbol();
if (variableType?.GetNavTypeKindSafe() != NavTypeKind.Record) return;

ITableTypeSymbol targetTable = (ITableTypeSymbol)((IRecordTypeSymbol)variableType).OriginalDefinition;

if (ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol().NavTypeKind == NavTypeKind.Page)
if (ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol()?.NavTypeKind == NavTypeKind.Page)
{
IPropertySymbol sourceTableProperty = ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol().GetProperty(PropertyKind.SourceTable);
IPropertySymbol? sourceTableProperty = ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol()?.GetProperty(PropertyKind.SourceTable);
if (sourceTableProperty != null)
if (sourceTableProperty.Value == targetTable)
return;
Expand All @@ -121,7 +121,7 @@ private void CheckObjectPermission(OperationAnalysisContext ctx)
if (ctx.ContainingSymbol is IMethodSymbol symbol)
inherentPermissions = symbol.Attributes.Where(attribute => attribute.Name == "InherentPermissions");

IPropertySymbol objectPermissions = ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol().GetProperty(PropertyKind.Permissions);
IPropertySymbol? objectPermissions = ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol()?.GetProperty(PropertyKind.Permissions);
//variableType.OriginalDefinition.ContainingNamespace
if (buildInTableDataReadMethodNames.Contains(operation.TargetMethod.Name.ToLowerInvariant()))
{
Expand Down Expand Up @@ -153,12 +153,12 @@ private bool ProcedureHasInherentPermission(IEnumerable<IAttributeSymbol> inhere

foreach (var inherentPermission in inherentPermissions)
{
var inherentPermissionAsString = inherentPermission.DeclaringSyntaxReference.GetSyntax().ToString();
var inherentPermissionAsString = inherentPermission.DeclaringSyntaxReference?.GetSyntax().ToString();



var permissions = inherentPermissionAsString.Split(new[] { '[', ']', '(', ')', ',' }, StringSplitOptions.RemoveEmptyEntries);
if (permissions[1].Trim() != "PermissionObjectType::TableData") continue;
var permissions = inherentPermissionAsString?.Split(new[] { '[', ']', '(', ')', ',' }, StringSplitOptions.RemoveEmptyEntries);
if (permissions?[1].Trim() != "PermissionObjectType::TableData") continue;

var typeAndObjectName = permissions[2].Trim();
var permissionValue = permissions[3].Trim().Trim(new[] { '\'', ' ' });
Expand All @@ -169,7 +169,7 @@ private bool ProcedureHasInherentPermission(IEnumerable<IAttributeSymbol> inhere
var objectName = typeParts[1].Trim().Trim('"');
if (objectName.ToLowerInvariant() != variableType.Name.ToLowerInvariant())
#if Fall2023RV1
if (objectName.Replace("\"","").ToLowerInvariant() != (variableType.OriginalDefinition.ContainingNamespace.QualifiedName.ToLowerInvariant() + "." + variableType.Name.ToLowerInvariant()))
if (objectName.UnquoteIdentifier().ToLowerInvariant() != (variableType.OriginalDefinition.ContainingNamespace.QualifiedName.ToLowerInvariant() + "." + variableType.Name.ToLowerInvariant()))
#endif
continue;

Expand All @@ -181,7 +181,7 @@ private bool ProcedureHasInherentPermission(IEnumerable<IAttributeSymbol> inhere
return false;
}

private void CheckProcedureInvocation(IPropertySymbol objectPermissions, ITypeSymbol variableType, char requestedPermission, Action<Diagnostic> ReportDiagnostic, Microsoft.Dynamics.Nav.CodeAnalysis.Text.Location location, ITableTypeSymbol targetTable)
private void CheckProcedureInvocation(IPropertySymbol? objectPermissions, ITypeSymbol variableType, char requestedPermission, Action<Diagnostic> ReportDiagnostic, Microsoft.Dynamics.Nav.CodeAnalysis.Text.Location location, ITableTypeSymbol targetTable)
{
if (TableHasInherentPermission(targetTable, requestedPermission)) return;

Expand Down Expand Up @@ -218,7 +218,7 @@ private void CheckProcedureInvocation(IPropertySymbol objectPermissions, ITypeSy

bool nameSpaceNameMatch = false;
#if Fall2023RV1
nameSpaceNameMatch = objectName.Replace("\"","") == (variableType.OriginalDefinition.ContainingNamespace.QualifiedName.ToLowerInvariant() + "." + variableType.Name.ToLowerInvariant());
nameSpaceNameMatch = objectName.UnquoteIdentifier() == (variableType.OriginalDefinition.ContainingNamespace.QualifiedName.ToLowerInvariant() + "." + variableType.Name.ToLowerInvariant());
#endif

// Match against the parameters of the procedure
Expand All @@ -241,12 +241,11 @@ private void CheckProcedureInvocation(IPropertySymbol objectPermissions, ITypeSy

private bool TableHasInherentPermission(ITableTypeSymbol table, char requestedPermission)
{
IPropertySymbol permissionProperty = table.GetProperty(PropertyKind.InherentPermissions);
if (permissionProperty == null) return false;
IPropertySymbol? permissionProperty = table.GetProperty(PropertyKind.InherentPermissions);
// InherentPermissions = RIMD;
var permissions = permissionProperty.Value.ToString().ToLowerInvariant().Split(new[] { '=' }, 2)[0].Trim().ToCharArray();
char[]? permissions = permissionProperty?.Value.ToString().ToLowerInvariant().Split(new[] { '=' }, 2)[0].Trim().ToCharArray();

if (permissions.Contains(requestedPermission.ToString().ToLowerInvariant()[0]))
if (permissions is not null && permissions.Contains(requestedPermission.ToString().ToLowerInvariant()[0]))
return true;

return false;
Expand Down