in src/Features/CSharp/Portable/EditAndContinue/StatementSyntaxComparer.cs [255:494]
internal static Label Classify(SyntaxKind kind, SyntaxNode nodeOpt, out bool isLeaf)
{
// Notes:
// A descendant of a leaf node may be a labeled node that we don't want to visit if
// we are comparing its parent node (used for lambda bodies).
//
// Expressions are ignored but they may contain nodes that should be matched by tree comparer.
// (e.g. lambdas, declaration expressions). Descending to these nodes is handled in EnumerateChildren.
isLeaf = false;
// If the node is a for loop Initializer, Condition, or Incrementor expression we label it as "ForStatementPart".
// We need to capture it in the match since these expressions can be "active statements" and as such we need to map them.
//
// The parent is not available only when comparing nodes for value equality.
if (nodeOpt != null && nodeOpt.Parent.IsKind(SyntaxKind.ForStatement) && nodeOpt is ExpressionSyntax)
{
return Label.ForStatementPart;
}
switch (kind)
{
case SyntaxKind.ConstructorDeclaration:
// Root when matching constructor bodies.
return Label.ConstructorDeclaration;
case SyntaxKind.Block:
return Label.Block;
case SyntaxKind.LocalDeclarationStatement:
return Label.LocalDeclarationStatement;
case SyntaxKind.VariableDeclaration:
return Label.LocalVariableDeclaration;
case SyntaxKind.VariableDeclarator:
return Label.LocalVariableDeclarator;
case SyntaxKind.SingleVariableDesignation:
return Label.SingleVariableDesignation;
case SyntaxKind.LabeledStatement:
return Label.LabeledStatement;
case SyntaxKind.EmptyStatement:
isLeaf = true;
return Label.Ignored;
case SyntaxKind.GotoStatement:
isLeaf = true;
return Label.GotoStatement;
case SyntaxKind.GotoCaseStatement:
case SyntaxKind.GotoDefaultStatement:
isLeaf = true;
return Label.GotoCaseStatement;
case SyntaxKind.BreakStatement:
case SyntaxKind.ContinueStatement:
isLeaf = true;
return Label.BreakContinueStatement;
case SyntaxKind.ReturnStatement:
case SyntaxKind.ThrowStatement:
return Label.ReturnThrowStatement;
case SyntaxKind.ExpressionStatement:
return Label.ExpressionStatement;
case SyntaxKind.YieldBreakStatement:
case SyntaxKind.YieldReturnStatement:
return Label.YieldStatement;
case SyntaxKind.DoStatement:
return Label.DoStatement;
case SyntaxKind.WhileStatement:
return Label.WhileStatement;
case SyntaxKind.ForStatement:
return Label.ForStatement;
case SyntaxKind.ForEachVariableStatement:
case SyntaxKind.ForEachStatement:
return Label.ForEachStatement;
case SyntaxKind.UsingStatement:
return Label.UsingStatement;
case SyntaxKind.FixedStatement:
return Label.FixedStatement;
case SyntaxKind.CheckedStatement:
case SyntaxKind.UncheckedStatement:
return Label.CheckedStatement;
case SyntaxKind.UnsafeStatement:
return Label.UnsafeStatement;
case SyntaxKind.LockStatement:
return Label.LockStatement;
case SyntaxKind.IfStatement:
return Label.IfStatement;
case SyntaxKind.ElseClause:
return Label.ElseClause;
case SyntaxKind.SwitchStatement:
return Label.SwitchStatement;
case SyntaxKind.SwitchSection:
return Label.SwitchSection;
case SyntaxKind.CaseSwitchLabel:
case SyntaxKind.DefaultSwitchLabel:
// Switch labels are included in the "value" of the containing switch section.
// We don't need to analyze case expressions.
isLeaf = true;
return Label.Ignored;
case SyntaxKind.WhenClause:
return Label.WhenClause;
case SyntaxKind.CasePatternSwitchLabel:
return Label.CasePatternSwitchLabel;
case SyntaxKind.TryStatement:
return Label.TryStatement;
case SyntaxKind.CatchClause:
return Label.CatchClause;
case SyntaxKind.CatchDeclaration:
// the declarator of the exception variable
return Label.CatchDeclaration;
case SyntaxKind.CatchFilterClause:
return Label.CatchFilterClause;
case SyntaxKind.FinallyClause:
return Label.FinallyClause;
case SyntaxKind.LocalFunctionStatement:
case SyntaxKind.ParenthesizedLambdaExpression:
case SyntaxKind.SimpleLambdaExpression:
case SyntaxKind.AnonymousMethodExpression:
return Label.NestedFunction;
case SyntaxKind.FromClause:
// The first from clause of a query is not a lambda.
// We have to assign it a label different from "FromClauseLambda"
// so that we won't match lambda-from to non-lambda-from.
//
// Since FromClause declares range variables we need to include it in the map,
// so that we are able to map range variable declarations.
// Therefore we assign it a dedicated label.
//
// The parent is not available only when comparing nodes for value equality.
// In that case it doesn't matter what label the node has as long as it has some.
if (nodeOpt == null || nodeOpt.Parent.IsKind(SyntaxKind.QueryExpression))
{
return Label.FromClause;
}
return Label.FromClauseLambda;
case SyntaxKind.QueryBody:
return Label.QueryBody;
case SyntaxKind.QueryContinuation:
return Label.QueryContinuation;
case SyntaxKind.LetClause:
return Label.LetClauseLambda;
case SyntaxKind.WhereClause:
return Label.WhereClauseLambda;
case SyntaxKind.OrderByClause:
return Label.OrderByClause;
case SyntaxKind.AscendingOrdering:
case SyntaxKind.DescendingOrdering:
return Label.OrderingLambda;
case SyntaxKind.SelectClause:
return Label.SelectClauseLambda;
case SyntaxKind.JoinClause:
return Label.JoinClauseLambda;
case SyntaxKind.JoinIntoClause:
return Label.JoinIntoClause;
case SyntaxKind.GroupClause:
return Label.GroupClauseLambda;
case SyntaxKind.IdentifierName:
case SyntaxKind.QualifiedName:
case SyntaxKind.GenericName:
case SyntaxKind.TypeArgumentList:
case SyntaxKind.AliasQualifiedName:
case SyntaxKind.PredefinedType:
case SyntaxKind.ArrayType:
case SyntaxKind.ArrayRankSpecifier:
case SyntaxKind.PointerType:
case SyntaxKind.NullableType:
case SyntaxKind.TupleType:
case SyntaxKind.RefType:
case SyntaxKind.OmittedTypeArgument:
case SyntaxKind.NameColon:
case SyntaxKind.StackAllocArrayCreationExpression:
case SyntaxKind.OmittedArraySizeExpression:
case SyntaxKind.ThisExpression:
case SyntaxKind.BaseExpression:
case SyntaxKind.ArgListExpression:
case SyntaxKind.NumericLiteralExpression:
case SyntaxKind.StringLiteralExpression:
case SyntaxKind.CharacterLiteralExpression:
case SyntaxKind.TrueLiteralExpression:
case SyntaxKind.FalseLiteralExpression:
case SyntaxKind.NullLiteralExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.SizeOfExpression:
case SyntaxKind.DefaultExpression:
case SyntaxKind.ConstantPattern:
case SyntaxKind.DiscardDesignation:
// can't contain a lambda/await/anonymous type:
isLeaf = true;
return Label.Ignored;
case SyntaxKind.AwaitExpression:
return Label.AwaitExpression;
default:
// any other node may contain a lambda:
return Label.Ignored;
}
}