Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -206,5 +206,35 @@ public void ExcludedHostsMatchingTest(string testString, bool isMatch)
}
});
}

[DataRow(0, @"
@description('Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.')
param keyVaultUri string
")]
[DataRow(0, @"
@sys.description('Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.')
param keyVaultUri string
")]
[DataRow(0, @"
@metadata({
description: 'Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.'
})
param keyVaultUri string
")]
[DataRow(0, @"
@metadata({
description: 'Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.',
otherProperty: 'some other value'
})
param keyVaultUri string
")]
[DataRow(1, @"
param keyVaultUri string = 'https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>'
")]
[DataTestMethod]
public void ShouldSkipDescriptionAndMetadataDecorators(int diagnosticCount, string text)
{
AssertLinterRuleDiagnostics(NoHardcodedEnvironmentUrlsRule.Code, text, diagnosticCount, new Options(OnCompileErrors.Ignore));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public override IEnumerable<IDiagnostic> AnalyzeInternal(SemanticModel model, Di

if (disallowedHosts.Any())
{
var visitor = new Visitor(disallowedHosts, disallowedHosts.Min(h => h.Length), excludedHosts);
var visitor = new Visitor(disallowedHosts, disallowedHosts.Min(h => h.Length), excludedHosts, model.SourceFile.Hierarchy);
visitor.Visit(model.SourceFile.ProgramSyntax);

return visitor.DisallowedHostSpans.Select(entry => CreateDiagnosticForSpan(diagnosticLevel, entry.Key, entry.Value));
Expand Down Expand Up @@ -102,12 +102,14 @@ private sealed class Visitor : AstVisitor
private readonly ImmutableArray<string> disallowedHosts;
private readonly int minHostLen;
private readonly ImmutableArray<string> excludedHosts;
private readonly ISyntaxHierarchy syntaxHierarchy;

public Visitor(ImmutableArray<string> disallowedHosts, int minHostLen, ImmutableArray<string> excludedHosts)
public Visitor(ImmutableArray<string> disallowedHosts, int minHostLen, ImmutableArray<string> excludedHosts, ISyntaxHierarchy syntaxHierarchy)
{
this.disallowedHosts = disallowedHosts;
this.minHostLen = minHostLen;
this.excludedHosts = excludedHosts;
this.syntaxHierarchy = syntaxHierarchy;
}

public static IEnumerable<(TextSpan RelativeSpan, string Value)> RemoveOverlapping(IEnumerable<(TextSpan RelativeSpan, string Value)> matches)
Expand All @@ -126,8 +128,59 @@ public Visitor(ImmutableArray<string> disallowedHosts, int minHostLen, Immutable
}
}

private bool IsStringInDescriptionOrMetadataDecorator(StringSyntax syntax)
{
// Check if this StringSyntax is part of a @description or @metadata decorator
var current = syntaxHierarchy.GetParent(syntax);
while (current is not null)
{
if (current is DecoratorSyntax decoratorSyntax)
{
// Check if it's a @description decorator
if (decoratorSyntax.Expression is FunctionCallSyntax functionCall)
{
if (functionCall.NameEquals("description"))
{
return true;
}
}
else if (decoratorSyntax.Expression is InstanceFunctionCallSyntax instanceFunctionCall)
{
// Check for @sys.description
if (instanceFunctionCall.NameEquals("description") &&
instanceFunctionCall.BaseExpression is VariableAccessSyntax variableAccess &&
variableAccess.NameEquals("sys"))
{
return true;
}
}

// Check if it's a @metadata decorator
if (decoratorSyntax.Expression is FunctionCallSyntax metadataFunctionCall)
{
if (metadataFunctionCall.NameEquals("metadata"))
{
return true;
}
}

break;
}

current = syntaxHierarchy.GetParent(current);
}

return false;
}

public override void VisitStringSyntax(StringSyntax syntax)
{
// Skip strings that are part of @description or @metadata decorators
if (IsStringInDescriptionOrMetadataDecorator(syntax))
{
return;
}

// shortcut check by testing length of full span
if (syntax.Span.Length > minHostLen)
{
Expand Down
Loading