Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
7c168cf0
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,发现更多精彩内容 >>
提交
7c168cf0
编写于
12月 16, 2015
作者:
B
Balaji Krishnan
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
initial tests for C# usevar.
shelving, edit this commit later.
上级
f345e01c
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
801 addition
and
24 deletion
+801
-24
src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj
...EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj
+1
-0
src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitTyping/UseImplicitTypingTests.cs
...t/Diagnostics/UseImplicitTyping/UseImplicitTypingTests.cs
+732
-0
src/EditorFeatures/TestUtilities/Traits.cs
src/EditorFeatures/TestUtilities/Traits.cs
+1
-0
src/Features/CSharp/Portable/CodeFixes/UseImplicitTyping/UseImplicitTypingCodeFixProvider.cs
...xes/UseImplicitTyping/UseImplicitTypingCodeFixProvider.cs
+9
-2
src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseImplicitTypingDiagnosticAnalyzer.cs
...cs/Analyzers/CSharpUseImplicitTypingDiagnosticAnalyzer.cs
+58
-22
未找到文件。
src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj
浏览文件 @
7c168cf0
...
...
@@ -212,6 +212,7 @@
<Compile
Include=
"Completion\CompletionProviders\XmlDocumentationCommentCompletionProviderTests.cs"
/>
<Compile
Include=
"Completion\LoadDirectiveCompletionProviderTests.cs"
/>
<Compile
Include=
"Completion\ReferenceDirectiveCompletionProviderTests.cs"
/>
<Compile
Include=
"Diagnostics\UseImplicitTyping\UseImplicitTypingTests.cs"
/>
<Compile
Include=
"GoToAdjacentMember\CSharpGoToAdjacentMemberTests.cs"
/>
<Compile
Include=
"Diagnostics\AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest.cs"
/>
<Compile
Include=
"Diagnostics\AddUsing\AddUsingTests.cs"
/>
...
...
src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitTyping/UseImplicitTypingTests.cs
0 → 100644
浏览文件 @
7c168cf0
// 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.Collections.Generic
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeFixes
;
using
Microsoft.CodeAnalysis.CSharp.CodeFixes.UseImplicitTyping
;
using
Microsoft.CodeAnalysis.CSharp.Diagnostics.UseImplicitTyping
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Text
;
using
Roslyn.Test.Utilities
;
using
Xunit
;
namespace
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.UseImplicitTyping
{
public
class
UseImplicitTypingTests
:
AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal
override
Tuple
<
DiagnosticAnalyzer
,
CodeFixProvider
>
CreateDiagnosticProviderAndFixer
(
Workspace
workspace
)
{
return
new
Tuple
<
DiagnosticAnalyzer
,
CodeFixProvider
>(
new
CSharpUseImplicitTypingDiagnosticAnalyzer
(),
new
UseImplicitTypingCodeFixProvider
());
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnFieldDeclaration
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
[|int|] _myfield = 5;
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnFieldLikeEvents
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
public event [|D|] _myevent;
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnConstants
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
const [|int|] x = 5;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnNullLiteral
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|Program|] x = null;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnDynamic
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|dynamic|] x = 1;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnAnonymousMethodExpression
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|Func<string, bool>|] comparer = delegate(string value) {
return value != ""0"";
};
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnLambdaExpression
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|Func<int, int>|] x = y => y * y;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnMethodGroup
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|Func<string, string>|] copyStr = string.Copy;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnDeclarationWithMultipleDeclarators
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|int|] x = 5, y = x;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnDeclarationWithoutInitializer
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|Program|] x;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnIFormattable
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|IFormattable|] s = $""Hello, {name}""
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnFormattableString
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|FormattableString|] s = $""Hello, {name}""
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotInCatchDeclaration
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
try
{
}
catch ([|Exception|] e)
{
throw;
}
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotDuringConflicts
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|Program|] p = new Program();
}
class var
{
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotIfAlreadyImplicitlyTyped
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
[|var|] p = new Program();
}
}"
);
}
[
WpfFact
(
Skip
=
"TODO"
),
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnImplicitConversion
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
}
}"
);
}
// TODO: should we or should we not? also, check boxing cases.
[
WpfFact
(
Skip
=
"TODO"
),
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnExplicitConversion
()
{
await
TestMissingAsync
(
@"using System;
class Program
{
void Method()
{
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnRHS
()
{
await
TestMissingAsync
(
@"using System;
class C
{
void M()
{
C c = new [|C|]();
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnVariablesUsedInInitalizerExpression
()
{
await
TestMissingAsync
(
@"using System;
class C
{
void M()
{
[|int|] i = (i = 20);
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
NotOnArrayInitializerWithoutNewKeyword
()
{
await
TestMissingAsync
(
@"using System;
class C
{
static void M()
{
[|int[]|] n1 = {2, 4, 6, 8};
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnLocalWithIntrinsicTypeString
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|string|] s = ""hello"";
}
}"
,
@"using System;
class C
{
static void M()
{
var s = ""hello"";
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnIntrinsicType
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|int|] s = 5;
}
}"
,
@"using System;
class C
{
static void M()
{
var s = 5;
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnFrameworkType
()
{
await
TestAsync
(
@"using System.Collections.Generic;
class C
{
static void M()
{
[|List<int>|] c = new List<int>();
}
}"
,
@"using System.Collections.Generic;
class C
{
static void M()
{
var c = new List<int>();
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnUserDefinedType
()
{
await
TestAsync
(
@"using System;
class C
{
void M()
{
[|C|] c = new C();
}
}"
,
@"using System;
class C
{
void M()
{
var c = new C();
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnGenericType
()
{
await
TestAsync
(
@"using System;
class C<T>
{
static void M()
{
[|C<int>|] c = new C<int>();
}
}"
,
@"using System;
class C<T>
{
static void M()
{
var c = new C<int>();
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnSingleDimensionalArrayTypeWithNewOperator
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|int[]|] n1 = new int[4] {2, 4, 6, 8};
}
}"
,
@"using System;
class C
{
static void M()
{
var n1 = new int[4] {2, 4, 6, 8};
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnSingleDimensionalArrayTypeWithNewOperator2
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|int[]|] n1 = new[] {2, 4, 6, 8};
}
}"
,
@"using System;
class C
{
static void M()
{
var n1 = new[] {2, 4, 6, 8};
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnSingleDimensionalJaggedArrayType
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|int[][]|] cs = new[]
{
new[]{1,2,3,4},
new[]{5,6,7,8}
};
}
}"
,
@"using System;
class C
{
static void M()
{
var cs = new[]
{
new[]{1,2,3,4},
new[]{5,6,7,8}
};
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnDeclarationWithObjectInitializer
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|Customer|] cc = new Customer { City = ""Madras"" };
}
private class Customer
{
public string City { get; set; }
}
}"
,
@"using System;
class C
{
static void M()
{
var cc = new Customer { City = ""Madras"" };
}
private class Customer
{
public string City { get; set; }
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnDeclarationWithCollectionInitializer
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|List<int>|] digits = new List<int> { 1, 2, 3 };
}
}"
,
@"using System;
class C
{
static void M()
{
var digits = new List<int> { 1, 2, 3 };
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnDeclarationWithCollectionAndObjectInitializers
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
[|List<Customer>|] cs = new List<Customer>
{
new Customer { City = ""Madras"" }
};
}
private class Customer
{
public string City { get; set; }
}
}"
,
@"using System;
class C
{
static void M()
{
var cs = new List<Customer>
{
new Customer { City = ""Madras"" }
};
}
private class Customer
{
public string City { get; set; }
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnForStatement
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
for ([|int|] i = 0; i < 5; i++)
{
}
}
}"
,
@"using System;
class C
{
static void M()
{
for (var i = 0; i < 5; i++)
{
}
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnForeachStatement
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
var l = new List<int> { 1, 3, 5 };
foreach ([|int|] item in l)
{
}
}
}"
,
@"using System;
class C
{
static void M()
{
var l = new List<int> { 1, 3, 5 };
foreach (var item in l)
{
}
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarOnQueryExpression
()
{
await
TestAsync
(
@"using System;
using System.Collections.Generic;
using System.Linq;
class C
{
static void M()
{
var customers = new List<Customer>();
[|IEnumerable<Customer>|] expr =
from c in customers
where c.City == ""London""
select c;
}
private class Customer
{
public string City { get; set; }
}
}
}"
,
@"using System;
using System.Collections.Generic;
using System.Linq;
class C
{
static void M()
{
var customers = new List<Customer>();
var expr =
from c in customers
where c.City == ""London""
select c;
}
private class Customer
{
public string City { get; set; }
}
}
}"
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseImplicitTyping
)]
public
async
Task
SuggestVarInUsingStatement
()
{
await
TestAsync
(
@"using System;
class C
{
static void M()
{
using ([|Res|] r = new Res())
{
}
}
private class Res : IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
}
}"
,
@"using System;
class C
{
static void M()
{
using (var r = new Res())
{
}
}
private class Res : IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
}
}"
);
}
}
}
\ No newline at end of file
src/EditorFeatures/TestUtilities/Traits.cs
浏览文件 @
7c168cf0
...
...
@@ -73,6 +73,7 @@ public static class Features
public
const
string
CodeActionsSpellcheck
=
"CodeActions.Spellcheck"
;
public
const
string
CodeActionsSuppression
=
"CodeActions.Suppression"
;
public
const
string
CodeActionsUseAutoProperty
=
"CodeActions.UseAutoProperty"
;
public
const
string
CodeActionsUseImplicitTyping
=
"CodeActions.UseImplicitTyping"
;
public
const
string
CodeGeneration
=
nameof
(
CodeGeneration
);
public
const
string
CodeGenerationSortDeclarations
=
"CodeGeneration.SortDeclarations"
;
public
const
string
CodeModel
=
nameof
(
CodeModel
);
...
...
src/Features/CSharp/Portable/CodeFixes/UseImplicitTyping/UseImplicitTypingCodeFixProvider.cs
浏览文件 @
7c168cf0
...
...
@@ -26,8 +26,15 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var
span
=
context
.
Span
;
var
root
=
await
document
.
GetSyntaxRootAsync
(
context
.
CancellationToken
).
ConfigureAwait
(
false
);
var
node
=
root
.
FindToken
(
span
.
Start
).
GetAncestors
<
SyntaxNode
>().
First
(
n
=>
n
.
Span
.
Contains
(
span
));
if
(!(
node
.
IsKind
(
SyntaxKind
.
PredefinedType
)
||
var
token
=
root
.
FindToken
(
span
.
Start
);
if
(!
token
.
Span
.
IntersectsWith
(
span
))
{
return
;
}
var
node
=
token
.
GetAncestors
<
SyntaxNode
>().
First
(
n
=>
n
.
Span
.
Contains
(
span
));
if
(
node
==
null
||
!(
node
.
IsKind
(
SyntaxKind
.
PredefinedType
)
||
node
.
IsKind
(
SyntaxKind
.
ArrayType
)
||
node
.
IsKind
(
SyntaxKind
.
IdentifierName
)
||
node
.
IsKind
(
SyntaxKind
.
GenericName
)
||
...
...
src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseImplicitTypingDiagnosticAnalyzer.cs
浏览文件 @
7c168cf0
...
...
@@ -19,7 +19,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.UseImplicitTyping
* 1. pipe through options
* 2. Design an options page to support tweaks to settings
* e.g: use var 'except' on primitive types, do not use var 'except' when type is apparent from rhs.
* 3. Refactor CSharp and VB implementations to common base class.
* 3. Refactoring to common base class.
* a. UseImplicitType and UseExplicitType : AbstractCSharpUseTypingStyle
* b. CSharp and VB implementations to AbstractUseTypingStyle
*/
[
DiagnosticAnalyzer
(
LanguageNames
.
CSharp
)]
...
...
@@ -27,7 +29,8 @@ internal sealed class CSharpUseImplicitTypingDiagnosticAnalyzer : DiagnosticAnal
{
// TODO:
// 1. localize title and message
// 2. tweak severity and custom tags -- need to have various levels of diagnostics to report based on option settings.
// 2. tweak severity and custom tags
// a. need to have various levels of diagnostics to report based on option settings.
private
static
readonly
DiagnosticDescriptor
s_descriptorUseImplicitTyping
=
new
DiagnosticDescriptor
(
id
:
IDEDiagnosticIds
.
UseImplicitTypingDiagnosticId
,
title
:
"Use implicit typing"
,
...
...
@@ -48,15 +51,15 @@ public DiagnosticAnalyzerCategory GetAnalyzerCategory()
public
override
void
Initialize
(
AnalysisContext
context
)
{
// TODO: check for generatedcode and bail.
// context.ConfigureGeneratedCodeAnalysis() See https://github.com/dotnet/roslyn/pull/7526
context
.
RegisterSyntaxNodeAction
(
HandleVariableDeclaration
,
SyntaxKind
.
VariableDeclaration
);
context
.
RegisterSyntaxNodeAction
(
HandleForEachStatement
,
SyntaxKind
.
ForEachStatement
);
}
private
void
HandleVariableDeclaration
(
SyntaxNodeAnalysisContext
context
)
{
// TODO: check for generatedcode and bail.
var
variableDeclaration
=
(
VariableDeclarationSyntax
)
context
.
Node
;
// var is applicable only for local variables.
...
...
@@ -84,38 +87,62 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
}
}
// TODO: move this helper to a common place.
private
bool
IsTypeApparentFromRHS
()
{
// Factory Methods
// Generic methods with type parameters but not inferred
// constructors of form = new TypeSomething();
// int.Parse, TextSpan.From static methods?
// object creation expression that contains a typename and not an anonymous object creation expression.
// invocation expression
// a. int.Parse, TextSpan.From static methods?
// return type or 1 ref/out type matches some part of identifier name within a dotted name.
// also consider Generic method invocation with type parameters *and* not inferred
// c. Factory Methods
throw
new
NotImplementedException
();
}
private
bool
IntrinsicTypeInDeclaration
()
{
// Add support to not use var in place of intrinsic types
throw
new
NotImplementedException
();
}
private
void
HandleForEachStatement
(
SyntaxNodeAnalysisContext
context
)
{
var
forEachStatement
=
(
ForEachStatementSyntax
)
context
.
Node
;
TextSpan
diagnosticSpan
;
var
diagnostic
=
AnalyzeVariableDeclaration
(
forEachStatement
,
context
.
SemanticModel
,
context
.
CancellationToken
)
;
var
diagnostic
=
IsReplaceableByVar
(
forEachStatement
.
Type
,
context
.
SemanticModel
,
context
.
CancellationToken
,
out
diagnosticSpan
)
?
Diagnostic
.
Create
(
s_descriptorUseImplicitTyping
,
forEachStatement
.
SyntaxTree
.
GetLocation
(
diagnosticSpan
))
:
null
;
// TODO: Check options and bail.
if
(
diagnostic
!=
null
)
{
context
.
ReportDiagnostic
(
diagnostic
);
}
}
private
Diagnostic
AnalyzeVariableDeclaration
(
VariableDeclarationSyntax
variableDeclaration
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
private
Diagnostic
AnalyzeVariableDeclaration
(
SyntaxNode
declarationStatement
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
{
TextSpan
diagnosticSpan
;
TypeSyntax
declaredType
;
return
IsReplaceableByVar
(
variableDeclaration
.
Type
,
semanticModel
,
cancellationToken
,
out
diagnosticSpan
)
?
Diagnostic
.
Create
(
s_descriptorUseImplicitTyping
,
variableDeclaration
.
SyntaxTree
.
GetLocation
(
diagnosticSpan
))
if
(
declarationStatement
.
IsKind
(
SyntaxKind
.
VariableDeclaration
))
{
declaredType
=
((
VariableDeclarationSyntax
)
declarationStatement
).
Type
;
}
else
if
(
declarationStatement
.
IsKind
(
SyntaxKind
.
ForEachStatement
))
{
declaredType
=
((
ForEachStatementSyntax
)
declarationStatement
).
Type
;
}
else
{
Debug
.
Assert
(
false
,
$"unhandled kind
{
declarationStatement
.
Kind
().
ToString
()}
"
);
return
null
;
}
return
IsReplaceableByVar
(
declaredType
,
semanticModel
,
cancellationToken
,
out
diagnosticSpan
)
?
Diagnostic
.
Create
(
s_descriptorUseImplicitTyping
,
declarationStatement
.
SyntaxTree
.
GetLocation
(
diagnosticSpan
))
:
null
;
}
...
...
@@ -155,7 +182,8 @@ private bool IsReplaceableByVar(TypeSyntax typeName, SemanticModel semanticModel
return
false
;
}
if
(
CheckAssignment
(
typeName
,
variableDeclaration
.
Variables
.
Single
().
Initializer
,
semanticModel
,
cancellationToken
))
var
variable
=
variableDeclaration
.
Variables
.
Single
();
if
(
CheckAssignment
(
variable
.
Identifier
,
typeName
,
variable
.
Initializer
,
semanticModel
,
cancellationToken
))
{
issueSpan
=
candidateIssueSpan
;
}
...
...
@@ -168,7 +196,7 @@ private bool IsReplaceableByVar(TypeSyntax typeName, SemanticModel semanticModel
return
issueSpan
!=
default
(
TextSpan
);
}
private
bool
CheckAssignment
(
TypeSyntax
typeName
,
EqualsValueClauseSyntax
initializer
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
private
bool
CheckAssignment
(
SyntaxToken
identifier
,
TypeSyntax
typeName
,
EqualsValueClauseSyntax
initializer
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
{
// var cannot be assigned null
if
(
initializer
.
IsKind
(
SyntaxKind
.
NullLiteralExpression
))
...
...
@@ -178,7 +206,7 @@ private bool CheckAssignment(TypeSyntax typeName, EqualsValueClauseSyntax initia
// cannot use implicit typing on method group, anonymous function or on dynamic
var
declaredType
=
semanticModel
.
GetTypeInfo
(
typeName
,
cancellationToken
).
Type
;
if
(
declaredType
!=
null
&&
if
(
declaredType
!=
null
&&
(
declaredType
.
TypeKind
==
TypeKind
.
Delegate
||
declaredType
.
TypeKind
==
TypeKind
.
Dynamic
))
{
...
...
@@ -195,9 +223,10 @@ private bool CheckAssignment(TypeSyntax typeName, EqualsValueClauseSyntax initia
if
(
implicitlyConverted
)
{
return
false
;
// TODO, based on tests.
/*
*
string[] strings = { "a", "b" }; // doesn't work here. check all array initialization expressions.
*
object obj = 1;
*/
}
else
...
...
@@ -211,7 +240,14 @@ private bool CheckAssignment(TypeSyntax typeName, EqualsValueClauseSyntax initia
}
}
// TODO: check for compound assignments? Not necessary because they do not have an EqualsValueClause?
// variables declared using var cannot be used further in the same initialization expression.
if
(
initializer
.
DescendantNodesAndSelf
()
.
Where
(
n
=>
n
.
IsKind
(
SyntaxKind
.
IdentifierName
)
&&
((
IdentifierNameSyntax
)
n
).
Identifier
.
ValueText
.
Equals
(
identifier
.
ValueText
))
.
Any
(
n
=>
semanticModel
.
GetSymbolInfo
(
n
,
cancellationToken
).
Symbol
?.
IsKind
(
SymbolKind
.
Local
)
??
false
))
{
return
false
;
}
return
true
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录