diff --git a/.gitignore b/.gitignore
index fd5204b..1faa2e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -181,3 +181,4 @@ UpgradeLog*.htm
# Microsoft Fakes
FakesAssemblies/
+/NullParameterCheckRefactoring_(CS+VB)
diff --git a/NullParameterCheckRefactoring.sln b/NullParameterCheckRefactoring.sln
index a03ccef..5e0d27f 100644
--- a/NullParameterCheckRefactoring.sln
+++ b/NullParameterCheckRefactoring.sln
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22310.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NullParameterCheckRefactoring", "src\NullParameterCheckRefactoring\NullParameterCheckRefactoring.csproj", "{6FD2E415-46CD-4370-87BD-A5E2D03A5C0D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NullParameterCheckRefactoring.CSharp", "src\NullParameterCheckRefactoring.CSharp\NullParameterCheckRefactoring.CSharp.csproj", "{6FD2E415-46CD-4370-87BD-A5E2D03A5C0D}"
+EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "NullParameterCheckRefactoring.VB", "src\NullParameterCheckRefactoring.VB\NullParameterCheckRefactoring.VB.vbproj", "{5C5C6CFE-22CB-4E7A-9916-B6F28785B5C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NullParameterCheckRefactoring.Vsix", "src\NullParameterCheckRefactoring.Vsix\NullParameterCheckRefactoring.Vsix.csproj", "{E9BE117A-4BF4-41C3-843A-CB659B433963}"
EndProject
@@ -17,6 +19,10 @@ Global
{6FD2E415-46CD-4370-87BD-A5E2D03A5C0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FD2E415-46CD-4370-87BD-A5E2D03A5C0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FD2E415-46CD-4370-87BD-A5E2D03A5C0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5C5C6CFE-22CB-4E7A-9916-B6F28785B5C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5C5C6CFE-22CB-4E7A-9916-B6F28785B5C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5C5C6CFE-22CB-4E7A-9916-B6F28785B5C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5C5C6CFE-22CB-4E7A-9916-B6F28785B5C0}.Release|Any CPU.Build.0 = Release|Any CPU
{E9BE117A-4BF4-41C3-843A-CB659B433963}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9BE117A-4BF4-41C3-843A-CB659B433963}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9BE117A-4BF4-41C3-843A-CB659B433963}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/src/NullParameterCheckRefactoring/NullParameterCheckRefactoring.csproj b/src/NullParameterCheckRefactoring.CSharp/NullParameterCheckRefactoring.CSharp.csproj
similarity index 93%
rename from src/NullParameterCheckRefactoring/NullParameterCheckRefactoring.csproj
rename to src/NullParameterCheckRefactoring.CSharp/NullParameterCheckRefactoring.CSharp.csproj
index 46e3f77..78c052f 100644
--- a/src/NullParameterCheckRefactoring/NullParameterCheckRefactoring.csproj
+++ b/src/NullParameterCheckRefactoring.CSharp/NullParameterCheckRefactoring.CSharp.csproj
@@ -11,7 +11,7 @@
Library
Properties
NullParameterCheckRefactoring
- NullParameterCheckRefactoring
+ NullParameterCheckRefactoring.CSharp
Profile7
v4.5
@@ -53,6 +53,12 @@
..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0-beta1-20141031-01\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll
False
+
+ ..\..\packages\RoslynExts.1.0.7\lib\portable-net45+win8\RoslynExts.CS.dll
+
+
+ ..\..\packages\RoslynExts.1.0.7\lib\portable-net45+win8\RoslynExts.VB.dll
+
..\..\packages\System.Collections.Immutable.1.1.32-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
False
diff --git a/src/NullParameterCheckRefactoring.CSharp/NullParameterCheckRefactoringProvider.cs b/src/NullParameterCheckRefactoring.CSharp/NullParameterCheckRefactoringProvider.cs
new file mode 100644
index 0000000..8e083b3
--- /dev/null
+++ b/src/NullParameterCheckRefactoring.CSharp/NullParameterCheckRefactoringProvider.cs
@@ -0,0 +1,84 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Extensions;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using RoslynExts.CS;
+
+
+namespace NullParameterCheckRefactoring
+{
+ [ExportCodeRefactoringProvider(RefactoringId, LanguageNames.CSharp), Shared]
+ public class NullParameterCheckRefactoringProvider : CodeRefactoringProvider
+ {
+ internal const string RefactoringId = "TR0001";
+
+ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
+ {
+ SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ SyntaxNode node = root.FindNode(context.Span);
+ ParameterSyntax parameterSyntax = node as ParameterSyntax;
+
+ if (parameterSyntax != null)
+ {
+ TypeSyntax paramTypeName = parameterSyntax.Type;
+ SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken);
+ ITypeSymbol type = semanticModel.GetTypeInfo(paramTypeName).ConvertedType;
+
+ BaseMethodDeclarationSyntax methodDeclaration = parameterSyntax.Parent.Parent as BaseMethodDeclarationSyntax;
+ IEnumerable availableIfStatements = methodDeclaration.Body.ChildNodes().OfType();
+
+ if (type.IsReferenceType)
+ {
+ // check if the null check already exists.
+ bool isNullCheckAlreadyPresent = availableIfStatements.Any(ifStatement =>
+ {
+ return ifStatement.ChildNodes()
+ .OfType()
+ .Where(x => x.IsKind(SyntaxKind.EqualsExpression))
+ .Any(expression =>
+ {
+ if (expression.Right.IsKind(SyntaxKind.NullLiteralExpression))
+ {
+ var identifierSyntaxt = expression.ChildNodes().OfType().FirstOrDefault();
+ return (identifierSyntaxt != null) &&
+ (identifierSyntaxt.Identifier.Text.Equals(parameterSyntax.Identifier.Text, StringComparison.Ordinal));
+ }
+ return false;
+ });
+ });
+
+ if (isNullCheckAlreadyPresent == false)
+ {
+ CodeAction action = CodeAction.Create(
+ "Check parameter for null",
+ ct => AddParameterNullCheckAsync(context.Document, parameterSyntax, methodDeclaration, ct));
+
+ context.RegisterRefactoring(action);
+ }
+ }
+ }
+ }
+
+ private async Task AddParameterNullCheckAsync(Document document, ParameterSyntax parameter, BaseMethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
+ {
+
+ var nullCheckIfStatement =
+ "if( \{parameter.Identifier} == null ) { throw new ArgumentNullException( nameof( \{parameter.Identifier.Text} )); };".ToSExpr();
+ SyntaxList newStatements = methodDeclaration.Body.Statements.Insert(0, nullCheckIfStatement);
+ BlockSyntax newBlock = SyntaxFactory.Block(newStatements).WithAdditionalAnnotations(Formatter.Annotation);
+ SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken);
+ SyntaxNode newRoot = root.ReplaceNode(methodDeclaration.Body, newBlock);
+
+ return document.WithSyntaxRoot(newRoot);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring/Properties/AssemblyInfo.cs b/src/NullParameterCheckRefactoring.CSharp/Properties/AssemblyInfo.cs
similarity index 89%
rename from src/NullParameterCheckRefactoring/Properties/AssemblyInfo.cs
rename to src/NullParameterCheckRefactoring.CSharp/Properties/AssemblyInfo.cs
index 2c1029b..90a67cb 100644
--- a/src/NullParameterCheckRefactoring/Properties/AssemblyInfo.cs
+++ b/src/NullParameterCheckRefactoring.CSharp/Properties/AssemblyInfo.cs
@@ -4,11 +4,11 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[assembly: AssemblyTitle("NullParameterCheckRefactoring")]
+[assembly: AssemblyTitle("NullParameterCheckRefactoring.CSharp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("NullParameterCheckRefactoring")]
+[assembly: AssemblyProduct("NullParameterCheckRefactoring.CSharp")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/src/NullParameterCheckRefactoring/packages.config b/src/NullParameterCheckRefactoring.CSharp/packages.config
similarity index 91%
rename from src/NullParameterCheckRefactoring/packages.config
rename to src/NullParameterCheckRefactoring.CSharp/packages.config
index c1e36d2..17c9bcd 100644
--- a/src/NullParameterCheckRefactoring/packages.config
+++ b/src/NullParameterCheckRefactoring.CSharp/packages.config
@@ -5,6 +5,7 @@
+
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring.VB/CodeRefactoringProvider.vb b/src/NullParameterCheckRefactoring.VB/CodeRefactoringProvider.vb
new file mode 100644
index 0000000..27a1965
--- /dev/null
+++ b/src/NullParameterCheckRefactoring.VB/CodeRefactoringProvider.vb
@@ -0,0 +1,187 @@
+Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory
+'Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxKind
+Imports RoslynExts.VB
+
+
+
+Friend Class NullCheck_CodeRefactoringCodeRefactoringProvider
+ Inherits CodeRefactoringProvider
+
+ Public Const RefactoringId As String = "TR0001"
+
+ Public NotOverridable Overrides Async Function ComputeRefactoringsAsync(context As CodeRefactoringContext) As Task
+ Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False)
+ ' Find the node at the selection.
+ Dim node = root.FindNode(context.Span)
+ ' Only offer a refactoring if the selected node is a type statement node.
+ Dim _Identifier_ = node.Try(Of ModifiedIdentifierSyntax) : If _Identifier_ Is Nothing Then Return
+ Dim _parmeter_ = _Identifier_.Parent.Try(of ParameterSyntax) : If _parmeter_ Is Nothing Then Return
+ Dim _method_ = _parmeter_.Parent.Parent.Parent.Try(of MethodBlockSyntax) : If _method_ Is Nothing Then Return
+
+ Dim _Model_ = Await context.Document.GetSemanticModelAsync(context.CancellationToken)
+
+ Dim ifStatements = _method_.Statements.Where(Function(s) (TypeOf s Is MultiLineIfBlockSyntax) OrElse (TypeOf s Is SingleLineIfStatementSyntax))
+ Dim pinfo = _Model_.GetTypeInfo(_parmeter_.AsClause.Type, context.CancellationToken)
+ If pinfo.ConvertedType.IsReferenceType = False Then Return
+ Dim GuardStatements = ifStatements.Where(NullChecks(_parmeter_))
+
+ Dim IsNullCheckAlreadyPresent = GuardStatements.Any
+ If Not IsNullCheckAlreadyPresent Then context.RegisterRefactoring(CodeAction.Create("Check Parameter for null", Function(ct As CancellationToken) AddParameterNullCheckAsync(context.Document, _parmeter_, _method_, ct)))
+ End Function
+
+ Private Shared Function NullChecks(_parmeter_ As ParameterSyntax) As Func(Of StatementSyntax, Boolean)
+ Return Function(s)
+ If TypeOf s Is SingleLineIfStatementSyntax Then
+ Dim singleIF = s.As(of SingleLineIfStatementSyntax)
+ Dim isExpr = singleIF.Condition.Try(of BinaryExpressionSyntax)
+ If (isExpr Is Nothing) OrElse (Not isExpr.IsKind(SyntaxKind.IsExpression)) Then Return False
+ Dim res = CheckIfCondition(_parmeter_, isExpr)
+ If Not res Then Return res
+ Dim _sif_ = GetGuardStatement(_parmeter_).NormalizeWhitespace
+ Return Not singleIF.IsEquivalentTo(_sif_)
+ ElseIf TypeOf s Is MultiLineIfBlockSyntax Then
+ Dim multiIF = s.As(Of MultiLineIfBlockSyntax)
+ Dim isExpr = multiIF.IfStatement.Condition.Try(of BinaryExpressionSyntax)
+ If (isExpr Is Nothing) OrElse (Not isExpr.IsKind(SyntaxKind.IsExpression)) Then Return False
+ Dim res = CheckIfCondition(_parmeter_, isExpr)
+ If Not res Then Return res
+ Dim _mif_ = GetMultiLineGuardStatement(_parmeter_)
+ Return Not multiIF.WithoutAnnotations().IsEquivalentTo(_mif_)
+ End If
+ Return False
+ End Function
+ End Function
+
+ Private Shared Function CheckIfCondition(paramSyntax As ParameterSyntax, isExpr As BinaryExpressionSyntax) As Boolean
+ Dim l = isExpr.Left.Try(of IdentifierNameSyntax)
+ Dim r = isExpr.Right.Try(Of LiteralExpressionSyntax)
+ If l Is Nothing OrElse r Is Nothing Then Return False
+ If r.IsKind(SyntaxKind.NothingLiteralExpression) = False Then Return False
+ Return String.Compare(l.Identifier.Text, paramSyntax.Identifier.Identifier.Text, StringComparison.Ordinal) = 0
+ End Function
+
+ Private Shared Function CheckIfCondition(isExpr As BinaryExpressionSyntax) As Boolean
+ Dim l = isExpr.Left.Try(Of IdentifierNameSyntax)
+ Dim r = isExpr.Right.Try(Of LiteralExpressionSyntax)
+ If l Is Nothing OrElse r Is Nothing Then Return False
+ Return r.IsKind(SyntaxKind.NothingLiteralExpression)
+ End Function
+
+ Private Async Function AddParameterNullCheckAsync(document As Document,
+ _parmeter_ As ParameterSyntax,
+ method As MethodBlockSyntax,
+ cancellationToken As CancellationToken) As Task(Of Document)
+
+ Dim NewGuardStatement = GetGuardStatement(_parmeter_)
+
+ Dim ifStatements = method.Statements.Where(Function(s) (TypeOf s Is MultiLineIfBlockSyntax) OrElse (TypeOf s Is SingleLineIfStatementSyntax))
+ ' Dim ifStatements = method.Statements.OfType(Of MultiLineIfBlockSyntax, SingleLineIfStatementSyntax)
+
+ Dim ExistingGuards = ifStatements.Where(
+ Function(s)
+ If TypeOf s Is SingleLineIfStatementSyntax Then Return CheckIfCondition(s.As(Of SingleLineIfStatementSyntax).Condition.Try(Of BinaryExpressionSyntax))
+ If TypeOf s Is MultiLineIfBlockSyntax Then Return CheckIfCondition(s.As(Of MultiLineIfBlockSyntax).IfStatement.Condition.Try(Of BinaryExpressionSyntax))
+ Return False
+ End Function)
+
+ Dim ExistingGuardParameters = ExistingGuards.Select(
+ Function(s)
+ If TypeOf s Is SingleLineIfStatementSyntax Then Return s.As(Of SingleLineIfStatementSyntax).Condition.Try(Of BinaryExpressionSyntax)?.Left.As(Of IdentifierNameSyntax)
+ If TypeOf s Is MultiLineIfBlockSyntax Then Return s.As(Of MultiLineIfBlockSyntax).IfStatement.Condition.Try(Of BinaryExpressionSyntax)?.Left.As(Of IdentifierNameSyntax)
+ Return Nothing
+ End Function)
+
+
+ Dim parameters = method.Begin.ParameterList.Parameters
+ Dim NumberOfParameters = parameters.Count
+
+
+ Dim Guards = Enumerable.Repeat(Of StatementSyntax)(Nothing, NumberOfParameters).ToArray
+ Dim parameterNames = parameters.Select(Function(p) p.Identifier).ToArray
+
+ For i = 0 To ExistingGuards.Count - 1
+ Dim eg = ExistingGuards(i)
+ Dim Id = ExistingGuardParameters(i)
+ Dim index = FindGuardIndex(parameterNames, Id)
+ If index.HasValue Then Guards(index.Value) = eg '.WithSameTriviaAs(eg)
+ Next
+
+ Dim NewGuardIndex = FindGuardIndex(parameterNames, _parmeter_.Identifier)
+ If NewGuardIndex.HasValue Then Guards(NewGuardIndex.Value) = NewGuardStatement.AddEOL
+
+ ' Remove the existing guard statement
+ Dim newmethod = method.RemoveNodes(ExistingGuards, SyntaxRemoveOptions.KeepNoTrivia)
+ ' Get the Guards that will exist
+ Dim NonNullGuards = Guards.WhereNonNull
+ ' Insert them into the code
+ Dim newStatements = newmethod.Statements.InsertRange(0, NonNullGuards)
+ newmethod = newmethod.WithStatements(newStatements)
+ Dim newBlock = newmethod.WithAdditionalAnnotations(Formatting.Formatter.Annotation)
+ ' Get the new document with the applied changes
+ Return document.WithSyntaxRoot((Await document.GetSyntaxRootAsync(cancellationToken)).ReplaceNode(method, newBlock))
+ End Function
+
+ Private Shared Function FindGuardIndex(ParametersNames() As ModifiedIdentifierSyntax, Id As IdentifierNameSyntax) As Integer?
+ For j = 0 To ParametersNames.Count - 1
+ If String.Compare(ParametersNames(j).Identifier.Text,
+ Id.Identifier.Text, StringComparison.Ordinal) = 0 Then Return New Integer?(j)
+ Next j
+ Return New Integer?()
+ End Function
+
+ Private Shared Function FindGuardIndex(ParametersNames() As ModifiedIdentifierSyntax, Id As ModifiedIdentifierSyntax) As Integer?
+ For j = 0 To ParametersNames.Count - 1
+ If String.Compare(ParametersNames(j).Identifier.Text,
+ Id.Identifier.Text, StringComparison.Ordinal) = 0 Then Return New Integer?(j)
+ Next j
+ Return New Integer?()
+ End Function
+
+
+
+ Private Shared Function GetGuardStatement(parameterStmt As ParameterSyntax) As SingleLineIfStatementSyntax
+ Return String.Format("If {0} Then {1}", GetIsNothingExpr(parameterStmt), GetThrowStatementForParameter(parameterStmt)).ToSExpr(Of SingleLineIfStatementSyntax)
+ End Function
+
+ Private Shared Function GetThrowStatementForParameter(parameterStmt As ParameterSyntax) As ThrowStatementSyntax
+ Return String.Format(" Throw New System.ArgumentNullException({0})", GetParameterName(parameterStmt)).ToSExpr(Of ThrowStatementSyntax)
+ End Function
+
+ Private Shared Function GetIsNothingExpr(forParameter As ParameterSyntax) As BinaryExpressionSyntax
+ Return String.Format(" {0} Is Nothing ", forParameter.Identifier.Identifier.Text).ToExpr(Of BinaryExpressionSyntax)
+ End Function
+
+ Private Shared Function GetMultiLineGuardStatement(parameterStmt As ParameterSyntax) As MultiLineIfBlockSyntax
+ Return String.Format("If {0} Then
+ {1}
+End If",
+ GetIsNothingExpr(parameterStmt),
+ GetThrowStatementForParameter(parameterStmt)).ToSExpr(Of MultiLineIfBlockSyntax)
+
+ End Function
+
+ Private Shared Function GetParameterName(parameterStmt As ParameterSyntax) As LiteralExpressionSyntax
+ ' Note: If I can find the nameof feature in VB.net, then I'll change this line to reflect that
+ Return StringLiteralExpression(Literal(parameterStmt.Identifier.Identifier.Text))
+ End Function
+
+End Class
+
+Public Module Exts
+
+
+ Public Function WhereNonNull(Of T As Class)(xs As IEnumerable(Of T)) As IEnumerable(Of T)
+ Return xs.Where(Function(x) x IsNot Nothing)
+ End Function
+
+
+ Public Function OfType(Of xT, T1 As xT, T2 As xT)(xs As IEnumerable(Of xT)) As IEnumerable(Of xT)
+ Return xs.Where(Function(x) (TypeOf xs Is T1) OrElse (TypeOf xs Is T2))
+ End Function
+
+
+ '
+ 'Public Function AddEOL(Of T0 As SyntaxNode)(node As T0) As T0
+ ' Return node.WithTrailingTrivia(SyntaxFactory.SyntaxTrivia(SyntaxKind.EndOfLineTrivia, Environment.NewLine))
+ 'End Function
+End Module
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring.VB/My Project/AssemblyInfo.vb b/src/NullParameterCheckRefactoring.VB/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..343f7f7
--- /dev/null
+++ b/src/NullParameterCheckRefactoring.VB/My Project/AssemblyInfo.vb
@@ -0,0 +1,29 @@
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' General Information about an assembly is controlled through the following
+' set of attributes. Change these attribute values to modify the information
+' associated with an assembly.
+
+' Review the values of the assembly attributes
+
+
+
+
+
+
+
+
+
+
+' Version information for an assembly consists of the following four values:
+'
+' Major Version
+' Minor Version
+' Build Number
+' Revision
+'
+' You can specify all the values or you can default the Build and Revision Numbers
+' by using the '*' as shown below:
+
+
diff --git a/src/NullParameterCheckRefactoring.VB/NullParameterCheckRefactoring.VB.vbproj b/src/NullParameterCheckRefactoring.VB/NullParameterCheckRefactoring.VB.vbproj
new file mode 100644
index 0000000..676056b
--- /dev/null
+++ b/src/NullParameterCheckRefactoring.VB/NullParameterCheckRefactoring.VB.vbproj
@@ -0,0 +1,142 @@
+
+
+
+
+ 11.0
+ Debug
+ AnyCPU
+ 2.0
+ {14182A97-F7F0-4C62-8B27-98AA8AE2109A};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}
+ {5C5C6CFE-22CB-4E7A-9916-B6F28785B5C0}
+ Library
+ NullParameterCheckRefactoring
+ NullParameterCheckRefactoring.VB
+ Profile7
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ true
+ true
+ prompt
+ 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036
+
+
+ pdbonly
+ true
+ bin\Release\
+ false
+ true
+ prompt
+ 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036
+
+
+ On
+
+
+ Binary
+
+
+ On
+
+
+ On
+
+
+ Program
+ $(DevEnvDir)devenv.exe
+ /rootsuffix Roslyn
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0-beta1-20141031-01\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll
+ False
+
+
+ ..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.0.0-beta1-20141031-01\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.dll
+ False
+
+
+ ..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.0.0-beta1-20141031-01\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll
+ False
+
+
+ ..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0-beta1-20141031-01\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll
+ False
+
+
+ ..\..\packages\RoslynExts.1.0.7\lib\portable-net45+win8\RoslynExts.CS.dll
+
+
+ ..\..\packages\RoslynExts.1.0.7\lib\portable-net45+win8\RoslynExts.VB.dll
+
+
+ ..\..\packages\System.Collections.Immutable.1.1.32-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+ False
+
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
+ False
+
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll
+ False
+
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll
+ False
+
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll
+ False
+
+
+ ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll
+ False
+
+
+ ..\..\packages\System.Reflection.Metadata.1.0.17-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll
+ False
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring.VB/packages.config b/src/NullParameterCheckRefactoring.VB/packages.config
new file mode 100644
index 0000000..fd86554
--- /dev/null
+++ b/src/NullParameterCheckRefactoring.VB/packages.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring.Vsix/NullParameterCheckRefactoring.Vsix.csproj b/src/NullParameterCheckRefactoring.Vsix/NullParameterCheckRefactoring.Vsix.csproj
index 0a70eb5..043518d 100644
--- a/src/NullParameterCheckRefactoring.Vsix/NullParameterCheckRefactoring.Vsix.csproj
+++ b/src/NullParameterCheckRefactoring.Vsix/NullParameterCheckRefactoring.Vsix.csproj
@@ -47,15 +47,30 @@
/rootsuffix Roslyn
+
Designer
-
+
{6FD2E415-46CD-4370-87BD-A5E2D03A5C0D}
- NullParameterCheckRefactoring
+ NullParameterCheckRefactoring.CSharp
+
+ {5c5c6cfe-22cb-4e7a-9916-b6f28785b5c0}
+ NullParameterCheckRefactoring.VB
+
+
+
+
+ False
+ ..\..\packages\RoslynExts.1.0.7\lib\portable-net45+win8\RoslynExts.CS.dll
+
+
+ False
+ ..\..\packages\RoslynExts.1.0.7\lib\portable-net45+win8\RoslynExts.VB.dll
+
diff --git a/src/NullParameterCheckRefactoring.Vsix/packages.config b/src/NullParameterCheckRefactoring.Vsix/packages.config
new file mode 100644
index 0000000..263cef5
--- /dev/null
+++ b/src/NullParameterCheckRefactoring.Vsix/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring.Vsix/source.extension.vsixmanifest b/src/NullParameterCheckRefactoring.Vsix/source.extension.vsixmanifest
index bdb9f36..df0b51f 100644
--- a/src/NullParameterCheckRefactoring.Vsix/source.extension.vsixmanifest
+++ b/src/NullParameterCheckRefactoring.Vsix/source.extension.vsixmanifest
@@ -3,7 +3,8 @@
NullParameterCheckRefactoring.Vsix
- This is a sample code refactoring extension for the .NET Compiler Platform ("Roslyn").
+ Add Guard Statement for Reference Parameter Types. This code refactoring extension for the .NET Compiler Platform ("Roslyn").
+ https://github.com/DotNetAnalyzers/NullParameterCheckRefactoring
@@ -15,6 +16,7 @@
-
+
+
\ No newline at end of file
diff --git a/src/NullParameterCheckRefactoring/NullParameterCheckRefactoringProvider.cs b/src/NullParameterCheckRefactoring/NullParameterCheckRefactoringProvider.cs
deleted file mode 100644
index 34e8677..0000000
--- a/src/NullParameterCheckRefactoring/NullParameterCheckRefactoringProvider.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeRefactorings;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Formatting;
-using System;
-using System.Collections.Generic;
-using System.Composition;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NullParameterCheckRefactoring
-{
- [ExportCodeRefactoringProvider(RefactoringId, LanguageNames.CSharp), Shared]
- public class NullParameterCheckRefactoringProvider : CodeRefactoringProvider
- {
- internal const string RefactoringId = "TR0001";
-
- public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
- {
- SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- SyntaxNode node = root.FindNode(context.Span);
- ParameterSyntax parameterSyntax = node as ParameterSyntax;
-
- if(parameterSyntax != null)
- {
- TypeSyntax paramTypeName = parameterSyntax.Type;
- SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken);
- ITypeSymbol type = semanticModel.GetTypeInfo(paramTypeName).ConvertedType;
-
- BaseMethodDeclarationSyntax methodDeclaration = parameterSyntax.Parent.Parent as BaseMethodDeclarationSyntax;
- IEnumerable availableIfStatements = methodDeclaration.Body.ChildNodes().OfType();
-
- if (type.IsReferenceType)
- {
- // check if the null check already exists.
- bool isNullCheckAlreadyPresent = availableIfStatements.Any(ifStatement =>
- {
- return ifStatement.ChildNodes()
- .OfType()
- .Where(x => x.IsKind(SyntaxKind.EqualsExpression))
- .Any(expression =>
- {
- bool result;
- bool isNullCheck = expression.Right.IsKind(SyntaxKind.NullLiteralExpression);
- if (isNullCheck)
- {
- IdentifierNameSyntax identifierSyntaxt = expression.ChildNodes().OfType().FirstOrDefault();
- if (identifierSyntaxt != null)
- {
- string identifierText = identifierSyntaxt.Identifier.Text;
- string paramText = parameterSyntax.Identifier.Text;
-
- if (identifierText.Equals(paramText, StringComparison.Ordinal))
- {
- // There is already a null check for this parameter. Skip it.
- result = true;
- }
- else
- {
- result = false;
- }
- }
- else
- {
- result = false;
- }
- }
- else
- {
- result = false;
- }
-
- return result;
- });
- });
-
- if(isNullCheckAlreadyPresent == false)
- {
- CodeAction action = CodeAction.Create(
- "Check parameter for null",
- ct => AddParameterNullCheckAsync(context.Document, parameterSyntax, methodDeclaration, ct));
-
- context.RegisterRefactoring(action);
- }
- }
- }
- }
-
- private async Task AddParameterNullCheckAsync(Document document, ParameterSyntax parameter, BaseMethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
- {
- BinaryExpressionSyntax binaryExpression = SyntaxFactory.BinaryExpression(
- SyntaxKind.EqualsExpression,
- SyntaxFactory.IdentifierName(parameter.Identifier),
- SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression));
-
- NameOfExpressionSyntax nameOfExpression = SyntaxFactory.NameOfExpression(
- "nameof",
- SyntaxFactory.ParseTypeName(parameter.Identifier.Text));
-
- ObjectCreationExpressionSyntax objectCreationExpression = SyntaxFactory.ObjectCreationExpression(
- SyntaxFactory.ParseTypeName(nameof(ArgumentNullException)),
- SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(nameOfExpression) })),
- null);
-
- BlockSyntax syntaxBlock = SyntaxFactory.Block(
- SyntaxFactory.Token(SyntaxKind.OpenBraceToken),
- new SyntaxList().Add(SyntaxFactory.ThrowStatement(objectCreationExpression)),
- SyntaxFactory.Token(SyntaxKind.CloseBraceToken)).WithAdditionalAnnotations(Formatter.Annotation);
-
- IfStatementSyntax nullCheckIfStatement = SyntaxFactory.IfStatement(
- SyntaxFactory.Token(SyntaxKind.IfKeyword),
- SyntaxFactory.Token(SyntaxKind.OpenParenToken),
- binaryExpression,
- SyntaxFactory.Token(SyntaxKind.CloseParenToken),
- syntaxBlock, null).WithAdditionalAnnotations(Formatter.Annotation);
-
- SyntaxList newStatements = methodDeclaration.Body.Statements.Insert(0, nullCheckIfStatement);
- BlockSyntax newBlock = SyntaxFactory.Block(newStatements).WithAdditionalAnnotations(Formatter.Annotation);
- SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken);
- SyntaxNode newRoot = root.ReplaceNode(methodDeclaration.Body, newBlock);
-
- return document.WithSyntaxRoot(newRoot);
- }
- }
-}
\ No newline at end of file