I'm trying to write Code Analyzer in .NET for a custom query language that evaluates string literals that are being assigned to a type called OGraphStringQuery. I then try to identify if there are any syntax errors which then reports a diagnostic error.
Currently Roslyn does not support embedded language syntax and even though they've exposed StringSyntaxAttribute
in .NET 7 it requires the use of these interfaces that are currently internal to Roslyn.
My strategy is to identify String Literals and back-peddle to get the type being assigned. I'm not sure what the best strategy is but here is the route I am taking though I am not sure how to back-peddle for the type in which OGraphStringQuery is being assigned.
Is the current path I'm taking the correct
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class OGraphStringQueryAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "APN0001";
private static readonly LocalizableString Title = default!;
private static readonly LocalizableString MessageFormat = default!;
private static readonly LocalizableString Description = default!;
private static readonly DiagnosticDescriptor Rule = default!;
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.RegisterSemanticModelAction(static context =>
{
var model = context.SemanticModel;
var tree = model.SyntaxTree;
var root = tree.GetRoot();
var descendants = root.DescendantNodes();
foreach (var literal in descendants.OfType<LiteralExpressionSyntax>())
{
if (literal.IsKind(SyntaxKind.StringLiteralExpression))
{
// Get the raw String Value
var value = literal.Token.ValueText;
if (literal.Parent is EqualsValueClauseSyntax equal)
{
if (equal.Parent is VariableDeclaratorSyntax declarator && declarator.Parent is VariableDeclarationSyntax declaration)
{
var item = model.GetSymbolInfo(declaration);
}
}
context.ReportDiagnostic(Diagnostic.Create(
Rule,
literal.GetLocation(),
value));
}
}
});
}
}
// For reference here is what the OGraphQuerString would look like
// FYI: logic removed to reduce verbosity
public readonly struct OGraphStringQuery
{
public OGraphStringQuery(sting query)
{
}
public static implicit operator OGraphStringQuery(string query) => new OGraphStringQuery(query);
}
What I would like to happen.
public class Program
{
public void Main(string[] args)
{
OGraphStringQuery query = "some query string";
// ^
// |
// Analyzers spits out error for string only for
// OGraphStringQuery type being assinged
}
}