Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
a82ed0ed
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,发现更多精彩内容 >>
未验证
提交
a82ed0ed
编写于
11月 04, 2017
作者:
C
Charles Stoner
提交者:
GitHub
11月 04, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Separate nullability flow analysis from DataFlowPass (#22932)
Separate nullability flow analysis from DataFlowPass
上级
e25fa14b
变更
10
展开全部
隐藏空白更改
内联
并排
Showing
10 changed file
with
3723 addition
and
2984 deletion
+3723
-2984
src/Compilers/CSharp/Portable/FlowAnalysis/AlwaysAssignedWalker.cs
...lers/CSharp/Portable/FlowAnalysis/AlwaysAssignedWalker.cs
+1
-1
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs
...harp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs
+3
-3
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.VariableIdentifier.cs
.../Portable/FlowAnalysis/DataFlowPass.VariableIdentifier.cs
+1
-1
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
+381
-2943
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs
...ompilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs
+317
-0
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowsOutWalker.cs
...pilers/CSharp/Portable/FlowAnalysis/DataFlowsOutWalker.cs
+2
-2
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.ObjectCreationPlaceholderLocal.cs
...Analysis/NullableWalker.ObjectCreationPlaceholderLocal.cs
+2
-2
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+2898
-0
src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
...Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
+5
-5
src/Compilers/CSharp/Test/Semantic/Semantics/StaticNullChecking.cs
...lers/CSharp/Test/Semantic/Semantics/StaticNullChecking.cs
+113
-27
未找到文件。
src/Compilers/CSharp/Portable/FlowAnalysis/AlwaysAssignedWalker.cs
浏览文件 @
a82ed0ed
...
...
@@ -70,7 +70,7 @@ protected override void WriteArgument(BoundExpression arg, RefKind refKind, Meth
// ref parameter does not "always" assign.
if
(
refKind
==
RefKind
.
Out
)
{
Assign
(
arg
,
value
:
null
,
valueIsNotNull
:
null
);
Assign
(
arg
,
value
:
null
);
}
}
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs
浏览文件 @
a82ed0ed
...
...
@@ -72,8 +72,8 @@ private void ReplayReads(ref BitVector reads, SyntaxNode syntax)
/// </summary>
/// <remarks>
/// Specifying the slot manually may be necessary if the symbol is a field,
/// in which case <see cref="
VariableSlot(Symbol, int)"/> will not know
/// which containing slot to look for.
/// in which case <see cref="
DataFlowPassBase{TLocalState}.VariableSlot(Symbol, int)"/>
/// w
ill not know w
hich containing slot to look for.
/// </remarks>
private
void
CheckIfAssignedDuringLocalFunctionReplay
(
Symbol
symbol
,
SyntaxNode
node
,
int
slot
)
{
...
...
@@ -86,7 +86,7 @@ private void CheckIfAssignedDuringLocalFunctionReplay(Symbol symbol, SyntaxNode
{
if
(
slot
>=
this
.
State
.
Assigned
.
Capacity
)
{
Normalize
Assigned
(
ref
this
.
State
);
Normalize
(
ref
this
.
State
);
}
if
(
slot
>
0
&&
!
this
.
State
.
IsAssigned
(
slot
))
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.VariableIdentifier.cs
浏览文件 @
a82ed0ed
...
...
@@ -6,7 +6,7 @@
namespace
Microsoft.CodeAnalysis.CSharp
{
internal
partial
class
DataFlowPass
internal
partial
class
DataFlowPass
Base
<
TLocalState
>
{
protected
struct
VariableIdentifier
:
IEquatable
<
VariableIdentifier
>
{
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
浏览文件 @
a82ed0ed
此差异已折叠。
点击以展开。
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs
0 → 100644
浏览文件 @
a82ed0ed
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using
System
;
using
System.Diagnostics
;
using
System.Linq
;
using
Microsoft.CodeAnalysis.CSharp.Symbols
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.CSharp
{
internal
abstract
partial
class
DataFlowPassBase
<
TLocalState
>
:
AbstractFlowPass
<
TLocalState
>
where
TLocalState
:
PreciseAbstractFlowPass
<
TLocalState
>.
AbstractLocalState
{
/// <summary>
/// A mapping from local variables to the index of their slot in a flow analysis local state.
/// </summary>
private
readonly
PooledDictionary
<
VariableIdentifier
,
int
>
_variableSlot
=
PooledDictionary
<
VariableIdentifier
,
int
>.
GetInstance
();
/// <summary>
/// A mapping from the local variable slot to the symbol for the local variable itself. This
/// is used in the implementation of region analysis (support for extract method) to compute
/// the set of variables "always assigned" in a region of code.
/// </summary>
protected
VariableIdentifier
[]
variableBySlot
=
new
VariableIdentifier
[
1
];
/// <summary>
/// Variable slots are allocated to local variables sequentially and never reused. This is
/// the index of the next slot number to use.
/// </summary>
protected
int
nextVariableSlot
=
1
;
/// <summary>
/// A cache for remember which structs are empty.
/// </summary>
protected
readonly
EmptyStructTypeCache
_emptyStructTypeCache
;
protected
DataFlowPassBase
(
CSharpCompilation
compilation
,
Symbol
member
,
BoundNode
node
,
EmptyStructTypeCache
emptyStructs
,
bool
trackUnassignments
,
bool
trackClassFields
)
:
base
(
compilation
,
member
,
node
,
trackUnassignments
:
trackUnassignments
,
trackClassFields
:
trackClassFields
)
{
_emptyStructTypeCache
=
emptyStructs
;
}
protected
DataFlowPassBase
(
CSharpCompilation
compilation
,
Symbol
member
,
BoundNode
node
,
EmptyStructTypeCache
emptyStructs
,
BoundNode
firstInRegion
,
BoundNode
lastInRegion
,
bool
trackRegions
,
bool
trackUnassignments
)
:
base
(
compilation
,
member
,
node
,
firstInRegion
,
lastInRegion
,
trackRegions
:
trackRegions
,
trackUnassignments
:
trackUnassignments
)
{
_emptyStructTypeCache
=
emptyStructs
;
}
protected
override
void
Free
()
{
_variableSlot
.
Free
();
base
.
Free
();
}
/// <summary>
/// Locals are given slots when their declarations are encountered. We only need give slots
/// to local variables, out parameters, and the "this" variable of a struct constructs.
/// Other variables are not given slots, and are therefore not tracked by the analysis. This
/// returns -1 for a variable that is not tracked, for fields of structs that have the same
/// assigned status as the container, and for structs that (recursively) contain no data members.
/// We do not need to track references to
/// variables that occur before the variable is declared, as those are reported in an
/// earlier phase as "use before declaration". That allows us to avoid giving slots to local
/// variables before processing their declarations.
/// </summary>
protected
int
VariableSlot
(
Symbol
symbol
,
int
containingSlot
=
0
)
{
containingSlot
=
DescendThroughTupleRestFields
(
ref
symbol
,
containingSlot
,
forceContainingSlotsToExist
:
false
);
int
slot
;
return
(
_variableSlot
.
TryGetValue
(
new
VariableIdentifier
(
symbol
,
containingSlot
),
out
slot
))
?
slot
:
-
1
;
}
/// <summary>
/// Force a variable to have a slot. Returns -1 if the variable has an empty struct type.
/// </summary>
protected
int
GetOrCreateSlot
(
Symbol
symbol
,
int
containingSlot
=
0
)
{
if
(
symbol
is
RangeVariableSymbol
)
return
-
1
;
containingSlot
=
DescendThroughTupleRestFields
(
ref
symbol
,
containingSlot
,
forceContainingSlotsToExist
:
true
);
VariableIdentifier
identifier
=
new
VariableIdentifier
(
symbol
,
containingSlot
);
int
slot
;
// Since analysis may proceed in multiple passes, it is possible the slot is already assigned.
if
(!
_variableSlot
.
TryGetValue
(
identifier
,
out
slot
))
{
var
variableType
=
VariableType
(
symbol
)?.
TypeSymbol
;
if
(
_emptyStructTypeCache
.
IsEmptyStructType
(
variableType
))
{
return
-
1
;
}
slot
=
nextVariableSlot
++;
_variableSlot
.
Add
(
identifier
,
slot
);
if
(
slot
>=
variableBySlot
.
Length
)
{
Array
.
Resize
(
ref
this
.
variableBySlot
,
slot
*
2
);
}
variableBySlot
[
slot
]
=
identifier
;
}
Normalize
(
ref
this
.
State
);
return
slot
;
}
protected
abstract
void
Normalize
(
ref
TLocalState
state
);
/// <summary>
/// Descends through Rest fields of a tuple if "symbol" is an extended field
/// As a result the "symbol" will be adjusted to be the field of the innermost tuple
/// and a corresponding containingSlot is returned.
/// Return value -1 indicates a failure which could happen for the following reasons
/// a) Rest field does not exist, which could happen in rare error scenarios involving broken ValueTuple types
/// b) Rest is not tracked already and forceSlotsToExist is false (otherwise we create slots on demand)
/// </summary>
private
int
DescendThroughTupleRestFields
(
ref
Symbol
symbol
,
int
containingSlot
,
bool
forceContainingSlotsToExist
)
{
var
fieldSymbol
=
symbol
as
TupleFieldSymbol
;
if
((
object
)
fieldSymbol
!=
null
)
{
TypeSymbol
containingType
=
((
TupleTypeSymbol
)
symbol
.
ContainingType
).
UnderlyingNamedType
;
// for tuple fields the variable identifier represents the underlying field
symbol
=
fieldSymbol
.
TupleUnderlyingField
;
// descend through Rest fields
// force corresponding slots if do not exist
while
(
containingType
!=
symbol
.
ContainingType
)
{
var
restField
=
containingType
.
GetMembers
(
TupleTypeSymbol
.
RestFieldName
).
FirstOrDefault
()
as
FieldSymbol
;
if
((
object
)
restField
==
null
)
{
return
-
1
;
}
if
(
forceContainingSlotsToExist
)
{
containingSlot
=
GetOrCreateSlot
(
restField
,
containingSlot
);
}
else
{
if
(!
_variableSlot
.
TryGetValue
(
new
VariableIdentifier
(
restField
,
containingSlot
),
out
containingSlot
))
{
return
-
1
;
}
}
containingType
=
restField
.
Type
.
TypeSymbol
.
TupleUnderlyingTypeOrSelf
();
}
}
return
containingSlot
;
}
protected
virtual
bool
TryGetReceiverAndMember
(
BoundExpression
expr
,
out
BoundExpression
receiver
,
out
Symbol
member
)
{
receiver
=
null
;
member
=
null
;
switch
(
expr
.
Kind
)
{
case
BoundKind
.
FieldAccess
:
{
var
fieldAccess
=
(
BoundFieldAccess
)
expr
;
var
fieldSymbol
=
fieldAccess
.
FieldSymbol
;
if
(
fieldSymbol
.
IsStatic
||
fieldSymbol
.
IsFixed
)
{
return
false
;
}
member
=
fieldSymbol
;
receiver
=
fieldAccess
.
ReceiverOpt
;
break
;
}
case
BoundKind
.
EventAccess
:
{
var
eventAccess
=
(
BoundEventAccess
)
expr
;
var
eventSymbol
=
eventAccess
.
EventSymbol
;
if
(
eventSymbol
.
IsStatic
||
!
eventSymbol
.
HasAssociatedField
)
{
return
false
;
}
member
=
eventSymbol
.
AssociatedField
;
receiver
=
eventAccess
.
ReceiverOpt
;
break
;
}
case
BoundKind
.
PropertyAccess
:
{
var
propAccess
=
(
BoundPropertyAccess
)
expr
;
var
propSymbol
=
propAccess
.
PropertySymbol
;
if
(
propSymbol
.
IsStatic
)
{
return
false
;
}
member
=
(
propSymbol
as
SourcePropertySymbol
)?.
BackingField
;
receiver
=
propAccess
.
ReceiverOpt
;
break
;
}
}
return
(
object
)
member
!=
null
&&
(
object
)
receiver
!=
null
&&
receiver
.
Kind
!=
BoundKind
.
TypeExpression
&&
MayRequireTrackingReceiverType
(
receiver
.
Type
);
}
/// <summary>
/// Return the slot for a variable, or -1 if it is not tracked (because, for example, it is an empty struct).
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected
virtual
int
MakeSlot
(
BoundExpression
node
)
{
switch
(
node
.
Kind
)
{
case
BoundKind
.
ThisReference
:
return
(
object
)
MethodThisParameter
!=
null
?
GetOrCreateSlot
(
MethodThisParameter
)
:
-
1
;
case
BoundKind
.
BaseReference
:
return
GetOrCreateSlot
(
MethodThisParameter
);
case
BoundKind
.
Local
:
return
GetOrCreateSlot
(((
BoundLocal
)
node
).
LocalSymbol
);
case
BoundKind
.
Parameter
:
return
GetOrCreateSlot
(((
BoundParameter
)
node
).
ParameterSymbol
);
case
BoundKind
.
RangeVariable
:
return
MakeSlot
(((
BoundRangeVariable
)
node
).
Value
);
case
BoundKind
.
FieldAccess
:
case
BoundKind
.
EventAccess
:
case
BoundKind
.
PropertyAccess
:
if
(
TryGetReceiverAndMember
(
node
,
out
BoundExpression
receiver
,
out
Symbol
member
))
{
int
containingSlot
=
MakeSlot
(
receiver
);
return
(
containingSlot
==
-
1
)
?
-
1
:
GetOrCreateSlot
(
member
,
containingSlot
);
}
break
;
case
BoundKind
.
AssignmentOperator
:
return
MakeSlot
(((
BoundAssignmentOperator
)
node
).
Left
);
}
return
-
1
;
}
protected
void
VisitStatementsWithLocalFunctions
(
BoundBlock
block
)
{
// Visit the statements in two phases:
// 1. Local function declarations
// 2. Everything else
//
// The idea behind visiting local functions first is
// that we may be able to gather the captured variables
// they read and write ahead of time in a single pass, so
// when they are used by other statements in the block we
// won't have to recompute the set by doing multiple passes.
//
// If the local functions contain forward calls to other local
// functions then we may have to do another pass regardless,
// but hopefully that will be an uncommon case in real-world code.
// First phase
if
(!
block
.
LocalFunctions
.
IsDefaultOrEmpty
)
{
foreach
(
var
stmt
in
block
.
Statements
)
{
if
(
stmt
.
Kind
==
BoundKind
.
LocalFunctionStatement
)
{
VisitAlways
(
stmt
);
}
}
}
// Second phase
foreach
(
var
stmt
in
block
.
Statements
)
{
if
(
stmt
.
Kind
!=
BoundKind
.
LocalFunctionStatement
)
{
VisitStatement
(
stmt
);
}
}
}
protected
static
TypeSymbolWithAnnotations
VariableType
(
Symbol
s
)
{
switch
(
s
.
Kind
)
{
case
SymbolKind
.
Local
:
return
((
LocalSymbol
)
s
).
Type
;
case
SymbolKind
.
Field
:
return
((
FieldSymbol
)
s
).
Type
;
case
SymbolKind
.
Parameter
:
return
((
ParameterSymbol
)
s
).
Type
;
case
SymbolKind
.
Method
:
Debug
.
Assert
(((
MethodSymbol
)
s
).
MethodKind
==
MethodKind
.
LocalFunction
);
return
null
;
case
SymbolKind
.
Property
:
Debug
.
Assert
(
s
.
ContainingType
.
IsAnonymousType
);
return
((
PropertySymbol
)
s
).
Type
;
default
:
throw
ExceptionUtilities
.
UnexpectedValue
(
s
.
Kind
);
}
}
}
}
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowsOutWalker.cs
浏览文件 @
a82ed0ed
...
...
@@ -183,7 +183,7 @@ private Symbol GetNodeSymbol(BoundNode node)
}
#endif
protected
override
void
AssignImpl
(
BoundNode
node
,
BoundExpression
value
,
bool
?
valueIsNotNull
,
RefKind
refKind
,
bool
written
,
bool
read
)
protected
override
void
AssignImpl
(
BoundNode
node
,
BoundExpression
value
,
RefKind
refKind
,
bool
written
,
bool
read
)
{
if
(
IsInside
)
{
...
...
@@ -209,7 +209,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, bool?
}
}
base
.
AssignImpl
(
node
,
value
,
valueIsNotNull
,
refKind
,
written
,
read
);
base
.
AssignImpl
(
node
,
value
,
refKind
,
written
,
read
);
}
private
bool
FlowsOut
(
ParameterSymbol
param
)
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/
DataFlowPass
.ObjectCreationPlaceholderLocal.cs
→
src/Compilers/CSharp/Portable/FlowAnalysis/
NullableWalker
.ObjectCreationPlaceholderLocal.cs
浏览文件 @
a82ed0ed
...
...
@@ -8,7 +8,7 @@
namespace
Microsoft.CodeAnalysis.CSharp
{
internal
partial
class
DataFlowPass
internal
partial
class
NullableWalker
{
/// <summary>
/// A symbol to represent a placeholder for an instance being constructed by
...
...
@@ -162,4 +162,4 @@ internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocal
}
}
}
}
\ No newline at end of file
}
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
0 → 100644
浏览文件 @
a82ed0ed
此差异已折叠。
点击以展开。
src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
浏览文件 @
a82ed0ed
...
...
@@ -172,7 +172,7 @@ private void NoteReceiverReadOrWritten(BoundFieldAccess expr, HashSet<Symbol> re
}
}
protected
override
void
AssignImpl
(
BoundNode
node
,
BoundExpression
value
,
bool
?
valueIsNotNull
,
RefKind
refKind
,
bool
written
,
bool
read
)
protected
override
void
AssignImpl
(
BoundNode
node
,
BoundExpression
value
,
RefKind
refKind
,
bool
written
,
bool
read
)
{
switch
(
node
.
Kind
)
{
...
...
@@ -182,7 +182,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, bool?
case
BoundKind
.
QueryClause
:
{
base
.
AssignImpl
(
node
,
value
,
valueIsNotNull
,
refKind
,
written
,
read
);
base
.
AssignImpl
(
node
,
value
,
refKind
,
written
,
read
);
var
symbol
=
((
BoundQueryClause
)
node
).
DefinedSymbol
;
if
((
object
)
symbol
!=
null
)
{
...
...
@@ -193,7 +193,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, bool?
case
BoundKind
.
FieldAccess
:
{
base
.
AssignImpl
(
node
,
value
,
valueIsNotNull
,
refKind
,
written
,
read
);
base
.
AssignImpl
(
node
,
value
,
refKind
,
written
,
read
);
var
fieldAccess
=
node
as
BoundFieldAccess
;
if
(!
IsInside
&&
node
.
Syntax
!=
null
&&
node
.
Syntax
.
Span
.
Contains
(
RegionSpan
))
{
...
...
@@ -203,7 +203,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, bool?
break
;
default
:
base
.
AssignImpl
(
node
,
value
,
valueIsNotNull
,
refKind
,
written
,
read
);
base
.
AssignImpl
(
node
,
value
,
refKind
,
written
,
read
);
break
;
}
}
...
...
@@ -246,7 +246,7 @@ private static ParameterSymbol GetRangeVariableUnderlyingParameter(BoundNode und
public
override
BoundNode
VisitQueryClause
(
BoundQueryClause
node
)
{
Assign
(
node
,
value
:
null
,
valueIsNotNull
:
null
);
Assign
(
node
,
value
:
null
);
return
base
.
VisitQueryClause
(
node
);
}
}
...
...
src/Compilers/CSharp/Test/Semantic/Semantics/StaticNullChecking.cs
浏览文件 @
a82ed0ed
...
...
@@ -3251,12 +3251,12 @@ struct S2
// (150,15): warning CS8601: Possible null reference assignment.
// u16 = y16.F4;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y16.F4").WithLocation(150, 15),
// (159,15): warning CS8601: Possible null reference assignment.
// u17 = y17.F4;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y17.F4").WithLocation(159, 15),
// (161,15): error CS0165: Use of unassigned local variable 'x17'
// y17 = x17;
Diagnostic(ErrorCode.ERR_UseDefViolation, "x17").WithArguments("x17").WithLocation(161, 15),
// (159,15): warning CS8601: Possible null reference assignment.
// u17 = y17.F4;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y17.F4").WithLocation(159, 15),
// (170,18): error CS0165: Use of unassigned local variable 'x18'
// S1 y18 = x18;
Diagnostic(ErrorCode.ERR_UseDefViolation, "x18").WithArguments("x18").WithLocation(170, 18),
...
...
@@ -6433,30 +6433,30 @@ struct S1
", parseOptions: TestOptions.Regular8);
c.VerifyDiagnostics(
// (11,17): error CS0165: Use of unassigned local variable 'y1'
// S1 z1 = y1;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y1").WithArguments("y1").WithLocation(11, 17),
// (34,19): error CS0170: Use of possibly unassigned field 'F3
'
// CL1? z3 = y3.F3
;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y3.F3").WithArguments("F3").WithLocation(34, 19
),
// (42,14
): error CS0170: Use of possibly unassigned field 'F3'
// z4 = y4
.F3;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y4.F3").WithArguments("F3").WithLocation(42, 14
),
// (25,18): error CS0165: Use of unassigned local variable 'y2
'
// z2 = y2
;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y2").WithArguments("y2").WithLocation(25, 18
),
// (50,29): error CS0170: Use of possibly unassigned field 'F3'
// var z5 = new { F3 = y5.F3 };
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y5.F3").WithArguments("F3").WithLocation(50, 29),
// (59,14): error CS0165: Use of unassigned local variable 'y6'
// z6 = y6;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y6").WithArguments("y6").WithLocation(59, 14),
// (68,29): error CS0165: Use of unassigned local variable 'y7'
// var z7 = new { F3 = y7 };
Diagnostic(ErrorCode.ERR_UseDefViolation, "y7").WithArguments("y7").WithLocation(68, 29),
// (81,18): error CS0170: Use of possibly unassigned field 'F3'
// z8 = y8.F3;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y8.F3").WithArguments("F3").WithLocation(81, 18)
// (11,17): error CS0165: Use of unassigned local variable 'y1'
// S1 z1 = y1;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y1").WithArguments("y1").WithLocation(11, 17),
// (25,18): error CS0165: Use of unassigned local variable 'y2
'
// z2 = y2
;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y2").WithArguments("y2").WithLocation(25, 18
),
// (34,19
): error CS0170: Use of possibly unassigned field 'F3'
// CL1? z3 = y3
.F3;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y3.F3").WithArguments("F3").WithLocation(34, 19
),
// (42,14): error CS0170: Use of possibly unassigned field 'F3
'
// z4 = y4.F3
;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y4.F3").WithArguments("F3").WithLocation(42, 14
),
// (50,29): error CS0170: Use of possibly unassigned field 'F3'
// var z5 = new { F3 = y5.F3 };
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y5.F3").WithArguments("F3").WithLocation(50, 29),
// (59,14): error CS0165: Use of unassigned local variable 'y6'
// z6 = y6;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y6").WithArguments("y6").WithLocation(59, 14),
// (68,29): error CS0165: Use of unassigned local variable 'y7'
// var z7 = new { F3 = y7 };
Diagnostic(ErrorCode.ERR_UseDefViolation, "y7").WithArguments("y7").WithLocation(68, 29),
// (81,18): error CS0170: Use of possibly unassigned field 'F3'
// z8 = y8.F3;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "y8.F3").WithArguments("F3").WithLocation(81, 18)
);
}
...
...
@@ -16827,5 +16827,91 @@ class A : System.Attribute
// string P => null;
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 17));
}
[Fact]
public void UnassignedParameterField()
{
var source =
@"class C
{
static void F(out S s)
{
C c;
c = s.F;
s.F.ToString();
}
}
struct S
{
internal C? F;
}";
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (6,13): error CS0170: Use of possibly unassigned field 'F'
// c = s.F;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "s.F").WithArguments("F").WithLocation(6, 13),
// (3,17): error CS0177: The out parameter 's' must be assigned to before control leaves the current method
// static void F(out S s)
Diagnostic(ErrorCode.ERR_ParamUnassigned, "F").WithArguments("s").WithLocation(3, 17),
// (12,17): warning CS0649: Field 'S.F' is never assigned to, and will always have its default value null
// internal C? F;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("S.F", "null").WithLocation(12, 17));
}
[Fact]
public void UnassignedLocalField()
{
var source =
@"class C
{
static void F()
{
S s;
C c;
c = s.F;
s.F.ToString();
}
}
struct S
{
internal C? F;
}";
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (7,13): error CS0170: Use of possibly unassigned field 'F'
// c = s.F;
Diagnostic(ErrorCode.ERR_UseDefViolationField, "s.F").WithArguments("F").WithLocation(7, 13),
// (13,17): warning CS0649: Field 'S.F' is never assigned to, and will always have its default value null
// internal C? F;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("S.F", "null").WithLocation(13, 17));
}
[Fact]
public void UnassignedLocalProperty()
{
var source =
@"class C
{
static void F()
{
S s;
C c;
c = s.P;
s.P.ToString();
}
}
struct S
{
internal C? P { get => null; }
}";
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (7,13): warning CS8601: Possible null reference assignment.
// c = s.P;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "s.P").WithLocation(7, 13),
// (8,9): warning CS8602: Possible dereference of a null reference.
// s.P.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.P").WithLocation(8, 9));
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录