using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Codelyzer.Analysis.CSharp
{
///
/// Helper class for getting semantic info
///
public static class SemanticHelper
{
///
/// Gets SymbolInfo for a syntax node
///
/// The node to get symbol info for
/// An instance of the semantic model
/// SymbolInfo of a node
public static SymbolInfo? GetSymbolInfo(SyntaxNode syntaxNode,
SemanticModel semanticModel)
{
return semanticModel?.GetSymbolInfo(syntaxNode);
}
///
/// Gets name of type from TypeSyntax
///
/// The TypeSyntax parameter to get info about
/// An instance of the semantic model
/// Name of the type
public static string GetSemanticType(TypeSyntax typeSyntax,
SemanticModel semanticModel,
SemanticModel preportSemanticModel = null)
{
if (semanticModel == null && preportSemanticModel == null) return null;
string type = null;
var typeInfo = semanticModel.GetTypeInfo(typeSyntax);
if (typeInfo.Type == null && preportSemanticModel != null)
{
try
{
typeInfo = preportSemanticModel.GetTypeInfo(typeSyntax);
}
catch (Exception)
{
//When looking for a symbol, and the semantic model is not passed, this generates an error.
//We don't log this error because this is an expected behavior when there's no previous semantic models
}
}
if (typeInfo.Type != null)
{
type = typeInfo.Type.Name;
}
return type;
}
///
/// Gets name of type from ExpressionSyntax
///
/// The ExpressionSyntax to get info about
/// An instance of the semantic model
/// Name of the type
public static string GetSemanticType(ExpressionSyntax expressionSyntax,
SemanticModel semanticModel,
SemanticModel preportSemanticModel = null)
{
if (semanticModel == null && preportSemanticModel == null) return null;
string type = null;
var typeInfo = semanticModel.GetTypeInfo(expressionSyntax);
if (typeInfo.Type == null && preportSemanticModel != null)
{
try
{
typeInfo = preportSemanticModel.GetTypeInfo(expressionSyntax);
}
catch (Exception)
{
//When looking for a symbol, and the semantic model is not passed, this generates an error.
//We don't log this error because this is an expected behavior when there's no previous semantic models
}
}
if (typeInfo.Type != null)
{
type = typeInfo.Type.Name;
}
return type;
}
public static ISymbol GetSemanticSymbol(SyntaxNode syntaxNode,
SemanticModel semanticModel,
SemanticModel preportSemanticModel = null)
{
if (semanticModel == null && preportSemanticModel == null) return null;
var symbol = semanticModel?.GetSymbolInfo(syntaxNode).Symbol;
if (symbol == null && preportSemanticModel != null)
{
try
{
symbol = preportSemanticModel.GetSymbolInfo(syntaxNode).Symbol;
}
catch (Exception)
{
//When looking for a symbol, and the semantic model is not passed, this generates an error.
//We don't log this error because this is an expected behavior when there's no previous semantic models
}
}
try
{
var symbolInfo = semanticModel?.GetSymbolInfo(syntaxNode);
if (symbol == null && symbolInfo.Value.CandidateSymbols.Length > 0)
{
symbol = symbolInfo.Value.CandidateSymbols[0];
}
}
catch (Exception)
{
// We're trying to get candidate symbols, and we might not find any so we're ok with this erroring out
}
return symbol;
}
public static INamedTypeSymbol GetDeclaredSymbol(SyntaxNode syntaxNode,
SemanticModel semanticModel,
SemanticModel preportSemanticModel = null)
{
if (semanticModel == null && preportSemanticModel == null) return null;
var symbol = semanticModel?.GetDeclaredSymbol(syntaxNode) as INamedTypeSymbol;
if (symbol == null && preportSemanticModel != null)
{
try
{
symbol = preportSemanticModel.GetDeclaredSymbol(syntaxNode) as INamedTypeSymbol;
}
catch (Exception)
{
//When looking for a symbol, and the semantic model is not passed, this generates an error.
//We don't log this error because this is an expected behavior when there's no previous semantic models
}
}
return symbol;
}
public static ISymbol GetDeclaredOriginalSymbol(SyntaxNode syntaxNode,
SemanticModel semanticModel,
SemanticModel preportSemanticModel = null)
{
if (semanticModel == null && preportSemanticModel == null) return null;
var symbol = semanticModel?.GetDeclaredSymbol(syntaxNode);
if (symbol == null && preportSemanticModel != null)
{
try
{
symbol = preportSemanticModel.GetDeclaredSymbol(syntaxNode);
}
catch (Exception)
{
//When looking for a symbol, and the semantic model is not passed, this generates an error.
//We don't log this error because this is an expected behavior when there's no previous semantic models
}
}
return symbol;
}
///
/// Gets name of type from IdentifierNameSyntax
///
/// The IdentifierNameSyntax to get info about
/// An instance of the semantic model
/// Name of the type
public static string GetSemanticType(IdentifierNameSyntax identifierNameSyntax,
SemanticModel semanticModel,
SemanticModel preportSemanticModel)
{
if (semanticModel == null && preportSemanticModel == null) return null;
string type = null;
var typeInfo = semanticModel.GetTypeInfo(identifierNameSyntax);
if (typeInfo.Type == null && preportSemanticModel != null)
{
try
{
typeInfo = preportSemanticModel.GetTypeInfo(identifierNameSyntax);
}
catch (Exception)
{
//When looking for a symbol, and the semantic model is not passed, this generates an error.
//We don't log this error because this is an expected behavior when there's no previous semantic models
}
}
if (typeInfo.Type != null)
{
type = typeInfo.Type.Name;
}
return type;
}
///
/// Populates a List with all the method properties
///
/// The method to analyze
/// The List to populate
public static void AddMethodProperties(IMethodSymbol invokedSymbol, List properties)
{
//Set method properties
properties.Add(invokedSymbol.DeclaredAccessibility.ToString());
if (invokedSymbol.IsAsync) properties.Add("async");
if (invokedSymbol.IsOverride) properties.Add("override");
if (invokedSymbol.IsAbstract) properties.Add("abstract");
if (invokedSymbol.IsExtern) properties.Add("extern");
if (invokedSymbol.IsSealed) properties.Add("sealed");
if (invokedSymbol.IsStatic) properties.Add("static");
if (invokedSymbol.IsVirtual) properties.Add("virtual");
if (invokedSymbol.IsReadOnly) properties.Add("readonly");
}
public static string GetSemanticClassType(string classNameWithNamespace, string semanticNamespace)
{
Match match = Regex.Match(classNameWithNamespace, String.Format("{0}.(.*)", Regex.Escape(semanticNamespace)));
return match.Success ? match.Groups[1].Value : classNameWithNamespace;
}
///
/// Returns the semantic method signature of a method declaration (fully qualified method names and parameter types)
///
/// Semantic model of syntax tree containing the method declaration
/// Method declaration node
/// The semantic method signature
public static string GetSemanticMethodSignature(SemanticModel semanticModel, SemanticModel originalSemanticModel, BaseMethodDeclarationSyntax syntaxNode)
{
var semanticMethodNameAndParameters = GetDeclaredOriginalSymbol(syntaxNode, semanticModel, originalSemanticModel)?.ToString();
var joinedModifiers = string.Join(" ", syntaxNode.Modifiers.Select(m => m.ToString()));
return $"{joinedModifiers} {semanticMethodNameAndParameters}".Trim();
}
}
}