/// <summary> /// Analyze thr MemberAcessExpressionSyntax Nodes /// </summary> /// <param name="memberAccessExpressions"></param> /// <param name="cryslData"></param> /// <param name="context"></param> /// <returns></returns> public ValidEvents AnalyzeMemAccessExprSyntax(IdentifierNameSyntax identifier, IEnumerable <CryptoSignature> cryptoMethods, Methods methods, CryslJsonModel cryslData, SyntaxNodeAnalysisContext context, IMethodSymbol identifierSymbolInfo, TextSpan nodeSPan) { ValidEvents validEvents = new ValidEvents(); // Check for valid event only if Identifier is of Spec type in Crysl. if (identifierSymbolInfo.ReturnType.ToString().Equals(cryslData.Spec_Section.Class_Name)) { List <MethodSignatureModel> methodSignatureModelsList = new List <MethodSignatureModel>(); foreach (var method in cryptoMethods) { ICommonUtilities commonUtilities = serviceProvider.GetService <ICommonUtilities>(); //Check if the Event is Valid bool isValidEvent = commonUtilities.IsMethodInEvents(method, identifierSymbolInfo, cryslData.Object_Section.Objects_Declaration); if (isValidEvent) { MethodSignatureModel currentValidEvent = new MethodSignatureModel { MethodName = identifierSymbolInfo.Name, Parameters = method.Argument_types, }; methodSignatureModelsList.Add(currentValidEvent); //Go to the Containing Method Declaration Node var containingMethodDeclarationNode = identifier.FirstAncestorOrSelf <MethodDeclarationSyntax>(); var invExprSyntaxWalker = new InvocationExpressionSyntaxWalker(cryslData, context, nodeSPan); //Walk through the current method to find all invocations of the given type invExprSyntaxWalker.Visit(containingMethodDeclarationNode); Dictionary <string, List <MethodSignatureModel> > validEventsDict = invExprSyntaxWalker.GetMethodsList(); if (!validEventsDict.ContainsKey(method.Event_Var_Name)) { validEventsDict.Add(method.Event_Var_Name, methodSignatureModelsList); } //If there are two events of same type else if (validEventsDict.ContainsKey(method.Event_Var_Name)) { foreach (var methodSig in validEventsDict.Values) { methodSignatureModelsList.AddRange(methodSig); } validEventsDict[method.Event_Var_Name] = methodSignatureModelsList; } //Check if the Aggregator Condition Satisfies bool isAggregatorCondition = commonUtilities.CheckAggregator(validEventsDict, methods.Aggregator.Aggregators); if (isAggregatorCondition) { validEvents.IsValidEvent = true; validEvents.ValidEventsDict = validEventsDict; validEvents.AggregatorName = methods.Aggregator.Aggregator_Name; } else { validEvents.IsValidEvent = false; } return(validEvents); } } } validEvents.IsValidEvent = false; return(validEvents); }
public override void VisitIdentifierName(IdentifierNameSyntax node) { // See if we're part of a qualified name var qname = node.FirstAncestorOrSelf <QualifiedNameSyntax>(); var syntaxNode = qname == null ? (SyntaxNode)node : qname; // Get the symbol var symbolInfo = _semanticModel.GetSymbolInfo(syntaxNode, _cancellationToken); if (symbolInfo.Symbol == null) { _logger.LogWarning(node.GetLocation(), "Failed to resolve symbol for: {Syntax}", syntaxNode.ToString()); } else if (symbolInfo.Symbol is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.TypeKind == TypeKind.Class) { _logger.LogTrace(node.GetLocation(), "Referenced symbol: {Kind}::{Name}", symbolInfo.Symbol.Kind, symbolInfo.Symbol.Name); _builder.Snapshot.ReferenceSymbol(symbolInfo.Symbol, node.GetLocation()); }
public override void VisitIdentifierName(IdentifierNameSyntax node) { if (symbols.FirstOrDefault(x => node.NameIs(x.Name) && x.Equals(semanticModel.GetSymbolInfo(node).Symbol)) is { } symbol) { isMuted = IsInTupleAssignmentTarget() || IsUsedInLocalFunction(symbol) || IsInUnsupportedExpression(); InspectTryCatch(node); } base.VisitIdentifierName(node); bool IsInTupleAssignmentTarget() => node.Parent is ArgumentSyntax argument && argument.IsInTupleAssignmentTarget(); bool IsUsedInLocalFunction(ISymbol symbol) => // We don't mute it if it's declared and used in local function !(symbol.ContainingSymbol is IMethodSymbol containingSymbol && containingSymbol.MethodKind == MethodKindEx.LocalFunction) && HasAncestor(node, SyntaxKindEx.LocalFunctionStatement); bool IsInUnsupportedExpression() => node.FirstAncestorOrSelf <SyntaxNode>(x => x.IsAnyKind(SyntaxKindEx.IndexExpression, SyntaxKindEx.RangeExpression)) != null; }
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { // Get related symbol ISymbol symbol = this.model.GetSymbolInfo(node).Symbol; // Check does the symbol refer to stored parameter if (symbol != null && symbol.Equals(this.parameterSymbol)) { // Create reference to temporary variable IdentifierNameSyntax tempVariableReference = Syntax.IdentifierName(this.variableName) .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); // Check is the IdentifierNameExpression on the left side of binary expression if (node.Parent != null && node.Parent is BinaryExpressionSyntax) { BinaryExpressionSyntax binaryExpression = (BinaryExpressionSyntax)node.Parent; if (IsComplexAssignment(binaryExpression) && binaryExpression.Left != null && binaryExpression.Left.Equals(node)) { // Assignment operation is rewritten to utilize new temporary variable return(tempVariableReference); } } // Verify has the parameter symbol been already assigned new value // If not, then no replacement should take place (we can still read the original value directly from parameter) StatementSyntax parentStatement = node.FirstAncestorOrSelf <StatementSyntax>(); if (IsInConditionExpression(parentStatement, this.parameterSymbol)) { return(tempVariableReference); } if (IsAlreadyAssignedNewValue(parentStatement, this.parameterSymbol)) { return(tempVariableReference); } } return(base.VisitIdentifierName(node)); }
public void HandleIdentifierNameSyntax(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { IdentifierNameSyntax identifierNameSyntax = (IdentifierNameSyntax)context.Node; if (identifierNameSyntax.IsVar) { return; } if (identifierNameSyntax.Identifier.IsMissing) { return; } switch (identifierNameSyntax.Identifier.ValueText) { case "bool": case "byte": case "char": case "decimal": case "double": case "short": case "int": case "long": case "object": case "sbyte": case "float": case "string": case "ushort": case "uint": case "ulong": return; default: break; } if (identifierNameSyntax.FirstAncestorOrSelf <UsingDirectiveSyntax>() != null && identifierNameSyntax.FirstAncestorOrSelf <TypeArgumentListSyntax>() == null) { return; } // Most source files will not have any using alias directives. Then we don't have to use semantics // if the identifier name doesn't match the name of a special type if (settings.ReadabilityRules.AllowBuiltInTypeAliases || !identifierNameSyntax.SyntaxTree.ContainsUsingAlias(this.usingAliasCache)) { switch (identifierNameSyntax.Identifier.ValueText) { case nameof(Boolean): case nameof(Byte): case nameof(Char): case nameof(Decimal): case nameof(Double): case nameof(Int16): case nameof(Int32): case nameof(Int64): case nameof(Object): case nameof(SByte): case nameof(Single): case nameof(String): case nameof(UInt16): case nameof(UInt32): case nameof(UInt64): break; default: return; } } SemanticModel semanticModel = context.SemanticModel; // We go straight to the symbol here. We don't need to check alias information because aliases will fall // into one of two categories: // // 1. The alias to a built-in type matches the name of a built-in type (e.g. using Int32 = Int32;). In // this case, a diagnostic is reported even if allowBuiltInTypeAliases=true. // 2. The alias to a built-in type is a different name. In this case, if allowBuiltInTypeAliases is true // then the above code would have already returned due to the renamed symbol not being in the set of // strings checked by the analyzer above. INamedTypeSymbol symbol = semanticModel.GetSymbolInfo(identifierNameSyntax, context.CancellationToken).Symbol as INamedTypeSymbol; switch (symbol?.SpecialType) { case SpecialType.System_Boolean: case SpecialType.System_Byte: case SpecialType.System_Char: case SpecialType.System_Decimal: case SpecialType.System_Double: case SpecialType.System_Int16: case SpecialType.System_Int32: case SpecialType.System_Int64: case SpecialType.System_Object: case SpecialType.System_SByte: case SpecialType.System_Single: case SpecialType.System_String: case SpecialType.System_UInt16: case SpecialType.System_UInt32: case SpecialType.System_UInt64: break; default: return; } SyntaxNode locationNode = identifierNameSyntax; if (identifierNameSyntax.Parent is QualifiedNameSyntax) { locationNode = identifierNameSyntax.Parent; } else if ((identifierNameSyntax.Parent as MemberAccessExpressionSyntax)?.Name == identifierNameSyntax) { // this "weird" syntax appears for qualified references within a nameof expression locationNode = identifierNameSyntax.Parent; } else if (identifierNameSyntax.Parent is NameMemberCrefSyntax && identifierNameSyntax.Parent.Parent is QualifiedCrefSyntax) { locationNode = identifierNameSyntax.Parent.Parent; } // Allow nameof if (IsNameInNameOfExpression(identifierNameSyntax)) { return; } // Use built-in type alias context.ReportDiagnostic(Diagnostic.Create(Descriptor, locationNode.GetLocation())); }
private void HandleIdentifierNameSyntax(SyntaxNodeAnalysisContext context) { IdentifierNameSyntax identifierNameSyntax = context.Node as IdentifierNameSyntax; if (identifierNameSyntax == null || identifierNameSyntax.IsVar) { return; } if (identifierNameSyntax.Identifier.IsMissing) { return; } switch (identifierNameSyntax.Identifier.Text) { case "bool": case "byte": case "char": case "decimal": case "double": case "short": case "int": case "long": case "object": case "sbyte": case "float": case "string": case "ushort": case "uint": case "ulong": return; default: break; } if (identifierNameSyntax.FirstAncestorOrSelf <UsingDirectiveSyntax>() != null) { return; } SemanticModel semanticModel = context.SemanticModel; INamedTypeSymbol symbol = semanticModel.GetSymbolInfo(identifierNameSyntax, context.CancellationToken).Symbol as INamedTypeSymbol; switch (symbol?.SpecialType) { case SpecialType.System_Boolean: case SpecialType.System_Byte: case SpecialType.System_Char: case SpecialType.System_Decimal: case SpecialType.System_Double: case SpecialType.System_Int16: case SpecialType.System_Int32: case SpecialType.System_Int64: case SpecialType.System_Object: case SpecialType.System_SByte: case SpecialType.System_Single: case SpecialType.System_String: case SpecialType.System_UInt16: case SpecialType.System_UInt32: case SpecialType.System_UInt64: break; default: return; } SyntaxNode locationNode = identifierNameSyntax; if (identifierNameSyntax.Parent is QualifiedNameSyntax) { locationNode = identifierNameSyntax.Parent; } else if ((identifierNameSyntax.Parent as MemberAccessExpressionSyntax)?.Name == identifierNameSyntax) { // this "weird" syntax appears for qualified references within a nameof expression locationNode = identifierNameSyntax.Parent; } else if (identifierNameSyntax.Parent is NameMemberCrefSyntax && identifierNameSyntax.Parent.Parent is QualifiedCrefSyntax) { locationNode = identifierNameSyntax.Parent.Parent; } // Allow nameof if (this.IsNameInNameOfExpression(identifierNameSyntax)) { return; } // Use built-in type alias context.ReportDiagnostic(Diagnostic.Create(Descriptor, locationNode.GetLocation())); }
private static void HandleIdentifierNameSyntax(SyntaxNodeAnalysisContext context) { IdentifierNameSyntax identifierNameSyntax = (IdentifierNameSyntax)context.Node; if (identifierNameSyntax.IsVar) { return; } if (identifierNameSyntax.Identifier.IsMissing) { return; } switch (identifierNameSyntax.Identifier.ValueText) { case "bool": case "byte": case "char": case "decimal": case "double": case "short": case "int": case "long": case "object": case "sbyte": case "float": case "string": case "ushort": case "uint": case "ulong": return; default: break; } if (identifierNameSyntax.FirstAncestorOrSelf <UsingDirectiveSyntax>() != null && identifierNameSyntax.FirstAncestorOrSelf <TypeArgumentListSyntax>() == null) { return; } // Most source files will not have any using alias directives. Then we don't have to use semantics // if the identifier name doesn't match the name of a special type if (!identifierNameSyntax.SyntaxTree.ContainsUsingAlias()) { switch (identifierNameSyntax.Identifier.ValueText) { case nameof(Boolean): case nameof(Byte): case nameof(Char): case nameof(Decimal): case nameof(Double): case nameof(Int16): case nameof(Int32): case nameof(Int64): case nameof(Object): case nameof(SByte): case nameof(Single): case nameof(String): case nameof(UInt16): case nameof(UInt32): case nameof(UInt64): break; default: return; } } SemanticModel semanticModel = context.SemanticModel; INamedTypeSymbol symbol = semanticModel.GetSymbolInfo(identifierNameSyntax, context.CancellationToken).Symbol as INamedTypeSymbol; switch (symbol?.SpecialType) { case SpecialType.System_Boolean: case SpecialType.System_Byte: case SpecialType.System_Char: case SpecialType.System_Decimal: case SpecialType.System_Double: case SpecialType.System_Int16: case SpecialType.System_Int32: case SpecialType.System_Int64: case SpecialType.System_Object: case SpecialType.System_SByte: case SpecialType.System_Single: case SpecialType.System_String: case SpecialType.System_UInt16: case SpecialType.System_UInt32: case SpecialType.System_UInt64: break; default: return; } SyntaxNode locationNode = identifierNameSyntax; if (identifierNameSyntax.Parent is QualifiedNameSyntax) { locationNode = identifierNameSyntax.Parent; } else if ((identifierNameSyntax.Parent as MemberAccessExpressionSyntax)?.Name == identifierNameSyntax) { // this "weird" syntax appears for qualified references within a nameof expression locationNode = identifierNameSyntax.Parent; } else if (identifierNameSyntax.Parent is NameMemberCrefSyntax && identifierNameSyntax.Parent.Parent is QualifiedCrefSyntax) { locationNode = identifierNameSyntax.Parent.Parent; } // Allow nameof if (IsNameInNameOfExpression(identifierNameSyntax)) { return; } // Use built-in type alias context.ReportDiagnostic(Diagnostic.Create(Descriptor, locationNode.GetLocation())); }
private static Location GetSquigglesLocation(IdentifierNameSyntax identifier) => identifier.FirstAncestorOrSelf <MemberAccessExpressionSyntax>().GetLocation();
public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken) { SyntaxNode root = (SyntaxNode)document.GetSyntaxRoot(cancellationToken); SyntaxToken token = root.FindToken(textSpan.Start, findInsideTrivia: true); SyntaxNode parentNode = token.Parent; if (parentNode == null) { return(null); } // Verify is the selected token an identifier of a method if (token.Kind == SyntaxKind.IdentifierToken && parentNode.Kind == SyntaxKind.IdentifierName && token.Span.Start <= textSpan.End && textSpan.End <= token.Span.End) { IdentifierNameSyntax identifier = (IdentifierNameSyntax)parentNode; InvocationExpressionSyntax invocationExpression = identifier.FirstAncestorOrSelf <InvocationExpressionSyntax>(); if (invocationExpression == null || invocationExpression.HasDiagnostics) { return(null); } ISemanticModel model = document.GetSemanticModel(cancellationToken); ISymbol methodSymbol = model.GetSymbolInfo(invocationExpression.Expression, cancellationToken).Symbol; if (methodSymbol == null) { return(null); } // Check is the method defined in source, so that its body can be read and inlined CommonLocation methodDeclarationLocation = methodSymbol.Locations.First(); if (methodDeclarationLocation == null || !methodDeclarationLocation.IsInSource) { return(null); } // Get method declaration based on location int position = methodDeclarationLocation.SourceSpan.Start; MethodDeclarationSyntax methodDeclaration = methodDeclarationLocation.SourceTree.GetRoot().FindToken(position).Parent.FirstAncestorOrSelf <MethodDeclarationSyntax>(); if (methodDeclaration == null) { return(null); } BlockSyntax methodBody = methodDeclaration.Body; // Method can be inlined only if it has only one statement, which is return statement if (methodBody.Statements.Count != 1 || methodBody.Statements[0].Kind != SyntaxKind.ReturnStatement) { return(null); } ReturnStatementSyntax returnStatement = (ReturnStatementSyntax)methodBody.Statements[0]; if (returnStatement == null || returnStatement.Expression == null) { return(null); } // If inlined method's invocation expression is the only expression in statement (so its direct parent is ExpressionStatement) // then the expression in ReturnStatement should be one of: invocation, object creation, increment, decrement, assignment (or complex assignment). if (invocationExpression.Parent != null && invocationExpression.Parent.Kind == SyntaxKind.ExpressionStatement) { if (!IsIndependentExpression(returnStatement.Expression)) { return(null); } } // If method is polymorphic, then it should not be inlined. Late binding does not take place. MethodSymbol declaredMethodSymbol = (MethodSymbol)model.GetDeclaredSymbol(methodDeclaration); if (declaredMethodSymbol.OverriddenMethod != null || declaredMethodSymbol.MethodKind == MethodKind.ExplicitInterfaceImplementation || declaredMethodSymbol.IsVirtual || declaredMethodSymbol.IsOverride) { return(null); } var analysis = model.AnalyzeStatementDataFlow(returnStatement); // If parameter is assigned value, it must be either `out' or `ref' to preserve semantics when method is inlined // That is, if parameter is modified, the change is reflected before inlining and after inlining foreach (var parameter in methodDeclaration.ParameterList.Parameters) { ISymbol parameterSymbol = model.GetDeclaredSymbol(parameter, cancellationToken); // Check is the parameter changed in method's body if (analysis.WrittenInside.Contains(parameterSymbol)) { // Verify if the modified parameter defined with either `ref' or `out' keyword if (!parameter.Modifiers.Any(n => n.Kind == SyntaxKind.OutKeyword || n.Kind == SyntaxKind.RefKeyword)) { return(null); } } } return(new CodeRefactoring( new[] { new InlineMethodAction(document, invocationExpression, methodDeclaration, returnStatement.Expression) } , invocationExpression.Span)); } return(null); }