Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
db1f92d5
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
db1f92d5
编写于
12月 21, 2016
作者:
N
Neal Gafter
提交者:
GitHub
12月 21, 2016
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Correct an off-by-one error in the precedence for is-pattern parsing. (#15917)
Fixes #15734
上级
e459e69d
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
416 addition
and
54 deletion
+416
-54
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+4
-1
src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs
...mpilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs
+28
-53
src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs
src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs
+10
-0
src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs
...mpilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs
+374
-0
未找到文件。
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
浏览文件 @
db1f92d5
...
...
@@ -9208,6 +9208,9 @@ private bool IsAwaitExpression()
return
false
;
}
/// <summary>
/// Parse a subexpression of the enclosing operator of the given precedence.
/// </summary>
private
ExpressionSyntax
ParseSubExpression
(
Precedence
precedence
)
{
_recursionDepth
++;
...
...
@@ -9434,7 +9437,7 @@ private ExpressionSyntax ParseThrowExpression()
private
ExpressionSyntax
ParseIsExpression
(
ExpressionSyntax
leftOperand
,
SyntaxToken
opToken
)
{
var
node
=
this
.
ParseTypeOrPattern
();
var
node
=
this
.
ParseTypeOrPattern
ForIsOperator
();
if
(
node
is
PatternSyntax
)
{
var
result
=
_syntaxFactory
.
IsPatternExpression
(
leftOperand
,
opToken
,
(
PatternSyntax
)
node
);
...
...
src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs
浏览文件 @
db1f92d5
...
...
@@ -7,13 +7,15 @@ namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
{
internal
partial
class
LanguageParser
:
SyntaxParser
{
// Priority is the TypeSyntax. It might return TypeSyntax which might be a constant pattern such as enum 'Days.Sunday'
// We handle such cases in the binder of is operator.
// It is used for parsing patterns in the is operators.
private
CSharpSyntaxNode
ParseTypeOrPattern
()
/// <summary>
/// Parses the type, or pattern, right-hand operand of an is expression.
/// Priority is the TypeSyntax. It may return a TypeSyntax which turns out in binding to
/// be a constant pattern such as enum 'Days.Sunday'. We handle such cases in the binder of the is operator.
/// </summary>
private
CSharpSyntaxNode
ParseTypeOrPatternForIsOperator
()
{
var
tk
=
this
.
CurrentToken
.
Kind
;
CSharpSyntaxNode
node
=
null
;
Precedence
precedence
=
GetPrecedence
(
SyntaxKind
.
IsPatternExpression
)
;
switch
(
tk
)
{
...
...
@@ -39,67 +41,40 @@ private CSharpSyntaxNode ParseTypeOrPattern()
{
TypeSyntax
type
=
this
.
ParseType
(
ParseTypeMode
.
AfterIsOrCase
);
tk
=
this
.
CurrentToken
.
ContextualKind
;
if
(!
type
.
IsMissing
)
if
(!
type
.
IsMissing
&&
this
.
IsTrueIdentifier
())
{
if
(
this
.
IsTrueIdentifier
())
{
var
designation
=
ParseSimpleDesignation
();
node
=
_syntaxFactory
.
DeclarationPattern
(
type
,
designation
);
}
var
designation
=
ParseSimpleDesignation
();
return
_syntaxFactory
.
DeclarationPattern
(
type
,
designation
);
}
if
(
node
==
null
)
tk
=
this
.
CurrentToken
.
ContextualKind
;
if
((!
IsExpectedBinaryOperator
(
tk
)
||
GetPrecedence
(
SyntaxFacts
.
GetBinaryExpression
(
tk
))
<=
precedence
)
&&
// member selection is not formally a binary operator but has higher precedence than relational
tk
!=
SyntaxKind
.
DotToken
)
{
Debug
.
Assert
(
Precedence
.
Shift
==
Precedence
.
Relational
+
1
);
if
((
IsExpectedBinaryOperator
(
tk
)
&&
GetPrecedence
(
SyntaxFacts
.
GetBinaryExpression
(
tk
))
>
Precedence
.
Relational
)
||
tk
==
SyntaxKind
.
DotToken
)
// member selection is not formally a binary operator but has higher precedence than relational
{
this
.
Reset
(
ref
resetPoint
);
// We parse a shift-expression ONLY (nothing looser) - i.e. not a relational expression
// So x is y < z should be parsed as (x is y) < z
// But x is y << z should be parsed as x is (y << z)
node
=
_syntaxFactory
.
ConstantPattern
(
this
.
ParseSubExpression
(
Precedence
.
Shift
));
}
// it is a typical "is Type" operator
else
{
// Note that we don't bother checking for primary expressions such as X[e], X(e), X++, and X--
// as those are never semantically valid constant expressions for a pattern
node
=
type
;
}
// it is a typical "is Type" operator.
// Note that we don't bother checking for primary expressions such as X[e], X(e), X++, and X--
// as those are never semantically valid constant expressions for a pattern
return
type
;
}
this
.
Reset
(
ref
resetPoint
);
}
finally
{
this
.
Release
(
ref
resetPoint
);
}
}
else
{
// In places where a pattern is supported, we do not support tuple types
// due to both syntactic and semantic ambiguities between tuple types and positional patterns.
// But it still might be a pattern such as (operand is 3) or (operand is nameof(x))
node
=
_syntaxFactory
.
ConstantPattern
(
this
.
ParseExpressionCore
());
}
return
node
;
}
// This method is used when we always want a pattern as a result.
// For instance, it is used in parsing recursivepattern and propertypattern.
// SubPatterns in these (recursivepattern, propertypattern) must be a type of Pattern.
private
PatternSyntax
ParsePattern
()
{
var
node
=
this
.
ParseExpressionOrPattern
(
whenIsKeyword
:
false
);
if
(
node
is
PatternSyntax
)
{
return
(
PatternSyntax
)
node
;
}
// We parse a shift-expression ONLY (nothing looser) - i.e. not a relational expression
// So x is y < z should be parsed as (x is y) < z
// But x is y << z should be parsed as x is (y << z)
Debug
.
Assert
(
Precedence
.
Shift
==
precedence
+
1
);
Debug
.
Assert
(
node
is
ExpressionSyntax
);
return
_syntaxFactory
.
ConstantPattern
((
ExpressionSyntax
)
node
);
// In places where a pattern is supported, we do not support tuple types
// due to both syntactic and semantic ambiguities between tuple types and positional patterns.
// But it still might be a pattern such as (operand is 3) or (operand is nameof(x))
return
_syntaxFactory
.
ConstantPattern
(
this
.
ParseSubExpressionCore
(
precedence
));
}
//
...
...
src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs
浏览文件 @
db1f92d5
...
...
@@ -56,6 +56,16 @@ internal void UsingStatement(string text, params DiagnosticDescription[] expecte
UsingNode
(
node
);
}
internal
void
UsingExpression
(
string
text
,
params
DiagnosticDescription
[]
expectedErrors
)
{
var
node
=
SyntaxFactory
.
ParseExpression
(
text
);
// we validate the text roundtrips
Assert
.
Equal
(
text
,
node
.
ToFullString
());
var
actualErrors
=
node
.
GetDiagnostics
();
actualErrors
.
Verify
(
expectedErrors
);
UsingNode
(
node
);
}
/// <summary>
/// Parses given string and initializes a depth-first preorder enumerator.
/// </summary>
...
...
src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs
浏览文件 @
db1f92d5
...
...
@@ -532,5 +532,379 @@ public void TypeDisambiguation_03()
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence00
()
{
UsingExpression
(
"A is B << C"
);
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
LeftShiftExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
N
(
SyntaxKind
.
LessThanLessThanToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"C"
);
}
}
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence01
()
{
UsingExpression
(
"A is 1 << 2"
);
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
LeftShiftExpression
);
{
N
(
SyntaxKind
.
NumericLiteralExpression
);
{
N
(
SyntaxKind
.
NumericLiteralToken
,
"1"
);
}
N
(
SyntaxKind
.
LessThanLessThanToken
);
N
(
SyntaxKind
.
NumericLiteralExpression
);
{
N
(
SyntaxKind
.
NumericLiteralToken
,
"2"
);
}
}
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence02
()
{
UsingExpression
(
"A is null < B"
);
N
(
SyntaxKind
.
LessThanExpression
);
{
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
}
}
N
(
SyntaxKind
.
LessThanToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence02b
()
{
UsingExpression
(
"A is B < C"
);
N
(
SyntaxKind
.
LessThanExpression
);
{
N
(
SyntaxKind
.
IsExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
N
(
SyntaxKind
.
LessThanToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"C"
);
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence03
()
{
UsingExpression
(
"A is null == B"
);
N
(
SyntaxKind
.
EqualsExpression
);
{
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
}
}
N
(
SyntaxKind
.
EqualsEqualsToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence04
()
{
UsingExpression
(
"A is null & B"
);
N
(
SyntaxKind
.
BitwiseAndExpression
);
{
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
}
}
N
(
SyntaxKind
.
AmpersandToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence05
()
{
UsingExpression
(
"A is null && B"
);
N
(
SyntaxKind
.
LogicalAndExpression
);
{
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
}
}
N
(
SyntaxKind
.
AmpersandAmpersandToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence05b
()
{
UsingExpression
(
"A is null || B"
);
N
(
SyntaxKind
.
LogicalOrExpression
);
{
N
(
SyntaxKind
.
IsPatternExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"A"
);
}
N
(
SyntaxKind
.
IsKeyword
);
N
(
SyntaxKind
.
ConstantPattern
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
}
}
N
(
SyntaxKind
.
BarBarToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
EOF
();
}
[
Fact
,
WorkItem
(
15734
,
"https://github.com/dotnet/roslyn/issues/15734"
)]
public
void
PatternExpressionPrecedence06
()
{
UsingStatement
(
@"switch (e) {
case 1 << 2:
case B << C:
case null < B:
case null == B:
case null & B:
case null && B:
break;
}"
);
N
(
SyntaxKind
.
SwitchStatement
);
{
N
(
SyntaxKind
.
SwitchKeyword
);
N
(
SyntaxKind
.
OpenParenToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"e"
);
}
N
(
SyntaxKind
.
CloseParenToken
);
N
(
SyntaxKind
.
OpenBraceToken
);
N
(
SyntaxKind
.
SwitchSection
);
{
N
(
SyntaxKind
.
CaseSwitchLabel
);
{
N
(
SyntaxKind
.
CaseKeyword
);
N
(
SyntaxKind
.
LeftShiftExpression
);
{
N
(
SyntaxKind
.
NumericLiteralExpression
);
{
N
(
SyntaxKind
.
NumericLiteralToken
,
"1"
);
}
N
(
SyntaxKind
.
LessThanLessThanToken
);
N
(
SyntaxKind
.
NumericLiteralExpression
);
{
N
(
SyntaxKind
.
NumericLiteralToken
,
"2"
);
}
}
N
(
SyntaxKind
.
ColonToken
);
}
N
(
SyntaxKind
.
CaseSwitchLabel
);
{
N
(
SyntaxKind
.
CaseKeyword
);
N
(
SyntaxKind
.
LeftShiftExpression
);
{
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
N
(
SyntaxKind
.
LessThanLessThanToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"C"
);
}
}
N
(
SyntaxKind
.
ColonToken
);
}
N
(
SyntaxKind
.
CaseSwitchLabel
);
{
N
(
SyntaxKind
.
CaseKeyword
);
N
(
SyntaxKind
.
LessThanExpression
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
N
(
SyntaxKind
.
LessThanToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
N
(
SyntaxKind
.
ColonToken
);
}
N
(
SyntaxKind
.
CaseSwitchLabel
);
{
N
(
SyntaxKind
.
CaseKeyword
);
N
(
SyntaxKind
.
EqualsExpression
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
N
(
SyntaxKind
.
EqualsEqualsToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
N
(
SyntaxKind
.
ColonToken
);
}
N
(
SyntaxKind
.
CaseSwitchLabel
);
{
N
(
SyntaxKind
.
CaseKeyword
);
N
(
SyntaxKind
.
BitwiseAndExpression
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
N
(
SyntaxKind
.
AmpersandToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
N
(
SyntaxKind
.
ColonToken
);
}
N
(
SyntaxKind
.
CaseSwitchLabel
);
{
N
(
SyntaxKind
.
CaseKeyword
);
N
(
SyntaxKind
.
LogicalAndExpression
);
{
N
(
SyntaxKind
.
NullLiteralExpression
);
{
N
(
SyntaxKind
.
NullKeyword
);
}
N
(
SyntaxKind
.
AmpersandAmpersandToken
);
N
(
SyntaxKind
.
IdentifierName
);
{
N
(
SyntaxKind
.
IdentifierToken
,
"B"
);
}
}
N
(
SyntaxKind
.
ColonToken
);
}
N
(
SyntaxKind
.
BreakStatement
);
{
N
(
SyntaxKind
.
BreakKeyword
);
N
(
SyntaxKind
.
SemicolonToken
);
}
}
N
(
SyntaxKind
.
CloseBraceToken
);
}
EOF
();
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录