Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
e4019b2a
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,发现更多精彩内容 >>
未验证
提交
e4019b2a
编写于
7月 01, 2019
作者:
R
Rikki Gibson
提交者:
GitHub
7月 01, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Learn from calls to Equals methods in NullableWalker (#36722)
上级
54142de3
变更
9
展开全部
隐藏空白更改
内联
并排
Showing
9 changed file
with
1105 addition
and
8 deletion
+1105
-8
docs/features/nullable-reference-types.md
docs/features/nullable-reference-types.md
+6
-0
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+103
-4
src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
+1
-1
src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
...rp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
+969
-2
src/Compilers/Core/Portable/SpecialMember.cs
src/Compilers/Core/Portable/SpecialMember.cs
+1
-0
src/Compilers/Core/Portable/SpecialMembers.cs
src/Compilers/Core/Portable/SpecialMembers.cs
+10
-0
src/Compilers/Core/Portable/WellKnownMember.cs
src/Compilers/Core/Portable/WellKnownMember.cs
+2
-0
src/Compilers/Core/Portable/WellKnownMembers.cs
src/Compilers/Core/Portable/WellKnownMembers.cs
+10
-0
src/Compilers/Core/Portable/WellKnownTypes.cs
src/Compilers/Core/Portable/WellKnownTypes.cs
+3
-1
未找到文件。
docs/features/nullable-reference-types.md
浏览文件 @
e4019b2a
...
...
@@ -39,6 +39,12 @@ If the analysis determines that a null check always (or never) passes, a hidden
A number of null checks affect the flow state when tested for:
-
comparisons to
`null`
:
`x == null`
and
`x != null`
-
`is`
operator:
`x is null`
,
`x is K`
(where
`K`
is a constant),
`x is string`
,
`x is string s`
-
calls to well-known equality methods, including:
-
`static bool object.Equals(object, object)`
-
`static bool object.ReferenceEquals(object, object)`
-
`bool object.Equals(object)`
and overrides
-
`bool IEquatable<T>(T)`
and implementations
-
`bool IEqualityComparer<T>(T, T)`
and implementations
Invocation of methods annotated with the following attributes will also affect flow analysis:
-
simple pre-conditions:
`[AllowNull]`
and
`[DisallowNull]`
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
浏览文件 @
e4019b2a
...
...
@@ -2168,8 +2168,6 @@ protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary)
if
(
operandComparedToNull
!=
null
)
{
operandComparedToNull
=
SkipReferenceConversions
(
operandComparedToNull
);
// Set all nested conditional slots. For example in a?.b?.c we'll set a, b, and c.
bool
nonNullCase
=
op
!=
BinaryOperatorKind
.
Equal
;
// true represents WhenTrue
splitAndLearnFromNonNullTest
(
operandComparedToNull
,
whenTrue
:
nonNullCase
);
...
...
@@ -2817,8 +2815,11 @@ private void ReinferMethodAndVisitArguments(BoundCall node, TypeWithState receiv
method
=
(
MethodSymbol
)
AsMemberOfType
(
receiverType
.
Type
,
method
);
}
method
=
VisitArguments
(
node
,
node
.
Arguments
,
refKindsOpt
,
method
.
Parameters
,
node
.
ArgsToParamsOpt
,
node
.
Expanded
,
node
.
InvokedAsExtensionMethod
,
method
).
method
;
ImmutableArray
<
VisitArgumentResult
>
results
;
(
method
,
results
)
=
VisitArguments
(
node
,
node
.
Arguments
,
refKindsOpt
,
method
.
Parameters
,
node
.
ArgsToParamsOpt
,
node
.
Expanded
,
node
.
InvokedAsExtensionMethod
,
method
);
LearnFromEqualsMethod
(
method
,
node
,
receiverType
,
results
);
if
(
method
.
MethodKind
==
MethodKind
.
LocalFunction
)
{
...
...
@@ -2829,6 +2830,104 @@ private void ReinferMethodAndVisitArguments(BoundCall node, TypeWithState receiv
SetResult
(
node
,
GetReturnTypeWithState
(
method
),
method
.
ReturnTypeWithAnnotations
);
}
private
void
LearnFromEqualsMethod
(
MethodSymbol
method
,
BoundCall
node
,
TypeWithState
receiverType
,
ImmutableArray
<
VisitArgumentResult
>
results
)
{
// easy out
var
parameterCount
=
method
.
ParameterCount
;
if
((
parameterCount
!=
1
&&
parameterCount
!=
2
)
||
method
.
MethodKind
!=
MethodKind
.
Ordinary
||
method
.
ReturnType
.
SpecialType
!=
SpecialType
.
System_Boolean
||
(
method
.
Name
!=
SpecialMembers
.
GetDescriptor
(
SpecialMember
.
System_Object__Equals
).
Name
&&
method
.
Name
!=
SpecialMembers
.
GetDescriptor
(
SpecialMember
.
System_Object__ReferenceEquals
).
Name
))
{
return
;
}
var
arguments
=
node
.
Arguments
;
var
isStaticEqualsMethod
=
method
.
Equals
(
compilation
.
GetSpecialTypeMember
(
SpecialMember
.
System_Object__EqualsObjectObject
))
||
method
.
Equals
(
compilation
.
GetSpecialTypeMember
(
SpecialMember
.
System_Object__ReferenceEquals
));
if
(
isStaticEqualsMethod
||
isWellKnownEqualityMethodOrImplementation
(
compilation
,
method
,
WellKnownMember
.
System_Collections_Generic_IEqualityComparer_T__Equals
))
{
Debug
.
Assert
(
arguments
.
Length
==
2
);
learnFromEqualsMethodArguments
(
arguments
[
0
],
results
[
0
].
RValueType
,
arguments
[
1
],
results
[
1
].
RValueType
);
return
;
}
var
isObjectEqualsMethodOrOverride
=
method
.
GetLeastOverriddenMethod
(
accessingTypeOpt
:
null
)
.
Equals
(
compilation
.
GetSpecialTypeMember
(
SpecialMember
.
System_Object__Equals
));
if
(
isObjectEqualsMethodOrOverride
||
isWellKnownEqualityMethodOrImplementation
(
compilation
,
method
,
WellKnownMember
.
System_IEquatable_T__Equals
))
{
Debug
.
Assert
(
arguments
.
Length
==
1
);
learnFromEqualsMethodArguments
(
node
.
ReceiverOpt
,
receiverType
,
arguments
[
0
],
results
[
0
].
RValueType
);
return
;
}
static
bool
isWellKnownEqualityMethodOrImplementation
(
CSharpCompilation
compilation
,
MethodSymbol
method
,
WellKnownMember
wellKnownMember
)
{
var
wellKnownMethod
=
compilation
.
GetWellKnownTypeMember
(
wellKnownMember
);
if
(
wellKnownMethod
is
null
)
{
return
false
;
}
var
wellKnownType
=
wellKnownMethod
.
ContainingType
;
var
parameterType
=
method
.
Parameters
[
0
].
TypeWithAnnotations
;
var
constructedType
=
wellKnownType
.
Construct
(
ImmutableArray
.
Create
(
parameterType
));
Symbol
constructedMethod
=
null
;
foreach
(
var
member
in
constructedType
.
GetMembers
(
WellKnownMemberNames
.
ObjectEquals
))
{
if
(
member
.
OriginalDefinition
.
Equals
(
wellKnownMethod
))
{
constructedMethod
=
member
;
break
;
}
}
Debug
.
Assert
(
constructedMethod
!=
null
,
"the original definition is present but the constructed method isn't present"
);
// FindImplementationForInterfaceMember doesn't check if this method is itself the interface method we're looking for
if
(
constructedMethod
.
Equals
(
method
))
{
return
true
;
}
var
implementationMethod
=
method
.
ContainingType
.
FindImplementationForInterfaceMember
(
constructedMethod
);
return
method
.
Equals
(
implementationMethod
);
}
void
learnFromEqualsMethodArguments
(
BoundExpression
left
,
TypeWithState
leftType
,
BoundExpression
right
,
TypeWithState
rightType
)
{
// comparing anything to a null literal gives maybe-null when true and not-null when false
// comparing a maybe-null to a not-null gives us not-null when true, nothing learned when false
if
(
left
.
ConstantValue
?.
IsNull
==
true
)
{
Split
();
LearnFromNullTest
(
right
,
ref
StateWhenTrue
);
LearnFromNonNullTest
(
right
,
ref
StateWhenFalse
);
}
else
if
(
right
.
ConstantValue
?.
IsNull
==
true
)
{
Split
();
LearnFromNullTest
(
left
,
ref
StateWhenTrue
);
LearnFromNonNullTest
(
left
,
ref
StateWhenFalse
);
}
else
if
(
leftType
.
MayBeNull
&&
rightType
.
IsNotNull
)
{
Split
();
LearnFromNonNullTest
(
left
,
ref
StateWhenTrue
);
}
else
if
(
rightType
.
MayBeNull
&&
leftType
.
IsNotNull
)
{
Split
();
LearnFromNonNullTest
(
right
,
ref
StateWhenTrue
);
}
}
}
private
TypeWithState
VisitCallReceiver
(
BoundCall
node
)
{
var
receiverOpt
=
node
.
ReceiverOpt
;
...
...
src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
浏览文件 @
e4019b2a
...
...
@@ -1707,7 +1707,7 @@ private static Location GetInterfaceLocation(Symbol interfaceMember, TypeSymbol
snt
=
implementingType
as
SourceMemberContainerTypeSymbol
;
}
return
snt
?.
GetImplementsLocation
(
@interface
)
??
implementingType
.
Locations
[
0
]
;
return
snt
?.
GetImplementsLocation
(
@interface
)
??
implementingType
.
Locations
.
FirstOrNone
()
;
}
private
static
bool
ReportAnyMismatchedConstraints
(
MethodSymbol
interfaceMethod
,
TypeSymbol
implementingType
,
MethodSymbol
implicitImpl
,
DiagnosticBag
diagnostics
)
...
...
src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
浏览文件 @
e4019b2a
此差异已折叠。
点击以展开。
src/Compilers/Core/Portable/SpecialMember.cs
浏览文件 @
e4019b2a
...
...
@@ -122,6 +122,7 @@ internal enum SpecialMember
System_Object__GetHashCode
,
System_Object__Equals
,
System_Object__EqualsObjectObject
,
System_Object__ToString
,
System_Object__ReferenceEquals
,
...
...
src/Compilers/Core/Portable/SpecialMembers.cs
浏览文件 @
e4019b2a
...
...
@@ -834,6 +834,15 @@ static SpecialMembers()
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Boolean
,
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Object
,
// System_Object__EqualsObjectObject
(
byte
)(
MemberFlags
.
Method
|
MemberFlags
.
Static
),
// Flags
(
byte
)
SpecialType
.
System_Object
,
// DeclaringTypeId
0
,
// Arity
2
,
// Method Signature
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Boolean
,
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Object
,
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Object
,
// System_Object__ToString
(
byte
)(
MemberFlags
.
Method
|
MemberFlags
.
Virtual
),
// Flags
(
byte
)
SpecialType
.
System_Object
,
// DeclaringTypeId
...
...
@@ -1099,6 +1108,7 @@ static SpecialMembers()
"GetUpperBound"
,
// System_Array__GetUpperBound
"GetHashCode"
,
// System_Object__GetHashCode
"Equals"
,
// System_Object__Equals
"Equals"
,
// System_Object__EqualsObjectObject
"ToString"
,
// System_Object__ToString
"ReferenceEquals"
,
// System_Object__ReferenceEquals
"op_Explicit"
,
// System_IntPtr__op_Explicit_ToPointer
...
...
src/Compilers/Core/Portable/WellKnownMember.cs
浏览文件 @
e4019b2a
...
...
@@ -68,6 +68,8 @@ internal enum WellKnownMember
System_IEquatable_T__Equals
,
System_Collections_Generic_IEqualityComparer_T__Equals
,
System_Collections_Generic_EqualityComparer_T__Equals
,
System_Collections_Generic_EqualityComparer_T__GetHashCode
,
System_Collections_Generic_EqualityComparer_T__get_Default
,
...
...
src/Compilers/Core/Portable/WellKnownMembers.cs
浏览文件 @
e4019b2a
...
...
@@ -448,6 +448,15 @@ static WellKnownMembers()
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Boolean
,
// Return Type
(
byte
)
SignatureTypeCode
.
GenericTypeParameter
,
0
,
// System_Collections_Generic_IEqualityComparer_T__Equals
(
byte
)(
MemberFlags
.
Method
|
MemberFlags
.
Virtual
),
// Flags
(
byte
)
WellKnownType
.
ExtSentinel
,
(
byte
)(
WellKnownType
.
System_Collections_Generic_IEqualityComparer_T
-
WellKnownType
.
ExtSentinel
),
// DeclaringTypeId
0
,
// Arity
2
,
// Method Signature
(
byte
)
SignatureTypeCode
.
TypeHandle
,
(
byte
)
SpecialType
.
System_Boolean
,
// Return Type
(
byte
)
SignatureTypeCode
.
GenericTypeParameter
,
0
,
(
byte
)
SignatureTypeCode
.
GenericTypeParameter
,
0
,
// System_Collections_Generic_EqualityComparer_T__Equals
(
byte
)(
MemberFlags
.
Method
|
MemberFlags
.
Virtual
),
// Flags
(
byte
)
WellKnownType
.
System_Collections_Generic_EqualityComparer_T
,
// DeclaringTypeId
...
...
@@ -3494,6 +3503,7 @@ static WellKnownMembers()
"GetFieldFromHandle"
,
// System_Reflection_FieldInfo__GetFieldFromHandle2
"Value"
,
// System_Reflection_Missing__Value
"Equals"
,
// System_IEquatable_T__Equals
"Equals"
,
// System_Collections_Generic_IEqualityComparer_T__Equals
"Equals"
,
// System_Collections_Generic_EqualityComparer_T__Equals
"GetHashCode"
,
// System_Collections_Generic_EqualityComparer_T__GetHashCode
"get_Default"
,
// System_Collections_Generic_EqualityComparer_T__get_Default
...
...
src/Compilers/Core/Portable/WellKnownTypes.cs
浏览文件 @
e4019b2a
...
...
@@ -303,6 +303,7 @@ internal enum WellKnownType
System_InvalidOperationException
,
System_Runtime_CompilerServices_SwitchExpressionException
,
System_Collections_Generic_IEqualityComparer_T
,
NextAvailable
,
...
...
@@ -602,7 +603,8 @@ internal static class WellKnownTypes
"System.Threading.CancellationTokenSource"
,
"System.InvalidOperationException"
,
"System.Runtime.CompilerServices.SwitchExpressionException"
"System.Runtime.CompilerServices.SwitchExpressionException"
,
"System.Collections.Generic.IEqualityComparer`1"
,
};
private
readonly
static
Dictionary
<
string
,
WellKnownType
>
s_nameToTypeIdMap
=
new
Dictionary
<
string
,
WellKnownType
>((
int
)
Count
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录