/// <summary> /// Construct a new <see cref="Snippet"/> from a string containing a C# expression. /// </summary> /// <param name="text">String containing a C# expression, possibly with wildcards (single-character variables).</param> public Snippet(string?text) { // TODO: try parsing as statement first? Expression = SyntaxFactory.ParseExpression(text); // TODO: make this error! just not sure . . . how. if (!Expression.DescendantNodes().Any()) { throw new UnknownExpressionException(); } var lc = new Regex(@"^\p{Ll}$"); var replacementNodes = Expression.DescendantNodes() .OfType <IdentifierNameSyntax>() .Where(nameSyntax => lc.IsMatch(nameSyntax.Identifier.ValueText)) .GroupBy(nameSyntax => nameSyntax.Identifier.ValueText); SubexpressionIdentifiers = replacementNodes .Select(g => g.Key) .ToList(); if (replacementNodes.Any(g => g.Count() > 1)) { throw new NotImplementedException("Matching the same subexpression is not yet supported: https://github.com/rainersigwald/bumblebee/issues/4"); } }
public void LexicalTokenMatching_Usage() { var compiler = new RoslynCompiler(); var lexical = compiler.Lexical(); lexical .match() .any('(', '=', ',') .token("function", named: "fn") .enclosed('(', ')') .token('{', named: "brace") .then(compiler.Lexical().transform() .remove("fn") .insert("=>", before: "brace")) .match() .any(new[] { '(', '=', ',' }, named: "start") .enclosed('[', ']', start: "open", end: "close") .then(compiler.Lexical().transform() .insert("new []", after: "start") .replace("open", "{") .replace("close", "}")); ExpressionSyntax exprFunction = compiler.CompileExpression("call(10, function(x, y) {})"); Assert.IsTrue(exprFunction.DescendantNodes() .OfType <ParenthesizedLambdaExpressionSyntax>() .Any()); ExpressionSyntax exprArray = compiler.CompileExpression("call([1, 2, 3], 4, [5, 6, 7])"); Assert.IsTrue(exprArray.DescendantNodes() .OfType <ImplicitArrayCreationExpressionSyntax>() .Count() == 2); }
private FieldDeclarationSyntax GetStaticField(string name, List <ParameterSyntax> parameterList, TypeSyntax returType, ExpressionSyntax bodyExpression, SemanticModel sm, ITypeSymbol type) { GenericNameSyntax expressionType = GetExpressionTypeSyntax(parameterList, returType); ExpressionSyntax newBody = bodyExpression; if (parameterList.Count > 0 & parameterList[0].Identifier.ToString() == "@this") { newBody = AddImplicitThis(newBody, sm, type); newBody = newBody.ReplaceNodes(newBody.DescendantNodes().OfType <ThisExpressionSyntax>().ToList(), (thisExp, _) => SyntaxFactory.IdentifierName(parameterList[0].Identifier)); } if (newBody.Span.Length > 80) { newBody = newBody.WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed); } var parameters = parameterList.Select(p => SyntaxFactory.Parameter(p.Identifier)).ToArray(); var lambda = parameters.Length == 1 ? (LambdaExpressionSyntax)SyntaxFactory.SimpleLambdaExpression(parameters.Single(), newBody) : (LambdaExpressionSyntax)SyntaxFactory.ParenthesizedLambdaExpression(SyntaxFactory.ParameterList().AddParameters(parameters), newBody); var variable = SyntaxFactory.VariableDeclaration(expressionType).AddVariables( SyntaxFactory.VariableDeclarator(name).WithInitializer( SyntaxFactory.EqualsValueClause(lambda))); return(SyntaxFactory.FieldDeclaration(variable).WithModifiers(SyntaxTokenList.Create(SyntaxFactory.Token(SyntaxKind.StaticKeyword))) .NormalizeWhitespace() .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)); }
public IdentifierNameSyntax GetMethodIdentifier(ExpressionSyntax invocation, string methodName) { return(invocation .DescendantNodes() .OfType <IdentifierNameSyntax>() .FirstOrDefault(i => i.WithoutTrivia().ToString() == methodName)); }
public static bool ContainsOutArgumentWithLocal( ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { foreach (SyntaxNode node in expression.DescendantNodes()) { if (node.Kind() == SyntaxKind.Argument) { var argument = (ArgumentSyntax)node; if (argument.RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword) { ExpressionSyntax argumentExpression = argument.Expression; if (argumentExpression?.IsMissing == false && semanticModel.GetSymbol(argumentExpression, cancellationToken)?.Kind == SymbolKind.Local) { return(true); } } } } return(false); }
public void FunctionUsage() { RoslynCompiler compiler = new RoslynCompiler(); Functions.Apply(compiler); //XSModule.Apply(compiler); //as lambda ExpressionSyntax exprFunction = compiler.CompileExpression("call(10, function(x, y) {})"); Assert.IsTrue(exprFunction.DescendantNodes() .OfType <ParenthesizedLambdaExpressionSyntax>() .Any()); //as typed method string result = compiler.ApplyLexicalPass("class foo { public int function bar(int x) {}}"); Assert.IsTrue(result == "class foo { public int bar(int x) {}}"); SyntaxTree tree = null; string text = null; //as untyped method tree = compiler.ApplySemanticalPass("class foo { public function bar() {}}", out text); Assert.IsTrue(tree.GetRoot() .DescendantNodes() .OfType <MethodDeclarationSyntax>() .First() .ReturnType .ToString() == "void"); //must have added a return type //as code function tree = compiler.ApplySemanticalPass("class foo { public function bar() { function foobar(int x) {return 3;}}}", out text); Assert.IsTrue(tree.GetRoot() .DescendantNodes() .OfType <ParenthesizedLambdaExpressionSyntax>() .Any()); //code functions replaced by a lambda declaration //as type, without return type tree = compiler.ApplySemanticalPass("class foo { void bar() { function<void, string> foobar; }}", out text); Assert.IsTrue(tree.GetRoot() .DescendantNodes() .OfType <LocalDeclarationStatementSyntax>() .First() .Declaration .Type .ToString() == "Action<string>"); //must have changed the function type into an action (because of the void) //as type, with return type tree = compiler.ApplySemanticalPass("class foo { void bar() { function<int, string> foobar; }}", out text); Assert.IsTrue(tree.GetRoot() .DescendantNodes() .OfType <LocalDeclarationStatementSyntax>() .First() .Declaration .Type .ToString() == "Func<string,int>"); //must have changed the function type, moving the return type to the end }
protected ExpressionSyntax RenameIdentifier(ExpressionSyntax expression, string oldName, string newName) { var identifierNode = expression.DescendantNodes() .OfType <IdentifierNameSyntax>() .First(node => node.Identifier.Text == oldName); return(expression.ReplaceNode(identifierNode, identifierNode.WithIdentifier(SyntaxFactory.Identifier(newName).WithTriviaFrom(identifierNode.Identifier)))); }
public IdentifierNameSyntax GetMethodIdentifier(ExpressionSyntax invocation) { var nodes = invocation .DescendantNodes() .OfType <IdentifierNameSyntax>().ToList(); return(nodes.ElementAtOrDefault(1) ?? nodes.ElementAtOrDefault(0) ?? null); }
private InvocationExpressionSyntax ReplaceIdentifier(MemberAccessExpressionSyntax mockedObjectIdentifier, ParameterSyntax param, ExpressionSyntax lambdaBody) { var nameToken = lambdaBody.DescendantNodes().OfType <IdentifierNameSyntax>() .First(x => x.Identifier.ValueText == param.Identifier.ValueText); return(lambdaBody.ReplaceNode(nameToken, mockedObjectIdentifier) as InvocationExpressionSyntax); }
public static void AnalyzeNamedType(SymbolAnalysisContext context, INamedTypeSymbol flagsAttribute) { var enumSymbol = (INamedTypeSymbol)context.Symbol; if (enumSymbol.IsEnum() && enumSymbol.HasAttribute(flagsAttribute)) { var infos = default(ImmutableArray <EnumFieldInfo>); foreach (ISymbol member in enumSymbol.GetMembers()) { if (member.IsField()) { var fieldSymbol = (IFieldSymbol)member; if (!fieldSymbol.HasConstantValue) { break; } var info = new EnumFieldInfo(fieldSymbol); if (info.IsComposite()) { var declaration = (EnumMemberDeclarationSyntax)info.Symbol.GetSyntax(context.CancellationToken); ExpressionSyntax valueExpression = declaration.EqualsValue?.Value; if (valueExpression != null && (valueExpression.IsKind(SyntaxKind.NumericLiteralExpression) || valueExpression .DescendantNodes() .Any(f => f.IsKind(SyntaxKind.NumericLiteralExpression)))) { if (infos.IsDefault) { infos = EnumFieldInfo.CreateRange(enumSymbol); if (infos.IsDefault) { break; } } List <EnumFieldInfo> values = info.Decompose(infos); if (values?.Count > 1) { context.ReportDiagnostic( DiagnosticDescriptors.DeclareEnumValueAsCombinationOfNames, valueExpression); } } } } } } }
private (ExpressionSyntax fullInvocation, string identifierToken) PrepandCallToInvocation(IdentifierNameSyntax mockedObjectIdentifier, string prepandCall, ExpressionSyntax lambdaBody) { var prependInvocation = SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, mockedObjectIdentifier, SyntaxFactory.IdentifierName(prepandCall))); var nameToken = lambdaBody.DescendantNodes().First(x => x.Kind() == mockedObjectIdentifier.Kind() && ((IdentifierNameSyntax)x).Identifier.ValueText == mockedObjectIdentifier.Identifier.ValueText); var fullInvocation = lambdaBody.ReplaceNode(nameToken, prependInvocation); return(fullInvocation, mockedObjectIdentifier.Identifier.ValueText); }
private BoundExpression BindAggregate(ExpressionSyntax aggregate, BoundAggregateExpression boundAggregate) { var affectedQueryScopes = aggregate.DescendantNodes() .Select(GetBoundNode <BoundColumnExpression>) .Where(n => n != null) .Select(b => b.Symbol) .OfType <TableColumnInstanceSymbol>() .Select(c => FindQueryState(c.TableInstance)) .Distinct() .Take(2) .ToImmutableArray(); if (affectedQueryScopes.Length > 1) { Diagnostics.ReportAggregateContainsColumnsFromDifferentQueries(aggregate.Span); } var queryState = affectedQueryScopes.DefaultIfEmpty(QueryState) .First(); if (queryState == null) { Diagnostics.ReportAggregateInvalidInCurrentContext(aggregate.Span); } else { var existingSlot = FindComputedValue(aggregate, queryState.ComputedAggregates); if (existingSlot == null) { var slot = ValueSlotFactory.CreateTemporary(boundAggregate.Type); queryState.ComputedAggregates.Add(new BoundComputedValueWithSyntax(aggregate, boundAggregate, slot)); } } var aggregateBelongsToCurrentQuery = QueryState == queryState; if (InOnClause && aggregateBelongsToCurrentQuery) { Diagnostics.ReportAggregateInOn(aggregate.Span); } else if (InWhereClause && aggregateBelongsToCurrentQuery) { Diagnostics.ReportAggregateInWhere(aggregate.Span); } else if (InGroupByClause && aggregateBelongsToCurrentQuery) { Diagnostics.ReportAggregateInGroupBy(aggregate.Span); } else if (InAggregateArgument) { Diagnostics.ReportAggregateInAggregateArgument(aggregate.Span); } return(boundAggregate); }
private static bool IsNullableTypeInPointerExpression(ExpressionSyntax expression, ExpressionSyntax simplifiedNode) { // Note: nullable type syntax is not allowed in pointer type syntax if (simplifiedNode.Kind() == SyntaxKind.NullableType && simplifiedNode.DescendantNodes().Any(n => n is PointerTypeSyntax)) { return(true); } return(false); }
public void Arrays() { RoslynCompiler compiler = new RoslynCompiler(); XSLang.Apply(compiler); ExpressionSyntax exprArray = compiler.CompileExpression("x = [[1, 2, 3], [4, 5, 6]]"); Assert.IsTrue(exprArray.DescendantNodes() .OfType <ImplicitArrayCreationExpressionSyntax>() .Count() == 3); }
private bool MethodContainsUserInputMethod(ExpressionSyntax invocationExpressionSyntax, SemanticModel semanticModel) { bool methodContainsUserInputMethod = false; foreach (InvocationExpressionSyntax childInvocation in invocationExpressionSyntax.DescendantNodes().OfType <InvocationExpressionSyntax>()) { IMethodSymbol methodSymbol = semanticModel.GetSymbolInfo(childInvocation).Symbol as IMethodSymbol; if (IsPotentialUserInputMethod(methodSymbol)) { methodContainsUserInputMethod = true; } } return(methodContainsUserInputMethod); }
private string GetBuilderSetterMethod(ExpressionSyntax assigment) { var nodes = assigment.DescendantNodes <IdentifierNameSyntax>(); if (assigment is IdentifierNameSyntax) { nodes = nodes.Prepend(assigment.As <IdentifierNameSyntax>()); } var parameter = nodes .Select(p => p.Identifier.Text) .Select(p => _parameters.FirstOrDefault(q => q.Identifier.Text == p)) .FirstOrDefault(p => p != null); return(GetAssigmentMethodName(parameter)); }
private StatementSyntax GetNewTaskVariable() { var varType = "var".ToIdentifierName(); var taskLambda = _expr.F(ParenthesizedLambdaExpression); if (_expr.DescendantNodes <AwaitExpressionSyntax>().Any()) { taskLambda = taskLambda.WithAsyncKeyword(AsyncKeyword.ToToken()); } var newTaskExpr = "Task".AccessTo("Run").ToInvocation(taskLambda); return(GetTaskVariableName() .ToVariableDeclaration(varType, newTaskExpr) .ToLocalDeclaration()); }
private InvocationExpressionSyntax ReplaceIdentifier(MemberAccessExpressionSyntax mockedObjectIdentifier, ParameterSyntax param, ExpressionSyntax lambdaBody) { try { //var prependInvocation = SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, // mockedObjectIdentifier,SyntaxFactory.IdentifierName(prepandCall))); //var nameToken = lambdaBody.DescendantNodes().First(x => x.Kind() == mockedObjectIdentifier.Kind() && ((IdentifierNameSyntax)x).Identifier.ValueText == mockedObjectIdentifier.Identifier.ValueText); var nameToken = lambdaBody.DescendantNodes().OfType <IdentifierNameSyntax>() .First(x => x.Identifier.ValueText == param.Identifier.ValueText); return(lambdaBody.ReplaceNode(nameToken, mockedObjectIdentifier) as InvocationExpressionSyntax); } catch (Exception e) { throw new Exception(); } }
public SyntaxTemplate(string source) { Syntax = SyntaxFactory.ParseExpression(source); var identifiers = ImmutableDictionary <string, ImmutableList <IdentifierNameSyntax> .Builder> .Empty.ToBuilder(); foreach (var node in Syntax.DescendantNodes().OfType <IdentifierNameSyntax>()) { ImmutableList <IdentifierNameSyntax> .Builder list; if (!identifiers.TryGetValue(node.Identifier.Text, out list)) { list = identifiers[node.Identifier.Text] = ImmutableList <IdentifierNameSyntax> .Empty.ToBuilder(); } list.Add(node); } _identifiers = identifiers.ToImmutableDictionary( p => p.Key, p => p.Value.ToImmutableList()); }
private static bool ContainsInterpolatedString(SeparatedSyntaxList <VariableDeclaratorSyntax> variables) { foreach (VariableDeclaratorSyntax declarator in variables) { ExpressionSyntax value = declarator.Initializer.Value.WalkDownParentheses(); if (value is not LiteralExpressionSyntax) { foreach (SyntaxNode node in value.DescendantNodes()) { if (node.IsKind(SyntaxKind.InterpolatedStringExpression)) { return(true); } } } } return(false); }
private static void AnalyzeNamedType(SymbolAnalysisContext context) { var typeSymbol = (INamedTypeSymbol)context.Symbol; if (typeSymbol.IsImplicitlyDeclared) { return; } if (typeSymbol.TypeKind != TypeKind.Enum) { return; } bool hasFlagsAttribute = typeSymbol.HasAttribute(MetadataNames.System_FlagsAttribute); ImmutableArray <ISymbol> members = default; if (hasFlagsAttribute && DiagnosticRules.DeclareEnumMemberWithZeroValue.IsEffective(context)) { members = typeSymbol.GetMembers(); if (!ContainsFieldWithZeroValue(members)) { var enumDeclaration = (EnumDeclarationSyntax)typeSymbol.GetSyntax(context.CancellationToken); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.DeclareEnumMemberWithZeroValue, enumDeclaration.Identifier); } } EnumSymbolInfo enumInfo = default; if (hasFlagsAttribute && DiagnosticRules.CompositeEnumValueContainsUndefinedFlag.IsEffective(context)) { enumInfo = EnumSymbolInfo.Create(typeSymbol); foreach (EnumFieldSymbolInfo field in enumInfo.Fields) { if (field.HasValue && ConvertHelpers.CanConvertFromUInt64(field.Value, typeSymbol.EnumUnderlyingType.SpecialType) && !IsMaxValue(field.Value, typeSymbol.EnumUnderlyingType.SpecialType) && field.HasCompositeValue()) { foreach (ulong value in (field.GetFlags())) { if (!enumInfo.Contains(value)) { ReportUndefinedFlag(context, field.Symbol, value.ToString()); } } } } } if (hasFlagsAttribute && DiagnosticRules.DeclareEnumValueAsCombinationOfNames.IsEffective(context)) { if (members.IsDefault) { members = typeSymbol.GetMembers(); } foreach (ISymbol member in members) { if (!(member is IFieldSymbol fieldSymbol)) { continue; } if (!fieldSymbol.HasConstantValue) { break; } EnumFieldSymbolInfo fieldInfo = EnumFieldSymbolInfo.Create(fieldSymbol); if (!fieldInfo.HasCompositeValue()) { continue; } var declaration = (EnumMemberDeclarationSyntax)fieldInfo.Symbol.GetSyntax(context.CancellationToken); ExpressionSyntax expression = declaration.EqualsValue?.Value.WalkDownParentheses(); if (expression != null && (expression.IsKind(SyntaxKind.NumericLiteralExpression) || expression .DescendantNodes() .Any(f => f.IsKind(SyntaxKind.NumericLiteralExpression)))) { if (enumInfo.IsDefault) { enumInfo = EnumSymbolInfo.Create(typeSymbol); if (enumInfo.Fields.Any(f => !f.HasValue)) { break; } } List <EnumFieldSymbolInfo> values = enumInfo.Decompose(fieldInfo); if (values?.Count > 1) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.DeclareEnumValueAsCombinationOfNames, expression); } } } } if (hasFlagsAttribute && DiagnosticRules.UseBitShiftOperator.IsEffective(context)) { if (members.IsDefault) { members = typeSymbol.GetMembers(); } foreach (ISymbol member in members) { if (!(member is IFieldSymbol fieldSymbol)) { continue; } if (!fieldSymbol.HasConstantValue) { continue; } EnumFieldSymbolInfo fieldInfo = EnumFieldSymbolInfo.Create(fieldSymbol); if (fieldInfo.Value <= 1) { continue; } if (fieldInfo.HasCompositeValue()) { continue; } var declaration = (EnumMemberDeclarationSyntax)fieldInfo.Symbol.GetSyntax(context.CancellationToken); ExpressionSyntax expression = declaration.EqualsValue?.Value.WalkDownParentheses(); if (expression.IsKind(SyntaxKind.NumericLiteralExpression)) { var enumDeclaration = (EnumDeclarationSyntax)typeSymbol.GetSyntax(context.CancellationToken); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseBitShiftOperator, enumDeclaration.Identifier); break; } } } if (DiagnosticRules.DuplicateEnumValue.IsEffective(context)) { if (enumInfo.IsDefault) { enumInfo = EnumSymbolInfo.Create(typeSymbol); } ImmutableArray <EnumFieldSymbolInfo> fields = enumInfo.Fields; if (fields.Length > 1) { EnumFieldSymbolInfo symbolInfo1 = fields[0]; EnumFieldSymbolInfo symbolInfo2 = default; for (int i = 1; i < fields.Length; i++, symbolInfo1 = symbolInfo2) { symbolInfo2 = fields[i]; if (!symbolInfo1.HasValue || !symbolInfo2.HasValue || symbolInfo1.Value != symbolInfo2.Value) { continue; } var enumMember1 = (EnumMemberDeclarationSyntax)symbolInfo1.Symbol.GetSyntax(context.CancellationToken); if (enumMember1 == null) { continue; } var enumMember2 = (EnumMemberDeclarationSyntax)symbolInfo2.Symbol.GetSyntax(context.CancellationToken); if (enumMember2 == null) { continue; } ExpressionSyntax value1 = enumMember1.EqualsValue?.Value?.WalkDownParentheses(); ExpressionSyntax value2 = enumMember2.EqualsValue?.Value?.WalkDownParentheses(); if (value1 == null) { if (value2 != null) { ReportDuplicateValue(context, enumMember1, value2); } } else if (value2 == null) { ReportDuplicateValue(context, enumMember2, value1); } else { SyntaxKind kind1 = value1.Kind(); SyntaxKind kind2 = value2.Kind(); if (kind1 == SyntaxKind.NumericLiteralExpression) { if (kind2 == SyntaxKind.NumericLiteralExpression) { var enumDeclaration = (EnumDeclarationSyntax)enumMember1.Parent; SeparatedSyntaxList <EnumMemberDeclarationSyntax> enumMembers = enumDeclaration.Members; if (enumMembers.IndexOf(enumMember1) < enumMembers.IndexOf(enumMember2)) { ReportDuplicateValue(context, value2); } else { ReportDuplicateValue(context, value1); } } else if (!string.Equals((value2 as IdentifierNameSyntax)?.Identifier.ValueText, enumMember1.Identifier.ValueText, StringComparison.Ordinal)) { ReportDuplicateValue(context, value1); } } else if (kind2 == SyntaxKind.NumericLiteralExpression && !string.Equals((value1 as IdentifierNameSyntax)?.Identifier.ValueText, enumMember2.Identifier.ValueText, StringComparison.Ordinal)) { ReportDuplicateValue(context, value2); } } } } } }
/// <summary> /// Determines whether an expression has an initializer syntax. /// </summary> /// <param name="syntax">The syntax.</param> /// <returns> /// <see langword="true"/> if the specified expression has an initializer; otherwise, <see langword="false"/>. /// </returns> public static bool HasInitializer(this ExpressionSyntax syntax) { var i = syntax?.DescendantNodes().OfType <InitializerExpressionSyntax>().FirstOrDefault(); return(i != null); }
// does the expression contain declaration? public static bool ContainsDeclarations(this ExpressionSyntax node) { return(node.DescendantNodes().Any(x => x.IsKind(SyntaxKind.DeclarationExpression) || x.IsKind(SyntaxKind.DeclarationPattern))); }
private static bool IsNullableTypeInPointerExpression(ExpressionSyntax expression, ExpressionSyntax simplifiedNode) { // Note: nullable type syntax is not allowed in pointer type syntax if (simplifiedNode.Kind() == SyntaxKind.NullableType && simplifiedNode.DescendantNodes().Any(n => n is PointerTypeSyntax)) { return true; } return false; }
private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext context) { var parenthesizedExpression = (ParenthesizedExpressionSyntax)context.Node; ExpressionSyntax expression = parenthesizedExpression.Expression; if (expression?.IsMissing != false) { return; } SyntaxToken openParen = parenthesizedExpression.OpenParenToken; if (openParen.IsMissing) { return; } SyntaxToken closeParen = parenthesizedExpression.CloseParenToken; if (closeParen.IsMissing) { return; } SyntaxNode parent = parenthesizedExpression.Parent; SyntaxKind parentKind = parent.Kind(); switch (parentKind) { case SyntaxKind.ParenthesizedExpression: case SyntaxKind.ArrowExpressionClause: case SyntaxKind.AttributeArgument: case SyntaxKind.Argument: case SyntaxKind.ExpressionStatement: case SyntaxKind.ReturnStatement: case SyntaxKind.YieldReturnStatement: case SyntaxKind.WhileStatement: case SyntaxKind.DoStatement: case SyntaxKind.UsingStatement: case SyntaxKind.LockStatement: case SyntaxKind.IfStatement: case SyntaxKind.SwitchStatement: case SyntaxKind.ArrayRankSpecifier: { ReportDiagnostic(); break; } case SyntaxKind.LessThanExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: { if (expression.IsKind(SyntaxKind.IdentifierName) || expression is LiteralExpressionSyntax) { ReportDiagnostic(); } break; } case SyntaxKind.MultiplyExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: { SyntaxKind kind = expression.Kind(); if (kind == SyntaxKind.IdentifierName || expression is LiteralExpressionSyntax) { ReportDiagnostic(); } else if (kind == parentKind && ((BinaryExpressionSyntax)parent).Left == parenthesizedExpression) { ReportDiagnostic(); } break; } case SyntaxKind.LogicalNotExpression: { switch (expression.Kind()) { case SyntaxKind.IdentifierName: case SyntaxKind.GenericName: case SyntaxKind.InvocationExpression: case SyntaxKind.SimpleMemberAccessExpression: case SyntaxKind.ElementAccessExpression: case SyntaxKind.ConditionalAccessExpression: { ReportDiagnostic(); break; } } break; } case SyntaxKind.SimpleAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.AndAssignmentExpression: case SyntaxKind.ExclusiveOrAssignmentExpression: case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: { if (((AssignmentExpressionSyntax)parent).Left == parenthesizedExpression) { ReportDiagnostic(); } else if (expression.IsKind(SyntaxKind.IdentifierName) || expression is LiteralExpressionSyntax) { ReportDiagnostic(); } break; } case SyntaxKind.Interpolation: { if (!expression.IsKind(SyntaxKind.ConditionalExpression) && !expression.DescendantNodes().Any(f => f.IsKind(SyntaxKind.AliasQualifiedName)) && ((InterpolationSyntax)parent).Expression == parenthesizedExpression) { ReportDiagnostic(); } break; } case SyntaxKind.AwaitExpression: { if (parenthesizedExpression.Expression.IsKind(SyntaxKind.SwitchExpression)) { return; } if (CSharpFacts.GetOperatorPrecedence(expression.Kind()) <= CSharpFacts.GetOperatorPrecedence(SyntaxKind.AwaitExpression)) { ReportDiagnostic(); } break; } case SyntaxKind.ArrayInitializerExpression: case SyntaxKind.CollectionInitializerExpression: { if (!(expression is AssignmentExpressionSyntax)) { ReportDiagnostic(); } break; } } void ReportDiagnostic() { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.RemoveRedundantParentheses, openParen.GetLocation(), additionalLocations: ImmutableArray.Create(closeParen.GetLocation())); DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantParenthesesFadeOut, openParen); DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantParenthesesFadeOut, closeParen); } }