using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Codelyzer.Analysis.VisualBasic { /// /// 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 } } 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 void AddPropertyProperties(IPropertySymbol invokedSymbol, List properties) { properties.Add(invokedSymbol.DeclaredAccessibility.ToString()); 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, MethodBlockBaseSyntax syntaxNode) { var semanticMethodNameAndParameters = GetDeclaredOriginalSymbol(syntaxNode, semanticModel, originalSemanticModel)?.ToString(); var joinedModifiers = string.Join(" ", syntaxNode.BlockStatement.Modifiers.Select(m => m.ToString())); return $"{joinedModifiers} {semanticMethodNameAndParameters}".Trim(); } } }