Skip to content

Commit

Permalink
Merge pull request #1 from code-cracker/master
Browse files Browse the repository at this point in the history
update
  • Loading branch information
kindermannhubert authored Dec 6, 2016
2 parents 0e2adc0 + 285c2d1 commit abe4d5d
Show file tree
Hide file tree
Showing 44 changed files with 1,613 additions and 91 deletions.
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Change Log

## [v1.0.1](https://github.com/code-cracker/code-cracker/tree/v1.0.1) (2016-09-06)
[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0...v1.0.1)

**Implemented enhancements:**

- Auto generated files detection [\#773](https://github.com/code-cracker/code-cracker/issues/773)

**Fixed bugs:**

- Bug: "UseStaticRegexIsMatchAnalyzer" causes an exception \(CC0081\) [\#822](https://github.com/code-cracker/code-cracker/issues/822)
- CC0006 could break code when changing to foreach [\#814](https://github.com/code-cracker/code-cracker/issues/814)
- BUG: Make readonly \(CC0052\) is incorrectly raised if constructor shows up after member that uses the field [\#812](https://github.com/code-cracker/code-cracker/issues/812)
- Bug: ArgumentNullException on CallExtensionMethodAsExtensionAnalyzer \(CC0026\) [\#810](https://github.com/code-cracker/code-cracker/issues/810)
- BUG: GC.SuppressFinalize with arrow methods \(CC0029\) [\#809](https://github.com/code-cracker/code-cracker/issues/809)
- Bug: CC0039 False positive when concatenating to loop variable propery/field \(StringBuilderInLoop\) [\#797](https://github.com/code-cracker/code-cracker/issues/797)
- Bug: CC0033 appears again after adding 'this' keyword [\#795](https://github.com/code-cracker/code-cracker/issues/795)
- CC0061: Implementing interface using async [\#793](https://github.com/code-cracker/code-cracker/issues/793)
- CC0052 Make field readonly does not take ref out into consideration. [\#788](https://github.com/code-cracker/code-cracker/issues/788)
- BUG: CallExtensionMethodAsExtensionAnalyzer threw exception when project language was C\# 5.0 [\#781](https://github.com/code-cracker/code-cracker/issues/781)
- Bug: UseInvokeMethodToFireEventAnalyzer \(CC0031\) should not raise a diagnostic when already checked for null with a ternary [\#779](https://github.com/code-cracker/code-cracker/issues/779)
- BUG: GC.SuppressFinalize within any block \(CC0029\) [\#776](https://github.com/code-cracker/code-cracker/issues/776)
- BUG: CC0052 \(Make readonly\) should not be applied to complex value types [\#775](https://github.com/code-cracker/code-cracker/issues/775)
- BUG: CC0030 should not try to make a pointer const [\#774](https://github.com/code-cracker/code-cracker/issues/774)

**Closed issues:**

- Verify impact of upgrading to Roslyn 1.1 [\#770](https://github.com/code-cracker/code-cracker/issues/770)

## [v1.0.0](https://github.com/code-cracker/code-cracker/tree/v1.0.0) (2016-04-03)
[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc6...v1.0.0)

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ msbuild

Then add a reference to CodeCracker.dll from within the Analyzers node inside References, in Visual Studio.

## SonarQube Plugin

CodeCracker has a SonarQube Plugin that can downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins).

## Contributing

Questions, comments, bug reports, and pull requests are all welcome.
Expand Down
2 changes: 1 addition & 1 deletion src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="CodeCracker.Vsix..5b99e64c-1418-4a06-990c-fd4cf01f4f63" Version="1.0.0.15" Language="en-US" Publisher="Code Cracker"/>
<Identity Id="CodeCracker.Vsix..5b99e64c-1418-4a06-990c-fd4cf01f4f63" Version="1.1.0" Language="en-US" Publisher="Code Cracker"/>
<DisplayName>Code Cracker for C#</DisplayName>
<Description xml:space="preserve">An analyzer library for C# that uses Roslyn to produce refactorings, code analysis, and other niceties.
Check the official project site on code-cracker.github.io.
Expand Down
4 changes: 4 additions & 0 deletions src/CSharp/CodeCracker/CodeCracker.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
<Compile Include="Design\InconsistentAccessibility\InconsistentAccessibilityInPropertyType.cs" />
<Compile Include="Design\MakeMethodStaticAnalyzer.cs" />
<Compile Include="Design\MakeMethodStaticCodeFixProvider.cs" />
<Compile Include="Design\SwitchWithoutDefaultAnalyzer.cs" />
<Compile Include="Design\SwitchWithoutDefaultCodeFixProvider.cs" />
<Compile Include="Extensions\CSharpAnalyzerExtensions.cs" />
<Compile Include="Extensions\CSharpGeneratedCodeAnalysisExtensions.cs" />
<Compile Include="Extensions\InitializerState.cs" />
Expand Down Expand Up @@ -83,6 +85,8 @@
<Compile Include="Style\ConsoleWriteLineCodeFixProvider.cs" />
<Compile Include="Style\StringFormatFixAllProvider.cs" />
<Compile Include="Style\SwitchToAutoPropCodeFixAllProvider.cs" />
<Compile Include="Style\UnnecessaryToStringInStringConcatenationAnalyzer.cs" />
<Compile Include="Style\UnnecessaryToStringInStringConcatenationCodeFixProvider.cs" />
<Compile Include="Style\UseEmptyStringAnalyzer.cs" />
<Compile Include="Style\UseEmptyStringCodeFixProvider.cs" />
<Compile Include="Style\UseEmptyStringCodeFixProviderAll.cs" />
Expand Down
3 changes: 2 additions & 1 deletion src/CSharp/CodeCracker/CodeCracker.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
<metadata>
<id>codecracker.CSharp</id>
<version>1.0.0</version>
<version>1.1.0</version>
<title>CodeCracker for C#</title>
<authors>giggio,elemarjr,carloscds</authors>
<owners>giggio,elemarjr,carloscds</owners>
Expand All @@ -19,6 +19,7 @@ This is a community project, free and open source. Everyone is invited to contri
<frameworkAssemblies>
<frameworkAssembly assemblyName="System" targetFramework="" />
</frameworkAssemblies>
<developmentDependency>true</developmentDependency>
</metadata>
<files>
<file src="bin\release\*.dll" target="analyzers\dotnet\cs" exclude="**\Microsoft.CodeAnalysis.*;**\System.Collections.Immutable.*;**\System.Reflection.Metadata.*;**\System.Composition.*" />
Expand Down
12 changes: 2 additions & 10 deletions src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,8 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context)

var semanticModel = context.SemanticModel;
var methodSymbol = semanticModel.GetDeclaredSymbol(method);
var theClass = methodSymbol.ContainingType;
if (theClass.TypeKind == TypeKind.Interface) return;

var interfaceMembersWithSameName = theClass.AllInterfaces.SelectMany(i => i.GetMembers(methodSymbol.Name));
foreach (var memberSymbol in interfaceMembersWithSameName)
{
if (memberSymbol.Kind != SymbolKind.Method) continue;
var implementation = theClass.FindImplementationForInterfaceMember(memberSymbol);
if (implementation != null && implementation.Equals(methodSymbol)) return;
}
if (methodSymbol == null) return;
if (methodSymbol.IsImplementingInterface()) return;

if (method.Body == null)
{
Expand Down
66 changes: 66 additions & 0 deletions src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;


namespace CodeCracker.CSharp.Design
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class SwitchWithoutDefaultAnalyzer : DiagnosticAnalyzer
{
internal const string Title = "Your Switch maybe include default clause";
internal const string MessageFormat = "{0}";
internal const string Category = SupportedCategories.Design;
internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
DiagnosticId.SwitchCaseWithoutDefault.ToDiagnosticId(),
Title,
MessageFormat,
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.SwitchCaseWithoutDefault));

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(Analyzer, SyntaxKind.SwitchStatement);

private static void Analyzer(SyntaxNodeAnalysisContext context)
{
if (context.IsGenerated()) return;
// checks if the compile error CS0151 it has fired.If Yes, don't report the diagnostic
var diagnostics = from dia in context.SemanticModel.GetDiagnostics()
where dia.Id == "CS0151"
select dia;
if (diagnostics.Any()) return;
if (context.Node.IsKind(SyntaxKind.SwitchStatement))
{
var switchStatementToAnalyse = (SwitchStatementSyntax)context.Node;
if (switchStatementToAnalyse.DescendantNodes().Where(n => n.Kind() == SyntaxKind.DefaultSwitchLabel).ToList().Count == 0)
{
var hasInitializer = from nodes in switchStatementToAnalyse.DescendantNodes()
where nodes.Kind() == SyntaxKind.IdentifierName
select nodes;
if (!hasInitializer.Any())
return;
var hasTrueExpression = from nodes in switchStatementToAnalyse.DescendantNodes()
where nodes.Kind() == SyntaxKind.FalseLiteralExpression
select nodes;
var hasfalseExpression = from nodes in switchStatementToAnalyse.DescendantNodes()
where nodes.Kind() == SyntaxKind.TrueLiteralExpression
select nodes;
if ((hasfalseExpression.Any()) && (hasTrueExpression.Any()))
return;
var diagnostic = Diagnostic.Create(Rule, switchStatementToAnalyse.GetLocation(), "Consider put an default clause in Switch.");
context.ReportDiagnostic(diagnostic);
}
}
}
}
}
121 changes: 121 additions & 0 deletions src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace CodeCracker.CSharp.Design
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(SwitchWithoutDefaultCodeFixProvider)), Shared]
public class SwitchWithoutDefaultCodeFixProvider : CodeFixProvider
{
private const string EmptyString = "\"\"";
private const string BreakString = "\n\t\t\t\t\tbreak;";
private const string ThrowString = "throw new Exception(\"Unexpected Case\");";
public sealed override ImmutableArray<string> FixableDiagnosticIds =>
ImmutableArray.Create(DiagnosticId.SwitchCaseWithoutDefault.ToDiagnosticId());
public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var diagnostic = context.Diagnostics.First();
context.RegisterCodeFix(CodeAction.Create("Add a default clause", c => SwitchWithoutDefaultAsync(context.Document, diagnostic, c),
nameof(SwitchWithoutDefaultCodeFixProvider)), diagnostic);
return Task.FromResult(0);
}

private async static Task<Document> SwitchWithoutDefaultAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var switchCaseLabel = new SyntaxList<SwitchLabelSyntax>();
var kindOfVariable = string.Empty;
var idForVariable = string.Empty;
var breakStatement = new SyntaxList<StatementSyntax>();
var diagnosticSpan = diagnostic.Location.SourceSpan;
var newSections = new List<SwitchSectionSyntax>();
var switchCaseStatement = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<SwitchStatementSyntax>().First();
idForVariable = ((IdentifierNameSyntax)switchCaseStatement.ChildNodes().ToList().First(n => n.Kind() == SyntaxKind.IdentifierName)).Identifier.ValueText;
var parametersOfMethod = from init in root.DescendantNodesAndSelf()
where init.Kind() == SyntaxKind.Parameter
select init;
// Verify if the variable of Switch as a same of Method Parameter
foreach (var parameter in parametersOfMethod)
if (idForVariable == ((ParameterSyntax)parameter).Identifier.ValueText)
kindOfVariable = ((ParameterSyntax)parameter).Type.ToString();

if (kindOfVariable == string.Empty)
{
var statements = ((BlockSyntax)switchCaseStatement.Parent).Statements;
var inicializerOfSwitch = from init in statements
where init.Kind() == SyntaxKind.LocalDeclarationStatement
select init;
if (inicializerOfSwitch.Any())
{
var local = (LocalDeclarationStatementSyntax)inicializerOfSwitch.First();
var switchCaseVariable = ((local).Declaration).Variables[0];
kindOfVariable = ((LiteralExpressionSyntax)(switchCaseVariable.Initializer.Value)).Kind().ToString();
}
}

if ((kindOfVariable.Equals("FalseLiteralExpression")) || (kindOfVariable.Equals("TrueLiteralExpression"))
|| (kindOfVariable.Equals("bool")))
{
var oldSections = switchCaseStatement.Sections.ToList();
var type = string.Empty;
foreach (var sec in oldSections)
{
newSections.Add(sec);
type = (((CaseSwitchLabelSyntax)((SwitchSectionSyntax)sec).ChildNodes().ToList().First()).Value).GetFirstToken().Text;
}
var againstType = string.Empty;
if (type.Equals("true")) againstType = "false"; else againstType = "true";

newSections.Add(SyntaxFactory.SwitchSection().WithLabels(
switchCaseLabel.Add(SyntaxFactory.CaseSwitchLabel(SyntaxFactory.ParseExpression(againstType)))).
WithStatements(breakStatement.Add(SyntaxFactory.ParseStatement(BreakString))));
}
else
{
var oldSections = switchCaseStatement.Sections.ToList();
foreach (var sec in oldSections)
newSections.Add(sec);

breakStatement = breakStatement.Add(SyntaxFactory.ParseStatement(BreakString));
newSections.Add(CreateSection(SyntaxFactory.DefaultSwitchLabel(), SyntaxFactory.ParseStatement(ThrowString)));
}
var switchExpression = SyntaxFactory.ParseExpression(idForVariable);
var newsSwitchCaseStatement = SyntaxFactory.SwitchStatement(switchExpression).
WithSections(new SyntaxList<SwitchSectionSyntax>().AddRange(newSections));
var newRoot = root.ReplaceNode(switchCaseStatement, newsSwitchCaseStatement);
var newDocument = document.WithSyntaxRoot(newRoot);
return newDocument;
}
static SwitchSectionSyntax CreateSection(SwitchLabelSyntax label, StatementSyntax statement)
{
var labels = new SyntaxList<SwitchLabelSyntax>();
labels = labels.Add(label);
return SyntaxFactory.SwitchSection(labels, CreateSectionStatements(statement));
}

static SyntaxList<StatementSyntax> CreateSectionStatements(StatementSyntax source)
{
var result = new SyntaxList<StatementSyntax>();
if (source is BlockSyntax)
{
var block = source as BlockSyntax;
result = result.AddRange(block.Statements);
}
else
{
result = result.Add(source);
}
return result;
}
}
}
Loading

0 comments on commit abe4d5d

Please sign in to comment.