From 50d099029200892026093d0d2e70e1023c7fc75e Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 2 Oct 2015 22:31:27 -0300 Subject: [PATCH 001/358] Add changelog --- CHANGELOG.md | 280 ++++++++++++++++++++++++++++++++++++++++++++++++ CodeCracker.sln | 3 +- 2 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..1c62a35b6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,280 @@ +# Change Log + +## [v1.0.0-rc3](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc3) (2015-10-03) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc2...v1.0.0-rc3) + +**Implemented enhancements:** + +- CC0013 Should be Information instead of Warning [\#520](https://github.com/code-cracker/code-cracker/issues/520) +- Extract Class to a New File [\#382](https://github.com/code-cracker/code-cracker/issues/382) +- Seal member if possible [\#372](https://github.com/code-cracker/code-cracker/issues/372) +- Remove virtual modifier if possible [\#371](https://github.com/code-cracker/code-cracker/issues/371) +- Remove async and return task directly [\#151](https://github.com/code-cracker/code-cracker/issues/151) +- Change from as operator to direct cast or the opposite [\#65](https://github.com/code-cracker/code-cracker/issues/65) +- Convert loop to linq expression [\#22](https://github.com/code-cracker/code-cracker/issues/22) + +**Fixed bugs:** + +- CC0017 Change to auto property codefix removes multiple variable declaration. [\#512](https://github.com/code-cracker/code-cracker/issues/512) +- CC0017 Change to auto property ignores field assignment. [\#500](https://github.com/code-cracker/code-cracker/issues/500) +- CC047 eats property trivia [\#492](https://github.com/code-cracker/code-cracker/issues/492) +- CC0091 makes static keyword come before trivia [\#486](https://github.com/code-cracker/code-cracker/issues/486) +- Useles suggestion of CC0039 rule [\#485](https://github.com/code-cracker/code-cracker/issues/485) +- CC0013 \(user ternary\) rule should be more careful with nullable types \(C\#\) [\#480](https://github.com/code-cracker/code-cracker/issues/480) +- CC0091 \(make method static\) Reported Incorrectly for explicitly implemented interface [\#479](https://github.com/code-cracker/code-cracker/issues/479) +- CC0068 \(method not used\) Reported Incorrectly for explicitly implemented interface [\#478](https://github.com/code-cracker/code-cracker/issues/478) +- Add additional checks for determining if generated code [\#476](https://github.com/code-cracker/code-cracker/issues/476) +- CC0013 & CC0014 for VB is reported in generated code [\#472](https://github.com/code-cracker/code-cracker/issues/472) +- CC0068 Reported Incorrectly for VB Event Handlers [\#469](https://github.com/code-cracker/code-cracker/issues/469) +- Bug on DisposableVariableNotDisposedAnalyzer \(CC0022\) when returning a disposable [\#466](https://github.com/code-cracker/code-cracker/issues/466) +- Bug on analyzer CC0031 \(UseInvokeMethodToFireEvent\) on parameterized functor [\#397](https://github.com/code-cracker/code-cracker/issues/397) +- BUG: Create code fix for update ReadonlyFieldCodeFixProvider so that the code does not break on public fields [\#293](https://github.com/code-cracker/code-cracker/issues/293) + +## [v1.0.0-rc2](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc2) (2015-08-19) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc1...v1.0.0-rc2) + +**Implemented enhancements:** + +- Update VB Allow Members Ordering to work with Modules [\#440](https://github.com/code-cracker/code-cracker/issues/440) +- Provide an equivalence key on all code fix providers [\#417](https://github.com/code-cracker/code-cracker/issues/417) +- Unit test methods raises CC0091 - "Make \ method static" [\#404](https://github.com/code-cracker/code-cracker/issues/404) +- Validate color from System.Drawing.ColorTranslator.FromHtml [\#1](https://github.com/code-cracker/code-cracker/issues/1) + +**Fixed bugs:** + +- Erroneous CC0039 message [\#461](https://github.com/code-cracker/code-cracker/issues/461) +- CC0029 DisposablesShouldCallSuppressFinalizeAnalyzer throws InvalidCastException [\#452](https://github.com/code-cracker/code-cracker/issues/452) +- Doc comments for parameters in wrong order \(XmlDocumentationCreateMissingParametersCodeFixProvider\) [\#437](https://github.com/code-cracker/code-cracker/issues/437) +- CC0022 disposable intantiation on constructor call [\#432](https://github.com/code-cracker/code-cracker/issues/432) +- CC0017 Change to auto property has Incorrect description [\#429](https://github.com/code-cracker/code-cracker/issues/429) +- BUG in CC0061 when the method is a override from a base class [\#424](https://github.com/code-cracker/code-cracker/issues/424) +- CC0021: nameof\(x\) suggested before x is declared \(VB\) [\#420](https://github.com/code-cracker/code-cracker/issues/420) +- Bug: RemoveUnusedVariablesCodeFixProvider is throwing on CatchDeclarations [\#419](https://github.com/code-cracker/code-cracker/issues/419) +- CC064 invalid error [\#418](https://github.com/code-cracker/code-cracker/issues/418) +- BUG: XmlDocumentationCreateMissingParametersCodeFixProvider throws when there are only remarks [\#412](https://github.com/code-cracker/code-cracker/issues/412) +- Bug: DisposableVariableNotDisposedCodeFixProvider throws when object creation is being passed as an argument \(CC0022\) [\#409](https://github.com/code-cracker/code-cracker/issues/409) +- CC0021: nameof\(x\) suggested before x is declared [\#408](https://github.com/code-cracker/code-cracker/issues/408) + +## [v1.0.0-rc1](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc1) (2015-07-23) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-beta1...v1.0.0-rc1) + +**Implemented enhancements:** + +- Verify if xml docs have the correct parameters [\#357](https://github.com/code-cracker/code-cracker/issues/357) + +**Fixed bugs:** + +- BUG: CopyEventToVariableBeforeFireCodeFixProvider throwing [\#411](https://github.com/code-cracker/code-cracker/issues/411) +- Incorrect spacing in string interpolation \(CC0048\) [\#410](https://github.com/code-cracker/code-cracker/issues/410) + +## [v1.0.0-beta1](https://github.com/code-cracker/code-cracker/tree/v1.0.0-beta1) (2015-07-04) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-alpha6...v1.0.0-beta1) + +**Implemented enhancements:** + +- Make method non async \(fix for CS1998\) [\#393](https://github.com/code-cracker/code-cracker/issues/393) +- Using the refactoring for CC0008 will result in a warning CC0015 [\#383](https://github.com/code-cracker/code-cracker/issues/383) +- Add string interpolation to Console.WriteLine [\#380](https://github.com/code-cracker/code-cracker/issues/380) +- Make method static if possible [\#364](https://github.com/code-cracker/code-cracker/issues/364) +- Update all existing code fixes that are doing too much work on RegisterCodeFixesAsync \(C\#\) [\#347](https://github.com/code-cracker/code-cracker/issues/347) +- Make accessibility consistent \(code fix for CS0051\) [\#321](https://github.com/code-cracker/code-cracker/issues/321) +- Expand CC0006 \(change for into a foreach\) [\#318](https://github.com/code-cracker/code-cracker/issues/318) +- Convert a "Not Any" query for a condition to a "All" query for the inverted condition [\#31](https://github.com/code-cracker/code-cracker/issues/31) + +**Fixed bugs:** + +- Ignore Disposables created on return statements [\#399](https://github.com/code-cracker/code-cracker/issues/399) +- Null Reference Exception on CodeCracker.CSharp.Usage.VirtualMethodOnConstructorAnalyzer [\#398](https://github.com/code-cracker/code-cracker/issues/398) +- Bug on ObjectInitializerCodeFixProvider when constructor already has initialization [\#396](https://github.com/code-cracker/code-cracker/issues/396) +- Async method can't be used with RegisterXXXXAction. [\#375](https://github.com/code-cracker/code-cracker/issues/375) +- Bug on CC0068 \(RemovePrivateMethodNeverUsed\) with Main [\#368](https://github.com/code-cracker/code-cracker/issues/368) +- Bug in CC0008 when used together with null coalescing operator ?? [\#366](https://github.com/code-cracker/code-cracker/issues/366) +- Bug: nameof analyzer \(CC0021\) being raised on self referencing initialization statement [\#359](https://github.com/code-cracker/code-cracker/issues/359) + +## [v1.0.0-alpha6](https://github.com/code-cracker/code-cracker/tree/v1.0.0-alpha6) (2015-06-01) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-alpha5...v1.0.0-alpha6) + +**Implemented enhancements:** + +- Remove redundant else [\#355](https://github.com/code-cracker/code-cracker/issues/355) +- Use "" instead of String.Empty [\#354](https://github.com/code-cracker/code-cracker/issues/354) +- Port changes from CC0021 \(nameof\) to VB [\#341](https://github.com/code-cracker/code-cracker/issues/341) +- Incorrect string.Format usage [\#335](https://github.com/code-cracker/code-cracker/issues/335) +- Expand NameOf Analyzer to work with any identifier in scope [\#263](https://github.com/code-cracker/code-cracker/issues/263) +- Test NameOfCodeFixProvider with keyword [\#198](https://github.com/code-cracker/code-cracker/issues/198) +- Use String.Empty instead "" [\#120](https://github.com/code-cracker/code-cracker/issues/120) +- Use auto property when possible [\#12](https://github.com/code-cracker/code-cracker/issues/12) +- Supress assignment of default value to field/property declarations [\#9](https://github.com/code-cracker/code-cracker/issues/9) + +**Fixed bugs:** + +- Bug on CallExtensionMethodAsExtensionAnalyzer \(CC0026\) throwing InvalidOperationException [\#345](https://github.com/code-cracker/code-cracker/issues/345) +- Bug on CC0068 \(RemovePrivateMethodNeverUsed\) with generic methods [\#343](https://github.com/code-cracker/code-cracker/issues/343) +- BUG: CC0056 Incorrectly classifying format strings [\#333](https://github.com/code-cracker/code-cracker/issues/333) +- CC0056 Incorrectly classifying format strings. [\#330](https://github.com/code-cracker/code-cracker/issues/330) + +## [v1.0.0-alpha5](https://github.com/code-cracker/code-cracker/tree/v1.0.0-alpha5) (2015-04-26) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-alpha4...v1.0.0-alpha5) + +**Implemented enhancements:** + +- Create infrastructure for testing multi culture values [\#313](https://github.com/code-cracker/code-cracker/issues/313) +- View lines covered by tests in coverwalls [\#304](https://github.com/code-cracker/code-cracker/issues/304) +- Regex performance: use static Regex.IsMatch [\#297](https://github.com/code-cracker/code-cracker/issues/297) +- Don't run CodeCracker on generated code [\#260](https://github.com/code-cracker/code-cracker/issues/260) +- Virtual method call in constructor [\#203](https://github.com/code-cracker/code-cracker/issues/203) +- Merge nested if statements [\#131](https://github.com/code-cracker/code-cracker/issues/131) +- Split 'if' with '&&' condition into nested 'if'-statements [\#130](https://github.com/code-cracker/code-cracker/issues/130) +- Convert numeric literal from decimal to hex and hex to decimal [\#119](https://github.com/code-cracker/code-cracker/issues/119) +- Compute value of an expression and replaces it whenever it's possible [\#117](https://github.com/code-cracker/code-cracker/issues/117) +- Check arguments in String.Format [\#116](https://github.com/code-cracker/code-cracker/issues/116) +- ArgumentExceptionAnalyzer ignores several code constructs [\#112](https://github.com/code-cracker/code-cracker/issues/112) +- Remove unused variables [\#23](https://github.com/code-cracker/code-cracker/issues/23) + +**Fixed bugs:** + +- Bug in CC0008 analyser for variable access. [\#324](https://github.com/code-cracker/code-cracker/issues/324) +- Bug: CC0022 being raised on using when not assigned [\#319](https://github.com/code-cracker/code-cracker/issues/319) +- Visual studio crash on initializer refactoring \(CC0009\) [\#315](https://github.com/code-cracker/code-cracker/issues/315) +- NameOf produces wrong results/ [\#309](https://github.com/code-cracker/code-cracker/issues/309) +- Bug on Unused parameter \(CC0057\) not checking for assignment [\#291](https://github.com/code-cracker/code-cracker/issues/291) +- BUG: Method not used \(CC0068\) fails to check partial classes [\#290](https://github.com/code-cracker/code-cracker/issues/290) +- Bug on CC0026 \(use extension method\) where selected overload would change [\#262](https://github.com/code-cracker/code-cracker/issues/262) +- Null Reference BUG on ConvertToExpressionBodiedMemberAnalyzer \(CC0038\) [\#192](https://github.com/code-cracker/code-cracker/issues/192) +- CC0029 should not be reported for some types with private constructors [\#110](https://github.com/code-cracker/code-cracker/issues/110) +- CC0029 should not be reported for some sealed types [\#109](https://github.com/code-cracker/code-cracker/issues/109) +- CC0029 should not be reported for structs [\#108](https://github.com/code-cracker/code-cracker/issues/108) +- CC0029 should not be reported for Dispose\(bool\) [\#107](https://github.com/code-cracker/code-cracker/issues/107) +- Fix analysis for CC0029 \(DisposablesShouldCallSuppressFinalizeAnalyzer\) [\#95](https://github.com/code-cracker/code-cracker/issues/95) + +## [v1.0.0-alpha4](https://github.com/code-cracker/code-cracker/tree/v1.0.0-alpha4) (2015-03-04) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-alpha3...v1.0.0-alpha4) + +**Implemented enhancements:** + +- Update to Roslyn RC1 and VS 2015 CTP 6 [\#288](https://github.com/code-cracker/code-cracker/issues/288) +- Review AllowMembersOrderingCodeFixProvider.Base to avoid running analyzis on ComputeFixesAsync method [\#273](https://github.com/code-cracker/code-cracker/issues/273) +- Add braces to switch case [\#252](https://github.com/code-cracker/code-cracker/issues/252) +- Unify DiagnosticId class on a separate assembly [\#248](https://github.com/code-cracker/code-cracker/issues/248) +- If method does not return a Task it shouldn't end with "Async" [\#245](https://github.com/code-cracker/code-cracker/issues/245) +- Use enum for diagnostic ids \(VB\) [\#244](https://github.com/code-cracker/code-cracker/issues/244) +- Introduce field from constructor [\#241](https://github.com/code-cracker/code-cracker/issues/241) +- Remove private method is never used in a class [\#204](https://github.com/code-cracker/code-cracker/issues/204) +- Detect read-only not private fields and fix adding the "readonly" modifier [\#177](https://github.com/code-cracker/code-cracker/issues/177) +- Convert Lambda to Method Group whenever it's possible [\#49](https://github.com/code-cracker/code-cracker/issues/49) +- Review Rules ID and Descriptions [\#41](https://github.com/code-cracker/code-cracker/issues/41) +- Remove unreachable code [\#21](https://github.com/code-cracker/code-cracker/issues/21) + +**Fixed bugs:** + +- RemovePrivateMethodNeverUsedAnalyzer \(CC0068\) throwing cast exception [\#276](https://github.com/code-cracker/code-cracker/issues/276) +- Bug on CC0071 \(introduce field\) for fix all [\#267](https://github.com/code-cracker/code-cracker/issues/267) +- BUG on CC0071 \(introduce field\), name clash [\#266](https://github.com/code-cracker/code-cracker/issues/266) +- BUG on CC0021 \(NameOf\) when using attribute [\#258](https://github.com/code-cracker/code-cracker/issues/258) +- CC0031 Formatting bug on comments [\#257](https://github.com/code-cracker/code-cracker/issues/257) +- Bug on CC0065, entire summary removed. [\#256](https://github.com/code-cracker/code-cracker/issues/256) +- CC0022 Batch Fixer does not work in edge cases [\#253](https://github.com/code-cracker/code-cracker/issues/253) +- BUG on CC0057 \(UnusedParameter\) on constructor that passes argument to base [\#251](https://github.com/code-cracker/code-cracker/issues/251) +- Bug in string interpolation \(CC0048\) when Insert uses a ternary operator [\#249](https://github.com/code-cracker/code-cracker/issues/249) + +## [v1.0.0-alpha3](https://github.com/code-cracker/code-cracker/tree/v1.0.0-alpha3) (2015-02-01) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-alpha2...v1.0.0-alpha3) + +**Implemented enhancements:** + +- Use ConfigureAwait\(false\) on awaited task [\#235](https://github.com/code-cracker/code-cracker/issues/235) +- CTP5 nuget "The assembly \<...\> does not contain any analyzers" [\#229](https://github.com/code-cracker/code-cracker/issues/229) +- Use enum for diagnostic ids [\#228](https://github.com/code-cracker/code-cracker/issues/228) +- Change verbatim string.format to use string interpolation [\#220](https://github.com/code-cracker/code-cracker/issues/220) +- Update CC to use VS 2015 CTP 5 [\#219](https://github.com/code-cracker/code-cracker/issues/219) +- Build with PSake and kill \(almost\) all scripts [\#215](https://github.com/code-cracker/code-cracker/issues/215) +- Remove trailling whitespace [\#201](https://github.com/code-cracker/code-cracker/issues/201) +- Validate IPAddress.Parse from System.Net [\#188](https://github.com/code-cracker/code-cracker/issues/188) +- Validade Uri from System.Uri [\#182](https://github.com/code-cracker/code-cracker/issues/182) +- Interfaces should start with an "I" [\#179](https://github.com/code-cracker/code-cracker/issues/179) +- If method returns a Task it should have the postfix "Async" [\#178](https://github.com/code-cracker/code-cracker/issues/178) +- Offer a fix for ordering members inside classes and structs following StyleCop patterns [\#172](https://github.com/code-cracker/code-cracker/issues/172) +- Abstract class ctors should not have public constructors [\#164](https://github.com/code-cracker/code-cracker/issues/164) +- Update string interpolation to use new version [\#146](https://github.com/code-cracker/code-cracker/issues/146) +- Allow formating on string interpolation substitutions of string.format [\#145](https://github.com/code-cracker/code-cracker/issues/145) +- Run Analysis on a large OSS project and make sure it does not throw [\#100](https://github.com/code-cracker/code-cracker/issues/100) +- Add code coverage metrics [\#99](https://github.com/code-cracker/code-cracker/issues/99) +- Update all analyzers to use the supported categories [\#97](https://github.com/code-cracker/code-cracker/issues/97) +- Detect read-only private fields and fix adding the "readonly" modifier [\#86](https://github.com/code-cracker/code-cracker/issues/86) +- Offer diagnostic to allow for ordering members inside classes and structs [\#76](https://github.com/code-cracker/code-cracker/issues/76) +- Excess parameters in methods [\#44](https://github.com/code-cracker/code-cracker/issues/44) +- Suggest use of stringbuilder when you have a while loop [\#34](https://github.com/code-cracker/code-cracker/issues/34) +- Private set by default for automatic properties [\#32](https://github.com/code-cracker/code-cracker/issues/32) +- Class that has IDisposable fields should implement IDisposable and dispose those fields [\#30](https://github.com/code-cracker/code-cracker/issues/30) +- IDisposable not assigned to a field is not being disposed [\#28](https://github.com/code-cracker/code-cracker/issues/28) +- Remove unused parameters [\#24](https://github.com/code-cracker/code-cracker/issues/24) +- Validate Json when used with Json.NET [\#2](https://github.com/code-cracker/code-cracker/issues/2) + +**Fixed bugs:** + +- BUG on string interpolation when indexes are inverted [\#246](https://github.com/code-cracker/code-cracker/issues/246) +- BUG on CC0049, simplify boolean comparison, not simmetric [\#238](https://github.com/code-cracker/code-cracker/issues/238) +- False positive on CC0049 \("You can remove this comparison"\) [\#236](https://github.com/code-cracker/code-cracker/issues/236) +- BUG on CC0032/3: DisposableFieldNotDisposedAnalyzer throwing when Dispose is abstract [\#227](https://github.com/code-cracker/code-cracker/issues/227) +- BUG on CC0012: RethrowExceptionAnalyzer throwing "Sequence contains no elements" [\#226](https://github.com/code-cracker/code-cracker/issues/226) +- BUG on CC0026: When there is a dynamic don't raise a diagnostic [\#225](https://github.com/code-cracker/code-cracker/issues/225) +- CC0029 should be reported for explicit IDisposable.Dispose implementation [\#222](https://github.com/code-cracker/code-cracker/issues/222) +- BUG on PrivateSetAnalyzer when there are no accessors [\#217](https://github.com/code-cracker/code-cracker/issues/217) +- BUG on UriAnalyzer when analyzing an expression [\#209](https://github.com/code-cracker/code-cracker/issues/209) +- BUG on ReadonlyFieldAnalyzer \(CC0052\) when analyzing partial classes [\#194](https://github.com/code-cracker/code-cracker/issues/194) +- Null Reference BUG on ForInArrayAnalyzer \(CC0006\) [\#193](https://github.com/code-cracker/code-cracker/issues/193) +- InvalidCastException in CC0016 and CC0031 [\#175](https://github.com/code-cracker/code-cracker/issues/175) +- Bug: CC0030 changes nullable type to const [\#167](https://github.com/code-cracker/code-cracker/issues/167) +- BUG: CC0009 \(from ObjectInitializerAnalyzer\) not being generated [\#165](https://github.com/code-cracker/code-cracker/issues/165) +- BUG on CC0047 \(private set\) should not report diagnostic when the property is being referenced outside the class [\#159](https://github.com/code-cracker/code-cracker/issues/159) + +## [v1.0.0-alpha2](https://github.com/code-cracker/code-cracker/tree/v1.0.0-alpha2) (2014-12-15) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-alpha1...v1.0.0-alpha2) + +**Implemented enhancements:** + +- Change verbatim string from refactoring to Hidden diagnostic + code fix [\#161](https://github.com/code-cracker/code-cracker/issues/161) +- Modify CC0037 to make set accessor private when that have code [\#150](https://github.com/code-cracker/code-cracker/issues/150) +- Change from string.Format to string interpolation [\#133](https://github.com/code-cracker/code-cracker/issues/133) +- Simplify redundant Boolean comparisons [\#124](https://github.com/code-cracker/code-cracker/issues/124) +- Convert method body to expression bodied member when applicable [\#101](https://github.com/code-cracker/code-cracker/issues/101) +- Remove commented code [\#98](https://github.com/code-cracker/code-cracker/issues/98) +- Invert loop for 0..n and n..0 [\#87](https://github.com/code-cracker/code-cracker/issues/87) +- Make a variable const whenever it's possible [\#79](https://github.com/code-cracker/code-cracker/issues/79) +- Check null on event to avoid race condition when invoking it [\#61](https://github.com/code-cracker/code-cracker/issues/61) +- Struct vs. Keyword [\#59](https://github.com/code-cracker/code-cracker/issues/59) +- Detect direct event invocation [\#55](https://github.com/code-cracker/code-cracker/issues/55) +- Create a build server and build every push and pull request [\#53](https://github.com/code-cracker/code-cracker/issues/53) +- Suggest nameof when encounter a string with the same name of a parameter [\#40](https://github.com/code-cracker/code-cracker/issues/40) +- Suggest switch if you have 3 or more nested if / else statements [\#39](https://github.com/code-cracker/code-cracker/issues/39) +- Call extension method as an extension [\#27](https://github.com/code-cracker/code-cracker/issues/27) +- Empty Catch block not allowed [\#15](https://github.com/code-cracker/code-cracker/issues/15) +- Remove empty object initializers [\#14](https://github.com/code-cracker/code-cracker/issues/14) +- Use existence ?. operator when possible in expressions [\#13](https://github.com/code-cracker/code-cracker/issues/13) +- Remove unnecessary parenthesis from class initialization [\#11](https://github.com/code-cracker/code-cracker/issues/11) +- Use class initializer where it makes sense [\#10](https://github.com/code-cracker/code-cracker/issues/10) +- Replace if check followed by return true or false [\#8](https://github.com/code-cracker/code-cracker/issues/8) +- On Linq clauses move predicate from Where to First, Single, etc when applicable [\#6](https://github.com/code-cracker/code-cracker/issues/6) +- Always use var [\#4](https://github.com/code-cracker/code-cracker/issues/4) + +**Fixed bugs:** + +- BUG when using "use string interpolation" code fix with string that contains line breaks [\#162](https://github.com/code-cracker/code-cracker/issues/162) +- Bug when running codefix for CC0031 \(UseInvokeMethodToFireEvent\) on statement without block [\#160](https://github.com/code-cracker/code-cracker/issues/160) +- Bug: Private set on props being suggested when there are inheritted members referencing [\#153](https://github.com/code-cracker/code-cracker/issues/153) +- Bug when running codefix for CC0031 \(UseInvokeMethodToFireEvent\) on parameters [\#152](https://github.com/code-cracker/code-cracker/issues/152) +- BUG when make const sees an string interpolation \(CC0030\) [\#140](https://github.com/code-cracker/code-cracker/issues/140) +- NullReferenceException in ArgumentExceptionAnalyzer [\#111](https://github.com/code-cracker/code-cracker/issues/111) +- When changing ifs to switch comments are lost [\#74](https://github.com/code-cracker/code-cracker/issues/74) +- TernaryOperatorAnalyzer throwing NullReferenceException [\#70](https://github.com/code-cracker/code-cracker/issues/70) +- Regex Analyzer/CodeFix tests ignores local culture [\#69](https://github.com/code-cracker/code-cracker/issues/69) + +## [v1.0.0-alpha1](https://github.com/code-cracker/code-cracker/tree/v1.0.0-alpha1) (2014-11-12) +**Implemented enhancements:** + +- Change if to ternary operator [\#7](https://github.com/code-cracker/code-cracker/issues/7) +- Transform for into a foreach [\#3](https://github.com/code-cracker/code-cracker/issues/3) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/CodeCracker.sln b/CodeCracker.sln index b0eef3877..0b2e60b2a 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22609.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" EndProject @@ -34,6 +34,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solution Items", ".Solutio ProjectSection(SolutionItems) = preProject .gitattributes = .gitattributes .gitignore = .gitignore + CHANGELOG.md = CHANGELOG.md README.md = README.md EndProjectSection EndProject From d303e7d534a29d940194a62d07235dd40574a1ca Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 2 Oct 2015 23:11:44 -0300 Subject: [PATCH 002/358] Remove enhancements from rc changelogs --- CHANGELOG.md | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c62a35b6..3c89cc244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,6 @@ ## [v1.0.0-rc3](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc3) (2015-10-03) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc2...v1.0.0-rc3) -**Implemented enhancements:** - -- CC0013 Should be Information instead of Warning [\#520](https://github.com/code-cracker/code-cracker/issues/520) -- Extract Class to a New File [\#382](https://github.com/code-cracker/code-cracker/issues/382) -- Seal member if possible [\#372](https://github.com/code-cracker/code-cracker/issues/372) -- Remove virtual modifier if possible [\#371](https://github.com/code-cracker/code-cracker/issues/371) -- Remove async and return task directly [\#151](https://github.com/code-cracker/code-cracker/issues/151) -- Change from as operator to direct cast or the opposite [\#65](https://github.com/code-cracker/code-cracker/issues/65) -- Convert loop to linq expression [\#22](https://github.com/code-cracker/code-cracker/issues/22) - **Fixed bugs:** - CC0017 Change to auto property codefix removes multiple variable declaration. [\#512](https://github.com/code-cracker/code-cracker/issues/512) @@ -33,13 +23,6 @@ ## [v1.0.0-rc2](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc2) (2015-08-19) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc1...v1.0.0-rc2) -**Implemented enhancements:** - -- Update VB Allow Members Ordering to work with Modules [\#440](https://github.com/code-cracker/code-cracker/issues/440) -- Provide an equivalence key on all code fix providers [\#417](https://github.com/code-cracker/code-cracker/issues/417) -- Unit test methods raises CC0091 - "Make \ method static" [\#404](https://github.com/code-cracker/code-cracker/issues/404) -- Validate color from System.Drawing.ColorTranslator.FromHtml [\#1](https://github.com/code-cracker/code-cracker/issues/1) - **Fixed bugs:** - Erroneous CC0039 message [\#461](https://github.com/code-cracker/code-cracker/issues/461) @@ -58,10 +41,6 @@ ## [v1.0.0-rc1](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc1) (2015-07-23) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-beta1...v1.0.0-rc1) -**Implemented enhancements:** - -- Verify if xml docs have the correct parameters [\#357](https://github.com/code-cracker/code-cracker/issues/357) - **Fixed bugs:** - BUG: CopyEventToVariableBeforeFireCodeFixProvider throwing [\#411](https://github.com/code-cracker/code-cracker/issues/411) @@ -202,7 +181,6 @@ - Update all analyzers to use the supported categories [\#97](https://github.com/code-cracker/code-cracker/issues/97) - Detect read-only private fields and fix adding the "readonly" modifier [\#86](https://github.com/code-cracker/code-cracker/issues/86) - Offer diagnostic to allow for ordering members inside classes and structs [\#76](https://github.com/code-cracker/code-cracker/issues/76) -- Excess parameters in methods [\#44](https://github.com/code-cracker/code-cracker/issues/44) - Suggest use of stringbuilder when you have a while loop [\#34](https://github.com/code-cracker/code-cracker/issues/34) - Private set by default for automatic properties [\#32](https://github.com/code-cracker/code-cracker/issues/32) - Class that has IDisposable fields should implement IDisposable and dispose those fields [\#30](https://github.com/code-cracker/code-cracker/issues/30) @@ -277,4 +255,4 @@ -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* From 646b27647e66551ef5cd922521c6a24455434eb7 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Sun, 13 Sep 2015 22:49:34 -0400 Subject: [PATCH 003/358] Fixes 496 --- .../Style/TernaryOperatorCodeFixProviders.vb | 74 ++++++++++++++----- .../Style/TernaryOperatorTests.vb | 49 +++++++++++- 2 files changed, 103 insertions(+), 20 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 407372a5e..e809e30db 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -12,13 +12,14 @@ Namespace Style Public Class TernaryOperatorWithReturnCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task + 'Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) Dim diagnostic = context.Diagnostics.First - Dim span = diagnostic.Location.SourceSpan - Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) - If declaration Is Nothing Then Exit Function - context.RegisterCodeFix(CodeAction.Create("Change to ternary operator", Function(c) MakeTernaryAsync(context.Document, declaration, c), NameOf(TernaryOperatorWithReturnCodeFixProvider)), diagnostic) + 'Dim span = diagnostic.Location.SourceSpan + 'Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) + 'If declaration Is Nothing Then Exit Function + context.RegisterCodeFix(CodeAction.Create("Change to ternary operator", Function(c) MakeTernaryAsync(context.Document, diagnostic, c), NameOf(TernaryOperatorWithReturnCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function Public Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = @@ -28,7 +29,12 @@ Namespace Style Return WellKnownFixAllProviders.BatchFixer End Function - Private Async Function MakeTernaryAsync(document As Document, ifBlock As MultiLineIfBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function MakeTernaryAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim span = diagnostic.Location.SourceSpan + + Dim ifBlock = root.FindToken(span.Start).Parent.FirstAncestorOrSelfOfType(Of MultiLineIfBlockSyntax) + Dim ifReturn = TryCast(ifBlock.Statements.FirstOrDefault(), ReturnStatementSyntax) Dim elseReturn = TryCast(ifBlock.ElseBlock?.Statements.FirstOrDefault(), ReturnStatementSyntax) Dim ternary = SyntaxFactory.TernaryConditionalExpression(ifBlock.IfStatement.Condition.WithoutTrailingTrivia(), @@ -39,7 +45,6 @@ Namespace Style WithAdditionalAnnotations(Formatter.Annotation) Dim returnStatement = SyntaxFactory.ReturnStatement(ternary) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken) Dim newRoot = root.ReplaceNode(ifBlock, returnStatement) Dim newDocument = document.WithSyntaxRoot(newRoot) Return newDocument @@ -50,13 +55,13 @@ Namespace Style Public Class TernaryOperatorWithAssignmentCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First - Dim span = diagnostic.Location.SourceSpan - Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) - If declaration Is Nothing Then Exit Function - context.RegisterCodeFix(CodeAction.Create("Change to ternary operator", Function(c) MakeTernaryAsync(context.Document, declaration, c), NameOf(TernaryOperatorWithAssignmentCodeFixProvider)), diagnostic) + 'Dim span = diagnostic.Location.SourceSpan + 'Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) + 'If declaration Is Nothing Then Exit Function + context.RegisterCodeFix(CodeAction.Create("Change to ternary operator", Function(c) MakeTernaryAsync(context.Document, diagnostic, c), NameOf(TernaryOperatorWithAssignmentCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function Public Overrides ReadOnly Property FixableDiagnosticIds() As ImmutableArray(Of String) = @@ -66,9 +71,28 @@ Namespace Style Return WellKnownFixAllProviders.BatchFixer End Function - Private Async Function MakeTernaryAsync(document As Document, ifBlock As MultiLineIfBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function MakeTernaryAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken) + Dim ifBlock = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) + Dim ifAssign = TryCast(ifBlock.Statements.FirstOrDefault(), AssignmentStatementSyntax) Dim elseAssign = TryCast(ifBlock.ElseBlock?.Statements.FirstOrDefault(), AssignmentStatementSyntax) + + Dim assignment As AssignmentStatementSyntax + If ifAssign.Left.Kind = SyntaxKind.IdentifierName Then + assignment = CreateIdentifier(ifBlock, ifAssign, elseAssign) + ElseIf ifAssign.Left.Kind = SyntaxKind.SimpleMemberAccessExpression + assignment = CreateMemberAssignment(ifBlock, ifAssign, elseAssign) + Else + Return document + End If + + Dim newRoot = root.ReplaceNode(ifBlock, assignment) + Dim newDocument = document.WithSyntaxRoot(newRoot) + Return newDocument + End Function + + Private Shared Function CreateIdentifier(ifBlock As MultiLineIfBlockSyntax, ifAssign As AssignmentStatementSyntax, elseAssign As AssignmentStatementSyntax) As AssignmentStatementSyntax Dim variableIdentifier = TryCast(ifAssign.Left, IdentifierNameSyntax) Dim ternary = SyntaxFactory.TernaryConditionalExpression( @@ -80,11 +104,23 @@ Namespace Style WithLeadingTrivia(ifBlock.GetLeadingTrivia()). WithTrailingTrivia(ifBlock.GetTrailingTrivia()). WithAdditionalAnnotations(Formatter.Annotation) + Return assignment + End Function - Dim root = Await document.GetSyntaxRootAsync(cancellationToken) - Dim newRoot = root.ReplaceNode(ifBlock, assignment) - Dim newDocument = document.WithSyntaxRoot(newRoot) - Return newDocument + Private Shared Function CreateMemberAssignment(ifBlock As MultiLineIfBlockSyntax, ifAssign As AssignmentStatementSyntax, elseAssign As AssignmentStatementSyntax) As AssignmentStatementSyntax + Dim variableIdentifier = TryCast(ifAssign.Left, MemberAccessExpressionSyntax) + + Dim ternary = SyntaxFactory.TernaryConditionalExpression( + ifBlock.IfStatement.Condition, + ifAssign.Right.WithoutTrailingTrivia(), + elseAssign.Right.WithoutTrailingTrivia()) + + Dim assignment = SyntaxFactory.SimpleAssignmentStatement(variableIdentifier, ternary). + WithLeadingTrivia(ifBlock.GetLeadingTrivia()). + WithTrailingTrivia(ifBlock.GetTrailingTrivia()). + WithAdditionalAnnotations(Formatter.Annotation) + + Return assignment End Function End Class diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 811762d42..b98329fff 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -178,6 +178,49 @@ Namespace ConsoleApplication1 End Namespace" Await VerifyBasicFixAllAsync(New String() {sourceAssign, sourceAssign.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) End Function + + + Public Async Function WhenTernaryWithObjectDoesApplyFix() As Task + Const source = " +Class MyCustomer + Public Property Value As String +End Class +Public Class ExcelLineRecordClass + Public Property LineNumber As Integer + Public Property imported As Boolean +End Class +Class Tester + Private Sub Test() + Dim ExcelRecord As New ExcelLineRecordClass + Dim lCell As New MyCustomer + If lCell Is Nothing Then + ExcelRecord.imported = False + Else + ExcelRecord.imported = If(lCell.Value, lCell.Value.ToString = ""X"") + End If + End Sub +End Class" + + Const fix = " +Class MyCustomer + Public Property Value As String +End Class +Public Class ExcelLineRecordClass + Public Property LineNumber As Integer + Public Property imported As Boolean +End Class +Class Tester + Private Sub Test() + Dim ExcelRecord As New ExcelLineRecordClass + Dim lCell As New MyCustomer + ExcelRecord.imported = If(lCell Is Nothing, False, If(lCell.Value, lCell.Value.ToString = ""X"")) + End Sub +End Class" + + Await VerifyBasicFixAsync(source, fix) + + End Function + End Class Public Class TernaryOperatorWithReturnTests @@ -346,6 +389,7 @@ End Namespace" Await VerifyBasicFixAllAsync(New String() {sourceReturn, sourceReturn.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) End Function + End Class Public Class TernaryOperatorFromIifTests @@ -479,4 +523,7 @@ End Class" Await VerifyBasicHasNoDiagnosticsAsync(source) End Function -End Class \ No newline at end of file + + +End Class + From f0c8cdd1b737a160bfff704da8f214077788ef85 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Sun, 13 Sep 2015 22:52:07 -0400 Subject: [PATCH 004/358] Remove commented code --- .../CodeCracker/Style/TernaryOperatorCodeFixProviders.vb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index e809e30db..8eb03c03f 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -13,11 +13,7 @@ Namespace Style Inherits CodeFixProvider Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - 'Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) Dim diagnostic = context.Diagnostics.First - 'Dim span = diagnostic.Location.SourceSpan - 'Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) - 'If declaration Is Nothing Then Exit Function context.RegisterCodeFix(CodeAction.Create("Change to ternary operator", Function(c) MakeTernaryAsync(context.Document, diagnostic, c), NameOf(TernaryOperatorWithReturnCodeFixProvider)), diagnostic) Return Task.FromResult(0) End Function @@ -57,9 +53,6 @@ Namespace Style Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First - 'Dim span = diagnostic.Location.SourceSpan - 'Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) - 'If declaration Is Nothing Then Exit Function context.RegisterCodeFix(CodeAction.Create("Change to ternary operator", Function(c) MakeTernaryAsync(context.Document, diagnostic, c), NameOf(TernaryOperatorWithAssignmentCodeFixProvider)), diagnostic) Return Task.FromResult(0) End Function From 48ec7fd5e895d3a280437acdadbb73a8225858cf Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 3 Oct 2015 00:49:27 -0300 Subject: [PATCH 005/358] Make external nameof disabled and on a different diagnostic id Closes #518 --- .../CodeCracker/Design/NameOfAnalyzer.cs | 30 +++++++++++----- .../Design/NameOfCodeFixProvider.cs | 2 +- src/Common/CodeCracker.Common/DiagnosticId.cs | 3 +- .../CodeCracker/Design/NameOfAnalyzer.vb | 34 +++++++++++++------ .../Design/NameOfCodeFixProvider.vb | 2 +- .../CodeCracker.Test/Design/NameOfTests.cs | 28 +++++++++++---- .../CodeCracker.Test/Design/NameOfTests.vb | 16 +++++++-- 7 files changed, 84 insertions(+), 31 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs index b5692202c..c7d448c9b 100644 --- a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs @@ -25,8 +25,17 @@ public class NameOfAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true, description: Description, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.NameOf)); + internal static DiagnosticDescriptor RuleExternal = new DiagnosticDescriptor( + DiagnosticId.NameOf_External.ToDiagnosticId(), + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: false, + description: Description, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.NameOf_External)); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule, RuleExternal); public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(LanguageVersion.CSharp6, Analyze, SyntaxKind.StringLiteralExpression); @@ -37,11 +46,12 @@ private static void Analyze(SyntaxNodeAnalysisContext context) var stringLiteral = context.Node as LiteralExpressionSyntax; if (string.IsNullOrWhiteSpace(stringLiteral?.Token.ValueText)) return; - var programElementName = GetProgramElementNameThatMatchStringLiteral(stringLiteral, context.SemanticModel); + bool externalSymbol; + var programElementName = GetProgramElementNameThatMatchStringLiteral(stringLiteral, context.SemanticModel, out externalSymbol); if (Found(programElementName) && OutSideOfDeclarationSideWithSameName(stringLiteral)) { - var diagnostic = Diagnostic.Create(Rule, stringLiteral.GetLocation(), programElementName); + var diagnostic = Diagnostic.Create(externalSymbol ? RuleExternal : Rule, stringLiteral.GetLocation(), programElementName); context.ReportDiagnostic(diagnostic); } } @@ -60,23 +70,25 @@ private static bool OutSideOfDeclarationSideWithSameName(LiteralExpressionSyntax return !string.Equals(propertyDeclaration?.Identifier.ValueText, stringLiteral.Token.ValueText, StringComparison.Ordinal); } - private static string GetProgramElementNameThatMatchStringLiteral(LiteralExpressionSyntax stringLiteral, SemanticModel semanticModel) + private static string GetProgramElementNameThatMatchStringLiteral(LiteralExpressionSyntax stringLiteral, SemanticModel semanticModel, out bool externalSymbol) { + externalSymbol = false; var programElementName = GetParameterNameThatMatchStringLiteral(stringLiteral); - if (!Found(programElementName)) { var literalValueText = stringLiteral.Token.ValueText; var symbol = semanticModel.LookupSymbols(stringLiteral.Token.SpanStart, null, literalValueText).FirstOrDefault(); + if (symbol == null) return null; + externalSymbol = !symbol.Locations.Any(l => l.IsInSource); - if (symbol?.Kind == SymbolKind.Local) + if (symbol.Kind == SymbolKind.Local) { var symbolSpan = symbol.Locations.Min(i => i.SourceSpan); if (symbolSpan.CompareTo(stringLiteral.Token.Span) > 0) - return string.Empty; + return null; } - programElementName = symbol?.ToDisplayParts().LastOrDefault(AnalyzerExtensions.IsName).ToString(); + programElementName = symbol.ToDisplayParts().LastOrDefault(AnalyzerExtensions.IsName).ToString(); } return programElementName; @@ -85,7 +97,7 @@ private static string GetProgramElementNameThatMatchStringLiteral(LiteralExpress private static string GetParameterNameThatMatchStringLiteral(LiteralExpressionSyntax stringLiteral) { var ancestorThatMightHaveParameters = stringLiteral.FirstAncestorOfType(typeof(AttributeListSyntax), typeof(MethodDeclarationSyntax), typeof(ConstructorDeclarationSyntax), typeof(IndexerDeclarationSyntax)); - var parameterName = string.Empty; + string parameterName = null; if (ancestorThatMightHaveParameters != null) { var parameters = new SeparatedSyntaxList(); diff --git a/src/CSharp/CodeCracker/Design/NameOfCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/NameOfCodeFixProvider.cs index f43803f5e..e805ebcab 100644 --- a/src/CSharp/CodeCracker/Design/NameOfCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/NameOfCodeFixProvider.cs @@ -16,7 +16,7 @@ namespace CodeCracker.CSharp.Design [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NameOfCodeFixProvider)), Shared] public class NameOfCodeFixProvider : CodeFixProvider { - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.NameOf.ToDiagnosticId()); + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.NameOf.ToDiagnosticId(), DiagnosticId.NameOf_External.ToDiagnosticId()); public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index 788601342..537a0a83a 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -77,5 +77,6 @@ public enum DiagnosticId MakeMethodStatic = 91, ChangeAllToAny = 92, ConsoleWriteLine = 95, + NameOf_External = 108, } -} +} \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/Design/NameOfAnalyzer.vb b/src/VisualBasic/CodeCracker/Design/NameOfAnalyzer.vb index 6467ecbf7..482eceea5 100644 --- a/src/VisualBasic/CodeCracker/Design/NameOfAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Design/NameOfAnalyzer.vb @@ -24,8 +24,17 @@ Namespace Design isEnabledByDefault:=True, description:=Description, helpLinkUri:=HelpLink.ForDiagnostic(DiagnosticId.NameOf)) + Protected Shared RuleExtenal As DiagnosticDescriptor = New DiagnosticDescriptor( + DiagnosticId.NameOf_External.ToDiagnosticId(), + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault:=True, + description:=Description, + helpLinkUri:=HelpLink.ForDiagnostic(DiagnosticId.NameOf_External)) - Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) = ImmutableArray.Create(Rule) + Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor) = ImmutableArray.Create(Rule, RuleExtenal) Public Overrides Sub Initialize(context As AnalysisContext) context.RegisterSyntaxNodeAction(LanguageVersion.VisualBasic14, AddressOf Analyzer, SyntaxKind.StringLiteralExpression) @@ -36,32 +45,35 @@ Namespace Design Dim stringLiteral = DirectCast(context.Node, LiteralExpressionSyntax) If String.IsNullOrWhiteSpace(stringLiteral?.Token.ValueText) Then Return - Dim programElementName = GetProgramElementNameThatMatchesStringLiteral(stringLiteral, context.SemanticModel) + Dim externalSymbol = False + Dim programElementName = GetProgramElementNameThatMatchesStringLiteral(stringLiteral, context.SemanticModel, externalSymbol) If (Found(programElementName)) Then - Dim diag = Diagnostic.Create(Rule, stringLiteral.GetLocation(), programElementName) + Dim diag = Diagnostic.Create(If(externalSymbol, RuleExtenal, Rule), stringLiteral.GetLocation(), programElementName) context.ReportDiagnostic(diag) End If End Sub - Private Shared Function GetProgramElementNameThatMatchesStringLiteral(stringLiteral As LiteralExpressionSyntax, model As SemanticModel) As String + Private Shared Function GetProgramElementNameThatMatchesStringLiteral(stringLiteral As LiteralExpressionSyntax, model As SemanticModel, ByRef externalSymbol As Boolean) As String Dim programElementName = GetParameterNameThatMatchesStringLiteral(stringLiteral) If Not Found(programElementName) Then Dim literalValueText = stringLiteral.Token.ValueText Dim symbol = model.LookupSymbols(stringLiteral.Token.SpanStart, Nothing, literalValueText).FirstOrDefault() - If symbol?.Kind = SymbolKind.Local Then + If symbol Is Nothing Then Return Nothing + externalSymbol = symbol.Locations.Any(Function(l) l.IsInSource) = False + If symbol.Kind = SymbolKind.Local Then ' Only register if local variable is declared before it is used. ' Don't recommend if variable is declared after string literal is used. Dim symbolSpan = symbol.Locations.Min(Function(i) i.SourceSpan) If symbolSpan.CompareTo(stringLiteral.Token.Span) > 0 Then - Return String.Empty + Return Nothing End If End If programElementName = symbol?.ToDisplayParts(). - Where(AddressOf IncludeOnlyPartsThatAreName). - LastOrDefault(Function(displayPart) displayPart.ToString() = literalValueText). - ToString() - End If - Return programElementName + Where(AddressOf IncludeOnlyPartsThatAreName). + LastOrDefault(Function(displayPart) displayPart.ToString() = literalValueText). + ToString() + End If + Return programElementName End Function Private Shared Function GetParameterNameThatMatchesStringLiteral(stringLiteral As LiteralExpressionSyntax) As String diff --git a/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb index 706d77a42..0bcffa58c 100644 --- a/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb @@ -12,7 +12,7 @@ Namespace Design Public Class NameOfCodeFixProvider Inherits CodeFixProvider - Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(NameOfAnalyzer.Id) + Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(NameOfAnalyzer.Id, DiagnosticId.NameOf_External.ToDiagnosticId()) Public Overrides Function GetFixAllProvider() As FixAllProvider Return WellKnownFixAllProviders.BatchFixer diff --git a/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs b/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs index 8dd2fc6c9..c6d3e5e4e 100644 --- a/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs @@ -118,6 +118,22 @@ void Foo(string a) await VerifyCSharpHasNoDiagnosticsAsync(test); } + [Fact] + public async Task WhenReferencingExternalSymbolShouldReportDiagnostic() + { + const string test = @" +using System; +public class TypeName +{ + public static void Foo() + { + var a = ""DateTime""; + } +}"; + var expected = CreateNameofDiagnosticResult("DateTime", 7, 17, DiagnosticId.NameOf_External); + await VerifyCSharpDiagnosticAsync(test, expected); + } + [Theory] [InlineData("xyz", false)] [InlineData("OtherProperty", true)] @@ -307,7 +323,7 @@ public class OtherTypeName public class TypeName { - + void Foo(string a) { var instance = new OtherTypeName @@ -331,7 +347,7 @@ public class TypeName { private readonly int readonlyField; public interface IInterface {} - + void Foo(string a) { var tab = new[] { ""readonlyField"", ""xyz"", ""IInterface"" }; @@ -352,7 +368,7 @@ public async Task WhenCreatingNewObjectWithStringLiterals() const string source = @" public struct TypeName { - + void Foo(string a) { var instance = new OtherTypeName(""b"", ""xyz""); @@ -395,7 +411,7 @@ public class @class : BaseTypeName public string someName = ""variable""; public string namespaceName = ""using""; public string namespaceName2 = ""N2""; - + void Foo() => string.Format(""{0}"", ""xyz""); void Foo2() => string.Format(""{0}"", ""readonlyField""); @@ -686,11 +702,11 @@ private void Invoke(string arg1, string arg2) await VerifyCSharpFixAllAsync(source.Replace("", $@"""{stringLiteral}"""), source.Replace("", $@"nameof({stringLiteral})")); } - private static DiagnosticResult CreateNameofDiagnosticResult(string nameofArgument, int diagnosticLine, int diagnosticColumn) + private static DiagnosticResult CreateNameofDiagnosticResult(string nameofArgument, int diagnosticLine, int diagnosticColumn, DiagnosticId id = DiagnosticId.NameOf) { return new DiagnosticResult { - Id = DiagnosticId.NameOf.ToDiagnosticId(), + Id = id.ToDiagnosticId(), Message = $"Use 'nameof({nameofArgument})' instead of specifying the program element name.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", diagnosticLine, diagnosticColumn) } diff --git a/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb b/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb index 9b5fb7933..641b65c8e 100644 --- a/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb @@ -20,6 +20,18 @@ End Class" Await VerifyBasicHasNoDiagnosticsAsync(source) End Function + + Public Async Function WhenReferencingExternalSymbolShouldReportDiagnostic() As Task + Dim source = $" +Imports System +Public Class TypeName + Sub Foo() + Dim a = ""Action"" + End Sub +End Class" + Dim expected = CreateNameofDiagnosticResult("Actio" + "n", 5, 17, DiagnosticId.NameOf_External) + Await VerifyBasicDiagnosticAsync(source, expected) + End Function @@ -578,10 +590,10 @@ End Class" Await VerifyBasicHasNoDiagnosticsAsync(test) End Function - Private Function CreateNameofDiagnosticResult(nameofArgument As String, diagnosticLine As Integer, diagnosticColumn As Integer) As DiagnosticResult + Private Function CreateNameofDiagnosticResult(nameofArgument As String, diagnosticLine As Integer, diagnosticColumn As Integer, Optional id As DiagnosticId = DiagnosticId.NameOf) As DiagnosticResult Return New DiagnosticResult With { - .Id = DiagnosticId.NameOf.ToDiagnosticId(), + .Id = id.ToDiagnosticId(), .Message = $"Use 'NameOf({nameofArgument})' instead of specifying the program element name.", .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, .Locations = {New DiagnosticResultLocation("Test0.vb", diagnosticLine, diagnosticColumn)} From 873afb151fac910ba31f13dcab24114219d32b58 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 3 Oct 2015 19:56:34 -0300 Subject: [PATCH 006/358] Enable params with UnusedParameters Fix #533 Also reenable the analyzer for VB --- .../Usage/UnusedParametersCodeFixProvider.cs | 16 ++++- .../Usage/UnusedParametersAnalyzer.vb | 2 +- .../Usage/UnusedParametersCodeFixProvider.vb | 19 ++++-- .../Usage/UnusedParametersTests.cs | 35 ++++++++-- .../Usage/UnusedParameterTests.vb | 66 ++++++++++++++++--- 5 files changed, 118 insertions(+), 20 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs index 3b53b735b..8041b3a8e 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs @@ -69,8 +69,20 @@ private async static Task RemoveParameterAsync(Document document, Diag var arguments = objectCreation != null ? objectCreation.ArgumentList : methodIdentifier.FirstAncestorOfType().ArgumentList; - var newArguments = arguments.WithArguments(arguments.Arguments.RemoveAt(parameterPosition)); - replacingArgs.Add(arguments, newArguments); + if (parameter.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword))) + { + var newArguments = arguments; + do + { + newArguments = newArguments.WithArguments(newArguments.Arguments.RemoveAt(parameterPosition)); + } while (newArguments.Arguments.Count > parameterPosition); + replacingArgs.Add(arguments, newArguments); + } + else + { + var newArguments = arguments.WithArguments(arguments.Arguments.RemoveAt(parameterPosition)); + replacingArgs.Add(arguments, newArguments); + } } var newLocRoot = locRoot.ReplaceNodes(replacingArgs.Keys, (original, rewritten) => replacingArgs[original]); newSolution = newSolution.WithDocumentSyntaxRoot(referencingDocument.Id, newLocRoot); diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb index eeaad5a8a..0270e0e2e 100644 --- a/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb @@ -20,7 +20,7 @@ You should delete the parameter in such cases." Message, SupportedCategories.Usage, DiagnosticSeverity.Warning, - False, + True, Description, HelpLink.ForDiagnostic(DiagnosticId.UnusedParameters), WellKnownDiagnosticTags.Unnecessary) diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb index 417474144..1d04cf467 100644 --- a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.FindSymbols +Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Usage @@ -16,16 +17,16 @@ Namespace Usage Dim diagnostic = context.Diagnostics.First Dim span = diagnostic.Location.SourceSpan Dim parameter = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of ParameterSyntax) - context.RegisterCodeFix(CodeAction.Create(String.Format("Remove unused parameter: '{0}'", parameter.Identifier.GetText()), Function(c) RemovePArameterAsync(root, context.Document, parameter, c), NameOf(UnusedParametersCodeFixProvider)), diagnostic) + context.RegisterCodeFix(CodeAction.Create(String.Format("Remove unused parameter: '{0}'", parameter.Identifier.GetText()), Function(c) RemoveParameterAsync(root, context.Document, parameter, c), NameOf(UnusedParametersCodeFixProvider)), diagnostic) End Function - Public Overrides NotOverridable ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.UnusedParameters.ToDiagnosticId()) + Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.UnusedParameters.ToDiagnosticId()) Public Overrides Function GetFixAllProvider() As FixAllProvider Return WellKnownFixAllProviders.BatchFixer End Function - Private Shared Async Function RemovePArameterAsync(root As SyntaxNode, document As Document, parameter As ParameterSyntax, cancellationToken As CancellationToken) As Task(Of Solution) + Private Shared Async Function RemoveParameterAsync(root As SyntaxNode, document As Document, parameter As ParameterSyntax, cancellationToken As CancellationToken) As Task(Of Solution) Dim solution = document.Project.Solution Dim parameterList = DirectCast(parameter.Parent, ParameterListSyntax) Dim parameterPosition = parameterList.Parameters.IndexOf(parameter) @@ -57,8 +58,16 @@ Namespace Usage Dim arguments = If(objectCreation IsNot Nothing, objectCreation.ArgumentList, methodIdentifier.FirstAncestorOfType(Of InvocationExpressionSyntax).ArgumentList) - Dim newArguments = arguments.WithArguments(arguments.Arguments.RemoveAt(parameterPosition)) - replacingArgs.Add(arguments, newArguments) + If parameter.Modifiers.Any(Function(m) m.IsKind(SyntaxKind.ParamArrayKeyword)) Then + Dim newArguments = arguments + Do + newArguments = newArguments.WithArguments(newArguments.Arguments.RemoveAt(parameterPosition)) + Loop While newArguments.Arguments.Count > parameterPosition + replacingArgs.Add(arguments, newArguments) + Else + Dim newArguments = arguments.WithArguments(arguments.Arguments.RemoveAt(parameterPosition)) + replacingArgs.Add(arguments, newArguments) + End If Next Dim newLocRoot = locRoot.ReplaceNodes(replacingArgs.Keys, Function(original, rewritten) replacingArgs(original)) newSolution = newSolution.WithDocumentSyntaxRoot(referencingDocument.Id, newLocRoot) diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index b7857b7b8..5b2aba0f7 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -312,6 +312,36 @@ public int Foo(int a) await VerifyCSharpFixAsync(source, fixtest); } + [Fact] + public async Task FixParams() + { + const string source = @" +class TypeName +{ + public void IsReferencing() + { + Foo(1, 2, 3, 4); + } + public void Foo(int a, int b, params int[] c) + { + a = b; + } +}"; + const string fixtest = @" +class TypeName +{ + public void IsReferencing() + { + Foo(1, 2); + } + public void Foo(int a, int b) + { + a = b; + } +}"; + await VerifyCSharpFixAsync(source, fixtest); + } + [Fact] public async Task FixWhenTheParametersHasReferenceOnDifferentClass() { @@ -539,7 +569,4 @@ bool TryParse(string input, out int output, out int out2) } } - -} - - +} \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb index f45211a33..4e40dab1f 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb @@ -1,6 +1,4 @@ Imports CodeCracker.VisualBasic.Usage -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Xunit Namespace Usage @@ -250,7 +248,7 @@ Class HasRef Dim x = New TypeName().Foo(1, 2) End Sub End Class -Class TypeName +Class TypeName Public Function Foo(a As Integer, b As Integer) as Integer Return a End Function @@ -261,7 +259,7 @@ Class HasRef Dim x = New TypeName().Foo(1) End Sub End Class -Class TypeName +Class TypeName Public Function Foo(a As Integer) as Integer Return a End Function @@ -278,7 +276,7 @@ Class HasRef TypeName.Foo(1, 2) End Sub End Class -Class TypeName +Class TypeName Public Shared Function Foo(a As Integer, b As Integer) as Integer Return a End Function @@ -289,7 +287,7 @@ Class HasRef TypeName.Foo(1) End Sub End Class -Class TypeName +Class TypeName Public Shared Function Foo(a As Integer) as Integer Return a End Function @@ -306,7 +304,7 @@ Class HasRef Dim x = New TypeName(1, 2) End Sub End Class -Class TypeName +Class TypeName Public Sub New(a As Integer, b As Integer) Dim x = a End Sub @@ -317,7 +315,7 @@ Class HasRef Dim x = New TypeName(1) End Sub End Class -Class TypeName +Class TypeName Public Sub New(a As Integer) Dim x = a End Sub @@ -326,6 +324,58 @@ End Class" Await VerifyBasicFixAsync(source, fix) End Function + + Public Async Function FixParamsInConstructor() As Task + Const source = " +Class HasRef + Public Sub IsReferencing() + Dim x = New TypeName(1, 2, 3) + End Sub +End Class +Class TypeName + Public Sub New(a As Integer, b As Integer, ParamArray c As Integer()) + b = a + End Sub +End Class" + Const fix = " +Class HasRef + Public Sub IsReferencing() + Dim x = New TypeName(1, 2) + End Sub +End Class +Class TypeName + Public Sub New(a As Integer, b As Integer) + b = a + End Sub +End Class" + Await VerifyBasicFixAsync(source, fix) + End Function + + + Public Async Function FixParams() As Task + Const source = " +Class Foo + Public Sub IsReferencing() + Dim x = Bar(1, 2, 3, 4) + End Sub + Public Function Bar(a As Integer, b As Integer, ParamArray c As Integer()) + b = a + return 1 + End Function +End Class" + Const fix = " +Class Foo + Public Sub IsReferencing() + Dim x = Bar(1, 2) + End Sub + Public Function Bar(a As Integer, b As Integer) + b = a + return 1 + End Function +End Class" + Await VerifyBasicFixAsync(source, fix) + End Function + Public Async Function CallToBaseDoesNotCreateDiagnostic() As Task From a291b7f43719accc661b0562d5e77c33a8051c90 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 4 Oct 2015 00:32:19 -0300 Subject: [PATCH 007/358] Fix all in UnusedParameters fix #534 Also update VB analyzer to send props to code fix and update code fix making it more effient when reporting the fix --- src/CSharp/CodeCracker/CodeCracker.csproj | 1 + .../UnusedParametersCodeFixAllProvider.cs | 132 ++++++++++++++++++ .../Usage/UnusedParametersCodeFixProvider.cs | 27 +++- .../CodeCracker/CodeCracker.vbproj | 1 + .../Usage/UnusedParametersAnalyzer.vb | 5 +- .../UnusedParametersCodeFixAllProvider.vb | 123 ++++++++++++++++ .../Usage/UnusedParametersCodeFixProvider.vb | 42 ++++-- .../Usage/UnusedParametersTests.cs | 68 +++++++++ .../Usage/UnusedParameterTests.vb | 52 ++++++- 9 files changed, 431 insertions(+), 20 deletions(-) create mode 100644 src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs create mode 100644 src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.vb diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 815308e38..6c30cddc6 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -136,6 +136,7 @@ + diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs new file mode 100644 index 000000000..4dc4c56fb --- /dev/null +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs @@ -0,0 +1,132 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace CodeCracker.CSharp.Usage +{ + public sealed class UnusedParametersCodeFixAllProvider : FixAllProvider + { + private UnusedParametersCodeFixAllProvider() { } + + private const string message = "Remove unused parameter"; + public static UnusedParametersCodeFixAllProvider Instance = new UnusedParametersCodeFixAllProvider(); + public override Task GetFixAsync(FixAllContext fixAllContext) + { + switch (fixAllContext.Scope) + { + case FixAllScope.Document: + return Task.FromResult(CodeAction.Create(message, + async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Document)))); + case FixAllScope.Project: + return Task.FromResult(CodeAction.Create(message, + async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Project)))); + case FixAllScope.Solution: + return Task.FromResult(CodeAction.Create(message, + async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Solution)))); + } + return null; + } + + private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Solution solution) + { + var docs = new List(); + var sol = new SolutionWithDocs { Docs = docs, Solution = solution }; + foreach (var pId in solution.Projects.Select(p => p.Id)) + { + var project = sol.Solution.GetProject(pId); + var newSol = await GetSolutionWithDocsAsync(fixAllContext, project).ConfigureAwait(false); + sol.Merge(newSol); + } + return sol; + } + + private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Project project) + { + var docs = new List(); + var newSolution = project.Solution; + foreach (var document in project.Documents) + { + var doc = await GetDiagnosticsInDocAsync(fixAllContext, document); + if (doc.Equals(DiagnosticsInDoc.Empty)) continue; + docs.Add(doc); + newSolution = newSolution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot); + } + var sol = new SolutionWithDocs { Docs = docs, Solution = newSolution }; + return sol; + } + + private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Document document) + { + var docs = new List(); + var doc = await GetDiagnosticsInDocAsync(fixAllContext, document); + docs.Add(doc); + var newSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot); + var sol = new SolutionWithDocs { Docs = docs, Solution = newSolution }; + return sol; + } + + private static async Task GetDiagnosticsInDocAsync(FixAllContext fixAllContext, Document document) + { + var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); + if (!diagnostics.Any()) return DiagnosticsInDoc.Empty; + var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var doc = DiagnosticsInDoc.Create(document.Id, diagnostics, root); + return doc; + } + + private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext, SolutionWithDocs sol) + { + var newSolution = sol.Solution; + foreach (var doc in sol.Docs) + { + foreach (var node in doc.Nodes) + { + var document = newSolution.GetDocument(doc.DocumentId); + var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var trackedNode = root.GetCurrentNode(node); + var parameter = trackedNode.AncestorsAndSelf().OfType().First(); + var docResults = await UnusedParametersCodeFixProvider.RemoveParameterAsync(document, parameter, root, fixAllContext.CancellationToken); + foreach (var docResult in docResults) + newSolution = newSolution.WithDocumentSyntaxRoot(docResult.DocumentId, docResult.Root); + } + } + return newSolution; + } + + private struct DiagnosticsInDoc + { + public static DiagnosticsInDoc Create(DocumentId documentId, IList diagnostics, SyntaxNode root) + { + var nodes = diagnostics.Select(d => root.FindNode(d.Location.SourceSpan)).Where(n => !n.IsMissing).ToList(); + var diagnosticsInDoc = new DiagnosticsInDoc + { + DocumentId = documentId, + TrackedRoot = root.TrackNodes(nodes), + Nodes = nodes + }; + return diagnosticsInDoc; + } + public DocumentId DocumentId; + public List Nodes; + public SyntaxNode TrackedRoot; + + private static readonly DiagnosticsInDoc empty = new DiagnosticsInDoc(); + public static DiagnosticsInDoc Empty => empty; + } + + private struct SolutionWithDocs + { + public Solution Solution; + public List Docs; + public void Merge(SolutionWithDocs sol) + { + Solution = sol.Solution; + Docs.AddRange(sol.Docs); + } + } + } +} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs index 8041b3a8e..6f31c01af 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs @@ -19,7 +19,7 @@ public class UnusedParametersCodeFixProvider : CodeFixProvider public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.UnusedParameters.ToDiagnosticId()); - public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => UnusedParametersCodeFixAllProvider.Instance; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -29,21 +29,31 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) return Task.FromResult(0); } - private async static Task RemoveParameterAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + public async static Task RemoveParameterAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { + var solution = document.Project.Solution; + var newSolution = solution; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var parameter = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var docs = await RemoveParameterAsync(document, parameter, root, cancellationToken); + foreach (var doc in docs) + newSolution = newSolution.WithDocumentSyntaxRoot(doc.DocumentId, doc.Root); + return newSolution; + } + + public async static Task> RemoveParameterAsync(Document document, ParameterSyntax parameter, SyntaxNode root, CancellationToken cancellationToken) + { var solution = document.Project.Solution; var parameterList = (ParameterListSyntax)parameter.Parent; var parameterPosition = parameterList.Parameters.IndexOf(parameter); var newParameterList = parameterList.WithParameters(parameterList.Parameters.Remove(parameter)); - var newSolution = solution; var foundDocument = false; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); var method = (BaseMethodDeclarationSyntax)parameter.Parent.Parent; var methodSymbol = semanticModel.GetDeclaredSymbol(method); var references = await SymbolFinder.FindReferencesAsync(methodSymbol, solution, cancellationToken).ConfigureAwait(false); var documentGroups = references.SelectMany(r => r.Locations).GroupBy(loc => loc.Document); + var docs = new List(); foreach (var documentGroup in documentGroups) { var referencingDocument = documentGroup.Key; @@ -85,15 +95,20 @@ private async static Task RemoveParameterAsync(Document document, Diag } } var newLocRoot = locRoot.ReplaceNodes(replacingArgs.Keys, (original, rewritten) => replacingArgs[original]); - newSolution = newSolution.WithDocumentSyntaxRoot(referencingDocument.Id, newLocRoot); + docs.Add(new DocumentIdAndRoot { DocumentId = referencingDocument.Id, Root = newLocRoot }); } if (!foundDocument) { var newRoot = root.ReplaceNode(parameterList, newParameterList); var newDocument = document.WithSyntaxRoot(newRoot); - newSolution = newSolution.WithDocumentSyntaxRoot(document.Id, newRoot); + docs.Add(new DocumentIdAndRoot { DocumentId = document.Id, Root = newRoot }); } - return newSolution; + return docs; + } + public struct DocumentIdAndRoot + { + internal DocumentId DocumentId; + internal SyntaxNode Root; } } } \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index ee0f6d02e..17eff7c39 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -139,6 +139,7 @@ + diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb index 0270e0e2e..5e338294a 100644 --- a/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb @@ -115,7 +115,10 @@ You should delete the parameter in such cases." End Function Private Function CreateDiagnostic(context As SyntaxNodeAnalysisContext, parameter As ParameterSyntax) As SyntaxNodeAnalysisContext - Dim diag = Diagnostic.Create(Rule, parameter.GetLocation(), parameter.Identifier.Identifier.ValueText) + Dim propsDic = New Dictionary(Of String, String) + propsDic.Add("identifier", parameter.Identifier.Identifier.Text) + Dim props = propsDic.ToImmutableDictionary() + Dim diag = Diagnostic.Create(Rule, parameter.GetLocation(), props, parameter.Identifier.Identifier.ValueText) context.ReportDiagnostic(diag) Return context End Function diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.vb new file mode 100644 index 000000000..ec30c6a5a --- /dev/null +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.vb @@ -0,0 +1,123 @@ +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeActions +Imports Microsoft.CodeAnalysis.CodeFixes +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports System.Collections.Generic +Imports System.Linq +Imports System.Threading.Tasks + +Namespace Usage + + Public NotInheritable Class UnusedParametersCodeFixAllProvider + Inherits FixAllProvider + + Private Sub New() + MyBase.New + + End Sub + + Public Shared Instance As UnusedParametersCodeFixAllProvider = New UnusedParametersCodeFixAllProvider + Private Const message As String = "Remove unused parameter" + + Public Overrides Function GetFixAsync(ByVal fixAllContext As FixAllContext) As Task(Of CodeAction) + Select Case (fixAllContext.Scope) + Case FixAllScope.Document + Return Task.FromResult(CodeAction.Create(message, Async Function(ct) Await GetFixedSolutionAsync(fixAllContext, Await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Document)))) + Case FixAllScope.Project + Return Task.FromResult(CodeAction.Create(message, Async Function(ct) Await GetFixedSolutionAsync(fixAllContext, Await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Project)))) + Case FixAllScope.Solution + Return Task.FromResult(CodeAction.Create(message, Async Function(ct) Await GetFixedSolutionAsync(fixAllContext, Await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Solution)))) + End Select + + Return Nothing + End Function + + Private Overloads Shared Async Function GetSolutionWithDocsAsync(ByVal fixAllContext As FixAllContext, ByVal solution As Solution) As Task(Of SolutionWithDocs) + Dim docs = New List(Of DiagnosticsInDoc) + Dim sol = New SolutionWithDocs() With {.Docs = docs, .Solution = solution} + For Each pId In solution.Projects.Select(Function(p) p.Id) + Dim project = sol.Solution.GetProject(pId) + Dim newSol = Await GetSolutionWithDocsAsync(fixAllContext, project).ConfigureAwait(False) + sol.Merge(newSol) + Next + Return sol + End Function + + Private Overloads Shared Async Function GetSolutionWithDocsAsync(ByVal fixAllContext As FixAllContext, ByVal project As Project) As Task(Of SolutionWithDocs) + Dim docs = New List(Of DiagnosticsInDoc) + Dim newSolution = project.Solution + For Each document In project.Documents + Dim doc = Await GetDiagnosticsInDocAsync(fixAllContext, document) + If doc.Equals(DiagnosticsInDoc.Empty) Then Continue For + docs.Add(doc) + newSolution = newSolution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot) + Next + Dim sol = New SolutionWithDocs() With {.Docs = docs, .Solution = newSolution} + Return sol + End Function + + Private Overloads Shared Async Function GetSolutionWithDocsAsync(ByVal fixAllContext As FixAllContext, ByVal document As Document) As Task(Of SolutionWithDocs) + Dim docs = New List(Of DiagnosticsInDoc) + Dim doc = Await GetDiagnosticsInDocAsync(fixAllContext, document) + docs.Add(doc) + Dim newSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot) + Dim sol = New SolutionWithDocs() With {.Docs = docs, .Solution = newSolution} + Return sol + End Function + + Private Shared Async Function GetDiagnosticsInDocAsync(ByVal fixAllContext As FixAllContext, ByVal document As Document) As Task(Of DiagnosticsInDoc) + Dim diagnostics = Await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(False) + If Not diagnostics.Any Then + Return DiagnosticsInDoc.Empty + End If + Dim root = Await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(False) + Dim doc = DiagnosticsInDoc.Create(document.Id, diagnostics, root) + Return doc + End Function + + Private Shared Async Function GetFixedSolutionAsync(ByVal fixAllContext As FixAllContext, ByVal sol As SolutionWithDocs) As Task(Of Solution) + Dim newSolution = sol.Solution + For Each doc In sol.Docs + For Each node In doc.Nodes + Dim document = newSolution.GetDocument(doc.DocumentId) + Dim root = Await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(False) + Dim trackedNode = root.GetCurrentNode(node) + Dim parameter = trackedNode.AncestorsAndSelf().OfType(Of ParameterSyntax).First() + Dim docResults = Await UnusedParametersCodeFixProvider.RemoveParameterAsync(document, parameter, root, fixAllContext.CancellationToken) + For Each docResult In docResults + newSolution = newSolution.WithDocumentSyntaxRoot(docResult.DocumentId, docResult.Root) + Next + Next + Next + Return newSolution + End Function + + Private Structure DiagnosticsInDoc + Public Shared Function Create(ByVal documentId As DocumentId, ByVal diagnostics As IList(Of Diagnostic), ByVal root As SyntaxNode) As DiagnosticsInDoc + Dim nodes = diagnostics.Select(Function(d) root.FindNode(d.Location.SourceSpan)).Where(Function(n) Not n.IsMissing).ToList() + Dim diagnosticsInDoc = New DiagnosticsInDoc() With {.DocumentId = documentId, .TrackedRoot = root.TrackNodes(nodes), .Nodes = nodes} + Return diagnosticsInDoc + End Function + + Public DocumentId As DocumentId + + Public Nodes As List(Of SyntaxNode) + + Public TrackedRoot As SyntaxNode + + Public Shared Property Empty As DiagnosticsInDoc = New DiagnosticsInDoc() + End Structure + + Private Structure SolutionWithDocs + + Public Solution As Solution + + Public Docs As List(Of DiagnosticsInDoc) + + Public Sub Merge(ByVal sol As SolutionWithDocs) + Solution = sol.Solution + Docs.AddRange(sol.Docs) + End Sub + End Structure + End Class +End Namespace \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb index 1d04cf467..975bd85fb 100644 --- a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb @@ -12,32 +12,45 @@ Namespace Usage Public Class UnusedParametersCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) - Dim diagnostic = context.Diagnostics.First - Dim span = diagnostic.Location.SourceSpan - Dim parameter = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of ParameterSyntax) - context.RegisterCodeFix(CodeAction.Create(String.Format("Remove unused parameter: '{0}'", parameter.Identifier.GetText()), Function(c) RemoveParameterAsync(root, context.Document, parameter, c), NameOf(UnusedParametersCodeFixProvider)), diagnostic) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task + Dim Diagnostic = context.Diagnostics.First() + context.RegisterCodeFix(CodeAction.Create( + String.Format("Remove unused parameter: '{0}'", Diagnostic.Properties("identifier")), + Function(c) RemoveParameterAsync(context.Document, Diagnostic, c), + NameOf(UnusedParametersCodeFixProvider)), + Diagnostic) + Return Task.FromResult(0) End Function Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.UnusedParameters.ToDiagnosticId()) Public Overrides Function GetFixAllProvider() As FixAllProvider - Return WellKnownFixAllProviders.BatchFixer + Return UnusedParametersCodeFixAllProvider.Instance + End Function + Private Shared Async Function RemoveParameterAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Solution) + Dim solution = document.Project.Solution + Dim newSolution = solution + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim parameter = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.FirstAncestorOrSelf(Of ParameterSyntax) + Dim docs = Await RemoveParameterAsync(document, parameter, root, cancellationToken) + For Each doc In docs + newSolution = newSolution.WithDocumentSyntaxRoot(doc.DocumentId, doc.Root) + Next + Return newSolution End Function - Private Shared Async Function RemoveParameterAsync(root As SyntaxNode, document As Document, parameter As ParameterSyntax, cancellationToken As CancellationToken) As Task(Of Solution) + Public Shared Async Function RemoveParameterAsync(document As Document, parameter As ParameterSyntax, root As SyntaxNode, cancellationToken As CancellationToken) As Task(Of List(Of DocumentIdAndRoot)) Dim solution = document.Project.Solution Dim parameterList = DirectCast(parameter.Parent, ParameterListSyntax) Dim parameterPosition = parameterList.Parameters.IndexOf(parameter) Dim newParameterList = parameterList.WithParameters(parameterList.Parameters.Remove(parameter)) - Dim newSolution = solution Dim foundDocument = False Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) Dim method = parameter.FirstAncestorOfType(GetType(SubNewStatementSyntax), GetType(MethodBlockSyntax)) Dim methodSymbol = semanticModel.GetDeclaredSymbol(method) Dim references = Await SymbolFinder.FindReferencesAsync(methodSymbol, solution, cancellationToken).ConfigureAwait(False) Dim documentGroups = references.SelectMany(Function(r) r.Locations).GroupBy(Function(loc) loc.Document) + Dim docs = New List(Of DocumentIdAndRoot) For Each documentGroup In documentGroups Dim referencingDocument = documentGroup.Key Dim locRoot As SyntaxNode @@ -70,14 +83,19 @@ Namespace Usage End If Next Dim newLocRoot = locRoot.ReplaceNodes(replacingArgs.Keys, Function(original, rewritten) replacingArgs(original)) - newSolution = newSolution.WithDocumentSyntaxRoot(referencingDocument.Id, newLocRoot) + docs.Add(New DocumentIdAndRoot With {.DocumentId = referencingDocument.Id, .Root = newLocRoot}) Next If Not foundDocument Then Dim newRoot = root.ReplaceNode(parameterList, newParameterList) Dim newDocument = document.WithSyntaxRoot(newRoot) - newSolution = newSolution.WithDocumentSyntaxRoot(document.Id, newRoot) + docs.Add(New DocumentIdAndRoot With {.DocumentId = document.Id, .Root = newRoot}) End If - Return newSolution + Return docs End Function + + Public Structure DocumentIdAndRoot + Friend DocumentId As DocumentId + Friend Root As SyntaxNode + End Structure End Class End Namespace \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 5b2aba0f7..6e5d5c92e 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -342,6 +342,74 @@ public void Foo(int a, int b) await VerifyCSharpFixAsync(source, fixtest); } + [Fact] + public async Task FixAllInSameClass() + { + const string source = @" +class TypeName +{ + public void IsReferencing() + { + Foo(1, 2, 3, 4); + } + public void Foo(int a, int b, params int[] c) + { + a = 1; + } +}"; + const string fixtest = @" +class TypeName +{ + public void IsReferencing() + { + Foo(1); + } + public void Foo(int a) + { + a = 1; + } +}"; + await VerifyCSharpFixAllAsync(source, fixtest); + } + + [Fact] + public async Task FixAllInDifferentClass() + { + const string source1 = @" +class TypeName +{ + public void IsReferencing() + { + Referenced.Foo(1, 2, 3, 4); + } +}"; + const string source2 = @" +class Referenced +{ + public static void Foo(int a, int b, params int[] c) + { + a = 1; + } +}"; + const string fix1 = @" +class TypeName +{ + public void IsReferencing() + { + Referenced.Foo(1); + } +}"; + const string fix2 = @" +class Referenced +{ + public static void Foo(int a) + { + a = 1; + } +}"; + await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { fix1, fix2 }); + } + [Fact] public async Task FixWhenTheParametersHasReferenceOnDifferentClass() { diff --git a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb index 4e40dab1f..cb06d5230 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb @@ -463,6 +463,57 @@ End Class Await VerifyBasicHasNoDiagnosticsAsync(source) End Function + + Public Async Function FixAllInSameClass() As Task + Const source As String = " +Class TypeName + Public Sub IsReferencing() + Me.Foo(1, 2, 3, 4) + End Sub + Public Sub Foo(ByVal a As Integer, ByVal b As Integer, ParamArray ByVal c() As Integer) + a = 1 + End Sub +End Class" + Const fixtest As String = " +Class TypeName + Public Sub IsReferencing() + Me.Foo(1) + End Sub + Public Sub Foo(ByVal a As Integer) + a = 1 + End Sub +End Class" + Await VerifyBasicFixAllAsync(source, fixtest) + End Function + + + Public Async Function FixAllInDifferentClass() As Task + Const source1 As String = " +Class TypeName + Public Sub IsReferencing() + Referenced.Foo(1, 2, 3, 4) + End Sub +End Class" + Const source2 As String = " +Class Referenced + Public Shared Sub Foo(ByVal a As Integer, ByVal b As Integer, ParamArray ByVal c() As Integer) + a = 1 + End Sub +End Class" + Const fix1 As String = " +Class TypeName + Public Sub IsReferencing() + Referenced.Foo(1) + End Sub +End Class" + Const fix2 As String = " +Class Referenced + Public Shared Sub Foo(ByVal a As Integer) + a = 1 + End Sub +End Class" + Await VerifyBasicFixAllAsync({source1, source2}, {fix1, fix2}) + End Function Private Function CreateDiagnosticResult(parameterName As String, line As Integer, column As Integer) As DiagnosticResult Return New DiagnosticResult With { @@ -472,6 +523,5 @@ End Class .Locations = {New DiagnosticResultLocation("Test0.vb", line, column)} } End Function - End Class End Namespace \ No newline at end of file From 7366b38f6dae879f6d6da25276c6d21f807d59e3 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 4 Oct 2015 01:45:18 -0300 Subject: [PATCH 008/358] Update the source browser to use the version from @KirillOsenkov Point it to: http://ccref.azurewebsites.net See the https://github.com/code-cracker/referencesource to see where the source for that site is. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2101e79dd..35d68f63b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ our task board, definition of done, definition of ready, etc. [![Nuget downloads](http://img.shields.io/nuget/dt/codecracker.svg)](https://www.nuget.org/packages/codecracker/) [![Issues open](http://img.shields.io/github/issues-raw/code-cracker/code-cracker.svg)](https://huboard.com/code-cracker/code-cracker/) [![Coverage Status](https://img.shields.io/coveralls/code-cracker/code-cracker/master.svg)](https://coveralls.io/r/code-cracker/code-cracker?branch=master) -[![Source Browser](https://img.shields.io/badge/Browse-Source-green.svg)](http://sourcebrowser.io/Browse/code-cracker/code-cracker) +[![Source Browser](https://img.shields.io/badge/Browse-Source-green.svg)](http://ccref.azurewebsites.net) This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. @@ -275,4 +275,4 @@ This software is open source, licensed under the Apache License, Version 2.0. See [LICENSE.txt](https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt) for details. Check out the terms of the license before you contribute, fork, copy or do anything with the code. If you decide to contribute you agree to grant copyright of all your contribution to this project, and agree to -mention clearly if do not agree to these terms. Your work will be licensed with the project at Apache V2, along the rest of the code. \ No newline at end of file +mention clearly if do not agree to these terms. Your work will be licensed with the project at Apache V2, along the rest of the code. From 9304b0672ae4731a7da68f2e7b4a891a3fe3f79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorgeir?= Date: Sun, 4 Oct 2015 22:19:14 +0000 Subject: [PATCH 009/358] Fixed BUG on CC0008 and CC0009 (ObjectInitializer) when used with collection. --- .../Style/ObjectInitializerAnalyzer.cs | 5 ++- .../Style/ObjectInitializerTests.cs | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs index 7dac5fc99..05e8f3b25 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs @@ -55,6 +55,7 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) if (expressionStatement?.Expression?.IsNotKind(SyntaxKind.SimpleAssignmentExpression) ?? true) return; var assignmentExpression = (AssignmentExpressionSyntax)expressionStatement.Expression; if (assignmentExpression.Right.IsNotKind(SyntaxKind.ObjectCreationExpression)) return; + if ((assignmentExpression.Right as ObjectCreationExpressionSyntax).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; var variableSymbol = semanticModel.GetSymbolInfo(assignmentExpression.Left).Symbol; var assignmentExpressions = FindAssignmentExpressions(semanticModel, expressionStatement, variableSymbol); if (!assignmentExpressions.Any()) return; @@ -70,7 +71,9 @@ private static void AnalyzeLocalDeclaration(SyntaxNodeAnalysisContext context) if (localDeclarationStatement == null) return; if (localDeclarationStatement.Declaration?.Variables.Count != 1) return; var variable = localDeclarationStatement.Declaration.Variables.Single(); - if ((variable.Initializer as EqualsValueClauseSyntax)?.Value.IsNotKind(SyntaxKind.ObjectCreationExpression) ?? true) return; + var equalsValueClauseSyntax = variable.Initializer as EqualsValueClauseSyntax; + if (equalsValueClauseSyntax?.Value.IsNotKind(SyntaxKind.ObjectCreationExpression) ?? true) return; + if ((equalsValueClauseSyntax.Value as ObjectCreationExpressionSyntax).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; var variableSymbol = semanticModel.GetDeclaredSymbol(variable); var assignmentExpressionStatements = FindAssignmentExpressions(semanticModel, localDeclarationStatement, variableSymbol); if (!assignmentExpressionStatements.Any()) return; diff --git a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs index 246d45b7e..44d77d365 100644 --- a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs @@ -42,6 +42,24 @@ public int Foo() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task WhenUsedWithCollectionDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + var ys = new System.Collections.Generic.List { 4 }; + ys.Capacity = 3; + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WhenVariableIsDeclaredAndObjectIsCreatedButNoAssignmentsHappenLaterAnalyzerDoesNotCreateDiagnostic() { @@ -348,6 +366,26 @@ public int Foo() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task WhenUsedWithCollectionDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + System.Collections.Generic.List ys; + ys = new System.Collections.Generic.List { 4 }; + ys.Capacity = 3; + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] public async Task WhenCreatingObjectAndAssigningPropertiesThenAnalyzerCreatesDiagnostic() { @@ -395,6 +433,7 @@ public int Foo() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] public async Task WhenObjectIsCreatedButOnlyUnrelatedAssignmentsHappenLaterAnalyzerDoesNotCreateDiagnostic() { From 95e2c95af8106bf1544e8c40612670429cd8b7cc Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 4 Oct 2015 20:57:24 -0300 Subject: [PATCH 010/358] Make direct cast on ObjectInitializerAnalyzer --- src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs index 05e8f3b25..c98a9c629 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs @@ -55,7 +55,7 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) if (expressionStatement?.Expression?.IsNotKind(SyntaxKind.SimpleAssignmentExpression) ?? true) return; var assignmentExpression = (AssignmentExpressionSyntax)expressionStatement.Expression; if (assignmentExpression.Right.IsNotKind(SyntaxKind.ObjectCreationExpression)) return; - if ((assignmentExpression.Right as ObjectCreationExpressionSyntax).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; + if (((ObjectCreationExpressionSyntax)assignmentExpression.Right).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; var variableSymbol = semanticModel.GetSymbolInfo(assignmentExpression.Left).Symbol; var assignmentExpressions = FindAssignmentExpressions(semanticModel, expressionStatement, variableSymbol); if (!assignmentExpressions.Any()) return; @@ -73,7 +73,7 @@ private static void AnalyzeLocalDeclaration(SyntaxNodeAnalysisContext context) var variable = localDeclarationStatement.Declaration.Variables.Single(); var equalsValueClauseSyntax = variable.Initializer as EqualsValueClauseSyntax; if (equalsValueClauseSyntax?.Value.IsNotKind(SyntaxKind.ObjectCreationExpression) ?? true) return; - if ((equalsValueClauseSyntax.Value as ObjectCreationExpressionSyntax).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; + if (((ObjectCreationExpressionSyntax)equalsValueClauseSyntax.Value).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; var variableSymbol = semanticModel.GetDeclaredSymbol(variable); var assignmentExpressionStatements = FindAssignmentExpressions(semanticModel, localDeclarationStatement, variableSymbol); if (!assignmentExpressionStatements.Any()) return; From 1b412281f2d80dfd621a82592a156d80ec1256c0 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 4 Oct 2015 21:17:22 -0300 Subject: [PATCH 011/358] Update codecracker to latest unstable (rc3) --- src/CSharp/CodeCracker/CodeCracker.csproj | 4 ++-- src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs | 2 +- .../Design/CopyEventToVariableBeforeFireAnalyzer.cs | 2 +- .../CodeCracker/Design/EmptyCatchBlockAnalyzer.cs | 2 +- .../CodeCracker/Design/MakeMethodStaticAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs | 4 ++-- .../Design/StaticConstructorExceptionAnalyzer.cs | 2 +- .../Design/UseInvokeMethodToFireEventAnalyzer.cs | 2 +- .../Maintainability/XmlDocumentationAnalyzer.cs | 2 +- .../Performance/EmptyFinalizerAnalyzer.cs | 2 +- ...MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs | 2 +- .../RemoveWhereWhenItIsPossibleAnalyzer.cs | 2 +- .../Performance/SealedAttributeAnalyzer.cs | 2 +- .../Performance/StringBuilderInLoopAnalyzer.cs | 2 +- .../Performance/UseStaticRegexIsMatchAnalyzer.cs | 2 +- .../Refactoring/AddBracesToSwitchSectionsAnalyzer.cs | 2 +- .../Refactoring/AllowMembersOrderingAnalyzer.cs | 2 +- .../Refactoring/ChangeAnyToAllAnalyzer.cs | 8 ++++---- .../Refactoring/ComputeExpressionAnalyzer.cs | 2 +- .../IntroduceFieldFromConstructorAnalyzer.cs | 2 +- ...ntroduceFieldFromConstructorCodeFixProviderAll.cs | 2 +- .../CodeCracker/Refactoring/InvertForAnalyzer.cs | 2 +- .../CodeCracker/Refactoring/MergeNestedIfAnalyzer.cs | 2 +- .../Refactoring/NumericLiteralAnalyzer.cs | 2 +- .../Refactoring/ParameterRefactoryAnalyzer.cs | 2 +- .../Refactoring/SplitIntoNestedIfAnalyzer.cs | 2 +- .../Refactoring/SplitIntoNestedIfFixAllProvider.cs | 2 +- .../Refactoring/StringRepresentationAnalyzer.cs | 4 ++-- .../Reliability/UseConfigureAwaitFalseAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs | 2 +- .../CodeCracker/Style/ConsoleWriteLineAnalyzer.cs | 2 +- .../ConvertLambdaExpressionToMethodGroupAnalyzer.cs | 2 +- .../Style/ConvertToExpressionBodiedMemberAnalyzer.cs | 2 +- .../CodeCracker/Style/ConvertToSwitchAnalyzer.cs | 2 +- .../Style/EmptyObjectInitializerAnalyzer.cs | 2 +- .../CodeCracker/Style/ExistenceOperatorAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs | 2 +- .../CodeCracker/Style/InterfaceNameAnalyzer.cs | 2 +- .../CodeCracker/Style/ObjectInitializerAnalyzer.cs | 4 ++-- .../CodeCracker/Style/PropertyPrivateSetAnalyzer.cs | 2 +- .../Style/RemoveAsyncFromMethodAnalyzer.cs | 2 +- .../CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs | 2 +- .../Style/RemoveTrailingWhitespaceAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Style/StringFormatAnalyzer.cs | 2 +- .../CodeCracker/Style/SwitchToAutoPropAnalyzer.cs | 2 +- .../CodeCracker/Style/TaskNameAsyncAnalyzer.cs | 2 +- .../CodeCracker/Style/TernaryOperatorAnalyzer.cs | 4 ++-- .../Style/UnnecessaryParenthesisAnalyzer.cs | 2 +- .../CodeCracker/Style/UseEmptyStringAnalyzer.cs | 2 +- .../Style/UseEmptyStringCodeFixProviderAll.cs | 2 +- .../CodeCracker/Style/UseStringEmptyAnalyzer.cs | 2 +- .../Style/UseStringEmptyCodeFixProviderAll.cs | 2 +- .../AbstractClassShouldNotHavePublicCtorsAnalyzer.cs | 2 +- .../CodeCracker/Usage/ArgumentExceptionAnalyzer.cs | 2 +- .../Usage/CallExtensionMethodAsExtensionAnalyzer.cs | 2 +- .../Usage/DisposableFieldNotDisposedAnalyzer.cs | 4 ++-- .../Usage/DisposableVariableNotDisposedAnalyzer.cs | 2 +- .../DisposableVariableNotDisposedFixAllProvider.cs | 2 +- .../DisposablesShouldCallSuppressFinalizeAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Usage/IfReturnTrueAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Usage/JsonNetAnalyzer.cs | 2 +- .../Usage/NoPrivateReadonlyFieldAnalyzer.cs | 2 +- .../CodeCracker/Usage/ReadonlyFieldAnalyzer.cs | 2 +- .../Usage/RedundantFieldAssignmentAnalyzer.cs | 2 +- src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs | 2 +- .../Usage/RemovePrivateMethodNeverUsedAnalyzer.cs | 2 +- .../Usage/RemoveRedundantElseClauseAnalyzer.cs | 2 +- .../Usage/RemoveUnreachableCodeFixAllProvider.cs | 2 +- .../CodeCracker/Usage/RethrowExceptionAnalyzer.cs | 2 +- .../SimplifyRedundantBooleanComparisonsAnalyzer.cs | 2 +- .../CodeCracker/Usage/StringFormatArgsAnalyzer.cs | 4 ++-- .../CodeCracker/Usage/UnusedParametersAnalyzer.cs | 2 +- .../Usage/UnusedParametersCodeFixAllProvider.cs | 2 +- src/CSharp/CodeCracker/Usage/UriAnalyzer.cs | 2 +- .../Usage/VirtualMethodOnConstructorAnalyzer.cs | 2 +- src/CSharp/CodeCracker/packages.config | 2 +- .../CodeCracker.Common/CodeCracker.Common.csproj | 4 ++-- src/Common/CodeCracker.Common/packages.config | 2 +- src/VisualBasic/CodeCracker/CodeCracker.vbproj | 4 ++-- .../CodeCracker/Design/NameOfCodeFixProvider.vb | 4 ++-- .../Refactoring/ChangeAnyToAllCodeFixProvider.vb | 6 +++--- src/VisualBasic/CodeCracker/packages.config | 2 +- test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj | 4 ++-- .../CodeCracker.Test/Style/SwitchToAutoPropTests.cs | 12 ++++++------ test/CSharp/CodeCracker.Test/packages.config | 2 +- .../CodeCracker.Test.Common.csproj | 4 ++-- .../Helpers/DiagnosticVerifier.Helper.cs | 12 ++++++------ test/Common/CodeCracker.Test.Common/packages.config | 2 +- .../CodeCracker.Test/CodeCracker.Test.vbproj | 4 ++-- .../Performance/StringBuilderInLoopTests.vb | 4 ++-- test/VisualBasic/CodeCracker.Test/packages.config | 2 +- 92 files changed, 121 insertions(+), 121 deletions(-) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 6c30cddc6..3e19c1e5b 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -219,8 +219,8 @@ - - + + diff --git a/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs b/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs index 8022e180a..2fe03bf9d 100644 --- a/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs @@ -12,7 +12,7 @@ public class CatchEmptyAnalyzer : DiagnosticAnalyzer internal const string Title = "Your catch maybe include some Exception"; internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Design; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.CatchEmpty.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs b/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs index aaa6b1fee..7f1658854 100644 --- a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs @@ -17,7 +17,7 @@ public class CopyEventToVariableBeforeFireAnalyzer : DiagnosticAnalyzer + "As in a multi-threading context it is possible for an event to be unsuscribed between " + "the moment where it is checked to be non-null and the moment it is raised the event must " + "be copied to a temporary variable before the check."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs b/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs index 43e1d02b1..d547dc5f4 100644 --- a/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs @@ -15,7 +15,7 @@ public class EmptyCatchBlockAnalyzer : DiagnosticAnalyzer const string Description = "An empty catch block suppress all errors and shouldn't be used.\r\n" +"If the error is expected consider logging it or changing the control flow such that it is explicit."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId.EmptyCatchBlock.ToDiagnosticId(), + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId.EmptyCatchBlock.ToDiagnosticId(), Title, MessageFormat, Category, diff --git a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs index bf982204f..d6ad156c9 100644 --- a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs @@ -17,7 +17,7 @@ public class MakeMethodStaticAnalyzer : DiagnosticAnalyzer "not creating a virtual, abstract, new or partial method, and if it is not a method override, " + "your instance method may be changed to a static method."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.MakeMethodStatic.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs index c7d448c9b..8f98c156e 100644 --- a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs @@ -16,7 +16,7 @@ public class NameOfAnalyzer : DiagnosticAnalyzer internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.NameOfAnalyzer_MessageFormat), Resources.ResourceManager, typeof(Resources)); internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.NameOfAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); internal const string Category = SupportedCategories.Design; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.NameOf.ToDiagnosticId(), Title, MessageFormat, @@ -25,7 +25,7 @@ public class NameOfAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true, description: Description, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.NameOf)); - internal static DiagnosticDescriptor RuleExternal = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleExternal = new DiagnosticDescriptor( DiagnosticId.NameOf_External.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs index 2bede249b..946cae300 100644 --- a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs @@ -18,7 +18,7 @@ public class StaticConstructorExceptionAnalyzer : DiagnosticAnalyzer + "Exception thrown in this context force callers to use 'try' block around any useage of the class " + "and should be avoided."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StaticConstructorException.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index dc6b973db..75c9fc28d 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -16,7 +16,7 @@ public class UseInvokeMethodToFireEventAnalyzer : DiagnosticAnalyzer const string Description = "In C#6 an event can be invoked using the null-propagating operator (?.) and it's" + "invoke method to avoid throwing a NullReference exception when there is no event handler attached."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs index 520e845e2..79fca59dd 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs @@ -14,7 +14,7 @@ public sealed class XmlDocumentationAnalyzer : DiagnosticAnalyzer { internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.XmlDocumentationAnalyzer_Title), Resources.ResourceManager, typeof(Resources)); - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.XmlDocumentation.ToDiagnosticId(), Title, Title, diff --git a/src/CSharp/CodeCracker/Performance/EmptyFinalizerAnalyzer.cs b/src/CSharp/CodeCracker/Performance/EmptyFinalizerAnalyzer.cs index eaa7a5deb..cd5a4f333 100644 --- a/src/CSharp/CodeCracker/Performance/EmptyFinalizerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/EmptyFinalizerAnalyzer.cs @@ -17,7 +17,7 @@ public class EmptyFinalizerAnalyzer : DiagnosticAnalyzer + "Garbage Collector when no longer used." + "It will instead be placed in the finalizer queue needlessly using resources."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.EmptyFinalizer.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs index c809e5db5..f5c8e2b29 100644 --- a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs @@ -15,7 +15,7 @@ public class MakeLocalVariableConstWhenItIsPossibleAnalyzer : internal const string MessageFormat = "This variables can be made const."; internal const string Category = SupportedCategories.Performance; const string Description = "This variable is assigned a constant value and never changed it can be made 'const'"; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs index 3671bb065..6ddf3bb23 100644 --- a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs @@ -27,7 +27,7 @@ public class RemoveWhereWhenItIsPossibleAnalyzer : DiagnosticAnalyzer "SingleOrDefault", "Count" }; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Performance/SealedAttributeAnalyzer.cs b/src/CSharp/CodeCracker/Performance/SealedAttributeAnalyzer.cs index 9f630d7b8..dc4cf7553 100644 --- a/src/CSharp/CodeCracker/Performance/SealedAttributeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/SealedAttributeAnalyzer.cs @@ -15,7 +15,7 @@ public class SealedAttributeAnalyzer : DiagnosticAnalyzer + "inheritence hierarchy of the attribute class. " + "Marking the type as sealed eliminate this search and can improve performance"; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId.SealedAttribute.ToDiagnosticId(), + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId.SealedAttribute.ToDiagnosticId(), Title, MessageFormat, Category, diff --git a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs index cab72e9b4..1ef255876 100644 --- a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs @@ -17,7 +17,7 @@ public class StringBuilderInLoopAnalyzer : DiagnosticAnalyzer const string Description = "Do not concatenate a string on a loop. It will alocate a lot of memory." + "Use a StringBuilder instead. It will will require less allocation, less garbage collector work, less CPU cycles, and less overall time."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs b/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs index c19ed7f34..2ecfa57dc 100644 --- a/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs @@ -15,7 +15,7 @@ public class UseStaticRegexIsMatchAnalyzer : DiagnosticAnalyzer const string Description = "Instantiating the Regex object multiple times might be bad for performance. " + "You may want to use the static IsMatch method from Regex class and/or compile the regex."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseStaticRegexIsMatch.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs index bbbd7b15a..33012a4af 100644 --- a/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs @@ -14,7 +14,7 @@ public class AddBracesToSwitchSectionsAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Add braces for each section in this switch"; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/AllowMembersOrderingAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/AllowMembersOrderingAnalyzer.cs index 1a7148ccd..eda3b461a 100644 --- a/src/CSharp/CodeCracker/Refactoring/AllowMembersOrderingAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/AllowMembersOrderingAnalyzer.cs @@ -13,7 +13,7 @@ public class AllowMembersOrderingAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Ordering member inside this type."; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.AllowMembersOrdering.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/ChangeAnyToAllAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/ChangeAnyToAllAnalyzer.cs index 946b0b4d4..c259c0cdd 100644 --- a/src/CSharp/CodeCracker/Refactoring/ChangeAnyToAllAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/ChangeAnyToAllAnalyzer.cs @@ -15,7 +15,7 @@ public class ChangeAnyToAllAnalyzer : DiagnosticAnalyzer internal const string TitleAll = MessageAll; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor RuleAny = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleAny = new DiagnosticDescriptor( DiagnosticId.ChangeAnyToAll.ToDiagnosticId(), TitleAny, MessageAny, @@ -23,7 +23,7 @@ public class ChangeAnyToAllAnalyzer : DiagnosticAnalyzer DiagnosticSeverity.Hidden, isEnabledByDefault: true, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.ChangeAnyToAll)); - internal static DiagnosticDescriptor RuleAll = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleAll = new DiagnosticDescriptor( DiagnosticId.ChangeAllToAny.ToDiagnosticId(), TitleAll, MessageAll, @@ -42,8 +42,8 @@ public class ChangeAnyToAllAnalyzer : DiagnosticAnalyzer private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; - var invocation = context.Node as InvocationExpressionSyntax; - if (invocation.Parent.IsKind(SyntaxKind.ExpressionStatement)) return; + var invocation = (InvocationExpressionSyntax)context.Node; + if (invocation.Parent?.IsKind(SyntaxKind.ExpressionStatement) ?? true) return; var diagnosticToRaise = GetCorrespondingDiagnostic(context.SemanticModel, invocation); if (diagnosticToRaise == null) return; var diagnostic = Diagnostic.Create(diagnosticToRaise, ((MemberAccessExpressionSyntax)invocation.Expression).Name.GetLocation()); diff --git a/src/CSharp/CodeCracker/Refactoring/ComputeExpressionAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/ComputeExpressionAnalyzer.cs index 8b883aebb..63224cd90 100644 --- a/src/CSharp/CodeCracker/Refactoring/ComputeExpressionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/ComputeExpressionAnalyzer.cs @@ -15,7 +15,7 @@ public class ComputeExpressionAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Refactoring; const string Description = "You may change an expression for its value if the expression is made of literal values."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ComputeExpression.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs index 545ee93f1..aada36ec3 100644 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs @@ -16,7 +16,7 @@ public class IntroduceFieldFromConstructorAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Refactoring; const string Description = "Consider introduce field for constructor parameters."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.IntroduceFieldFromConstructor.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs index 34abd1e24..81d29b07e 100644 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs +++ b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs @@ -11,7 +11,7 @@ public sealed class IntroduceFieldFromConstructorCodeFixAllProvider : FixAllProv { private static readonly SyntaxAnnotation introduceFieldAnnotation = new SyntaxAnnotation(nameof(IntroduceFieldFromConstructorCodeFixAllProvider)); private IntroduceFieldFromConstructorCodeFixAllProvider() { } - public static IntroduceFieldFromConstructorCodeFixAllProvider Instance = new IntroduceFieldFromConstructorCodeFixAllProvider(); + public static readonly IntroduceFieldFromConstructorCodeFixAllProvider Instance = new IntroduceFieldFromConstructorCodeFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { diff --git a/src/CSharp/CodeCracker/Refactoring/InvertForAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/InvertForAnalyzer.cs index fb2363ba7..75dc49e56 100644 --- a/src/CSharp/CodeCracker/Refactoring/InvertForAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/InvertForAnalyzer.cs @@ -13,7 +13,7 @@ public class InvertForAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Make it a for loop that {0} the counter."; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.InvertFor.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/MergeNestedIfAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/MergeNestedIfAnalyzer.cs index 0a04b580f..e4ffa333b 100644 --- a/src/CSharp/CodeCracker/Refactoring/MergeNestedIfAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/MergeNestedIfAnalyzer.cs @@ -13,7 +13,7 @@ public class MergeNestedIfAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Merge nested ifs into a single if"; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.MergeNestedIf.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/NumericLiteralAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/NumericLiteralAnalyzer.cs index e3d46b32b..f60caa320 100644 --- a/src/CSharp/CodeCracker/Refactoring/NumericLiteralAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/NumericLiteralAnalyzer.cs @@ -13,7 +13,7 @@ public class NumericLiteralAnalyzer : DiagnosticAnalyzer internal const string Message = "You may change {0} to a {1} literal type."; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.NumericLiteral.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryAnalyzer.cs index f5fdbe6dc..f113c416e 100644 --- a/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryAnalyzer.cs @@ -14,7 +14,7 @@ public class ParameterRefactoryAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "When the method has more than three parameters, use new class."; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ParameterRefactory.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfAnalyzer.cs index ef483a284..e37d41246 100644 --- a/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfAnalyzer.cs @@ -13,7 +13,7 @@ public class SplitIntoNestedIfAnalyzer : DiagnosticAnalyzer internal const string Message = "Split into nested if."; internal const string Category = SupportedCategories.Refactoring; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.SplitIntoNestedIf.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs b/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs index f1bf997d9..568e8af7c 100644 --- a/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs @@ -11,7 +11,7 @@ public sealed class SplitIntoNestedIfFixAllProvider : FixAllProvider { private static readonly SyntaxAnnotation nestedIfAnnotation = new SyntaxAnnotation(nameof(SplitIntoNestedIfFixAllProvider)); private SplitIntoNestedIfFixAllProvider() { } - public static SplitIntoNestedIfFixAllProvider Instance = new SplitIntoNestedIfFixAllProvider(); + public static readonly SplitIntoNestedIfFixAllProvider Instance = new SplitIntoNestedIfFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { switch (fixAllContext.Scope) diff --git a/src/CSharp/CodeCracker/Refactoring/StringRepresentationAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/StringRepresentationAnalyzer.cs index 7e44a8e6a..3c7bbd8a3 100644 --- a/src/CSharp/CodeCracker/Refactoring/StringRepresentationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/StringRepresentationAnalyzer.cs @@ -11,7 +11,7 @@ namespace CodeCracker.CSharp.Refactoring [DiagnosticAnalyzer(LanguageNames.CSharp)] public class StringRepresentationAnalyzer : DiagnosticAnalyzer { - internal static DiagnosticDescriptor RegularStringRule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RegularStringRule = new DiagnosticDescriptor( DiagnosticId.StringRepresentation_RegularString.ToDiagnosticId(), "Regular string", "Change to regular string", @@ -20,7 +20,7 @@ public class StringRepresentationAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.StringRepresentation_RegularString)); - internal static DiagnosticDescriptor VerbatimStringRule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor VerbatimStringRule = new DiagnosticDescriptor( DiagnosticId.StringRepresentation_VerbatimString.ToDiagnosticId(), "Verbatim string", "Change to verbatim string", diff --git a/src/CSharp/CodeCracker/Reliability/UseConfigureAwaitFalseAnalyzer.cs b/src/CSharp/CodeCracker/Reliability/UseConfigureAwaitFalseAnalyzer.cs index e73b3bcf6..4af4bbf13 100644 --- a/src/CSharp/CodeCracker/Reliability/UseConfigureAwaitFalseAnalyzer.cs +++ b/src/CSharp/CodeCracker/Reliability/UseConfigureAwaitFalseAnalyzer.cs @@ -13,7 +13,7 @@ public class UseConfigureAwaitFalseAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Consider using ConfigureAwait(false) on the awaited task."; internal const string Category = SupportedCategories.Reliability; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseConfigureAwaitFalse.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs b/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs index 87e9795a6..a320a29fb 100644 --- a/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs @@ -16,7 +16,7 @@ public class AlwaysUseVarAnalyzer : DiagnosticAnalyzer const string Description = "Usage of an implicit type improve readability of the code.\r\n" + "Code depending on types for their readability should be refactored with better variable " + "names or by introducing well-named methods."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.AlwaysUseVar.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ConsoleWriteLineAnalyzer.cs b/src/CSharp/CodeCracker/Style/ConsoleWriteLineAnalyzer.cs index fb8a85ae1..d9d34cf1c 100644 --- a/src/CSharp/CodeCracker/Style/ConsoleWriteLineAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ConsoleWriteLineAnalyzer.cs @@ -14,7 +14,7 @@ public class ConsoleWriteLineAnalyzer : DiagnosticAnalyzer internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.ConsoleWriteLineAnalyzer_MessageFormat), Resources.ResourceManager, typeof(Resources)); internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.ConsoleWriteLineAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs b/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs index 433230bff..671e55349 100644 --- a/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs @@ -15,7 +15,7 @@ public class ConvertLambdaExpressionToMethodGroupAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "The extra unnecessary layer of indirection induced by the lambda expression may be avoided by passing the method group instead."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ConvertToExpressionBodiedMemberAnalyzer.cs b/src/CSharp/CodeCracker/Style/ConvertToExpressionBodiedMemberAnalyzer.cs index 6e76427b5..ede46efcd 100644 --- a/src/CSharp/CodeCracker/Style/ConvertToExpressionBodiedMemberAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ConvertToExpressionBodiedMemberAnalyzer.cs @@ -14,7 +14,7 @@ public class ConvertToExpressionBodiedMemberAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Usage of an expression bodied members improve readability of the code."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ConvertToSwitchAnalyzer.cs b/src/CSharp/CodeCracker/Style/ConvertToSwitchAnalyzer.cs index e5cb11c13..4924daafe 100644 --- a/src/CSharp/CodeCracker/Style/ConvertToSwitchAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ConvertToSwitchAnalyzer.cs @@ -17,7 +17,7 @@ public class ConvertToSwitchAnalyzer : DiagnosticAnalyzer const string Description = "Multiple 'if' and 'else if' on the same variable can be replaced with a 'switch'" + "on the variable\r\n\r\n" + "Note: This diagnostic trigger for 3 or more 'case' statements"; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ConvertToSwitch.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs index df365f84a..7597ea48c 100644 --- a/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs @@ -15,7 +15,7 @@ public class EmptyObjectInitializerAnalyzer : DiagnosticAnalyzer const string Description = "An empty object initializer doesn't add any information and only clutter the code.\r\n" + "If there is no member to initialize, prefer using the standard constructor syntax."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.EmptyObjectInitializer.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ExistenceOperatorAnalyzer.cs b/src/CSharp/CodeCracker/Style/ExistenceOperatorAnalyzer.cs index cba57bd31..c22b39f18 100644 --- a/src/CSharp/CodeCracker/Style/ExistenceOperatorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ExistenceOperatorAnalyzer.cs @@ -13,7 +13,7 @@ public class ExistenceOperatorAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Style; const string Description = "The null-propagating operator allow for terse code to handle potentially null variables."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ExistenceOperator.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs index 98c6866de..5ef048995 100644 --- a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs @@ -14,7 +14,7 @@ public class ForInArrayAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Style; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ForInArray.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/InterfaceNameAnalyzer.cs b/src/CSharp/CodeCracker/Style/InterfaceNameAnalyzer.cs index a4270b9a1..4cce637cd 100644 --- a/src/CSharp/CodeCracker/Style/InterfaceNameAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/InterfaceNameAnalyzer.cs @@ -14,7 +14,7 @@ public class InterfaceNameAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Consider naming interfaces starting with 'I'."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.InterfaceName.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs index c98a9c629..dfb618e73 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs @@ -18,7 +18,7 @@ public class ObjectInitializerAnalyzer : DiagnosticAnalyzer const string Description = "When possible an object initializer should be used to initialize the properties of an " + "object instead of multiple assignments."; - internal static DiagnosticDescriptor RuleAssignment = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleAssignment = new DiagnosticDescriptor( DiagnosticId.ObjectInitializer_Assignment.ToDiagnosticId(), TitleLocalDeclaration, MessageFormat, @@ -28,7 +28,7 @@ public class ObjectInitializerAnalyzer : DiagnosticAnalyzer description: Description, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.ObjectInitializer_Assignment)); - internal static DiagnosticDescriptor RuleLocalDeclaration = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleLocalDeclaration = new DiagnosticDescriptor( DiagnosticId.ObjectInitializer_LocalDeclaration.ToDiagnosticId(), TitleLocalDeclaration, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/PropertyPrivateSetAnalyzer.cs b/src/CSharp/CodeCracker/Style/PropertyPrivateSetAnalyzer.cs index 0abbdeb82..58d6c3c9e 100644 --- a/src/CSharp/CodeCracker/Style/PropertyPrivateSetAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/PropertyPrivateSetAnalyzer.cs @@ -14,7 +14,7 @@ public class PropertyPrivateSetAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Use private set for automatic properties."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.PropertyPrivateSet.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/RemoveAsyncFromMethodAnalyzer.cs b/src/CSharp/CodeCracker/Style/RemoveAsyncFromMethodAnalyzer.cs index b89088111..8d68344e1 100644 --- a/src/CSharp/CodeCracker/Style/RemoveAsyncFromMethodAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/RemoveAsyncFromMethodAnalyzer.cs @@ -15,7 +15,7 @@ public class RemoveAsyncFromMethodAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Remove Async termination when method is not asynchronous."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveAsyncFromMethod.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs b/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs index 765dc1e10..d94d0374d 100644 --- a/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs @@ -14,7 +14,7 @@ public class RemoveCommentedCodeAnalyzer : DiagnosticAnalyzer internal const string Title = "Remove commented code."; internal const string MessageFormat = "Commented code should be removed."; internal const string Category = SupportedCategories.Style; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveCommentedCode.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceAnalyzer.cs b/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceAnalyzer.cs index 37aabc147..e34368cda 100644 --- a/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceAnalyzer.cs @@ -16,7 +16,7 @@ public class RemoveTrailingWhitespaceAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Trailing whitespaces are ugly and show sloppiness. Remove them."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveTrailingWhitespace.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/StringFormatAnalyzer.cs b/src/CSharp/CodeCracker/Style/StringFormatAnalyzer.cs index f2651e57a..55a9a819a 100644 --- a/src/CSharp/CodeCracker/Style/StringFormatAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/StringFormatAnalyzer.cs @@ -17,7 +17,7 @@ public class StringFormatAnalyzer : DiagnosticAnalyzer internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.StringFormatAnalyzer_MessageFormat), Resources.ResourceManager, typeof(Resources)); internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.StringFormatAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StringFormat.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs index 8cb745d9f..9bf20994f 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs @@ -17,7 +17,7 @@ public class SwitchToAutoPropAnalyzer : DiagnosticAnalyzer internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.SwitchToAutoPropAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); internal const string Category = SupportedCategories.Style; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.SwitchToAutoProp.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs index d3f91f05a..5fd40d27c 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs @@ -14,7 +14,7 @@ public class TaskNameAsyncAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Async method can be terminating with 'Async' name."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.TaskNameAsync.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorAnalyzer.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorAnalyzer.cs index 1231a8705..0b53d35e5 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorAnalyzer.cs @@ -15,7 +15,7 @@ public class TernaryOperatorAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; internal const string MessageFormatForIfWithAssignment = "{0}"; - internal static DiagnosticDescriptor RuleForIfWithReturn = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleForIfWithReturn = new DiagnosticDescriptor( DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), Title, MessageFormatForIfWithReturn, @@ -24,7 +24,7 @@ public class TernaryOperatorAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.TernaryOperator_Return)); - internal static DiagnosticDescriptor RuleForIfWithAssignment = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleForIfWithAssignment = new DiagnosticDescriptor( DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), Title, MessageFormatForIfWithAssignment, diff --git a/src/CSharp/CodeCracker/Style/UnnecessaryParenthesisAnalyzer.cs b/src/CSharp/CodeCracker/Style/UnnecessaryParenthesisAnalyzer.cs index 2021a075a..410eb60be 100644 --- a/src/CSharp/CodeCracker/Style/UnnecessaryParenthesisAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/UnnecessaryParenthesisAnalyzer.cs @@ -15,7 +15,7 @@ public class UnnecessaryParenthesisAnalyzer : DiagnosticAnalyzer const string Description = "There is no need to specify that the no-parameter constructor is used with " + " an initializer as it is implicit"; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UnnecessaryParenthesis.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/UseEmptyStringAnalyzer.cs b/src/CSharp/CodeCracker/Style/UseEmptyStringAnalyzer.cs index ad98257eb..cfba91fb3 100644 --- a/src/CSharp/CodeCracker/Style/UseEmptyStringAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/UseEmptyStringAnalyzer.cs @@ -18,7 +18,7 @@ public class UseEmptyStringAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Style; const string Description = "Consider using " + EmptyString + InsteadStringEmpty; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseEmptyString.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs b/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs index 516132f71..a26d828df 100644 --- a/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs +++ b/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs @@ -14,7 +14,7 @@ public sealed class UseEmptyStringCodeFixAllProvider : FixAllProvider { private static readonly SyntaxAnnotation useEmptyStringAnnotation = new SyntaxAnnotation(nameof(UseEmptyStringCodeFixAllProvider)); private UseEmptyStringCodeFixAllProvider() { } - public static UseEmptyStringCodeFixAllProvider Instance = new UseEmptyStringCodeFixAllProvider(); + public static readonly UseEmptyStringCodeFixAllProvider Instance = new UseEmptyStringCodeFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { diff --git a/src/CSharp/CodeCracker/Style/UseStringEmptyAnalyzer.cs b/src/CSharp/CodeCracker/Style/UseStringEmptyAnalyzer.cs index 42a184713..31e03ce1d 100644 --- a/src/CSharp/CodeCracker/Style/UseStringEmptyAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/UseStringEmptyAnalyzer.cs @@ -14,7 +14,7 @@ public class UseStringEmptyAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Use 'String.Empty' instead of \"\""; internal const string Category = SupportedCategories.Style; const string Description = "Consider user 'String.Empty' instead of \"\""; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseStringEmpty.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs b/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs index a70674ab9..0498b21d0 100644 --- a/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs +++ b/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs @@ -14,7 +14,7 @@ public sealed class UseStringEmptyCodeFixAllProvider : FixAllProvider { private static readonly SyntaxAnnotation useStringEmptyAnnotation = new SyntaxAnnotation(nameof(UseStringEmptyCodeFixAllProvider)); private UseStringEmptyCodeFixAllProvider() { } - public static UseStringEmptyCodeFixAllProvider Instance = new UseStringEmptyCodeFixAllProvider(); + public static readonly UseStringEmptyCodeFixAllProvider Instance = new UseStringEmptyCodeFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { diff --git a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs index 0acb2a014..4e70142cd 100644 --- a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs @@ -14,7 +14,7 @@ public class AbstractClassShouldNotHavePublicCtorsAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Constructor should not be public."; internal const string Category = SupportedCategories.Usage; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.AbstractClassShouldNotHavePublicCtors.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/ArgumentExceptionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ArgumentExceptionAnalyzer.cs index 9cf229b82..b2a1daa96 100644 --- a/src/CSharp/CodeCracker/Usage/ArgumentExceptionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ArgumentExceptionAnalyzer.cs @@ -17,7 +17,7 @@ public class ArgumentExceptionAnalyzer : DiagnosticAnalyzer const string Description = "The string passed as the 'paramName' argument of ArgumentException constructor " + "must be the name of one of the method arguments.\r\n" + "It can be either specified directly or using the nameof() operator (C#6 only)"; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ArgumentException.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index caf58b069..391435f81 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -17,7 +17,7 @@ public class CallExtensionMethodAsExtensionAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "Do not call '{0}' method of class '{1}' as a static method"; internal const string Category = SupportedCategories.Usage; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs index d90948001..60abe4830 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs @@ -16,7 +16,7 @@ public class DisposableFieldNotDisposedAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "This class has a disposable field and is not disposing it."; - internal static DiagnosticDescriptor RuleForReturned = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleForReturned = new DiagnosticDescriptor( DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Title, MessageFormat, @@ -25,7 +25,7 @@ public class DisposableFieldNotDisposedAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true, description: Description, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.DisposableFieldNotDisposed_Returned)); - internal static DiagnosticDescriptor RuleForCreated = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleForCreated = new DiagnosticDescriptor( DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index 506ba41fa..a157fd7e7 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -17,7 +17,7 @@ public class DisposableVariableNotDisposedAnalyzer : DiagnosticAnalyzer const string Description = "When a disposable object is created it should be disposed as soon as possible.\n" + "This warning will appear if you create a disposable object and don't store, return or dispose it."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs index b52ca3681..d49053746 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs @@ -11,7 +11,7 @@ public sealed class DisposableVariableNotDisposedFixAllProvider : FixAllProvider { private static readonly SyntaxAnnotation disposeAnnotation = new SyntaxAnnotation(nameof(DisposableVariableNotDisposedFixAllProvider)); private DisposableVariableNotDisposedFixAllProvider() { } - public static DisposableVariableNotDisposedFixAllProvider Instance = new DisposableVariableNotDisposedFixAllProvider(); + public static readonly DisposableVariableNotDisposedFixAllProvider Instance = new DisposableVariableNotDisposedFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { switch (fixAllContext.Scope) diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs index 15434698c..e57e1b769 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs @@ -15,7 +15,7 @@ public class DisposablesShouldCallSuppressFinalizeAnalyzer : DiagnosticAnalyzer const string Description = "Classes implementing IDisposable should call the GC.SuppressFinalize method in their " + "finalize method to avoid any finalizer from being called.\r\n" + "This rule should be followed even if the class doesn't have a finalizer as a derived class could have one."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs b/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs index 5513b0b0f..1cca30446 100644 --- a/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs @@ -19,7 +19,7 @@ public class IPAddressAnalyzer : DiagnosticAnalyzer "This diagnostic checks the IP Address string and triggers if the parsing fail " + "by throwing an exception."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.IPAddress.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/IfReturnTrueAnalyzer.cs b/src/CSharp/CodeCracker/Usage/IfReturnTrueAnalyzer.cs index 645073e91..17afe4477 100644 --- a/src/CSharp/CodeCracker/Usage/IfReturnTrueAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/IfReturnTrueAnalyzer.cs @@ -15,7 +15,7 @@ public class IfReturnTrueAnalyzer : DiagnosticAnalyzer const string Description = "Using an if/else to return true/false depending on the condition isn't useful.\r\n" + "As the condition is already a boolean it can be returned directly"; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.IfReturnTrue.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Usage/JsonNetAnalyzer.cs b/src/CSharp/CodeCracker/Usage/JsonNetAnalyzer.cs index 88fe95647..d69c802dc 100644 --- a/src/CSharp/CodeCracker/Usage/JsonNetAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/JsonNetAnalyzer.cs @@ -17,7 +17,7 @@ public class JsonNetAnalyzer : DiagnosticAnalyzer const string Description = "This diagnostic checks the json string and triggers if the parsing fail " + "by throwing an exception."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.JsonNet.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs index 31435b436..e1a2bbd90 100644 --- a/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs @@ -16,7 +16,7 @@ public class NoPrivateReadonlyFieldAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "A field that is only assigned on the constructor can be made readonly."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.NoPrivateReadonlyField.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 75a3f0ffe..9ecc58031 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -16,7 +16,7 @@ public class ReadonlyFieldAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "A field that is only assigned on the constructor can be made readonly."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.ReadonlyField.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Usage/RedundantFieldAssignmentAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RedundantFieldAssignmentAnalyzer.cs index 2d52923fc..7791f70cb 100644 --- a/src/CSharp/CodeCracker/Usage/RedundantFieldAssignmentAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RedundantFieldAssignmentAnalyzer.cs @@ -16,7 +16,7 @@ public class RedundantFieldAssignmentAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "It's recommend not to assign the default value to a field as a performance optimization."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs index 99769d481..6ce7c1a5d 100644 --- a/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs @@ -16,7 +16,7 @@ public class RegexAnalyzer : DiagnosticAnalyzer const string Description = "This diagnostic compile the Regex expression and trigger if the compilation fail " + "by throwing an exception."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.Regex.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs index ef357a17e..059fa8e3c 100644 --- a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs @@ -18,7 +18,7 @@ public class RemovePrivateMethodNeverUsedAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "When a private method declared does not used might bring incorrect conclusions."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemovePrivateMethodNeverUsed.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Usage/RemoveRedundantElseClauseAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RemoveRedundantElseClauseAnalyzer.cs index 3921eb943..03294eb66 100644 --- a/src/CSharp/CodeCracker/Usage/RemoveRedundantElseClauseAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RemoveRedundantElseClauseAnalyzer.cs @@ -14,7 +14,7 @@ public class RemoveRedundantElseClauseAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "An empty else clause only adds complexity. You may safely remove it."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs index 0276ea344..936cb1ef5 100644 --- a/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs @@ -11,7 +11,7 @@ public sealed class RemoveUnreachableCodeFixAllProvider : FixAllProvider { private static readonly SyntaxAnnotation removeUnreachableCodeAnnotation = new SyntaxAnnotation(nameof(RemoveUnreachableCodeFixAllProvider)); private RemoveUnreachableCodeFixAllProvider() { } - public static RemoveUnreachableCodeFixAllProvider Instance = new RemoveUnreachableCodeFixAllProvider(); + public static readonly RemoveUnreachableCodeFixAllProvider Instance = new RemoveUnreachableCodeFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { switch (fixAllContext.Scope) diff --git a/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs index a649c00b6..410c24501 100644 --- a/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs @@ -17,7 +17,7 @@ public class RethrowExceptionAnalyzer : DiagnosticAnalyzer + "stack trace and will make debugging this exception a lot more difficult.\r\n" + "The correct way to rethrow an exception without changing it is by using 'throw' without any parameter."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RethrowException.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsAnalyzer.cs index 07972fa73..0a149d2b5 100644 --- a/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsAnalyzer.cs @@ -13,7 +13,7 @@ public class SimplifyRedundantBooleanComparisonsAnalyzer : DiagnosticAnalyzer internal const string MessageFormat = "You can remove this comparison."; internal const string Category = SupportedCategories.Usage; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.SimplifyRedundantBooleanComparisons.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs index 9705738a8..cd386b625 100644 --- a/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs @@ -17,7 +17,7 @@ public class StringFormatArgsAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "The format argument in String.Format determines the number of argument, considering the {} inside. You should pass the correct number of arguments."; - internal static DiagnosticDescriptor IncorrectNumberOfArgs = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor IncorrectNumberOfArgs = new DiagnosticDescriptor( DiagnosticId.StringFormatArgs.ToDiagnosticId(), Title, IncorrectNumberOfArgsMessage, @@ -27,7 +27,7 @@ public class StringFormatArgsAnalyzer : DiagnosticAnalyzer description: Description, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.StringFormatArgs)); - internal static DiagnosticDescriptor InvalidArgsReference = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor InvalidArgsReference = new DiagnosticDescriptor( DiagnosticId.StringFormatArgs.ToDiagnosticId(), Title, InvalidArgsReferenceMessage, diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs index 5ba4d88ae..823ea9d1c 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs @@ -17,7 +17,7 @@ public class UnusedParametersAnalyzer : DiagnosticAnalyzer const string Description = "When a method declares a parameter and does not use it might bring incorrect conclusions for anyone reading the code and also demands the parameter when the method is called, unnecessarily.\r\n" + "You should delete the parameter in such cases."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UnusedParameters.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs index 4dc4c56fb..e41a8fa8b 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs @@ -13,7 +13,7 @@ public sealed class UnusedParametersCodeFixAllProvider : FixAllProvider private UnusedParametersCodeFixAllProvider() { } private const string message = "Remove unused parameter"; - public static UnusedParametersCodeFixAllProvider Instance = new UnusedParametersCodeFixAllProvider(); + public static readonly UnusedParametersCodeFixAllProvider Instance = new UnusedParametersCodeFixAllProvider(); public override Task GetFixAsync(FixAllContext fixAllContext) { switch (fixAllContext.Scope) diff --git a/src/CSharp/CodeCracker/Usage/UriAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UriAnalyzer.cs index 4cdee1157..464976212 100644 --- a/src/CSharp/CodeCracker/Usage/UriAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UriAnalyzer.cs @@ -17,7 +17,7 @@ public class UriAnalyzer : DiagnosticAnalyzer private const string Description = "This diagnostic checks the Uri string and triggers if the parsing fail " + "by throwing an exception."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.Uri.ToDiagnosticId(), Title, MessageFormat, diff --git a/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs b/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs index f0b2c179c..ce6cfa2eb 100644 --- a/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs @@ -18,7 +18,7 @@ public class VirtualMethodOnConstructorAnalyzer : DiagnosticAnalyzer "it is possible that the constructor for the instance that invokes the method " + "has not executed."; - internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), Title, Message, diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index 67601ec6f..647ea2d01 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 0a0fc5a52..df0772fc8 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -60,8 +60,8 @@ - - + + diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index af80b93b5..8e389d917 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 17eff7c39..9f34be72b 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -159,8 +159,8 @@ - - + + diff --git a/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb index 0bcffa58c..a7f875abf 100644 --- a/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb @@ -24,11 +24,11 @@ Namespace Design Dim diagnosticspan = diagnostic.Location.SourceSpan Dim stringLiteral = root.FindToken(diagnosticspan.Start).Parent.AncestorsAndSelf.OfType(Of LiteralExpressionSyntax).FirstOrDefault If stringLiteral IsNot Nothing Then - context.RegisterCodeFix(CodeAction.Create("use NameOf()", Function(c) MakeNameOf(context.Document, stringLiteral, root, diagnostic, c), NameOf(NameOfCodeFixProvider)), diagnostic) + context.RegisterCodeFix(CodeAction.Create("use NameOf()", Function(c) MakeNameOf(context.Document, stringLiteral, root), NameOf(NameOfCodeFixProvider)), diagnostic) End If End Function - Private Function MakeNameOf(document As Document, stringLiteral As LiteralExpressionSyntax, root As SyntaxNode, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Private Function MakeNameOf(document As Document, stringLiteral As LiteralExpressionSyntax, root As SyntaxNode) As Task(Of Document) Dim newNameof = SyntaxFactory.ParseExpression($"NameOf({stringLiteral.Token.ToString().Replace("""", "")})"). WithLeadingTrivia(stringLiteral.GetLeadingTrivia). WithTrailingTrivia(stringLiteral.GetTrailingTrivia). diff --git a/src/VisualBasic/CodeCracker/Refactoring/ChangeAnyToAllCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Refactoring/ChangeAnyToAllCodeFixProvider.vb index a347d977a..9f9f70a8b 100644 --- a/src/VisualBasic/CodeCracker/Refactoring/ChangeAnyToAllCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Refactoring/ChangeAnyToAllCodeFixProvider.vb @@ -34,7 +34,7 @@ Namespace Refactoring Private Shared Async Function ConvertAsync(Document As Document, diagnosticLocation As Location, cancellationToken As CancellationToken) As Task(Of Document) Dim root = Await Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim invocation = root.FindNode(diagnosticLocation.SourceSpan).FirstAncestorOfType(Of InvocationExpressionSyntax) - Dim newInvocation = createNewInvocation(invocation, root). + Dim newInvocation = CreateNewInvocation(invocation). WithAdditionalAnnotations(Formatter.Annotation) Dim newRoot = ReplaceInvocation(invocation, newInvocation, root) Dim newDocument = Document.WithSyntaxRoot(newRoot) @@ -50,9 +50,9 @@ Namespace Refactoring Return newRoot End Function - Friend Shared Function CreateNewInvocation(invocation As InvocationExpressionSyntax, root As SyntaxNode) As ExpressionSyntax + Friend Shared Function CreateNewInvocation(invocation As InvocationExpressionSyntax) As ExpressionSyntax Dim methodName = DirectCast(invocation.Expression, MemberAccessExpressionSyntax).Name.ToString - Dim nameToCheck = If(methodName = NameOf(System.Linq.Enumerable.Any), ChangeAnyToAllAnalyzer.allName, ChangeAnyToAllAnalyzer.anyName) + Dim nameToCheck = If(methodName = NameOf(Enumerable.Any), ChangeAnyToAllAnalyzer.allName, ChangeAnyToAllAnalyzer.anyName) Dim newInvocation = invocation.WithExpression(DirectCast(invocation.Expression, MemberAccessExpressionSyntax).WithName(nameToCheck)) Dim comparisonExpression = DirectCast(DirectCast(newInvocation.ArgumentList.Arguments.First().GetExpression(), SingleLineLambdaExpressionSyntax).Body, ExpressionSyntax) Dim newComparisonExpression = CreateNewComparison(comparisonExpression) diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index 3eed796a7..d9c4e3f3c 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 98f8cdc3d..b4c650860 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -233,8 +233,8 @@ - - + + diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index 65adf11b6..23e6c6001 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -323,7 +323,7 @@ public int Id [Fact] public async Task FixSimplePropWithMultipleFieldsIntoAutoProp() { - var source = @" + const string source = @" private int x = 42, y; //comment 1 public int X { @@ -331,7 +331,7 @@ public int X set { x = value; } }"; - var expected = @" + const string expected = @" private int y; //comment 1 public int X { get; set; } = 42;"; @@ -341,7 +341,7 @@ public int X [Fact] public async Task FixSimplePropWithVaribleDeclarationNotFirstIntoAutoProp() { - var source = @" + const string source = @" private int x, y = 42; //comment 1 public int Y { @@ -349,7 +349,7 @@ public int Y set { y = value; } }"; - var expected = @" + const string expected = @" private int x; //comment 1 public int Y { get; set; } = 42;"; @@ -360,7 +360,7 @@ public int Y [Fact(Skip = "Skip until the FixAll has been fixed.")] public async Task FixSimplePropWithMultipleFieldsIntoAutoPropAll() { - var source = @" + const string source = @" private int x = 42, y; private int z = int.MaxValue; @@ -382,7 +382,7 @@ public int Z set { z = value; } }"; - var expected = @" + const string expected = @" public int X { get; set; } = 42; public int Y { get; set; } public int Z { get; set; } = int.MaxValue;"; diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index 8bb09d28f..b087a68cb 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 4775e87f6..748cc5da6 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -141,8 +141,8 @@ - - + + diff --git a/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs b/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs index e8866d67f..192c1a920 100644 --- a/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs +++ b/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs @@ -27,12 +27,12 @@ public abstract partial class DiagnosticVerifier private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); private static readonly MetadataReference JsonNetReference = MetadataReference.CreateFromFile(typeof(JsonConvert).Assembly.Location); - internal static string DefaultFilePathPrefix = nameof(Test); - internal static string CSharpDefaultFileExt = "cs"; - internal static string VisualBasicDefaultExt = "vb"; - internal static string CSharpDefaultFilePath = DefaultFilePathPrefix + 0 + "." + CSharpDefaultFileExt; - internal static string VisualBasicDefaultFilePath = DefaultFilePathPrefix + 0 + "." + VisualBasicDefaultExt; - internal static string TestProjectName = "TestProject"; + internal static readonly string DefaultFilePathPrefix = nameof(Test); + internal static readonly string CSharpDefaultFileExt = "cs"; + internal static readonly string VisualBasicDefaultExt = "vb"; + internal static readonly string CSharpDefaultFilePath = DefaultFilePathPrefix + 0 + "." + CSharpDefaultFileExt; + internal static readonly string VisualBasicDefaultFilePath = DefaultFilePathPrefix + 0 + "." + VisualBasicDefaultExt; + internal static readonly string TestProjectName = "TestProject"; /// /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer to apply to it, return the diagnostics found in the string after converting it to a document. diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index 690a853fe..cc4f16c52 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 053ac1143..12660877e 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -226,8 +226,8 @@ - - + + diff --git a/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb b/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb index c23032ab9..02db187a8 100644 --- a/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb @@ -36,7 +36,7 @@ End Namespace" Public Async Function WhileWithoutStringConcatWithMethoParameterDoesNotCreateDiagnostic() As Task - Dim source = " + Const source = " Public Class TypeName Public Sub Looper(ByRef a As Integer) While a < 10 @@ -464,7 +464,7 @@ End Namespace" Public Async Function ForLoopInMethodWithoutStringShouldNotCreateDiagnostic() As Task - Dim source = " + Const source = " Public Class Test Private Sub AdjustSample(ByRef readIndex As Integer, writeBuffer() As Single, ByRef writeIndex As Integer) For i = 0 To 2 diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config index 8eef2be67..e50654a79 100644 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ b/test/VisualBasic/CodeCracker.Test/packages.config @@ -1,6 +1,6 @@  - + From 4eec122bcc4fdfcb09e8c8c0367e38f9185fb065 Mon Sep 17 00:00:00 2001 From: "coolrunr@drautage.com" Date: Wed, 7 Oct 2015 21:39:13 -0500 Subject: [PATCH 012/358] Fix for #468 ternary code fix with nullables --- .../Style/TernaryOperatorCodeFixProviders.vb | 109 +++++++++--------- .../Style/TernaryOperatorTests.vb | 98 ++++++++++++++++ 2 files changed, 150 insertions(+), 57 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 8eb03c03f..8403c474e 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -8,9 +8,25 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Style + + Public MustInherit Class TernaryOperatorCodeFixProviderBase + Inherits CodeFixProvider + + Protected Shared Function MakeTernaryOperand(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax + If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then + Dim constValue = semanticModel.GetConstantValue(expression) + If constValue.HasValue AndAlso constValue.Value Is Nothing Then + Return SyntaxFactory.DirectCastExpression(expression.WithoutTrailingTrivia(), typeSyntax) + End If + End If + + Return expression + End Function + End Class + Public Class TernaryOperatorWithReturnCodeFixProvider - Inherits CodeFixProvider + Inherits TernaryOperatorCodeFixProviderBase Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First @@ -28,28 +44,32 @@ Namespace Style Private Async Function MakeTernaryAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim span = diagnostic.Location.SourceSpan - Dim ifBlock = root.FindToken(span.Start).Parent.FirstAncestorOrSelfOfType(Of MultiLineIfBlockSyntax) Dim ifReturn = TryCast(ifBlock.Statements.FirstOrDefault(), ReturnStatementSyntax) Dim elseReturn = TryCast(ifBlock.ElseBlock?.Statements.FirstOrDefault(), ReturnStatementSyntax) + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) + Dim type = semanticModel.GetTypeInfo(ifReturn.Expression).ConvertedType + Dim typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, ifReturn.SpanStart)) + Dim trueExpression = MakeTernaryOperand(ifReturn.Expression, semanticModel, type, typeSyntax) + Dim falseExpression = MakeTernaryOperand(elseReturn.Expression, semanticModel, type, typeSyntax) Dim ternary = SyntaxFactory.TernaryConditionalExpression(ifBlock.IfStatement.Condition.WithoutTrailingTrivia(), - ifReturn.Expression.WithoutTrailingTrivia(), - elseReturn.Expression.WithoutTrailingTrivia()). - WithLeadingTrivia(ifBlock.GetLeadingTrivia()). - WithTrailingTrivia(ifBlock.GetTrailingTrivia()). - WithAdditionalAnnotations(Formatter.Annotation) + trueExpression.WithoutTrailingTrivia(), + falseExpression.WithoutTrailingTrivia()). + WithLeadingTrivia(ifBlock.GetLeadingTrivia()). + WithTrailingTrivia(ifBlock.GetTrailingTrivia()). + WithAdditionalAnnotations(Formatter.Annotation) Dim returnStatement = SyntaxFactory.ReturnStatement(ternary) - Dim newRoot = root.ReplaceNode(ifBlock, returnStatement) Dim newDocument = document.WithSyntaxRoot(newRoot) + Return newDocument End Function End Class Public Class TernaryOperatorWithAssignmentCodeFixProvider - Inherits CodeFixProvider + Inherits TernaryOperatorCodeFixProviderBase Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First @@ -65,55 +85,31 @@ Namespace Style End Function Private Async Function MakeTernaryAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim ifBlock = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.FirstAncestorOrSelf(Of MultiLineIfBlockSyntax) Dim ifAssign = TryCast(ifBlock.Statements.FirstOrDefault(), AssignmentStatementSyntax) Dim elseAssign = TryCast(ifBlock.ElseBlock?.Statements.FirstOrDefault(), AssignmentStatementSyntax) + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) + Dim type = semanticModel.GetTypeInfo(ifAssign.Left).ConvertedType + Dim typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, ifAssign.SpanStart)) + Dim trueExpression = MakeTernaryOperand(ifAssign.Right, semanticModel, type, typeSyntax) + Dim falseExpression = MakeTernaryOperand(elseAssign.Right, semanticModel, type, typeSyntax) + Dim ternary = SyntaxFactory.TernaryConditionalExpression(ifBlock.IfStatement.Condition.WithoutTrailingTrivia(), + trueExpression.WithoutTrailingTrivia(), + falseExpression.WithoutTrailingTrivia()). + WithLeadingTrivia(ifBlock.GetLeadingTrivia()). + WithTrailingTrivia(ifBlock.GetTrailingTrivia()). + WithAdditionalAnnotations(Formatter.Annotation) - Dim assignment As AssignmentStatementSyntax - If ifAssign.Left.Kind = SyntaxKind.IdentifierName Then - assignment = CreateIdentifier(ifBlock, ifAssign, elseAssign) - ElseIf ifAssign.Left.Kind = SyntaxKind.SimpleMemberAccessExpression - assignment = CreateMemberAssignment(ifBlock, ifAssign, elseAssign) - Else - Return document - End If - - Dim newRoot = root.ReplaceNode(ifBlock, assignment) - Dim newDocument = document.WithSyntaxRoot(newRoot) - Return newDocument - End Function - - Private Shared Function CreateIdentifier(ifBlock As MultiLineIfBlockSyntax, ifAssign As AssignmentStatementSyntax, elseAssign As AssignmentStatementSyntax) As AssignmentStatementSyntax - Dim variableIdentifier = TryCast(ifAssign.Left, IdentifierNameSyntax) - - Dim ternary = SyntaxFactory.TernaryConditionalExpression( - ifBlock.IfStatement.Condition, - ifAssign.Right.WithoutTrailingTrivia(), - elseAssign.Right.WithoutTrailingTrivia()) - - Dim assignment = SyntaxFactory.SimpleAssignmentStatement(variableIdentifier, ternary). - WithLeadingTrivia(ifBlock.GetLeadingTrivia()). - WithTrailingTrivia(ifBlock.GetTrailingTrivia()). - WithAdditionalAnnotations(Formatter.Annotation) - Return assignment - End Function - - Private Shared Function CreateMemberAssignment(ifBlock As MultiLineIfBlockSyntax, ifAssign As AssignmentStatementSyntax, elseAssign As AssignmentStatementSyntax) As AssignmentStatementSyntax - Dim variableIdentifier = TryCast(ifAssign.Left, MemberAccessExpressionSyntax) - - Dim ternary = SyntaxFactory.TernaryConditionalExpression( - ifBlock.IfStatement.Condition, - ifAssign.Right.WithoutTrailingTrivia(), - elseAssign.Right.WithoutTrailingTrivia()) - - Dim assignment = SyntaxFactory.SimpleAssignmentStatement(variableIdentifier, ternary). + Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left, ternary). WithLeadingTrivia(ifBlock.GetLeadingTrivia()). WithTrailingTrivia(ifBlock.GetTrailingTrivia()). WithAdditionalAnnotations(Formatter.Annotation) - Return assignment + Dim newRoot = root.ReplaceNode(ifBlock, assignment) + Dim newDocument = document.WithSyntaxRoot(newRoot) + Return newDocument End Function End Class @@ -121,13 +117,10 @@ Namespace Style Public Class TernaryOperatorFromIifCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First - Dim span = diagnostic.Location.SourceSpan - Dim declaration = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of InvocationExpressionSyntax) - If declaration Is Nothing Then Exit Function - context.RegisterCodeFix(CodeAction.Create("Change IIF to If to short circuit evaulations", Function(c) MakeTernaryAsync(context.Document, declaration, c), NameOf(TernaryOperatorFromIifCodeFixProvider)), diagnostic) + context.RegisterCodeFix(CodeAction.Create("Change IIF to If to short circuit evaulations", Function(c) MakeTernaryAsync(context.Document, diagnostic, c), NameOf(TernaryOperatorFromIifCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function Public Overrides ReadOnly Property FixableDiagnosticIds() As ImmutableArray(Of String) = @@ -137,7 +130,10 @@ Namespace Style Return WellKnownFixAllProviders.BatchFixer End Function - Private Async Function MakeTernaryAsync(document As Document, iifAssignment As InvocationExpressionSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function MakeTernaryAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim iifAssignment = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.FirstAncestorOrSelf(Of InvocationExpressionSyntax) + Dim ternary = SyntaxFactory.TernaryConditionalExpression( iifAssignment.ArgumentList.Arguments(0).GetExpression(), iifAssignment.ArgumentList.Arguments(1).GetExpression(), @@ -146,7 +142,6 @@ Namespace Style WithTrailingTrivia(iifAssignment.GetTrailingTrivia()). WithAdditionalAnnotations(Formatter.Annotation) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken) Dim newRoot = root.ReplaceNode(iifAssignment, ternary) Dim newDocument = document.WithSyntaxRoot(newRoot) Return newDocument diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index b98329fff..f526b8024 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -221,6 +221,57 @@ End Class" End Function + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFix() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim a As Integer? + If True Then + a = 1 + Else + a = Nothing + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim a As Integer? + a = If(True, 1, DirectCast(Nothing, Integer?)) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFixAll() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim a As Integer? + If True Then + a = 1 + Else + a = Nothing + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim a As Integer? + a = If(True, 1, DirectCast(Nothing, Integer?)) + End Sub +End Class" + + Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function + End Class Public Class TernaryOperatorWithReturnTests @@ -335,6 +386,53 @@ End Namespace" Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) End Function + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFix() As Task + Const source = " +Public Class MyType + Public Function Foo() As Integer? + If True Then + Return 1 + Else + Return Nothing + End If + End Function +End Class" + + Const fix = " +Public Class MyType + Public Function Foo() As Integer? + Return If(True, 1, DirectCast(Nothing, Integer?)) + End Function +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFixAll() As Task + Const source = " +Public Class MyType + Public Function Foo() As Integer? + If True Then + Return 1 + Else + Return Nothing + End If + End Function +End Class" + + Const fix = " +Public Class MyType + Public Function Foo() As Integer? + Return If(True, 1, DirectCast(Nothing, Integer?)) + End Function +End Class" + + Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function + Private Const sourceReturn = " Namespace ConsoleApplication1 Class MyType From 2ec163b4bf841e7401b57ce1a586b286845e02da Mon Sep 17 00:00:00 2001 From: "coolrunr@drautage.com" Date: Thu, 8 Oct 2015 00:02:44 -0500 Subject: [PATCH 013/358] Fix #493 by assigning trivia before the expression and after separators --- .../Style/ObjectInitializerCodeFixProvider.cs | 13 ++- .../Style/ObjectInitializerTests.cs | 92 +++++++++++++++++++ 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs index ae5a9ddfb..f14383bab 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs @@ -80,14 +80,13 @@ private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, Seman if (blockStatement.Equals(statement)) { var initializationExpressions = new List(); - foreach (var expressionStatement in assignmentExpressions) { var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; var newAssignmentExpression = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, propertyIdentifier, assignmentExpression.Right); - initializationExpressions.Add(newAssignmentExpression); + initializationExpressions.Add(newAssignmentExpression.WithTriviaFrom(expressionStatement)); } if (objectCreationExpression.Initializer != null) @@ -103,7 +102,15 @@ private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, Seman initializationExpressions.InsertRange(0, existentInitilizers); } - var initializers = SyntaxFactory.SeparatedList(initializationExpressions); + // Trailing trivia will be added before the separator if a simple separator list is used. This builds the separator token for expression + // such that the trailing trivia from the original expression is added after the comma on the same line. + var initializerSeparators = initializationExpressions.Take(initializationExpressions.Count - 1).Select(expr => SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(expr.GetTrailingTrivia())).ToList(); + var lastInitializer = initializationExpressions.Last(); // Preserve the last initializer before rebuilding the list. + // Get all but the last initializer without the trailing trivia. Trivia will be added after the separator from the list above. + initializationExpressions = initializationExpressions.Take(initializationExpressions.Count - 1).Select(expr => expr.WithoutTrailingTrivia()).ToList(); + initializationExpressions.Add(lastInitializer); // Add the last initializer with all of its trivia. + + var initializers = SyntaxFactory.SeparatedList(initializationExpressions, initializerSeparators); var newObjectCreationExpression = objectCreationExpression.WithInitializer( SyntaxFactory.InitializerExpression( diff --git a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs index 44d77d365..3b762148f 100644 --- a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs @@ -343,6 +343,49 @@ public void Bar() }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task WhenUsingANewVariableDeclaredAndAssigningToPropertiesOfJustCreatedObjectWithAssignmentTriviaChangeToObjectInitializersFix() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + string a; + var p = new Person(); + #pragma warning disable CS0618 + p.Name = ""Giovanni""; // A name. + #pragma warning restore CS0618 + p.Age = 25; // An age. + string b; + } + } + }"; + + const string fixtest = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + string a; + var p = new Person + { + #pragma warning disable CS0618 + Name = ""Giovanni"", // A name. + #pragma warning restore CS0618 + Age = 25 // An age. + }; + string b; + } + } + }"; + await VerifyCSharpFixAsync(source, fixtest, 0); + } } public class ObjectInitializerWithAssignmentTests : CodeFixVerifier @@ -499,6 +542,55 @@ public int Foo() await VerifyCSharpFixAsync(source, fixtest, 0); } + [Fact] + public async Task WhenUsingAPreviouslyDeclaredVariableAndAssigningToPropertiesOfJustCreatedObjectWithAssignmentTriviaChangeToObjectInitializersFix() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + string a; + //some comment before + Person p; + p = new Person(); + #pragma warning disable CS0618 + p.Name = ""Giovanni""; // A name. + #pragma warning restore CS0618 + p.Age = 25; // An age. + //some comment after + string b; + } + } + }"; + + const string fixtest = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + string a; + //some comment before + Person p; + p = new Person + { + #pragma warning disable CS0618 + Name = ""Giovanni"", // A name. + #pragma warning restore CS0618 + Age = 25 // An age. + }; + //some comment after + string b; + } + } + }"; + await VerifyCSharpFixAsync(source, fixtest, 0); + } + [Fact] public async Task ObjectCreationWithoutConstructorDoesNotCreateDiagnostic() { From 8b674ce48d1d590e344c1a769af641fbd96136ba Mon Sep 17 00:00:00 2001 From: Leo Shine Date: Sun, 11 Oct 2015 22:36:57 +0100 Subject: [PATCH 014/358] Fixed issue #537 by creating multiple variable declarations rather than a single declaration. --- .../Style/AlwaysUseVarCodeFixProvider.cs | 51 ++++++++++-- .../Style/AlwaysUseVarTests.cs | 80 ++++++++++++++++++- 2 files changed, 122 insertions(+), 9 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs index f88f139ad..b44987caa 100644 --- a/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; @@ -30,15 +31,49 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) private async static Task UseVarAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var diagnosticSpan = diagnostic.Location.SourceSpan; var localDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var variableDeclaration = localDeclaration.ChildNodes() - .OfType() - .FirstOrDefault(); - var @var = SyntaxFactory.IdentifierName("var") - .WithLeadingTrivia(variableDeclaration.Type.GetLeadingTrivia()) - .WithTrailingTrivia(variableDeclaration.Type.GetTrailingTrivia()); - var newRoot = root.ReplaceNode(variableDeclaration.Type, @var); + var variableDeclaration = localDeclaration.Declaration; + var numVariables = variableDeclaration.Variables.Count; + + var newVariableDeclarations = new VariableDeclarationSyntax[numVariables]; + + var varSyntax = SyntaxFactory.IdentifierName("var"); + + //Create a new var declaration for each variable. + for (var i = 0; i < numVariables; i++) + { + var originalVariable = variableDeclaration.Variables[i]; + var newLeadingTrivia = originalVariable.GetLeadingTrivia(); + + //Get the trivia from the separator as well + if (i != 0) + { + newLeadingTrivia = newLeadingTrivia.InsertRange(0, + variableDeclaration.Variables.GetSeparator(i-1).GetAllTrivia()); + } + + newVariableDeclarations[i] = SyntaxFactory.VariableDeclaration(varSyntax) + .AddVariables(originalVariable.WithLeadingTrivia(newLeadingTrivia)); + } + + //ensure trivia for leading type node is preserved + var originalTypeSyntax = variableDeclaration.Type; + newVariableDeclarations[0] = newVariableDeclarations[0] + .WithType((TypeSyntax) varSyntax.WithSameTriviaAs(originalTypeSyntax)); + + var newLocalDeclarationStatements = newVariableDeclarations.Select(SyntaxFactory.LocalDeclarationStatement).ToList(); + + + //Preserve the trivia for the entire statement at the start and at the end + newLocalDeclarationStatements[0] = + newLocalDeclarationStatements[0].WithLeadingTrivia(variableDeclaration.GetLeadingTrivia()); + var lastIndex = numVariables -1; + newLocalDeclarationStatements[lastIndex] = + newLocalDeclarationStatements[lastIndex].WithTrailingTrivia(localDeclaration.GetTrailingTrivia()); + + var newRoot = root.ReplaceNode(localDeclaration, newLocalDeclarationStatements); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; } diff --git a/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs b/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs index 148f41b20..e192d7eae 100644 --- a/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs @@ -215,5 +215,83 @@ public void Foo() }"; await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { fixtest1, fixtest2 }); } + + + [Fact] + public async Task FixReplacesMultipleDeclarationWithMultipleVars() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + int a = 10, b = 12; + } + } + }"; + + const string expected = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var a = 10; + var b = 12; + } + } + }"; + await VerifyCSharpFixAsync(test, expected); + } + + + + [Fact] + public async Task FixPreservesTriviaSensibly() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + int a = 10; //Blue + + /*variables for use*/ string /*desc of b*/b = /* why not*/ ""12"", /*Formatter does this My next variable*/ c /* is quite nice and it */ = ""23""; + } + } + }"; + + const string expected = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var a = 10; //Blue + + /*variables for use*/ var /*desc of b*/b = /* why not*/ ""12""; + var +/*Formatter does this My next variable*/ c /* is quite nice and it */ = ""23""; + } + } + }"; + await VerifyCSharpFixAllAsync(test, expected); + } } -} \ No newline at end of file +} + + From 068ddf217373c657f865ba7ad4e16a2d917489a8 Mon Sep 17 00:00:00 2001 From: Matthias GROSPERRIN Date: Sat, 17 Oct 2015 08:35:47 +0200 Subject: [PATCH 015/358] Fixes #544 by ignoring assignment of fields in Lambda in constructor --- .../Usage/ReadonlyFieldAnalyzer.cs | 18 ++++++++++++---- .../Usage/ReadonlyFieldTests.cs | 21 ++++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 9ecc58031..b53642e87 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -64,9 +64,9 @@ private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation c var fieldSymbol = syntaxRefSemanticModel.GetSymbolInfo(assignment.Left).Symbol as IFieldSymbol; if (fieldSymbol == null) continue; if (method.MethodKind == MethodKind.StaticConstructor && fieldSymbol.IsStatic) - AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(variablesToMakeReadonly, fieldSymbol); + AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(variablesToMakeReadonly, fieldSymbol, assignment); else if (method.MethodKind == MethodKind.Constructor && !fieldSymbol.IsStatic) - AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(variablesToMakeReadonly, fieldSymbol); + AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(variablesToMakeReadonly, fieldSymbol, assignment); else RemoveVariableThatHasAssignment(variablesToMakeReadonly, fieldSymbol); } @@ -81,8 +81,18 @@ private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation c } } - private static void AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(Dictionary variablesToMakeReadonly, IFieldSymbol fieldSymbol) + private static void AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(Dictionary variablesToMakeReadonly, IFieldSymbol fieldSymbol, AssignmentExpressionSyntax assignment) { + var parent = assignment.Parent; + while (parent != null) + { + if (parent is AnonymousFunctionExpressionSyntax) + return; + if (parent is ConstructorDeclarationSyntax) + break; + parent = parent.Parent; + } + if (!fieldSymbol.IsReadOnly && !variablesToMakeReadonly.Keys.Contains(fieldSymbol)) foreach (var variable in fieldSymbol.DeclaringSyntaxReferences) variablesToMakeReadonly.Add(fieldSymbol, (VariableDeclaratorSyntax)variable.GetSyntax()); @@ -137,4 +147,4 @@ private static List GetTypesInRoot(SyntaxNode root) return types; } } -} \ No newline at end of file +} diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index 0d50c52bd..c56097396 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -720,5 +720,24 @@ public void Foo() }"; await VerifyCSharpHasNoDiagnosticsAsync(source1, source2); } + + [Fact] + public async Task FieldsAssignedOnLambdaDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + internal class Test + { + private string _value; + + public Test() + { + Func factory = () => _value ?? (_value = ""Hello""); + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } -} \ No newline at end of file +} From 9386bc27b438e675eccdb11f11803681a80c2a64 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 20 Oct 2015 11:07:29 -0200 Subject: [PATCH 016/358] Fix incorrect diagnostic on anonymous funcions for DisposableVariableNotDisposed Closes #545 --- .../Extensions/CSharpAnalyzerExtensions.cs | 13 ++ .../DisposableVariableNotDisposedAnalyzer.cs | 57 ++++-- ...sableVariableNotDisposedCodeFixProvider.cs | 1 + .../DisposableVariableNotDisposedTests.cs | 193 ++++++++++++++++++ 4 files changed, 248 insertions(+), 16 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index d30d9a067..fa6c05e98 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -422,5 +422,18 @@ public static SyntaxTokenList CloneAccessibilityModifiers(this SyntaxTokenList m return SyntaxFactory.TokenList(accessibilityModifiers.EnsureProtectedBeforeInternal()); } + + public static SyntaxNode FirstAncestorOfKind(this SyntaxNode node, params SyntaxKind[] kinds) + { + var currentNode = node; + while (true) + { + var parent = currentNode.Parent; + if (parent == null) break; + if (parent.IsAnyKind(kinds)) return parent; + currentNode = parent; + } + return null; + } } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index a157fd7e7..9e80781cd 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -16,7 +16,7 @@ public class DisposableVariableNotDisposedAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "When a disposable object is created it should be disposed as soon as possible.\n" + "This warning will appear if you create a disposable object and don't store, return or dispose it."; - + public const string cantFix = "cantFix"; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), Title, @@ -36,12 +36,14 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) if (context.IsGenerated()) return; var objectCreation = context.Node as ObjectCreationExpressionSyntax; if (objectCreation == null) return; - if (objectCreation?.Parent is UsingStatementSyntax) return; - if (objectCreation?.Parent is ReturnStatementSyntax) return; + if (objectCreation.Parent == null) return; + if (objectCreation.Parent.IsAnyKind(SyntaxKind.ReturnStatement, SyntaxKind.UsingStatement)) + return; if (objectCreation.Ancestors().Any(i => i.IsAnyKind( SyntaxKind.ThisConstructorInitializer, SyntaxKind.BaseConstructorInitializer, - SyntaxKind.ObjectCreationExpression))) return; + SyntaxKind.ObjectCreationExpression))) + return; var semanticModel = context.SemanticModel; var type = semanticModel.GetSymbolInfo(objectCreation.Type).Symbol as INamedTypeSymbol; @@ -70,6 +72,14 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) statement = variableDeclaration.Parent as LocalDeclarationStatementSyntax; if ((statement?.FirstAncestorOrSelf()) == null) return; } + else if (objectCreation.Parent.IsAnyKind(SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression)) + { + var anonymousFunction = objectCreation.Parent as AnonymousFunctionExpressionSyntax; + var methodSymbol = semanticModel.GetSymbolInfo(anonymousFunction).Symbol as IMethodSymbol; + if (!methodSymbol.ReturnsVoid) return; + var props = new Dictionary { { "typeName", type.Name }, { cantFix, "" } }.ToImmutableDictionary(); + context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation(), props, type.Name.ToString())); + } else { var props = new Dictionary { { "typeName", type.Name } }.ToImmutableDictionary(); @@ -85,30 +95,45 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) } } - private static bool IsDisposedOrAssigned(SemanticModel semanticModel, SyntaxNode node, ILocalSymbol identitySymbol) + private static bool IsDisposedOrAssigned(SemanticModel semanticModel, StatementSyntax statement, ILocalSymbol identitySymbol) { - var method = node.FirstAncestorOrSelf(); + var method = statement.FirstAncestorOrSelf(); if (method == null) return false; - if (IsReturned(method, semanticModel, identitySymbol)) return true; - foreach (var statement in method.Body.DescendantNodes().OfType()) + if (IsReturned(method, statement, semanticModel, identitySymbol)) return true; + foreach (var childStatements in method.Body.DescendantNodes().OfType()) { - if (statement.SpanStart > node.SpanStart - && (IsCorrectDispose(statement as ExpressionStatementSyntax, semanticModel, identitySymbol) - || IsAssignedToField(statement as ExpressionStatementSyntax, semanticModel, identitySymbol))) + if (childStatements.SpanStart > statement.SpanStart + && (IsCorrectDispose(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol) + || IsAssignedToField(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol))) return true; } return false; } - private static bool IsReturned(MethodDeclarationSyntax method, SemanticModel semanticModel, ILocalSymbol identitySymbol) + private static bool IsReturned(MethodDeclarationSyntax method, StatementSyntax statement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { - var returnTypeSymbol = semanticModel.GetTypeInfo(method.ReturnType).Type; + var anonymousFunction = statement.FirstAncestorOfKind(SyntaxKind.ParenthesizedLambdaExpression, + SyntaxKind.SimpleLambdaExpression, SyntaxKind.AnonymousMethodExpression) as AnonymousFunctionExpressionSyntax; + IMethodSymbol methodSymbol; + BlockSyntax body; + if (anonymousFunction != null) + { + methodSymbol = semanticModel.GetSymbolInfo(anonymousFunction).Symbol as IMethodSymbol; + body = anonymousFunction.Body as BlockSyntax; + } + else + { + methodSymbol = semanticModel.GetDeclaredSymbol(method); + body = method.Body; + } + if (body == null) return true; + var returnExpressions = body.DescendantNodes().OfType().Select(r => r.Expression); + var returnTypeSymbol = methodSymbol?.ReturnType; if (returnTypeSymbol == null) return false; if (returnTypeSymbol.SpecialType == SpecialType.System_Void) return false; - var returns = method.Body.DescendantNodes().OfType(); - var isReturning = returns.Any(r => + var isReturning = returnExpressions.Any(returnExpression => { - var returnSymbol = semanticModel.GetSymbolInfo(r.Expression).Symbol; + var returnSymbol = semanticModel.GetSymbolInfo(returnExpression).Symbol; if (returnSymbol == null) return false; return returnSymbol.Equals(identitySymbol); }); diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs index 540f50796..303e2da3f 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs @@ -27,6 +27,7 @@ public class DisposableVariableNotDisposedCodeFixProvider : CodeFixProvider public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); + if (diagnostic.Properties.ContainsKey(DisposableVariableNotDisposedAnalyzer.cantFix)) return Task.FromResult(0); var title = string.Format(MessageFormat, diagnostic.Properties["typeName"]); context.RegisterCodeFix(CodeAction.Create(title, c => CreateUsingAsync(context.Document, diagnostic, c), nameof(DisposableVariableNotDisposedCodeFixProvider)), diagnostic); return Task.FromResult(0); diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index 51093f22a..08d1921d3 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -117,6 +117,199 @@ void System.IDisposable.Dispose() { } await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task IgnoredWhenPassedIntoParenthesizedLambdaExpression() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(() => new System.IO.MemoryStream()); + } + void Register(System.Func f) { } +} +"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoredWhenPassedIntoParenthesizedLambdaExpressionWithBlock() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(() => { + var memoryStream = new System.IO.MemoryStream(); + return memoryStream; + }); + } + void Register(System.Func f) { } +} +"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoredWhenPassedIntoSimpleLambdaExpression() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(i => new System.IO.MemoryStream()); + } + void Register(System.Func f) { } +} +"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoredWhenPassedIntoAnonymousDelegate() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(delegate () { + var memoryStream = new System.IO.MemoryStream(); + return memoryStream; + }); + } + void Register(System.Func f) { } +} +"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task WhenPassedIntoParenthesizedLambdaExpressionWithoutBlockCreatesDiagnostic() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(() => new System.IO.MemoryStream()); + } + void Register(System.Action f) { } +} +"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), + Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 34) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task WhenPassedIntoParenthesizedLambdaExpressionCreatesDiagnostic() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(() => { + var memoryStream = new System.IO.MemoryStream(); + }); + } + void Register(System.Action f) { } +} +"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), + Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 32) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task WhenPassedIntoSimpleLambdaExpressionCreatesDiagnostic() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(i => { + var memoryStream = new System.IO.MemoryStream(); + }); + } + void Register(System.Action f) { } +} +"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), + Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 32) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task WhenPassedIntoAnonymousDelegateCreatesDiagnostic() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(delegate () { + var memoryStream = new System.IO.MemoryStream(); + }); + } + void Register(System.Action f) { } +} +"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), + Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 32) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task NoFixForParenthesizedLambdaExpression() + { + const string source = @" +class Container +{ + static void Foo() + { + var container = new Container(); + container.Register(() => new System.IO.MemoryStream()); + } + void Register(System.Action f) { } +} +"; + await VerifyCSharpHasNoFixAsync(source); + } + [Fact] public async Task PassedToConstructorDoesNotCreateDiagnostic() { From 235e3fd772958bf58b4881ef82d95c868922892e Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 20 Oct 2015 23:14:48 -0300 Subject: [PATCH 017/358] Fix UnusedParametersCodeFixProvider crashing when removing params Closes #539 for both VB and C# --- .../Usage/UnusedParametersCodeFixProvider.cs | 4 +-- .../Usage/UnusedParametersCodeFixProvider.vb | 4 +-- .../Usage/UnusedParametersTests.cs | 30 +++++++++++++++++++ .../CodeCracker.Test/CodeCracker.Test.vbproj | 2 +- ...meterTests.vb => UnusedParametersTests.vb} | 27 ++++++++++++++++- 5 files changed, 61 insertions(+), 6 deletions(-) rename test/VisualBasic/CodeCracker.Test/Usage/{UnusedParameterTests.vb => UnusedParametersTests.vb} (95%) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs index 6f31c01af..91199debf 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs @@ -82,10 +82,10 @@ public async static Task> RemoveParameterAsync(Document if (parameter.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword))) { var newArguments = arguments; - do + while (newArguments.Arguments.Count > parameterPosition) { newArguments = newArguments.WithArguments(newArguments.Arguments.RemoveAt(parameterPosition)); - } while (newArguments.Arguments.Count > parameterPosition); + } replacingArgs.Add(arguments, newArguments); } else diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb index 975bd85fb..01fab8d8f 100644 --- a/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersCodeFixProvider.vb @@ -73,9 +73,9 @@ Namespace Usage methodIdentifier.FirstAncestorOfType(Of InvocationExpressionSyntax).ArgumentList) If parameter.Modifiers.Any(Function(m) m.IsKind(SyntaxKind.ParamArrayKeyword)) Then Dim newArguments = arguments - Do + While newArguments.Arguments.Count > parameterPosition newArguments = newArguments.WithArguments(newArguments.Arguments.RemoveAt(parameterPosition)) - Loop While newArguments.Arguments.Count > parameterPosition + End While replacingArgs.Add(arguments, newArguments) Else Dim newArguments = arguments.WithArguments(arguments.Arguments.RemoveAt(parameterPosition)) diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 6e5d5c92e..a968e566d 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -342,6 +342,36 @@ public void Foo(int a, int b) await VerifyCSharpFixAsync(source, fixtest); } + [Fact] + public async Task FixParamsWhenNotInUse() + { + const string source = @" +class TypeName +{ + public void IsReferencing() + { + Foo(1, 2); + } + public void Foo(int a, int b, params int[] c) + { + a = b; + } +}"; + const string fixtest = @" +class TypeName +{ + public void IsReferencing() + { + Foo(1, 2); + } + public void Foo(int a, int b) + { + a = b; + } +}"; + await VerifyCSharpFixAsync(source, fixtest); + } + [Fact] public async Task FixAllInSameClass() { diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 12660877e..da9ac7b1f 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -180,7 +180,7 @@ - + diff --git a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb similarity index 95% rename from test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb rename to test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb index cb06d5230..045fb0a23 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParameterTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb @@ -2,7 +2,7 @@ Imports Xunit Namespace Usage - Public Class UnusedParameterTests + Public Class UnusedParametersTests Inherits CodeFixVerifier(Of UnusedParametersAnalyzer, UnusedParametersCodeFixProvider) Public Async Function MethodWithoutParametersDoesNotCreateDiagnostic() As Task @@ -376,6 +376,31 @@ End Class" Await VerifyBasicFixAsync(source, fix) End Function + + Public Async Function FixParamsWhenNotInUse() As Task + Const source = " +Class Foo + Public Sub IsReferencing() + Dim x = Bar(1, 2) + End Sub + Public Function Bar(a As Integer, b As Integer, ParamArray c As Integer()) + b = a + return 1 + End Function +End Class" + Const fix = " +Class Foo + Public Sub IsReferencing() + Dim x = Bar(1, 2) + End Sub + Public Function Bar(a As Integer, b As Integer) + b = a + return 1 + End Function +End Class" + Await VerifyBasicFixAsync(source, fix) + End Function + Public Async Function CallToBaseDoesNotCreateDiagnostic() As Task From 83915f059926ae47779576781b5d82a53d78676e Mon Sep 17 00:00:00 2001 From: carloscds Date: Fri, 23 Oct 2015 21:36:16 -0200 Subject: [PATCH 018/358] bug fixed --- .../CallExtensionMethodAsExtensionAnalyzer.cs | 4 +++- .../CallExtensionMethodAsExtensionTests.cs | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index 391435f81..42bf62cde 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -52,7 +52,9 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, Compila var methodSymbol = GetCallerMethodSymbol(context.SemanticModel, methodCaller.Name, argumentsCount); if (methodSymbol == null || !methodSymbol.IsExtensionMethod) return; if (ContainsDynamicArgument(context.SemanticModel, childNodes)) return; - if (IsSelectingADifferentMethod(childNodes, methodCaller.Name, context.Node.SyntaxTree, methodSymbol, methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement(), compilation)) return; + var invocationStatement = methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement(); + if (invocationStatement == null) return; + if (IsSelectingADifferentMethod(childNodes, methodCaller.Name, context.Node.SyntaxTree, methodSymbol, invocationStatement, compilation)) return; context.ReportDiagnostic(Diagnostic.Create(Rule, methodCaller.GetLocation(), methodSymbol.Name, classSymbol.Name)); } diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index 5fdcc0c5f..30fffac65 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -262,5 +262,23 @@ public void Bar() }; await VerifyCSharpDiagnosticAsync(source, expected); } + + + [Fact] + public async Task WhenCallExtensionMethodWithoutInvocationStatement() + { + const string source = @" + using System.Linq; + namespace ConsoleApplication1 + { + public class Foo + { + static int[] source = new int[] { 1, 2, 3 }; + public static void Bar() => Enumerable.Any(source); + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From fb56d1c6b6b8abc777f7343ad63703059e832950 Mon Sep 17 00:00:00 2001 From: carloscds Date: Fri, 23 Oct 2015 22:09:06 -0200 Subject: [PATCH 019/358] Issue Fixed #548 --- .../Style/SwitchToAutoPropCodeFixProvider.cs | 3 +- .../Style/SwitchToAutoPropTests.cs | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs index c480982e3..d2fd1a6ed 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs @@ -53,8 +53,7 @@ private async static Task MakeAutoPropertyAsync(Document document, Dia returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; var newProperty = GetSimpleProperty(property, variableDeclarator) - .WithTrailingTrivia(property.AccessorList.GetTrailingTrivia()) - .WithLeadingTrivia(property.AccessorList.GetLeadingTrivia()) + .WithTriviaFrom(property) .WithAdditionalAnnotations(Formatter.Annotation); var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, returnIdentifierSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken); diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index 23e6c6001..cd0dc3f93 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -447,5 +447,33 @@ public void Foo() ".WrapInCSharpClass("OtherType"); await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { expected1, expected2 }); } + + [Fact] + public async Task FixPropIntoAutoPropAndFixKeepingXMLComments() + { + var source = @" + public class Foo + { + private int x = 10; + /// + /// comment 1 + /// + public int X + { + get { return x; } + set { x = value; } + } + }"; + + var expected = @" + public class Foo + { + /// + /// comment 1 + /// + public int X { get; set; } = 10; + }"; + await VerifyCSharpFixAllAsync(source, expected); + } } } \ No newline at end of file From 1b19d1b7b8d7c0ef6e8f923e5fde886959cc9728 Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 26 Oct 2015 19:32:11 -0200 Subject: [PATCH 020/358] Code Fixed for ArrowStatements --- .../CallExtensionMethodAsExtensionAnalyzer.cs | 20 +++++++++++++------ .../CallExtensionMethodAsExtensionTests.cs | 10 +++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index 42bf62cde..8bf1a6e5a 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -52,27 +52,35 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, Compila var methodSymbol = GetCallerMethodSymbol(context.SemanticModel, methodCaller.Name, argumentsCount); if (methodSymbol == null || !methodSymbol.IsExtensionMethod) return; if (ContainsDynamicArgument(context.SemanticModel, childNodes)) return; - var invocationStatement = methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement(); + ExpressionSyntax invocationStatement; + if (methodInvokeSyntax.Parent.GetType().ToString() != "Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax") + { + invocationStatement = (methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement() as ExpressionStatementSyntax).Expression; + } + else + { + invocationStatement = methodInvokeSyntax.FirstAncestorOrSelfOfType().Expression; + } if (invocationStatement == null) return; if (IsSelectingADifferentMethod(childNodes, methodCaller.Name, context.Node.SyntaxTree, methodSymbol, invocationStatement, compilation)) return; context.ReportDiagnostic(Diagnostic.Create(Rule, methodCaller.GetLocation(), methodSymbol.Name, classSymbol.Name)); } - private static bool IsSelectingADifferentMethod(IEnumerable childNodes, SimpleNameSyntax methodName, SyntaxTree tree, IMethodSymbol methodSymbol, StatementSyntax invocationStatement, Compilation compilation) + private static bool IsSelectingADifferentMethod(IEnumerable childNodes, SimpleNameSyntax methodName, SyntaxTree tree, IMethodSymbol methodSymbol, ExpressionSyntax invocationExpression, Compilation compilation) { var parameterExpressions = CallExtensionMethodAsExtensionCodeFixProvider.GetParameterExpressions(childNodes); var firstArgument = parameterExpressions.FirstOrDefault(); var argumentList = CallExtensionMethodAsExtensionCodeFixProvider.CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)); - var newInvocationStatement = SyntaxFactory.ExpressionStatement( + var newInvocationStatement = CallExtensionMethodAsExtensionCodeFixProvider.CreateInvocationExpression( - firstArgument, methodName, argumentList)).WithAdditionalAnnotations(introduceExtensionMethodAnnotation); + firstArgument, methodName, argumentList).WithAdditionalAnnotations(introduceExtensionMethodAnnotation); var extensionMethodNamespaceUsingDirective = SyntaxFactory.UsingDirective(methodSymbol.ContainingNamespace.ToNameSyntax()); var speculativeRootWithExtensionMethod = tree.GetCompilationUnitRoot() - .ReplaceNode(invocationStatement, newInvocationStatement) + .ReplaceNode(invocationExpression, newInvocationStatement) .AddUsings(extensionMethodNamespaceUsingDirective); var speculativeModel = compilation.ReplaceSyntaxTree(tree, speculativeRootWithExtensionMethod.SyntaxTree) .GetSemanticModel(speculativeRootWithExtensionMethod.SyntaxTree); - var speculativeInvocationStatement = speculativeRootWithExtensionMethod.SyntaxTree.GetCompilationUnitRoot().GetAnnotatedNodes(introduceExtensionMethodAnnotation).Single() as ExpressionStatementSyntax; + var speculativeInvocationStatement = speculativeRootWithExtensionMethod.SyntaxTree.GetCompilationUnitRoot().GetAnnotatedNodes(introduceExtensionMethodAnnotation).Single() as InvocationExpressionSyntax; var speculativeExtensionMethodSymbol = speculativeModel.GetSymbolInfo(speculativeInvocationStatement.Expression).Symbol as IMethodSymbol; var speculativeNonExtensionFormOfTheMethodSymbol = speculativeExtensionMethodSymbol?.GetConstructedReducedFrom(); return speculativeNonExtensionFormOfTheMethodSymbol == null || !speculativeNonExtensionFormOfTheMethodSymbol.Equals(methodSymbol); diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index 30fffac65..d967ce575 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -278,7 +278,15 @@ public class Foo } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + var expected = new DiagnosticResult + { + Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), + Message = "Do not call 'Any' method of class 'Enumerable' as a static method", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 51) } + }; + + await VerifyCSharpDiagnosticAsync(source, expected); } } } \ No newline at end of file From 9349828a0e659a84cb89de5434293b9c9f754052 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Oct 2015 13:06:07 -0300 Subject: [PATCH 021/358] Fix messages on UseInvokeMethodToFireEventAnalyzer and fix --- .../Design/UseInvokeMethodToFireEventAnalyzer.cs | 8 ++++---- .../Design/UseInvokeMethodToFireEventCodeFixProvider.cs | 2 +- .../Design/UseInvokeMethodToFireEventTests.cs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index 75c9fc28d..6278ed9d4 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -10,11 +10,11 @@ namespace CodeCracker.CSharp.Design [DiagnosticAnalyzer(LanguageNames.CSharp)] public class UseInvokeMethodToFireEventAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Use Invoke Method To Fire Event Analyzer"; - internal const string MessageFormat = "Use ?.Invoke operator and method to fire '{0}' event."; + internal const string Title = "Use Invoke Method To call on delegate"; + internal const string MessageFormat = "Use ?.Invoke operator and method to call on '{0}' delegate."; internal const string Category = SupportedCategories.Design; - const string Description = "In C#6 an event can be invoked using the null-propagating operator (?.) and it's" - + "invoke method to avoid throwing a NullReference exception when there is no event handler attached."; + const string Description = "In C#6 a delegate can be invoked using the null-propagating operator (?.) and it's" + + " invoke method to avoid throwing a NullReference exception when there is no method attached to the delegate."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs index 40c226049..a4a62017c 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs @@ -24,7 +24,7 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); context.RegisterCodeFix( - CodeAction.Create("Use ?.Invoke operator and method to fire an event.", ct => UseInvokeAsync(context.Document, diagnostic, ct), nameof(UseInvokeMethodToFireEventCodeFixProvider)), diagnostic); + CodeAction.Create("Change to ?.Invoke to call a delegate", ct => UseInvokeAsync(context.Document, diagnostic, ct), nameof(UseInvokeMethodToFireEventCodeFixProvider)), diagnostic); return Task.FromResult(0); } diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index e6dabcc73..7246442ba 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -23,7 +23,7 @@ public void Execute() var expected = new DiagnosticResult { Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = "Use ?.Invoke operator and method to fire 'MyEvent' event.", + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } }; @@ -53,7 +53,7 @@ public void Execute() var expected = new DiagnosticResult { Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = "Use ?.Invoke operator and method to fire 'MyEvent' event.", + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 25) } }; @@ -85,7 +85,7 @@ public void Execute() var expected = new DiagnosticResult { Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = "Use ?.Invoke operator and method to fire 'MyEvent' event.", + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 15, 25) } }; @@ -206,7 +206,7 @@ public static TReturn Method(System.Func getter) where T var expected = new DiagnosticResult { Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = "Use ?.Invoke operator and method to fire 'getter' event.", + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "getter"), Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 12) } }; From 1aeb0c253521f70f243e5f68d58c8c513e73e771 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 25 Oct 2015 23:27:43 -0300 Subject: [PATCH 022/358] Dont raise diag if checked for null in UseInvokeMethodToFireEventAnalyzer Fixes #536 --- .../UseInvokeMethodToFireEventAnalyzer.cs | 36 ++++++ .../Extensions/CSharpAnalyzerExtensions.cs | 14 +++ .../Design/UseInvokeMethodToFireEventTests.cs | 118 +++++++++++++++++- 3 files changed, 165 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index 6278ed9d4..546dfec2f 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using System; using System.Collections.Immutable; +using System.Linq; namespace CodeCracker.CSharp.Design { @@ -49,7 +50,42 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (invokedMethodSymbol == null) return; if (!invokedMethodSymbol.ReturnsVoid && !invokedMethodSymbol.ReturnType.IsReferenceType) return; + if (HasCheckForNull(invocation, context.SemanticModel, symbol)) return; context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation(), identifier.Identifier.Text)); } + + private static bool HasCheckForNull(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) + { + var method = invocation.FirstAncestorOfKind(SyntaxKind.MethodDeclaration) as MethodDeclarationSyntax; + if (method != null) + { + var ifs = method.Body.Statements.OfKind(SyntaxKind.IfStatement); + foreach (IfStatementSyntax @if in ifs) + { + if (!@if.Condition?.IsKind(SyntaxKind.EqualsExpression) ?? true) continue; + var equals = (BinaryExpressionSyntax)@if.Condition; + if (equals.Left == null || equals.Right == null) continue; + if (@if.GetLocation().SourceSpan.Start > invocation.GetLocation().SourceSpan.Start) return false; + ISymbol identifierSymbol; + if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName)) + identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol; + else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName)) + identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol; + else continue; + if (!symbol.Equals(identifierSymbol)) continue; + if (@if.Statement == null) continue; + if (@if.Statement.IsKind(SyntaxKind.Block)) + { + var ifBlock = (BlockSyntax)@if.Statement; + if (ifBlock.Statements.OfKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement).Any()) return true; + } + else + { + if (@if.Statement.IsAnyKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement)) return true; + } + } + } + return false; + } } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index fa6c05e98..f5b0d6874 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -435,5 +435,19 @@ public static SyntaxNode FirstAncestorOfKind(this SyntaxNode node, params Syntax } return null; } + + public static IEnumerable OfKind(this IEnumerable nodes, SyntaxKind kind) where TNode : SyntaxNode + { + foreach (var node in nodes) + if (node.IsKind(kind)) + yield return node; + } + + public static IEnumerable OfKind(this IEnumerable nodes, params SyntaxKind[] kinds) where TNode : SyntaxNode + { + foreach (var node in nodes) + if (node.IsAnyKind(kinds)) + yield return node; + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index 7246442ba..6b6f976fe 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -100,13 +100,126 @@ public async void NotWarningIfEventIsFiredWithInvokeMethod() public class MyClass { public event System.EventHandler MyEvent; - public void Execute() { MyEvent?.Invoke(this, System.EventArgs.Empty); } }"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async void RaiseDiagnosticEvenWhenVerifiedForNullAndNotReturnedOrThrown() + { + const string test = @" + public class MyClass + { + public static void Execute(System.Action action) + { + if (action == null) + { + var a = 1; + } + action(); + } + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 25) } + }; + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void RaiseDiagnosticEvenWhenVerifiedForNullAndNotReturnedOrThrownWithBlocklessIf() + { + const string test = @" + public class MyClass + { + public static void Execute(System.Action action) + { + if (action == null) + System.Console.WriteLine(); + action(); + } + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } + }; + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void RaiseDiagnosticIfNullCheckIsAfterInvocation() + { + const string test = @" + public class MyClass + { + public static void Execute(System.Action action) + { + action(); + if (action == null) throw new Exception(); + } + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } + }; + await VerifyCSharpDiagnosticAsync(test, expected); + } + [Fact] + public async void IgnoreIfAlreadyVerifiedForNullWithThrow() + { + const string test = @" + public class MyClass + { + public static void Execute(System.Action action) + { + if (action == null) throw new Exception(); + action(); + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async void IgnoreIfAlreadyVerifiedForNullInverted() + { + const string test = @" + public class MyClass + { + public static void Execute(System.Action action) + { + if (null == action) throw new Exception(); + action(); + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async void IgnoreIfAlreadyVerifiedForNullWithReturn() + { + const string test = @" + public class MyClass + { + public static void Execute(System.Action action) + { + if (action == null) return; + action(); + } + }"; await VerifyCSharpHasNoDiagnosticsAsync(test); } @@ -200,7 +313,6 @@ public async void ReportOnParametersWhenReturnTypeIsAReferenceType() var test = @" public static TReturn Method(System.Func getter) where T : System.Attribute where TReturn : class { - if (getter == null) return default(TReturn); return getter(default(T)); }".WrapInCSharpClass(); var expected = new DiagnosticResult @@ -208,7 +320,7 @@ public static TReturn Method(System.Func getter) where T Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "getter"), Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 12) } + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 12) } }; await VerifyCSharpDiagnosticAsync(test, expected); } From 5a121d835fa975bfac7c6176e6ac880265dd4e41 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 26 Oct 2015 01:55:33 -0200 Subject: [PATCH 023/358] Fix switch to auto property fix all Fixes #514 --- src/CSharp/CodeCracker/CodeCracker.csproj | 1 + .../SwitchToAutoPropCodeFixAllProvider.cs | 130 ++++++++++++++++++ .../Style/SwitchToAutoPropCodeFixProvider.cs | 18 +-- .../Style/SwitchToAutoPropTests.cs | 75 ++++++++-- .../Verifiers/CodeFixVerifier.cs | 5 +- 5 files changed, 200 insertions(+), 29 deletions(-) create mode 100644 src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 3e19c1e5b..26fb91930 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -79,6 +79,7 @@ + diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs new file mode 100644 index 000000000..5499d07c8 --- /dev/null +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs @@ -0,0 +1,130 @@ +using CodeCracker.Properties; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace CodeCracker.CSharp.Style +{ + public sealed class SwitchToAutoPropCodeFixAllProvider : FixAllProvider + { + private SwitchToAutoPropCodeFixAllProvider() { } + + public static readonly SwitchToAutoPropCodeFixAllProvider Instance = new SwitchToAutoPropCodeFixAllProvider(); + public override Task GetFixAsync(FixAllContext fixAllContext) + { + switch (fixAllContext.Scope) + { + case FixAllScope.Document: + return Task.FromResult(CodeAction.Create(Resources.SwitchToAutoPropCodeFixProvider_Title, + async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Document)))); + case FixAllScope.Project: + return Task.FromResult(CodeAction.Create(Resources.SwitchToAutoPropCodeFixProvider_Title, + async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Project)))); + case FixAllScope.Solution: + return Task.FromResult(CodeAction.Create(Resources.SwitchToAutoPropCodeFixProvider_Title, + async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Solution)))); + } + return null; + } + + private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Solution solution) + { + var docs = new List(); + var sol = new SolutionWithDocs { Docs = docs, Solution = solution }; + foreach (var pId in solution.Projects.Select(p => p.Id)) + { + var project = sol.Solution.GetProject(pId); + var newSol = await GetSolutionWithDocsAsync(fixAllContext, project).ConfigureAwait(false); + sol.Merge(newSol); + } + return sol; + } + + private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Project project) + { + var docs = new List(); + var newSolution = project.Solution; + foreach (var document in project.Documents) + { + var doc = await GetDiagnosticsInDocAsync(fixAllContext, document); + if (doc.Equals(DiagnosticsInDoc.Empty)) continue; + docs.Add(doc); + newSolution = newSolution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot); + } + var sol = new SolutionWithDocs { Docs = docs, Solution = newSolution }; + return sol; + } + + private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Document document) + { + var docs = new List(); + var doc = await GetDiagnosticsInDocAsync(fixAllContext, document); + docs.Add(doc); + var newSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot); + var sol = new SolutionWithDocs { Docs = docs, Solution = newSolution }; + return sol; + } + + private static async Task GetDiagnosticsInDocAsync(FixAllContext fixAllContext, Document document) + { + var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); + if (!diagnostics.Any()) return DiagnosticsInDoc.Empty; + var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var doc = DiagnosticsInDoc.Create(document.Id, diagnostics, root); + return doc; + } + + private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext, SolutionWithDocs sol) + { + var newSolution = sol.Solution; + foreach (var doc in sol.Docs) + { + foreach (var node in doc.Nodes) + { + var document = newSolution.GetDocument(doc.DocumentId); + var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var trackedNode = root.GetCurrentNode(node); + var property = trackedNode.AncestorsAndSelf().OfType().First(); + newSolution = await SwitchToAutoPropCodeFixProvider.MakeAutoPropertyAsync(document, root, property, fixAllContext.CancellationToken); + } + } + return newSolution; + } + + private struct DiagnosticsInDoc + { + public static DiagnosticsInDoc Create(DocumentId documentId, IList diagnostics, SyntaxNode root) + { + var nodes = diagnostics.Select(d => root.FindNode(d.Location.SourceSpan)).Where(n => !n.IsMissing).ToList(); + var diagnosticsInDoc = new DiagnosticsInDoc + { + DocumentId = documentId, + TrackedRoot = root.TrackNodes(nodes), + Nodes = nodes + }; + return diagnosticsInDoc; + } + public DocumentId DocumentId; + public List Nodes; + public SyntaxNode TrackedRoot; + + private static readonly DiagnosticsInDoc empty = new DiagnosticsInDoc(); + public static DiagnosticsInDoc Empty => empty; + } + + private struct SolutionWithDocs + { + public Solution Solution; + public List Docs; + public void Merge(SolutionWithDocs sol) + { + Solution = sol.Solution; + Docs.AddRange(sol.Docs); + } + } + } +} diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs index d2fd1a6ed..e58eef422 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs @@ -20,7 +20,7 @@ public class SwitchToAutoPropCodeFixProvider : CodeFixProvider public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.SwitchToAutoProp.ToDiagnosticId()); - public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => SwitchToAutoPropCodeFixAllProvider.Instance; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -33,35 +33,30 @@ private async static Task MakeAutoPropertyAsync(Document document, Dia { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var property = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - + return await MakeAutoPropertyAsync(document, root, property, cancellationToken); + } + public async static Task MakeAutoPropertyAsync(Document document, SyntaxNode root, PropertyDeclarationSyntax property, CancellationToken cancellationToken) + { + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); var getterReturn = (ReturnStatementSyntax)property.AccessorList.Accessors.First(a => a.Keyword.ValueText == "get").Body.Statements.First(); var returnIdentifier = (IdentifierNameSyntax)getterReturn.Expression; var returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; - - var variableDeclarator = (VariableDeclaratorSyntax)returnIdentifierSymbol.DeclaringSyntaxReferences.First().GetSyntax(); var fieldDeclaration = variableDeclarator.FirstAncestorOfType(); - - root = root.TrackNodes(returnIdentifier, fieldDeclaration, property); document = document.WithSyntaxRoot(root); root = await document.GetSyntaxRootAsync(cancellationToken); semanticModel = await document.GetSemanticModelAsync(cancellationToken); returnIdentifier = root.GetCurrentNode(returnIdentifier); returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; - var newProperty = GetSimpleProperty(property, variableDeclarator) .WithTriviaFrom(property) .WithAdditionalAnnotations(Formatter.Annotation); - var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, returnIdentifierSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken); document = newSolution.GetDocument(document.Id); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - root = root.InsertNodesAfter(root.GetCurrentNode(property), new[] { newProperty }); - var multipleVariableDeclaration = fieldDeclaration.Declaration.Variables.Count > 1; if (multipleVariableDeclaration) { @@ -73,7 +68,6 @@ private async static Task MakeAutoPropertyAsync(Document document, Dia { root = root.RemoveNodes(root.GetCurrentNodes(new SyntaxNode[] { fieldDeclaration, property }), SyntaxRemoveOptions.KeepNoTrivia); } - document = document.WithSyntaxRoot(root); return document.Project.Solution; } diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index cd0dc3f93..346432605 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -356,38 +356,83 @@ public int Y await VerifyCSharpFixAsync(source.WrapInCSharpClass(), expected.WrapInCSharpClass()); } - - [Fact(Skip = "Skip until the FixAll has been fixed.")] - public async Task FixSimplePropWithMultipleFieldsIntoAutoPropAll() + [Fact] + public async Task FixSimplePropWithMultipleFieldsIntoAutoPropAllInDoc() { - const string source = @" + var source = @" private int x = 42, y; private int z = int.MaxValue; - public int X { get { return x; } set { x = value; } } - public int Y { get { return y; } set { y = value; } } - public int Z { get { return z; } set { z = value; } - }"; - - const string expected = @" - public int X { get; set; } = 42; + }".WrapInCSharpClass(); + var expected = @"public int X { get; set; } = 42; public int Y { get; set; } - public int Z { get; set; } = int.MaxValue;"; + public int Z { get; set; } = int.MaxValue;".WrapInCSharpClass(); + await VerifyCSharpFixAllAsync(source, expected); + } - await VerifyCSharpFixAllAsync(source.WrapInCSharpClass(), expected.WrapInCSharpClass()); + [Fact] + public async Task FixSimplePropWithMultipleFieldsIntoAutoPropAllInSolution() + { + var source1 = @" + void Foo() + { + var other = new OtherType(); + other.z = 1; + } + public int x = 42, y; + public int X + { + get { return x; } + set { x = value; } + } + public int Y + { + get { return y; } + set { y = value; } + }".WrapInCSharpClass(); + var source2 = @" + void Foo() + { + var type = new TypeName(); + type.x = 1; + type.y = 2; + } + public int z = int.MaxValue; + public int Z + { + get { return z; } + set { z = value; } + }".WrapInCSharpClass("OtherType"); + var expected1 = @" + void Foo() + { + var other = new OtherType(); + other.Z = 1; + } + public int X { get; set; } = 42; + public int Y { get; set; }".WrapInCSharpClass(); + var expected2 = @" + void Foo() + { + var type = new TypeName(); + type.X = 1; + type.Y = 2; + } + public int Z { get; set; } = int.MaxValue;".WrapInCSharpClass("OtherType"); + await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { expected1, expected2 }); } [Fact] @@ -454,11 +499,11 @@ public async Task FixPropIntoAutoPropAndFixKeepingXMLComments() var source = @" public class Foo { - private int x = 10; + private int x = 10; /// /// comment 1 /// - public int X + public int X { get { return x; } set { x = value; } diff --git a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs index 6a263e004..4bfd2c517 100644 --- a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs +++ b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using FluentAssertions; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; @@ -326,7 +327,7 @@ private async static Task VerifyFixAllAsync(string language, DiagnosticAnalyzer { var document = docs[i]; var actual = await GetStringFromDocumentAsync(document).ConfigureAwait(true); - Assert.Equal(newSources[i], actual); + newSources[i].Should().Be(actual); } } From 3901f5d04ec6a453f8f186112a1aad76cdb61848 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 26 Oct 2015 22:28:04 -0200 Subject: [PATCH 024/358] Use IsKind instead of reflection on CallExtensionMethodAsExtension --- .../Usage/CallExtensionMethodAsExtensionAnalyzer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index 8bf1a6e5a..64cc76d99 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -53,7 +53,7 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, Compila if (methodSymbol == null || !methodSymbol.IsExtensionMethod) return; if (ContainsDynamicArgument(context.SemanticModel, childNodes)) return; ExpressionSyntax invocationStatement; - if (methodInvokeSyntax.Parent.GetType().ToString() != "Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax") + if (methodInvokeSyntax.Parent.IsNotKind(SyntaxKind.ArrowExpressionClause)) { invocationStatement = (methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement() as ExpressionStatementSyntax).Expression; } @@ -71,7 +71,7 @@ private static bool IsSelectingADifferentMethod(IEnumerable childNod var parameterExpressions = CallExtensionMethodAsExtensionCodeFixProvider.GetParameterExpressions(childNodes); var firstArgument = parameterExpressions.FirstOrDefault(); var argumentList = CallExtensionMethodAsExtensionCodeFixProvider.CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)); - var newInvocationStatement = + var newInvocationStatement = CallExtensionMethodAsExtensionCodeFixProvider.CreateInvocationExpression( firstArgument, methodName, argumentList).WithAdditionalAnnotations(introduceExtensionMethodAnnotation); var extensionMethodNamespaceUsingDirective = SyntaxFactory.UsingDirective(methodSymbol.ContainingNamespace.ToNameSyntax()); From 24c642798c759228a7c34d33947120815072136f Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 1 Nov 2015 17:16:14 -0800 Subject: [PATCH 025/358] Bump version to 1.0.0-rc4 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index f82634412..fc142a8a8 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index 1638208e5..8f64625a1 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.0-rc3 + 1.0.0-rc4 CodeCracker giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index 08892ea95..14016a4a2 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.10")] +[assembly: AssemblyFileVersion("1.0.0.11")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] \ No newline at end of file diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index 8a93b003f..8c0014c91 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.0-rc3 + 1.0.0-rc4 CodeCracker giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index bee783931..efcf0fb98 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.10")] +[assembly: AssemblyFileVersion("1.0.0.11")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] [assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 787120813..af8bf40d1 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 8a9f9a7be..e5e0482b8 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.0-rc3 + 1.0.0-rc4 CodeCracker giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 6360f51c1..e54299c29 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index 422edebdf..d84d807e5 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.10")] +[assembly: AssemblyFileVersion("1.0.0.11")] diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index d3cd6086a..c0786e7a5 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.10")] +[assembly: AssemblyFileVersion("1.0.0.11")] diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index 829f04730..4251692f0 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - + From 745bf9a6a9d04c1f6ba23a0f0f476f88c0f94a90 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 2 Nov 2015 10:15:11 -0800 Subject: [PATCH 026/358] Add RC4 to changelog --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c89cc244..85d7af31b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Change Log +## [v1.0.0-rc4](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc4) (2015-11-02) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc3...v1.0.0-rc4) + +**Implemented enhancements:** + +- NameOf Analyzer is too noisy [\#518](https://github.com/code-cracker/code-cracker/issues/518) + +**Fixed bugs:** + +- SwitchToAutoPropCodeFixProvider \(CC0017\) does not keep XML comment trivia [\#548](https://github.com/code-cracker/code-cracker/issues/548) +- CallExtensionMethodAsExtension \(CC0026\) throws NullReferenceException on expression bodied method statement [\#547](https://github.com/code-cracker/code-cracker/issues/547) +- CC0022 DI container delegate causes error [\#545](https://github.com/code-cracker/code-cracker/issues/545) +- BUG on ReadonlyFieldAnalyzer \(CC0052\) with assignment in Func\ in constructor [\#544](https://github.com/code-cracker/code-cracker/issues/544) +- UnusedParametersCodeFixProvider crashing when removing params [\#539](https://github.com/code-cracker/code-cracker/issues/539) +- CC0001 Is raised on multiple variable declarations. [\#537](https://github.com/code-cracker/code-cracker/issues/537) +- Bug: Use ?.Invoke operator and method to fire 'configuration' event, though configuration can't be null [\#536](https://github.com/code-cracker/code-cracker/issues/536) +- UnusedParametersCodeFixProvider fix all not working \(CC0057\) [\#534](https://github.com/code-cracker/code-cracker/issues/534) +- UnusedParametersCodeFixProvider will crash when it is trying to remove ParamArray [\#533](https://github.com/code-cracker/code-cracker/issues/533) +- CC0017 Change to auto property fix all not working [\#514](https://github.com/code-cracker/code-cracker/issues/514) +- BUG on CC0008 and CC0009 \(ObjectInitializer\) when used with collection [\#501](https://github.com/code-cracker/code-cracker/issues/501) +- 'TernaryOperatorWithAddignmentCodeFixProvider' encountered and error [\#496](https://github.com/code-cracker/code-cracker/issues/496) +- CC0009 eats pragmas and trivia [\#493](https://github.com/code-cracker/code-cracker/issues/493) +- CC0013 \(user ternary\) rule should be more careful with nullable types. \(VB\) [\#468](https://github.com/code-cracker/code-cracker/issues/468) + + ## [v1.0.0-rc3](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc3) (2015-10-03) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc2...v1.0.0-rc3) From fdcfe924b2d287ce36ae05be20822faf3c08c706 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 2 Nov 2015 13:52:27 -0800 Subject: [PATCH 027/358] Move tests on TernaryOperator tests to correct class --- .../Style/TernaryOperatorTests.cs | 281 +++++++++--------- 1 file changed, 139 insertions(+), 142 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 9940a298c..60aa7f5bd 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -7,22 +7,6 @@ namespace CodeCracker.Test.CSharp.Style { public class TernaryOperatorWithAssignmentTests : CodeFixVerifier { - private const string source = @" - namespace ConsoleApplication1 - { - class TypeName - { - public int Foo() - { - var something = true; - if (something) - return 1; - else - return 2; - } - } - }"; - [Fact] public async Task WhenUsingIfWithoutElseAnalyzerDoesNotCreateDiagnostic() { @@ -42,110 +26,6 @@ public int Foo() await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); } - [Fact] - public async Task WhenUsingIfWithElseButWithBlockWith2StatementsOnIfAnalyzerDoesNotCreateDiagnostic() - { - const string sourceWithoutElse = @" - namespace ConsoleApplication1 - { - class TypeName - { - public int Foo() - { - var something = true; - if (something) - { - string a = null; - return 1; - } - else - { - return 2; - } - } - } - }"; - await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); - } - - [Fact] - public async Task WhenUsingIfWithElseButWithBlockWith2StatementsOnElseAnalyzerDoesNotCreateDiagnostic() - { - const string sourceWithoutElse = @" - namespace ConsoleApplication1 - { - class TypeName - { - public int Foo() - { - var something = true; - if (something) - { - return 1; - } - else - { - string a = null; - return 2; - } - } - } - }"; - await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); - } - - [Fact] - public async Task WhenUsingIfWithElseButWithoutReturnOnElseAnalyzerDoesNotCreateDiagnostic() - { - const string sourceWithoutElse = @" - namespace ConsoleApplication1 - { - class TypeName - { - public int Foo() - { - var something = true; - if (something) - { - return 2; - } - else - { - string a = null; - } - return 1; - } - } - }"; - await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); - } - - [Fact] - public async Task WhenUsingIfWithElseButWithoutReturnOnIfAnalyzerDoesNotCreateDiagnostic() - { - const string sourceWithoutElse = @" - namespace ConsoleApplication1 - { - class TypeName - { - public int Foo() - { - var something = true; - if (something) - { - string a = null; - } - else - { - return 2; - } - return 1; - } - } - }"; - await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); - } - [Fact] public async Task TwoIfsInARowAnalyzerDoesNotCreateDiagnostic() { @@ -171,20 +51,6 @@ public int Foo() await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); } - [Fact] - public async Task WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() - { - var expected = new DiagnosticResult - { - Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), - Message = "You can use a ternary operator.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 17) } - }; - - await VerifyCSharpDiagnosticAsync(source, expected); - } - [Fact] public async Task WhenUsingIfAndElseWithAssignmentChangeToTernaryFix() { @@ -398,6 +264,39 @@ public int Foo() }"; await VerifyCSharpFixAllAsync(new string[] { source, source.Replace("TypeName", "TypeName1") }, new string[] { fixtest, fixtest.Replace("TypeName", "TypeName1") }); } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentAnalyzerCreatesDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + var something = true; + string a; + if (something) + { + a = ""a""; + } + else + { + a = ""b""; + } + } + } + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), + Message = "You can use a ternary operator.", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } public class TernaryOperatorWithReturnTests : CodeFixVerifier @@ -510,9 +409,9 @@ public int Foo() } [Fact] - public async Task WhenUsingIfAndElseWithAssignmentAnalyzerCreatesDiagnostic() + public async Task WhenUsingIfWithElseButWithoutReturnOnIfAnalyzerDoesNotCreateDiagnostic() { - const string source = @" + const string sourceWithoutElse = @" namespace ConsoleApplication1 { class TypeName @@ -520,26 +419,124 @@ class TypeName public int Foo() { var something = true; - string a; if (something) { - a = ""a""; + string a = null; } else { - a = ""b""; + return 2; + } + return 1; + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); + } + + [Fact] + public async Task WhenUsingIfWithElseButWithoutReturnOnElseAnalyzerDoesNotCreateDiagnostic() + { + const string sourceWithoutElse = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + var something = true; + if (something) + { + return 2; + } + else + { + string a = null; + } + return 1; + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); + } + + [Fact] + public async Task WhenUsingIfWithElseButWithBlockWith2StatementsOnElseAnalyzerDoesNotCreateDiagnostic() + { + const string sourceWithoutElse = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + var something = true; + if (something) + { + return 1; + } + else + { + string a = null; + return 2; + } + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); + } + + [Fact] + public async Task WhenUsingIfWithElseButWithBlockWith2StatementsOnIfAnalyzerDoesNotCreateDiagnostic() + { + const string sourceWithoutElse = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + var something = true; + if (something) + { + string a = null; + return 1; + } + else + { + return 2; } } } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(sourceWithoutElse); + } + + [Fact] + public async Task WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int Foo() + { + var something = true; + if (something) + return 1; + else + return 2; + } + } }"; var expected = new DiagnosticResult { - Id = DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), + Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), Message = "You can use a ternary operator.", Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 17) } }; - await VerifyCSharpDiagnosticAsync(source, expected); } } From 2cf3c71a8e573cd909d4f22008b8e893b24ada87 Mon Sep 17 00:00:00 2001 From: Andre Carlucci Date: Wed, 4 Nov 2015 10:44:01 -0800 Subject: [PATCH 028/358] fix #571 --- .../CodeCracker/Usage/IPAddressAnalyzer.cs | 5 ++++- .../Usage/IPAddressAnalyzerTests.cs | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs b/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs index 1cca30446..5bf5ea300 100644 --- a/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/IPAddressAnalyzer.cs @@ -41,9 +41,12 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) "System.Net.IPAddress.Parse(string)", args => { + if (!(args[0] is string)) { + return; + } parseMethodInfo.Value.Invoke(null, new[] { args[0].ToString() }); } - ); + ); var checker = new MethodChecker(context, Rule); checker.AnalyzeMethod(method); } diff --git a/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs index 72a1c5086..c0ee1d28a 100644 --- a/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs @@ -61,8 +61,23 @@ public async Task IfIsOtherTypeParseMethodDoesNotCreateDiagnostic() await VerifyCSharpHasNoDiagnosticsAsync(test); } + [Fact] + public async Task IfParseIdentifierFoundAndParameterIsNotStringLiteralDoesNotCreatesDiagnostic() + { + var test = string.Format(TestCode, @"var ip = ""; ""System.Net.IPAddress.Parse(ip)"); + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async Task IfAbbreviateParseIdentifierFoundAndParameterIsNotStringLiteralDoesNotCreatesDiagnostic() + { + var test = string.Format(TestCode, @"var ip = ""; ""IPAddress.Parse(ip)"); + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + - private static DiagnosticResult CreateDiagnosticResult(int line, int column, Action getErrorMessageAction) { + private static DiagnosticResult CreateDiagnosticResult(int line, int column, Action getErrorMessageAction) { return new DiagnosticResult { Id = DiagnosticId.IPAddress.ToDiagnosticId(), Message = GetErrorMessage(getErrorMessageAction), From 1c67add144da98879db7818338050dfbafdfad0b Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 4 Nov 2015 13:47:30 -0800 Subject: [PATCH 029/358] Run tests in sequence until we fix internationalization issues Problems ocurring in tests when ran in parallel --- build.targets.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.targets.ps1 b/build.targets.ps1 index 1bea77cb2..ab668b7e4 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -212,7 +212,7 @@ function RunTestWithCoverage($fullTestDllPaths) { if ($isAppVeyor) { $appVeyor = " -appveyor" } - $arguments = '-register:user', "`"-target:$xunitConsoleExe`"", "`"-targetargs:$targetArgs $appVeyor -noshadow -nologo -quiet`"", "`"-filter:+[CodeCracker*]* -[CodeCracker.Test*]*`"", "`"-output:$outputXml`"", '-coverbytest:*.Test.*.dll', '-log:All', '-returntargetcode' + $arguments = '-register:user', "`"-target:$xunitConsoleExe`"", "`"-targetargs:$targetArgs $appVeyor -noshadow -parallel none -nologo -quiet`"", "`"-filter:+[CodeCracker*]* -[CodeCracker.Test*]*`"", "`"-output:$outputXml`"", '-coverbytest:*.Test.*.dll', '-log:All', '-returntargetcode' Exec { . $openCoverExe $arguments } Write-Host -ForegroundColor DarkBlue "Exporting code coverage report" Exec { . $reportGeneratorExe -verbosity:Info -reports:$outputXml -targetdir:$coverageReportDir } From eb1e33bb55806ca746ff8851c154ca7554f7a294 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 3 Nov 2015 00:23:40 -0800 Subject: [PATCH 030/358] Fix ternary operator code fix when types differ Closes #521 --- .../Style/TernaryOperatorCodeFixProvider.cs | 127 +++++++++++++----- .../Style/TernaryOperatorTests.cs | 82 ++++++++++- 2 files changed, 173 insertions(+), 36 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 8cb60e2fc..0bc6bd886 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -12,24 +13,8 @@ namespace CodeCracker.CSharp.Style { - public abstract class TernaryOperatorCodeFixProviderBase : CodeFixProvider - { - protected static ExpressionSyntax MakeTernaryOperand(ExpressionSyntax expression, SemanticModel semanticModel, ITypeSymbol type, TypeSyntax typeSyntax) - { - if (type?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) - { - var constValue = semanticModel.GetConstantValue(expression); - if (constValue.HasValue && constValue.Value == null) - { - return SyntaxFactory.CastExpression(typeSyntax, expression); - } - } - return expression; - } - } - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(TernaryOperatorWithReturnCodeFixProvider)), Shared] - public class TernaryOperatorWithReturnCodeFixProvider : TernaryOperatorCodeFixProviderBase + public class TernaryOperatorWithReturnCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.TernaryOperator_Return.ToDiagnosticId()); @@ -48,16 +33,12 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var diagnosticSpan = diagnostic.Location.SourceSpan; var ifStatement = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var statementInsideIf = (ReturnStatementSyntax)(ifStatement.Statement is BlockSyntax ? ((BlockSyntax)ifStatement.Statement).Statements.Single() : ifStatement.Statement); + var returnStatementInsideIf = (ReturnStatementSyntax)(ifStatement.Statement is BlockSyntax ? ((BlockSyntax)ifStatement.Statement).Statements.Single() : ifStatement.Statement); var elseStatement = ifStatement.Else; - var statementInsideElse = (ReturnStatementSyntax)(elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement); - + var returnStatementInsideElse = (ReturnStatementSyntax)(elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement); var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var type = semanticModel.GetTypeInfo(statementInsideIf.Expression).ConvertedType; - var typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, statementInsideIf.SpanStart)); - var trueExpression = MakeTernaryOperand(statementInsideIf.Expression, semanticModel, type, typeSyntax); - var falseExpression = MakeTernaryOperand(statementInsideElse.Expression, semanticModel, type, typeSyntax); - + ExpressionSyntax trueExpression, falseExpression; + TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, semanticModel, out trueExpression, out falseExpression); var ternary = SyntaxFactory.ReturnStatement( SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression)) @@ -71,7 +52,7 @@ private static async Task MakeTernaryAsync(Document document, Diagnost } [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(TernaryOperatorWithAssignmentCodeFixProvider)), Shared] - public class TernaryOperatorWithAssignmentCodeFixProvider : TernaryOperatorCodeFixProviderBase + public class TernaryOperatorWithAssignmentCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId()); @@ -92,14 +73,11 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var expressionInsideIf = (ExpressionStatementSyntax)(ifStatement.Statement is BlockSyntax ? ((BlockSyntax)ifStatement.Statement).Statements.Single() : ifStatement.Statement); var elseStatement = ifStatement.Else; var expressionInsideElse = (ExpressionStatementSyntax)(elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement); - var assignmentExpressionInsideIf = (AssignmentExpressionSyntax)expressionInsideIf.Expression; var assignmentExpressionInsideElse = (AssignmentExpressionSyntax)expressionInsideElse.Expression; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var type = semanticModel.GetTypeInfo(assignmentExpressionInsideIf).Type; - var typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, assignmentExpressionInsideIf.SpanStart)); - var trueExpression = MakeTernaryOperand(assignmentExpressionInsideIf.Right, semanticModel, type, typeSyntax); - var falseExpression = MakeTernaryOperand(assignmentExpressionInsideElse.Right, semanticModel, type, typeSyntax); + ExpressionSyntax trueExpression, falseExpression; + TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, semanticModel, out trueExpression, out falseExpression); var ternary = SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( @@ -114,4 +92,91 @@ private static async Task MakeTernaryAsync(Document document, Diagnost return newDocument; } } + + internal static class TernaryOperatorCodeFixHelper + { + public static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel, out ExpressionSyntax trueExpression, out ExpressionSyntax falseExpression) + { + var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); + var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); + var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, + ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + } + + private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, + ITypeSymbol ifType, ITypeSymbol elseType, + ITypeSymbol ifConvertedType, ITypeSymbol elseConvertedType, + TypeSyntax typeSyntax, SemanticModel semanticModel, + out ExpressionSyntax trueExpression, out ExpressionSyntax falseExpression) + { + var isNullable = false; + if (ifConvertedType?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) + { + var constValue = semanticModel.GetConstantValue(ifExpression); + if (constValue.HasValue && constValue.Value == null) + trueExpression = SyntaxFactory.CastExpression(typeSyntax, ifExpression); + else + trueExpression = ifExpression; + isNullable = true; + } + else + { + trueExpression = ifExpression; + } + if (elseConvertedType?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) + { + var constValue = semanticModel.GetConstantValue(elseExpression); + if (constValue.HasValue && constValue.Value == null) + falseExpression = SyntaxFactory.CastExpression(typeSyntax, elseExpression); + else + falseExpression = elseExpression; + isNullable = true; + } + else + { + falseExpression = elseExpression; + } + if (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType)) + trueExpression = CastToBaseType(ifExpression, ifType, elseType, trueExpression); + } + + private static ExpressionSyntax CastToBaseType(ExpressionSyntax ifExpression, ITypeSymbol ifType, ITypeSymbol elseType, ExpressionSyntax trueExpression) + { + var commonBaseType = ifType.GetCommonBaseType(elseType); + if (commonBaseType != null) + trueExpression = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(commonBaseType.Name).WithAdditionalAnnotations(Simplifier.Annotation), ifExpression); + return trueExpression; + } + + private static bool CanBeAssignedTo(this ITypeSymbol type, ITypeSymbol possibleBaseType) + { + if (type == null || possibleBaseType == null) return true; + if (type.Kind == SymbolKind.ErrorType || possibleBaseType.Kind == SymbolKind.ErrorType) return true; + if (type == null || possibleBaseType == null) return true; + var baseType = type; + while (baseType != null && baseType.SpecialType != SpecialType.System_Object) + { + if (baseType.Equals(possibleBaseType)) return true; + baseType = baseType.BaseType; + } + return false; + } + + private static ITypeSymbol GetCommonBaseType(this ITypeSymbol type, ITypeSymbol otherType) + { + var baseType = type; + while (baseType != null) + { + var otherBaseType = otherType; + while (otherBaseType != null) + { + if (baseType.Equals(otherBaseType)) return baseType; + otherBaseType = otherBaseType.BaseType; + } + baseType = baseType.BaseType; + } + return null; + } + } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 60aa7f5bd..73ca6e47c 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -87,7 +87,7 @@ public int Foo() } } }"; - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] @@ -126,7 +126,7 @@ public void Foo() } } }"; - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest, allowNewCompilerDiagnostics: true); } [Fact] @@ -214,7 +214,7 @@ public int Foo() } } }"; - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] @@ -297,6 +297,43 @@ public int Foo() }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task FixConsidersAssignmentType() + { + const string source = @" +class Base { } +class A : Base { } +class B : Base { } +class Test2 +{ + public static void Foo() + { + var something = true; + Base b; + if (something) + b = new A(); + else + b = new B(); + } +} +"; + const string fixtest = @" +class Base { } +class A : Base { } +class B : Base { } +class Test2 +{ + public static void Foo() + { + var something = true; + Base b; + b = something ? (Base)new A() : new B(); + } +} +"; + await VerifyCSharpFixAsync(source, fixtest); + } } public class TernaryOperatorWithReturnTests : CodeFixVerifier @@ -332,7 +369,7 @@ public int Foo() } } }"; - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] @@ -366,7 +403,7 @@ class TypeName } } }"; - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest, allowNewCompilerDiagnostics: true); } [Fact] @@ -539,5 +576,40 @@ public int Foo() }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task FixConsidersReturnType() + { + const string source = @" +class Base { } +class A : Base { } +class B : Base { } +class Test +{ + public static Base Foo() + { + var something = true; + if (something) + return new A(); + else + return new B(); + } +} +"; + const string fixtest = @" +class Base { } +class A : Base { } +class B : Base { } +class Test +{ + public static Base Foo() + { + var something = true; + return something ? (Base)new A() : new B(); + } +} +"; + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From 3e8318be0e3b33c403353d0b7aeb230b3d7e89f4 Mon Sep 17 00:00:00 2001 From: plaurin Date: Thu, 5 Nov 2015 14:37:23 -0800 Subject: [PATCH 031/358] Added the french resource file. --- .../Design/EmptyCatchBlockAnalyzer.cs | 9 +- .../Design/EmptyCatchBlockCodeFixProvider.cs | 11 +- .../CodeCracker.Common.csproj | 9 + .../Properties/Resources.Designer.cs | 130 ++++++++--- .../Properties/Resources.fr.Designer.cs | 0 .../Properties/Resources.fr.resx | 217 ++++++++++++++++++ .../Properties/Resources.resx | 18 ++ 7 files changed, 349 insertions(+), 45 deletions(-) create mode 100644 src/Common/CodeCracker.Common/Properties/Resources.fr.Designer.cs create mode 100644 src/Common/CodeCracker.Common/Properties/Resources.fr.resx diff --git a/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs b/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs index d547dc5f4..f77e42f85 100644 --- a/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/EmptyCatchBlockAnalyzer.cs @@ -3,17 +3,18 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Immutable; +using CodeCracker.Properties; namespace CodeCracker.CSharp.Design { [DiagnosticAnalyzer(LanguageNames.CSharp)] public class EmptyCatchBlockAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Catch block cannot be empty"; + internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.EmptyCatchBlockAnalyzer_Title), Resources.ResourceManager, typeof(Resources)); internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Design; - const string Description = "An empty catch block suppress all errors and shouldn't be used.\r\n" - +"If the error is expected consider logging it or changing the control flow such that it is explicit."; + internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.EmptyCatchBlockAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString Message = new LocalizableResourceString(nameof(Resources.EmptyCatchBlockAnalyzer_Message), Resources.ResourceManager, typeof(Resources)); internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId.EmptyCatchBlock.ToDiagnosticId(), Title, @@ -34,7 +35,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (context.IsGenerated()) return; var catchStatement = (CatchClauseSyntax)context.Node; if (catchStatement?.Block?.Statements.Count != 0) return; - var diagnostic = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Empty Catch Block."); + var diagnostic = Diagnostic.Create(Rule, catchStatement.GetLocation(), Message); context.ReportDiagnostic(diagnostic); } } diff --git a/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs index 5ca79d356..4a0f80590 100644 --- a/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs @@ -9,12 +9,17 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using CodeCracker.Properties; namespace CodeCracker.CSharp.Design { [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(EmptyCatchBlockCodeFixProvider)), Shared] public class EmptyCatchBlockCodeFixProvider : CodeFixProvider { + internal static readonly LocalizableString FixRemoveEmptyCatchBlock = new LocalizableResourceString(nameof(Resources.EmptyCatchBlockCodeFixProvider_Remove), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString FixRemoveEmptyCatchBlockAndPutDocumentationLink = new LocalizableResourceString(nameof(Resources.EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString FixInsertExceptionClass = new LocalizableResourceString(nameof(Resources.EmptyCatchBlockCodeFixProvider_InsertException), Resources.ResourceManager, typeof(Resources)); + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.EmptyCatchBlock.ToDiagnosticId()); @@ -23,9 +28,9 @@ public class EmptyCatchBlockCodeFixProvider : CodeFixProvider public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); - context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", c => RemoveEmptyCatchBlockAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(RemoveEmptyCatchBlockAsync)), diagnostic); - context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block and Put a Documentation Link about Try...Catch use", c => RemoveEmptyCatchBlockPutCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider ) + nameof(RemoveEmptyCatchBlockPutCommentAsync)), diagnostic); - context.RegisterCodeFix(CodeAction.Create("Insert Exception class to Catch", c => InsertExceptionClassCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(InsertExceptionClassCommentAsync)), diagnostic); + context.RegisterCodeFix(CodeAction.Create(FixRemoveEmptyCatchBlock.ToString(), c => RemoveEmptyCatchBlockAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(RemoveEmptyCatchBlockAsync)), diagnostic); + context.RegisterCodeFix(CodeAction.Create(FixRemoveEmptyCatchBlockAndPutDocumentationLink.ToString(), c => RemoveEmptyCatchBlockPutCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider ) + nameof(RemoveEmptyCatchBlockPutCommentAsync)), diagnostic); + context.RegisterCodeFix(CodeAction.Create(FixInsertExceptionClass.ToString(), c => InsertExceptionClassCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(InsertExceptionClassCommentAsync)), diagnostic); return Task.FromResult(0); } diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index df0772fc8..caca05700 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -46,6 +46,11 @@ True Resources.resx + + True + True + Resources.fr.resx + @@ -54,6 +59,10 @@ + + ResXFileCodeGenerator + Resources.fr.Designer.cs + PublicResXFileCodeGenerator Resources.Designer.cs diff --git a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs index 5648e72dc..44ba556c4 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs +++ b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.42000 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. // //------------------------------------------------------------------------------ @@ -14,12 +14,12 @@ namespace CodeCracker.Properties { /// - /// A strongly-typed resource class, for looking up localized strings, etc. + /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. + // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder + // à l'aide d'un outil, tel que ResGen ou Visual Studio. + // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen + // avec l'option /str ou régénérez votre projet VS. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -34,7 +34,7 @@ internal Resources() { } /// - /// Returns the cached ResourceManager instance used by this class. + /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { @@ -48,8 +48,8 @@ internal Resources() { } /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. + /// Remplace la propriété CurrentUICulture du thread actuel pour toutes + /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { @@ -62,7 +62,7 @@ internal Resources() { } /// - /// Looks up a localized string similar to String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string.. + /// Recherche une chaîne localisée semblable à String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string.. /// public static string ConsoleWriteLineAnalyzer_Description { get { @@ -71,7 +71,7 @@ public static string ConsoleWriteLineAnalyzer_Description { } /// - /// Looks up a localized string similar to Use string interpolation. + /// Recherche une chaîne localisée semblable à Use string interpolation. /// public static string ConsoleWriteLineAnalyzer_MessageFormat { get { @@ -80,7 +80,7 @@ public static string ConsoleWriteLineAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use string interpolation instead of arguments on Console.WriteLine. + /// Recherche une chaîne localisée semblable à Use string interpolation instead of arguments on Console.WriteLine. /// public static string ConsoleWriteLineAnalyzer_Title { get { @@ -89,7 +89,7 @@ public static string ConsoleWriteLineAnalyzer_Title { } /// - /// Looks up a localized string similar to Change to string interpolation. + /// Recherche une chaîne localisée semblable à Change to string interpolation. /// public static string ConsoleWriteLineCodeFixProvider_Title { get { @@ -98,7 +98,61 @@ public static string ConsoleWriteLineCodeFixProvider_Title { } /// - /// Looks up a localized string similar to Change field type '{0}' accessibility to be as accessible as field '{1}'. + /// Recherche une chaîne localisée semblable à An empty catch block suppress all errors and shouldn't be used.\r\nIf the error is expected consider logging it or changing the control flow such that it is explicit.. + /// + public static string EmptyCatchBlockAnalyzer_Description { + get { + return ResourceManager.GetString("EmptyCatchBlockAnalyzer_Description", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Empty Catch Block.. + /// + public static string EmptyCatchBlockAnalyzer_Message { + get { + return ResourceManager.GetString("EmptyCatchBlockAnalyzer_Message", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Catch block cannot be empty. + /// + public static string EmptyCatchBlockAnalyzer_Title { + get { + return ResourceManager.GetString("EmptyCatchBlockAnalyzer_Title", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Insert Exception class to Catch. + /// + public static string EmptyCatchBlockCodeFixProvider_InsertException { + get { + return ResourceManager.GetString("EmptyCatchBlockCodeFixProvider_InsertException", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Remove Empty Catch Block. + /// + public static string EmptyCatchBlockCodeFixProvider_Remove { + get { + return ResourceManager.GetString("EmptyCatchBlockCodeFixProvider_Remove", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Remove Empty Catch Block and Put a Documentation Link about Try...Catch use. + /// + public static string EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation { + get { + return ResourceManager.GetString("EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Change field type '{0}' accessibility to be as accessible as field '{1}'. /// public static string InconsistentAccessibilityInFieldType_Title { get { @@ -107,7 +161,7 @@ public static string InconsistentAccessibilityInFieldType_Title { } /// - /// Looks up a localized string similar to Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. + /// Recherche une chaîne localisée semblable à Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. /// public static string InconsistentAccessibilityInIndexerParameter_Title { get { @@ -116,7 +170,7 @@ public static string InconsistentAccessibilityInIndexerParameter_Title { } /// - /// Looks up a localized string similar to Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. + /// Recherche une chaîne localisée semblable à Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. /// public static string InconsistentAccessibilityInIndexerReturnType_Title { get { @@ -125,7 +179,7 @@ public static string InconsistentAccessibilityInIndexerReturnType_Title { } /// - /// Looks up a localized string similar to Change parameter type '{0}' accessibility to be as accessible as method '{1}'. + /// Recherche une chaîne localisée semblable à Change parameter type '{0}' accessibility to be as accessible as method '{1}'. /// public static string InconsistentAccessibilityInMethodParameter_Title { get { @@ -134,7 +188,7 @@ public static string InconsistentAccessibilityInMethodParameter_Title { } /// - /// Looks up a localized string similar to Change return type '{0}' accessibility to be as accessible as method '{1}'. + /// Recherche une chaîne localisée semblable à Change return type '{0}' accessibility to be as accessible as method '{1}'. /// public static string InconsistentAccessibilityInMethodReturnType_Title { get { @@ -143,7 +197,7 @@ public static string InconsistentAccessibilityInMethodReturnType_Title { } /// - /// Looks up a localized string similar to Change property type '{0}' accessibility to be as accessible as property '{1}'. + /// Recherche une chaîne localisée semblable à Change property type '{0}' accessibility to be as accessible as property '{1}'. /// public static string InconsistentAccessibilityInPropertyType_Title { get { @@ -152,7 +206,7 @@ public static string InconsistentAccessibilityInPropertyType_Title { } /// - /// Looks up a localized string similar to Make method non async. + /// Recherche une chaîne localisée semblable à Make method non async. /// public static string MakeMethodNonAsyncCodeFixProvider_Title { get { @@ -161,7 +215,7 @@ public static string MakeMethodNonAsyncCodeFixProvider_Title { } /// - /// Looks up a localized string similar to In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor.. + /// Recherche une chaîne localisée semblable à In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor.. /// public static string NameOfAnalyzer_Description { get { @@ -170,7 +224,7 @@ public static string NameOfAnalyzer_Description { } /// - /// Looks up a localized string similar to Use 'nameof({0})' instead of specifying the program element name.. + /// Recherche une chaîne localisée semblable à Use 'nameof({0})' instead of specifying the program element name.. /// public static string NameOfAnalyzer_MessageFormat { get { @@ -179,7 +233,7 @@ public static string NameOfAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use nameof. + /// Recherche une chaîne localisée semblable à Use nameof. /// public static string NameOfAnalyzer_Title { get { @@ -188,7 +242,7 @@ public static string NameOfAnalyzer_Title { } /// - /// Looks up a localized string similar to Use nameof(). + /// Recherche une chaîne localisée semblable à Use nameof(). /// public static string NameOfCodeFixProvider_Title { get { @@ -197,7 +251,7 @@ public static string NameOfCodeFixProvider_Title { } /// - /// Looks up a localized string similar to String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string.. + /// Recherche une chaîne localisée semblable à String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string.. /// public static string StringFormatAnalyzer_Description { get { @@ -206,7 +260,7 @@ public static string StringFormatAnalyzer_Description { } /// - /// Looks up a localized string similar to Use string interpolation. + /// Recherche une chaîne localisée semblable à Use string interpolation. /// public static string StringFormatAnalyzer_MessageFormat { get { @@ -215,7 +269,7 @@ public static string StringFormatAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use string interpolation instead of String.Format. + /// Recherche une chaîne localisée semblable à Use string interpolation instead of String.Format. /// public static string StringFormatAnalyzer_Title { get { @@ -224,7 +278,7 @@ public static string StringFormatAnalyzer_Title { } /// - /// Looks up a localized string similar to Change to string interpolation. + /// Recherche une chaîne localisée semblable à Change to string interpolation. /// public static string StringFormatCodeFixProvider_Title { get { @@ -233,7 +287,7 @@ public static string StringFormatCodeFixProvider_Title { } /// - /// Looks up a localized string similar to Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties.. + /// Recherche une chaîne localisée semblable à Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties.. /// public static string SwitchToAutoPropAnalyzer_Description { get { @@ -242,7 +296,7 @@ public static string SwitchToAutoPropAnalyzer_Description { } /// - /// Looks up a localized string similar to Change {0} to an auto property. + /// Recherche une chaîne localisée semblable à Change {0} to an auto property. /// public static string SwitchToAutoPropAnalyzer_MessageFormat { get { @@ -251,7 +305,7 @@ public static string SwitchToAutoPropAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use auto property. + /// Recherche une chaîne localisée semblable à Use auto property. /// public static string SwitchToAutoPropAnalyzer_Title { get { @@ -260,7 +314,7 @@ public static string SwitchToAutoPropAnalyzer_Title { } /// - /// Looks up a localized string similar to Change to auto property. + /// Recherche une chaîne localisée semblable à Change to auto property. /// public static string SwitchToAutoPropCodeFixProvider_Title { get { @@ -269,7 +323,7 @@ public static string SwitchToAutoPropCodeFixProvider_Title { } /// - /// Looks up a localized string similar to You have missing/unexistent parameters in Xml Docs. + /// Recherche une chaîne localisée semblable à You have missing/unexistent parameters in Xml Docs. /// public static string XmlDocumentationAnalyzer_Title { get { @@ -278,7 +332,7 @@ public static string XmlDocumentationAnalyzer_Title { } /// - /// Looks up a localized string similar to Create missing parameters in xml docs. + /// Recherche une chaîne localisée semblable à Create missing parameters in xml docs. /// public static string XmlDocumentationCreateMissingParametersCodeFixProvider_Title { get { @@ -287,7 +341,7 @@ public static string XmlDocumentationCreateMissingParametersCodeFixProvider_Titl } /// - /// Looks up a localized string similar to Remove unexistent parameters in xml docs. + /// Recherche une chaîne localisée semblable à Remove unexistent parameters in xml docs. /// public static string XmlDocumentationRemoveNonExistentParametersCodeFixProvider_Title { get { diff --git a/src/Common/CodeCracker.Common/Properties/Resources.fr.Designer.cs b/src/Common/CodeCracker.Common/Properties/Resources.fr.Designer.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Common/CodeCracker.Common/Properties/Resources.fr.resx b/src/Common/CodeCracker.Common/Properties/Resources.fr.resx new file mode 100644 index 000000000..a7953b4d6 --- /dev/null +++ b/src/Common/CodeCracker.Common/Properties/Resources.fr.resx @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Change field type '{0}' accessibility to be as accessible as field '{1}' + + + Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]' + + + Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]' + + + Change parameter type '{0}' accessibility to be as accessible as method '{1}' + + + Change return type '{0}' accessibility to be as accessible as method '{1}' + + + Change property type '{0}' accessibility to be as accessible as property '{1}' + + + String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string. + + + Use string interpolation + + + Use string interpolation instead of arguments on Console.WriteLine + + + Change to string interpolation + + + In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor. + + + Use 'nameof({0})' instead of specifying the program element name. + + + Use nameof + + + Use nameof() + + + String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string. + + + Use string interpolation + + + Use string interpolation instead of String.Format + + + Change to string interpolation + + + Make method non async + + + You have missing/unexistent parameters in Xml Docs + + + Create missing parameters in xml docs + + + Remove unexistent parameters in xml docs + + + Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties. + + + Change {0} to an auto property + + + Use auto property + + + Change to auto property + + + Un block Catch vide avale toutes les erreurs et devrait être évité. +Si l'erreur est attendu considérer ajouter du logging ou modifier le flow de contrôle pour gérer l'erreur explicitement. + + + Block Catch Vide. + + + Un block catch ne peut etre vide + + + Insérer la classe Exception à la clause Catch + + + Enlever le block Catch vide + + + Enlever le block Catch vide et ajouter un lien vers la documentation des bonnes pratiques de Try...Catch + + \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/Properties/Resources.resx b/src/Common/CodeCracker.Common/Properties/Resources.resx index eb9bfeda3..60260ca81 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.resx +++ b/src/Common/CodeCracker.Common/Properties/Resources.resx @@ -195,4 +195,22 @@ Change to auto property + + An empty catch block suppress all errors and shouldn't be used.\r\nIf the error is expected consider logging it or changing the control flow such that it is explicit. + + + Empty Catch Block. + + + Catch block cannot be empty + + + Insert Exception class to Catch + + + Remove Empty Catch Block + + + Remove Empty Catch Block and Put a Documentation Link about Try...Catch use + \ No newline at end of file From fd11b52e10eb3e514f146d78ae915f9a592aeaa4 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 5 Nov 2015 14:48:22 -0800 Subject: [PATCH 032/358] Fix ObjectInitializerAnalyzer to work with self assignment Closes #525 --- .../Style/ObjectInitializerAnalyzer.cs | 5 +++-- .../Style/ObjectInitializerTests.cs | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs index dfb618e73..5dc26127d 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs @@ -57,8 +57,9 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) if (assignmentExpression.Right.IsNotKind(SyntaxKind.ObjectCreationExpression)) return; if (((ObjectCreationExpressionSyntax)assignmentExpression.Right).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; var variableSymbol = semanticModel.GetSymbolInfo(assignmentExpression.Left).Symbol; - var assignmentExpressions = FindAssignmentExpressions(semanticModel, expressionStatement, variableSymbol); - if (!assignmentExpressions.Any()) return; + var assignmentExpressionStatements = FindAssignmentExpressions(semanticModel, expressionStatement, variableSymbol); + if (!assignmentExpressionStatements.Any()) return; + if (HasAssignmentUsingDeclaredVariable(semanticModel, variableSymbol, assignmentExpressionStatements)) return; var diagnostic = Diagnostic.Create(RuleAssignment, expressionStatement.GetLocation(), "You can use initializers in here."); context.ReportDiagnostic(diagnostic); } diff --git a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs index 3b762148f..57a624dd3 100644 --- a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs @@ -7,7 +7,6 @@ namespace CodeCracker.Test.CSharp.Style { public class ObjectInitializerWithLocalDeclarationTests : CodeFixVerifier { - [Fact] public async Task WhenAssigningButNotCreatingAnalyzerDoesNotCreateDiagnostic() { @@ -699,5 +698,23 @@ public int Foo() }"; await VerifyCSharpFixAsync(source, fixtest, 0); } + + [Fact] + public async Task IgnoreSelfAssignment() + { + const string source = @" +class Foo +{ + public Foo F { get; set; } + static void Baz() + { + Foo foo; + foo = new Foo(); + foo.F = foo; + } +} +"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From ba67f1c149b5dc3c1685bffefd52f8054eb2d4df Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Tue, 3 Nov 2015 15:05:48 -0800 Subject: [PATCH 033/358] Fixes issue #552 caused by elseif and else --- .../Style/TernaryOperatorAnalyzer.vb | 4 ++++ .../Style/TernaryOperatorTests.vb | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb index 1f1aa5575..7b498b661 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb @@ -55,6 +55,10 @@ Namespace Style If ifStatement Is Nothing Then Exit Sub Dim ifBlock = TryCast(ifStatement.Parent, MultiLineIfBlockSyntax) If ifBlock Is Nothing Then Exit Sub + + ' Can't handle elseif clauses in ternary conditional + If ifBlock.ElseIfBlocks.Any() Then Exit Sub + If ifBlock.ElseBlock Is Nothing Then Exit Sub If ifBlock.Statements.Count <> 1 OrElse ifBlock.ElseBlock.Statements.Count <> 1 Then Exit Sub diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index f526b8024..4dd12d3f2 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -386,6 +386,7 @@ End Namespace" Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) End Function + Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFix() As Task Const source = " @@ -410,6 +411,26 @@ End Class" Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) End Function + + Public Async Function WhenUsingIfElseIfElseDoesNotCreate() As Task + Const sourceWithMultipleStatements = " +Namespace ConsoleApplication1 + Class TypeName + Public Sub Foo() + If 1 > 2 Then + Return 1 + ElseIf 2 > 3 Then + Return 2 + Else + Return 3 + End If + End Sub + End Class +End Namespace" + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFixAll() As Task Const source = " From a46aefa3ae58d87237384aeba11cee17cf2f67db Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Wed, 4 Nov 2015 10:13:25 -0800 Subject: [PATCH 034/358] Fix #550 concatnation with ternary operators fix #551 ternary operator retaining comments --- CodeCracker.sln | 2 - .../Style/TernaryOperatorCodeFixProviders.vb | 68 ++++++++-- .../Style/TernaryOperatorTests.vb | 127 ++++++++++++++++++ 3 files changed, 183 insertions(+), 14 deletions(-) diff --git a/CodeCracker.sln b/CodeCracker.sln index 0b2e60b2a..22de6636e 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -76,7 +76,6 @@ Global {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU @@ -93,7 +92,6 @@ Global {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 8403c474e..a0ccbbeb5 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -12,6 +12,31 @@ Namespace Style Public MustInherit Class TernaryOperatorCodeFixProviderBase Inherits CodeFixProvider + Protected Shared Function ExtractOperand(expression As AssignmentStatementSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax + Select Case expression.Kind + Case SyntaxKind.AddAssignmentStatement + Return SyntaxFactory.AddExpression(expression.Left, expression.Right) + Case SyntaxKind.SubtractAssignmentStatement + Return SyntaxFactory.SubtractExpression(expression.Left, expression.Right) + Case SyntaxKind.ConcatenateAssignmentStatement + Return SyntaxFactory.ConcatenateExpression(expression.Left, expression.Right) + Case SyntaxKind.DivideAssignmentStatement + Return SyntaxFactory.DivideExpression(expression.Left, expression.Right) + Case SyntaxKind.ExponentiateAssignmentStatement + Return SyntaxFactory.ExponentiateExpression(expression.Left, expression.Right) + Case SyntaxKind.IntegerDivideAssignmentStatement + Return SyntaxFactory.IntegerDivideExpression(expression.Left, expression.Right) + Case SyntaxKind.LeftShiftAssignmentStatement + Return SyntaxFactory.LeftShiftExpression(expression.Left, expression.Right) + Case SyntaxKind.MultiplyAssignmentStatement + Return SyntaxFactory.MultiplyExpression(expression.Left, expression.Right) + Case SyntaxKind.RightShiftAssignmentStatement + Return SyntaxFactory.RightShiftExpression(expression.Left, expression.Right) + Case Else + Return MakeTernaryOperand(expression.Right, semanticModel, type, typeSyntax) + End Select + End Function + Protected Shared Function MakeTernaryOperand(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then Dim constValue = semanticModel.GetConstantValue(expression) @@ -53,13 +78,23 @@ Namespace Style Dim typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, ifReturn.SpanStart)) Dim trueExpression = MakeTernaryOperand(ifReturn.Expression, semanticModel, type, typeSyntax) Dim falseExpression = MakeTernaryOperand(elseReturn.Expression, semanticModel, type, typeSyntax) + + Dim leadingTrivia = ifBlock.GetLeadingTrivia() + leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, ifReturn.GetLeadingTrivia().Where(Function(trivia) trivia.IsKind(SyntaxKind.CommentTrivia))) + leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, elseReturn.GetLeadingTrivia().Where(Function(trivia) trivia.IsKind(SyntaxKind.CommentTrivia))) + + Dim trailingTrivia = ifBlock.GetTrailingTrivia. + InsertRange(0, elseReturn.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))). + InsertRange(0, ifReturn.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))) + Dim ternary = SyntaxFactory.TernaryConditionalExpression(ifBlock.IfStatement.Condition.WithoutTrailingTrivia(), trueExpression.WithoutTrailingTrivia(), - falseExpression.WithoutTrailingTrivia()). - WithLeadingTrivia(ifBlock.GetLeadingTrivia()). - WithTrailingTrivia(ifBlock.GetTrailingTrivia()). - WithAdditionalAnnotations(Formatter.Annotation) - Dim returnStatement = SyntaxFactory.ReturnStatement(ternary) + falseExpression.WithoutTrailingTrivia()) + + Dim returnStatement = SyntaxFactory.ReturnStatement(ternary). + WithLeadingTrivia(leadingTrivia). + WithTrailingTrivia(trailingTrivia) + Dim newRoot = root.ReplaceNode(ifBlock, returnStatement) Dim newDocument = document.WithSyntaxRoot(newRoot) @@ -93,18 +128,27 @@ Namespace Style Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) Dim type = semanticModel.GetTypeInfo(ifAssign.Left).ConvertedType Dim typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, ifAssign.SpanStart)) - Dim trueExpression = MakeTernaryOperand(ifAssign.Right, semanticModel, type, typeSyntax) - Dim falseExpression = MakeTernaryOperand(elseAssign.Right, semanticModel, type, typeSyntax) + + Dim trueExpression = ExtractOperand(ifAssign, semanticModel, type, typeSyntax) + Dim falseExpression = ExtractOperand(elseAssign, semanticModel, type, typeSyntax) + + Dim leadingTrivia = ifBlock.GetLeadingTrivia. + AddRange(ifAssign.GetLeadingTrivia()). + AddRange(trueExpression.GetLeadingTrivia()). + AddRange(elseAssign.GetLeadingTrivia()). + AddRange(falseExpression.GetLeadingTrivia()) + Dim trailingTrivia = ifBlock.GetTrailingTrivia. + InsertRange(0, elseAssign.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))). + InsertRange(0, ifAssign.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))) + + Dim ternary = SyntaxFactory.TernaryConditionalExpression(ifBlock.IfStatement.Condition.WithoutTrailingTrivia(), trueExpression.WithoutTrailingTrivia(), falseExpression.WithoutTrailingTrivia()). - WithLeadingTrivia(ifBlock.GetLeadingTrivia()). - WithTrailingTrivia(ifBlock.GetTrailingTrivia()). WithAdditionalAnnotations(Formatter.Annotation) - Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left, ternary). - WithLeadingTrivia(ifBlock.GetLeadingTrivia()). - WithTrailingTrivia(ifBlock.GetTrailingTrivia()). + Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left.WithLeadingTrivia(leadingTrivia), ternary). + WithTrailingTrivia(trailingTrivia). WithAdditionalAnnotations(Formatter.Annotation) Dim newRoot = root.ReplaceNode(ifBlock, assignment) diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 4dd12d3f2..63796583d 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -120,6 +120,26 @@ End Namespace" Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) End Function + + Public Async Function WhenUsingIfElseIfElseDoesNotCreate() As Task + Const sourceWithMultipleStatements = " +Namespace ConsoleApplication1 + Class TypeName + Public Sub Foo() + Dim x = 0 + If 1 > 2 Then + x = 1 + ElseIf 2 > 3 Then + x = 2 + Else + x = 3 + End If + End Sub + End Class +End Namespace" + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function + Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task Dim expected As New DiagnosticResult With { @@ -247,6 +267,32 @@ End Class" Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) End Function + + Public Async Function WhenUsingCommentsConcatenateAtEndOfTernary() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim a As Integer + If True Then + a = 1 ' One Thing + Else + a = 2 ' Another + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim a As Integer + a = If(True, 1, 2) ' One Thing ' Another + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFixAll() As Task Const source = " @@ -272,6 +318,87 @@ End Class" Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) End Function + + Public Async Function WhenUsingConcatenationAssignmentExpandsToConcatenateAtEndOfTernary() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + If True Then + x = ""1"" + Else + x &= ""2"" + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + x = If(True, ""1"", x & ""2"") + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + + Public Async Function WhenUsingAddAssiginmentExpandsOperationProperly() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + If True Then + x = 1 + Else + x += 1 + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + x = If(True, 1, x + 1) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + Public Async Function WhenUsingSubtractAssiginmentExpandsOperationProperly() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + If True Then + x = 1 + Else + x -= 1 + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + x = If(True, 1, x - 1) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + End Class Public Class TernaryOperatorWithReturnTests From badc5c23d938b64643b72fa2d1b8d608cdb51798 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Thu, 5 Nov 2015 15:22:56 -0800 Subject: [PATCH 035/358] Fix ternary for differing return types --- CodeCracker.sln | 2 + .../Extensions/VBAnalyzerExtensions.vb | 81 +++++++++++- .../Style/TernaryOperatorCodeFixProviders.vb | 115 +++++++++++------- .../Style/TernaryOperatorTests.vb | 37 +++++- 4 files changed, 186 insertions(+), 49 deletions(-) diff --git a/CodeCracker.sln b/CodeCracker.sln index 22de6636e..0b2e60b2a 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -76,6 +76,7 @@ Global {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU @@ -92,6 +93,7 @@ Global {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU diff --git a/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb b/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb index f7db5bcb3..9b3ed1894 100644 --- a/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb +++ b/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb @@ -5,6 +5,85 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Public Module VBAnalyzerExtensions + + + Public Function GetCommonBaseType(source As ITypeSymbol, other As ITypeSymbol) As ITypeSymbol + If source Is Nothing AndAlso other IsNot Nothing Then + Return other + End If + If source IsNot Nothing AndAlso other Is Nothing Then + Return source + End If + + Dim baseType = source + While baseType IsNot Nothing + Dim otherBaseType = other + While otherBaseType IsNot Nothing + If baseType.Equals(otherBaseType) Then Return baseType + otherBaseType = otherBaseType.BaseType + End While + baseType = baseType.BaseType + End While + Return Nothing + End Function + + + Public Function CanBeAssignedTo(source As ITypeSymbol, targetType As ITypeSymbol) As Boolean + If source Is Nothing OrElse targetType Is Nothing Then Return True + If source.Kind = SymbolKind.ErrorType OrElse targetType.Kind = SymbolKind.ErrorType Then Return True + + Dim baseType = source + While baseType IsNot Nothing AndAlso baseType.SpecialType <> SpecialType.System_Object + If baseType.Equals(targetType) Then Return True + baseType = baseType.BaseType + End While + Return False + End Function + + + Public Function ConvertToBaseType(source As ExpressionSyntax, sourceType As ITypeSymbol, targetType As ITypeSymbol) As ExpressionSyntax + If targetType?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then Return source + Return If(sourceType IsNot Nothing AndAlso sourceType.Name = targetType.Name, source, SyntaxFactory.DirectCastExpression(source.WithoutTrailingTrivia, SyntaxFactory.ParseTypeName(targetType.Name))).WithTrailingTrivia(source.GetTrailingTrivia()) + End Function + + + Public Function EnsureNothingAsType(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax + If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then + Dim constValue = semanticModel.GetConstantValue(expression) + If constValue.HasValue AndAlso constValue.Value Is Nothing Then + Return SyntaxFactory.DirectCastExpression(expression.WithoutTrailingTrivia(), typeSyntax) + End If + End If + + Return expression + End Function + + + Public Function ExtractAssignmentAsExpressionSyntax(expression As AssignmentStatementSyntax) As ExpressionSyntax + Select Case expression.Kind + Case SyntaxKind.AddAssignmentStatement + Return SyntaxFactory.AddExpression(expression.Left, expression.Right) + Case SyntaxKind.SubtractAssignmentStatement + Return SyntaxFactory.SubtractExpression(expression.Left, expression.Right) + Case SyntaxKind.ConcatenateAssignmentStatement + Return SyntaxFactory.ConcatenateExpression(expression.Left, expression.Right) + Case SyntaxKind.DivideAssignmentStatement + Return SyntaxFactory.DivideExpression(expression.Left, expression.Right) + Case SyntaxKind.ExponentiateAssignmentStatement + Return SyntaxFactory.ExponentiateExpression(expression.Left, expression.Right) + Case SyntaxKind.IntegerDivideAssignmentStatement + Return SyntaxFactory.IntegerDivideExpression(expression.Left, expression.Right) + Case SyntaxKind.LeftShiftAssignmentStatement + Return SyntaxFactory.LeftShiftExpression(expression.Left, expression.Right) + Case SyntaxKind.MultiplyAssignmentStatement + Return SyntaxFactory.MultiplyExpression(expression.Left, expression.Right) + Case SyntaxKind.RightShiftAssignmentStatement + Return SyntaxFactory.RightShiftExpression(expression.Left, expression.Right) + Case Else + Return expression.Right + End Select + End Function + Public Sub RegisterSyntaxNodeAction(Of TLanguageKindEnum As Structure)(context As AnalysisContext, languageVersion As LanguageVersion, action As Action(Of SyntaxNodeAnalysisContext), ParamArray syntaxKinds As TLanguageKindEnum()) context.RegisterCompilationStartAction(languageVersion, Sub(compilationContext) compilationContext.RegisterSyntaxNodeAction(action, syntaxKinds)) End Sub @@ -36,7 +115,7 @@ Public Module VBAnalyzerExtensions End Sub Public Sub RunWithVB14OrGreater(languageVersion As LanguageVersion, action As Action) - languageVersion.RunWithVBVersionOrGreater(action, languageVersion.VisualBasic14) + languageVersion.RunWithVBVersionOrGreater(action, LanguageVersion.VisualBasic14) End Sub Public Sub RunWithVBVersionOrGreater(languageVersion As LanguageVersion, action As Action, greaterOrEqualThanLanguageVersion As LanguageVersion) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index a0ccbbeb5..fde069508 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -9,49 +9,49 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Style - Public MustInherit Class TernaryOperatorCodeFixProviderBase - Inherits CodeFixProvider - - Protected Shared Function ExtractOperand(expression As AssignmentStatementSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax - Select Case expression.Kind - Case SyntaxKind.AddAssignmentStatement - Return SyntaxFactory.AddExpression(expression.Left, expression.Right) - Case SyntaxKind.SubtractAssignmentStatement - Return SyntaxFactory.SubtractExpression(expression.Left, expression.Right) - Case SyntaxKind.ConcatenateAssignmentStatement - Return SyntaxFactory.ConcatenateExpression(expression.Left, expression.Right) - Case SyntaxKind.DivideAssignmentStatement - Return SyntaxFactory.DivideExpression(expression.Left, expression.Right) - Case SyntaxKind.ExponentiateAssignmentStatement - Return SyntaxFactory.ExponentiateExpression(expression.Left, expression.Right) - Case SyntaxKind.IntegerDivideAssignmentStatement - Return SyntaxFactory.IntegerDivideExpression(expression.Left, expression.Right) - Case SyntaxKind.LeftShiftAssignmentStatement - Return SyntaxFactory.LeftShiftExpression(expression.Left, expression.Right) - Case SyntaxKind.MultiplyAssignmentStatement - Return SyntaxFactory.MultiplyExpression(expression.Left, expression.Right) - Case SyntaxKind.RightShiftAssignmentStatement - Return SyntaxFactory.RightShiftExpression(expression.Left, expression.Right) - Case Else - Return MakeTernaryOperand(expression.Right, semanticModel, type, typeSyntax) - End Select - End Function - - Protected Shared Function MakeTernaryOperand(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax - If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then - Dim constValue = semanticModel.GetConstantValue(expression) - If constValue.HasValue AndAlso constValue.Value Is Nothing Then - Return SyntaxFactory.DirectCastExpression(expression.WithoutTrailingTrivia(), typeSyntax) - End If - End If - - Return expression - End Function - End Class + 'Public MustInherit Class TernaryOperatorCodeFixProviderBase + ' Inherits CodeFixProvider + + ' Protected Shared Function ExtractOperand(expression As AssignmentStatementSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax + ' Select Case expression.Kind + ' Case SyntaxKind.AddAssignmentStatement + ' Return SyntaxFactory.AddExpression(expression.Left, expression.Right) + ' Case SyntaxKind.SubtractAssignmentStatement + ' Return SyntaxFactory.SubtractExpression(expression.Left, expression.Right) + ' Case SyntaxKind.ConcatenateAssignmentStatement + ' Return SyntaxFactory.ConcatenateExpression(expression.Left, expression.Right) + ' Case SyntaxKind.DivideAssignmentStatement + ' Return SyntaxFactory.DivideExpression(expression.Left, expression.Right) + ' Case SyntaxKind.ExponentiateAssignmentStatement + ' Return SyntaxFactory.ExponentiateExpression(expression.Left, expression.Right) + ' Case SyntaxKind.IntegerDivideAssignmentStatement + ' Return SyntaxFactory.IntegerDivideExpression(expression.Left, expression.Right) + ' Case SyntaxKind.LeftShiftAssignmentStatement + ' Return SyntaxFactory.LeftShiftExpression(expression.Left, expression.Right) + ' Case SyntaxKind.MultiplyAssignmentStatement + ' Return SyntaxFactory.MultiplyExpression(expression.Left, expression.Right) + ' Case SyntaxKind.RightShiftAssignmentStatement + ' Return SyntaxFactory.RightShiftExpression(expression.Left, expression.Right) + ' Case Else + ' Return MakeTernaryOperand(expression.Right, semanticModel, type, typeSyntax) + ' End Select + ' End Function + + ' Protected Shared Function MakeTernaryOperand(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax + ' If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then + ' Dim constValue = semanticModel.GetConstantValue(expression) + ' If constValue.HasValue AndAlso constValue.Value Is Nothing Then + ' Return SyntaxFactory.DirectCastExpression(expression.WithoutTrailingTrivia(), typeSyntax) + ' End If + ' End If + + ' Return expression + ' End Function + 'End Class Public Class TernaryOperatorWithReturnCodeFixProvider - Inherits TernaryOperatorCodeFixProviderBase + Inherits CodeFixProvider Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First @@ -74,10 +74,19 @@ Namespace Style Dim ifReturn = TryCast(ifBlock.Statements.FirstOrDefault(), ReturnStatementSyntax) Dim elseReturn = TryCast(ifBlock.ElseBlock?.Statements.FirstOrDefault(), ReturnStatementSyntax) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) - Dim type = semanticModel.GetTypeInfo(ifReturn.Expression).ConvertedType + Dim type = GetCommonBaseType(semanticModel.GetTypeInfo(ifReturn.Expression).ConvertedType, semanticModel.GetTypeInfo(elseReturn.Expression).ConvertedType) + + Dim ifType = semanticModel.GetTypeInfo(ifReturn.Expression).Type + Dim elseType = semanticModel.GetTypeInfo(elseReturn.Expression).Type + Dim typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, ifReturn.SpanStart)) - Dim trueExpression = MakeTernaryOperand(ifReturn.Expression, semanticModel, type, typeSyntax) - Dim falseExpression = MakeTernaryOperand(elseReturn.Expression, semanticModel, type, typeSyntax) + Dim trueExpression = ifReturn.Expression. + ConvertToBaseType(ifType, type). + EnsureNothingAsType(semanticModel, type, typeSyntax) + + Dim falseExpression = elseReturn.Expression. + ConvertToBaseType(elseType, type). + EnsureNothingAsType(semanticModel, type, typeSyntax) Dim leadingTrivia = ifBlock.GetLeadingTrivia() leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, ifReturn.GetLeadingTrivia().Where(Function(trivia) trivia.IsKind(SyntaxKind.CommentTrivia))) @@ -104,7 +113,7 @@ Namespace Style Public Class TernaryOperatorWithAssignmentCodeFixProvider - Inherits TernaryOperatorCodeFixProviderBase + Inherits CodeFixProvider Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First @@ -126,17 +135,29 @@ Namespace Style Dim ifAssign = TryCast(ifBlock.Statements.FirstOrDefault(), AssignmentStatementSyntax) Dim elseAssign = TryCast(ifBlock.ElseBlock?.Statements.FirstOrDefault(), AssignmentStatementSyntax) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) - Dim type = semanticModel.GetTypeInfo(ifAssign.Left).ConvertedType + Dim type = GetCommonBaseType(semanticModel.GetTypeInfo(ifAssign.Left).ConvertedType, semanticModel.GetTypeInfo(elseAssign.Left).ConvertedType) Dim typeSyntax = SyntaxFactory.IdentifierName(type.ToMinimalDisplayString(semanticModel, ifAssign.SpanStart)) - Dim trueExpression = ExtractOperand(ifAssign, semanticModel, type, typeSyntax) - Dim falseExpression = ExtractOperand(elseAssign, semanticModel, type, typeSyntax) + Dim ifType = semanticModel.GetTypeInfo(ifAssign.Right).Type + Dim elseType = semanticModel.GetTypeInfo(elseAssign.Right).Type + + Dim trueExpression = ifAssign. + ExtractAssignmentAsExpressionSyntax(). + EnsureNothingAsType(semanticModel, type, typeSyntax). + ConvertToBaseType(ifType, type) + + Dim falseExpression = elseAssign. + ExtractAssignmentAsExpressionSyntax(). + EnsureNothingAsType(semanticModel, type, typeSyntax). + ConvertToBaseType(elseType, type) + Dim leadingTrivia = ifBlock.GetLeadingTrivia. AddRange(ifAssign.GetLeadingTrivia()). AddRange(trueExpression.GetLeadingTrivia()). AddRange(elseAssign.GetLeadingTrivia()). AddRange(falseExpression.GetLeadingTrivia()) + Dim trailingTrivia = ifBlock.GetTrailingTrivia. InsertRange(0, elseAssign.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))). InsertRange(0, ifAssign.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))) diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 63796583d..ef72d758e 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -233,7 +233,7 @@ Class Tester Private Sub Test() Dim ExcelRecord As New ExcelLineRecordClass Dim lCell As New MyCustomer - ExcelRecord.imported = If(lCell Is Nothing, False, If(lCell.Value, lCell.Value.ToString = ""X"")) + ExcelRecord.imported = If(lCell Is Nothing, False, DirectCast(If(lCell.Value, lCell.Value.ToString = ""X""), Boolean)) End Sub End Class" @@ -267,6 +267,41 @@ End Class" Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) End Function + + Public Async Function FixConsidersBaseTypeAssignent() As Task + Const source = " +Public Class Base +End Class +Public Class B + Inherits Base +End Class +Public Class MyType + Public Sub Foo() + Dim c As Base + If True Then + c = New Base() + Else + c = New B() + End If + End Sub +End Class" + + Const fix = " +Public Class Base +End Class +Public Class B + Inherits Base +End Class +Public Class MyType + Public Sub Foo() + Dim c As Base + c = If(True, New Base(), DirectCast(New B(), Base)) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function Public Async Function WhenUsingCommentsConcatenateAtEndOfTernary() As Task Const source = " From 34c4088885b5e5d00e11b52925fe2c3351a382c8 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Thu, 5 Nov 2015 15:25:21 -0800 Subject: [PATCH 036/358] Remove unneeded ternary base class --- .../Style/TernaryOperatorCodeFixProviders.vb | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index fde069508..6b24f9e72 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -9,46 +9,6 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Style - 'Public MustInherit Class TernaryOperatorCodeFixProviderBase - ' Inherits CodeFixProvider - - ' Protected Shared Function ExtractOperand(expression As AssignmentStatementSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax - ' Select Case expression.Kind - ' Case SyntaxKind.AddAssignmentStatement - ' Return SyntaxFactory.AddExpression(expression.Left, expression.Right) - ' Case SyntaxKind.SubtractAssignmentStatement - ' Return SyntaxFactory.SubtractExpression(expression.Left, expression.Right) - ' Case SyntaxKind.ConcatenateAssignmentStatement - ' Return SyntaxFactory.ConcatenateExpression(expression.Left, expression.Right) - ' Case SyntaxKind.DivideAssignmentStatement - ' Return SyntaxFactory.DivideExpression(expression.Left, expression.Right) - ' Case SyntaxKind.ExponentiateAssignmentStatement - ' Return SyntaxFactory.ExponentiateExpression(expression.Left, expression.Right) - ' Case SyntaxKind.IntegerDivideAssignmentStatement - ' Return SyntaxFactory.IntegerDivideExpression(expression.Left, expression.Right) - ' Case SyntaxKind.LeftShiftAssignmentStatement - ' Return SyntaxFactory.LeftShiftExpression(expression.Left, expression.Right) - ' Case SyntaxKind.MultiplyAssignmentStatement - ' Return SyntaxFactory.MultiplyExpression(expression.Left, expression.Right) - ' Case SyntaxKind.RightShiftAssignmentStatement - ' Return SyntaxFactory.RightShiftExpression(expression.Left, expression.Right) - ' Case Else - ' Return MakeTernaryOperand(expression.Right, semanticModel, type, typeSyntax) - ' End Select - ' End Function - - ' Protected Shared Function MakeTernaryOperand(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax - ' If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then - ' Dim constValue = semanticModel.GetConstantValue(expression) - ' If constValue.HasValue AndAlso constValue.Value Is Nothing Then - ' Return SyntaxFactory.DirectCastExpression(expression.WithoutTrailingTrivia(), typeSyntax) - ' End If - ' End If - - ' Return expression - ' End Function - 'End Class - Public Class TernaryOperatorWithReturnCodeFixProvider Inherits CodeFixProvider From 00d14b1cd3207007288122d038c74b99334fb43e Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Thu, 5 Nov 2015 17:03:09 -0800 Subject: [PATCH 037/358] Fixes #587 - stripping out non-selected catch blocks. Only remove try block option if single exception left. Fixes VB and C# implementations. --- .../Design/EmptyCatchBlockCodeFixProvider.cs | 33 ++++++++++-- .../Design/EmptyCatchBlockCodeFixProvider.vb | 17 ++++++- .../Design/EmptyCatchBlockTests.cs | 51 +++++++++++++++++++ .../Design/EmptyCatchBlockTests.vb | 35 +++++++++++++ 4 files changed, 130 insertions(+), 6 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs index 5ca79d356..1eefaa7cc 100644 --- a/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.cs @@ -20,21 +20,44 @@ public class EmptyCatchBlockCodeFixProvider : CodeFixProvider public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); - context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", c => RemoveEmptyCatchBlockAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(RemoveEmptyCatchBlockAsync)), diagnostic); - context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block and Put a Documentation Link about Try...Catch use", c => RemoveEmptyCatchBlockPutCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider ) + nameof(RemoveEmptyCatchBlockPutCommentAsync)), diagnostic); + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var catchStatement = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var tryStatement = (TryStatementSyntax)catchStatement.Parent; + + if (tryStatement.Catches.Count > 1) + { + context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", c => RemoveEmptyCatchBlockAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(RemoveEmptyCatchBlockAsync)), diagnostic); + } + else + { + context.RegisterCodeFix(CodeAction.Create("Remove Empty Try Block", c => RemoveEmptyTryBlockAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(RemoveEmptyCatchBlockAsync)), diagnostic); + context.RegisterCodeFix(CodeAction.Create("Remove Empty Try Block and Put a Documentation Link about Try...Catch use", c => RemoveEmptyCatchBlockPutCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(RemoveEmptyCatchBlockPutCommentAsync)), diagnostic); + } context.RegisterCodeFix(CodeAction.Create("Insert Exception class to Catch", c => InsertExceptionClassCommentAsync(context.Document, diagnostic, c), nameof(EmptyCatchBlockCodeFixProvider) + nameof(InsertExceptionClassCommentAsync)), diagnostic); - return Task.FromResult(0); } - private async static Task RemoveEmptyCatchBlockAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) => + private async static Task RemoveEmptyTryBlockAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) => await RemoveTryAsync(document, diagnostic, cancellationToken, insertComment: false); private async static Task RemoveEmptyCatchBlockPutCommentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) => await RemoveTryAsync(document, diagnostic, cancellationToken, insertComment: true); + private async static Task RemoveEmptyCatchBlockAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var catchStatement = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + + var newRoot = root.RemoveNode(catchStatement, SyntaxRemoveOptions.KeepNoTrivia); + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument; + + } + private async static Task RemoveTryAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken, bool insertComment) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb index 150d6bd0c..b413f9835 100644 --- a/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb @@ -23,10 +23,25 @@ Namespace Design Dim diag = context.Diagnostics.First Dim diagSpan = diag.Location.SourceSpan Dim declaration = root.FindToken(diagSpan.Start).Parent.AncestorsAndSelf.OfType(Of CatchBlockSyntax).First - context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", Function(c) RemoveTry(context.Document, declaration, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(RemoveTry)), diag) + + Dim tryBlock = DirectCast(declaration.Parent, TryBlockSyntax) + If tryBlock.CatchBlocks.Count > 1 Then + context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", Function(c) RemoveCatch(context.Document, declaration, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(RemoveTry)), diag) + Else + context.RegisterCodeFix(CodeAction.Create("Remove Entire Try Block", Function(c) RemoveTry(context.Document, declaration, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(RemoveTry)), diag) + End If context.RegisterCodeFix(CodeAction.Create("Insert Exception class to Catch", Function(c) InsertExceptionClassCommentAsync(context.Document, declaration, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(InsertExceptionClassCommentAsync)), diag) End Function + Private Async Function RemoveCatch(document As Document, catchBlock As CatchBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + + Dim newRoot = root.RemoveNode(catchBlock, SyntaxRemoveOptions.KeepNoTrivia) + + Dim newDocument = document.WithSyntaxRoot(newRoot) + Return newDocument + End Function + Private Async Function RemoveTry(document As Document, catchBlock As CatchBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) Dim tryBlock = DirectCast(catchBlock.Parent, TryBlockSyntax) Dim statements = tryBlock.Statements diff --git a/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs b/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs index 245361631..3af2833f4 100644 --- a/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs @@ -122,5 +122,56 @@ public async Task Foo() await VerifyCSharpFixAsync(test, fixtest, 2, false, true); } + + + [Fact] + public async Task WhenMultipleCatchOnlyRemoveSelected() + { + const string test = @" +using System; + +namespace ConsoleApplication1 +{ + class TypeName + { + public async Task Foo() + { + try + { + // do something + } + catch (System.ArgumentException ae) + { + } + catch (System.Exception ex) + { + int x = 0; + } + } + } +}"; + + const string fixtest = @" +using System; + +namespace ConsoleApplication1 +{ + class TypeName + { + public async Task Foo() + { + try + { + // do something + } + catch (System.Exception ex) + { + int x = 0; + } + } + } +}"; + await VerifyCSharpFixAsync(test, fixtest, 0); + } } } \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb b/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb index 0b25c0b04..80e6b4647 100644 --- a/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb @@ -70,5 +70,40 @@ End Namespace" Await VerifyBasicFixAsync(test, fix, 1) End Function + + + Public Async Function WhenMultipleCatchRemoveOnlySelectedEmpty() As Task + Const multipleTest As String = " +Imports System +Namespace ConsoleApplication1 + Class TypeName + Public Async Function Foo() As Task + Try + Dim a = ""A"" + Catch aex As ArgumentException + Catch ex As Exception + a = ""B"" + End Try + End Function + End Class +End Namespace" + + Const multipleFix = " +Imports System +Namespace ConsoleApplication1 + Class TypeName + Public Async Function Foo() As Task + Try + Dim a = ""A"" + Catch ex As Exception + a = ""B"" + End Try + End Function + End Class +End Namespace" + + Await VerifyBasicFixAsync(multipleTest, multipleFix, 0) + + End Function End Class End Namespace \ No newline at end of file From bca6c330bd622d42c5e461933a30b7dea454d052 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 6 Nov 2015 20:26:19 -0800 Subject: [PATCH 038/358] Fix cecil analysis and fix CallExtensionMethodAsExtensionAnalyzer Cecil analysis was not working properly after Roslyn RTM, as the message changed. Now we are correctly inspecting for the message, which involves looking for an AD0001 diagnostic on the build log. After reenabling the cecil build a bug was found on the CallExtensionMethodAsExtensionAnalyzer, so that was also fixed. --- .../CallExtensionMethodAsExtensionAnalyzer.cs | 36 ++++++------- ...tensionMethodAsExtensionCodeFixProvider.cs | 22 ++------ test/CSharp/AnalyzeCecil.ps1 | 12 +++-- .../CallExtensionMethodAsExtensionTests.cs | 50 ++++++++++++++++--- 4 files changed, 73 insertions(+), 47 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index 64cc76d99..15d9bff32 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System; namespace CodeCracker.CSharp.Usage { @@ -52,28 +51,17 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, Compila var methodSymbol = GetCallerMethodSymbol(context.SemanticModel, methodCaller.Name, argumentsCount); if (methodSymbol == null || !methodSymbol.IsExtensionMethod) return; if (ContainsDynamicArgument(context.SemanticModel, childNodes)) return; - ExpressionSyntax invocationStatement; - if (methodInvokeSyntax.Parent.IsNotKind(SyntaxKind.ArrowExpressionClause)) - { - invocationStatement = (methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement() as ExpressionStatementSyntax).Expression; - } - else - { - invocationStatement = methodInvokeSyntax.FirstAncestorOrSelfOfType().Expression; - } - if (invocationStatement == null) return; - if (IsSelectingADifferentMethod(childNodes, methodCaller.Name, context.Node.SyntaxTree, methodSymbol, invocationStatement, compilation)) return; + if (IsSelectingADifferentMethod(childNodes, methodCaller.Name, context.Node.SyntaxTree, methodSymbol, methodInvokeSyntax, compilation)) return; context.ReportDiagnostic(Diagnostic.Create(Rule, methodCaller.GetLocation(), methodSymbol.Name, classSymbol.Name)); } private static bool IsSelectingADifferentMethod(IEnumerable childNodes, SimpleNameSyntax methodName, SyntaxTree tree, IMethodSymbol methodSymbol, ExpressionSyntax invocationExpression, Compilation compilation) { - var parameterExpressions = CallExtensionMethodAsExtensionCodeFixProvider.GetParameterExpressions(childNodes); + var parameterExpressions = GetParameterExpressions(childNodes); var firstArgument = parameterExpressions.FirstOrDefault(); - var argumentList = CallExtensionMethodAsExtensionCodeFixProvider.CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)); - var newInvocationStatement = - CallExtensionMethodAsExtensionCodeFixProvider.CreateInvocationExpression( - firstArgument, methodName, argumentList).WithAdditionalAnnotations(introduceExtensionMethodAnnotation); + var argumentList = CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)); + var newInvocationStatement = CreateInvocationExpression(firstArgument, methodName, argumentList) + .WithAdditionalAnnotations(introduceExtensionMethodAnnotation); var extensionMethodNamespaceUsingDirective = SyntaxFactory.UsingDirective(methodSymbol.ContainingNamespace.ToNameSyntax()); var speculativeRootWithExtensionMethod = tree.GetCompilationUnitRoot() .ReplaceNode(invocationExpression, newInvocationStatement) @@ -107,5 +95,19 @@ private static bool ContainsDynamicArgument(SemanticModel sm, IEnumerable() .SelectMany(s => s.Arguments) .Any(a => sm.GetTypeInfo(a.Expression).Type?.Name == "dynamic"); + + public static IEnumerable GetParameterExpressions(IEnumerable childNodes) => + childNodes.OfType().SelectMany(s => s.Arguments).Select(s => s.Expression); + + public static ArgumentListSyntax CreateArgumentListSyntaxFrom(IEnumerable expressions) => + SyntaxFactory.ArgumentList().AddArguments(expressions.Select(s => SyntaxFactory.Argument(s)).ToArray()); + + public static InvocationExpressionSyntax CreateInvocationExpression(ExpressionSyntax sourceExpression, SimpleNameSyntax methodName, ArgumentListSyntax argumentList) => + SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + sourceExpression, + methodName), + argumentList); } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionCodeFixProvider.cs index 390a616b4..dad77490e 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionCodeFixProvider.cs @@ -4,12 +4,12 @@ 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.Usage { [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CallExtensionMethodAsExtensionCodeFixProvider)), Shared] @@ -40,7 +40,7 @@ private static async Task CallAsExtensionAsync(Document document, Diag .First(); var childNodes = staticInvocationExpression.ChildNodes(); - var parameterExpressions = GetParameterExpressions(childNodes); + var parameterExpressions = CallExtensionMethodAsExtensionAnalyzer.GetParameterExpressions(childNodes); var firstArgument = parameterExpressions.FirstOrDefault(); var callerMethod = childNodes.OfType().FirstOrDefault(); @@ -50,7 +50,7 @@ private static async Task CallAsExtensionAsync(Document document, Diag staticInvocationExpression, firstArgument, callerMethod.Name, - CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)) + CallExtensionMethodAsExtensionAnalyzer.CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)) ).WithAdditionalAnnotations(Formatter.Annotation); var semanticModel = await document.GetSemanticModelAsync(); @@ -60,27 +60,13 @@ private static async Task CallAsExtensionAsync(Document document, Diag return newDocument; } - public static IEnumerable GetParameterExpressions(IEnumerable childNodes) => - childNodes.OfType().SelectMany(s => s.Arguments).Select(s => s.Expression); - - public static ArgumentListSyntax CreateArgumentListSyntaxFrom(IEnumerable expressions) => - SyntaxFactory.ArgumentList().AddArguments(expressions.Select(s => SyntaxFactory.Argument(s)).ToArray()); - private static CompilationUnitSyntax ReplaceStaticCallWithExtionMethodCall(CompilationUnitSyntax root, InvocationExpressionSyntax staticInvocationExpression, ExpressionSyntax sourceExpression, SimpleNameSyntax methodName, ArgumentListSyntax argumentList) { - var extensionInvocationExpression = CreateInvocationExpression(sourceExpression, methodName, argumentList) + var extensionInvocationExpression = CallExtensionMethodAsExtensionAnalyzer.CreateInvocationExpression(sourceExpression, methodName, argumentList) .WithLeadingTrivia(staticInvocationExpression.GetLeadingTrivia()); return root.ReplaceNode(staticInvocationExpression, extensionInvocationExpression); } - public static InvocationExpressionSyntax CreateInvocationExpression(ExpressionSyntax sourceExpression, SimpleNameSyntax methodName, ArgumentListSyntax argumentList) => - SyntaxFactory.InvocationExpression( - SyntaxFactory.MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - sourceExpression, - methodName), - argumentList); - private static CompilationUnitSyntax ImportNeededNamespace(CompilationUnitSyntax root, SemanticModel semanticModel, MemberAccessExpressionSyntax callerMethod) { var symbolInfo = semanticModel.GetSymbolInfo(callerMethod.Name); diff --git a/test/CSharp/AnalyzeCecil.ps1 b/test/CSharp/AnalyzeCecil.ps1 index 55ba52733..6f9902b76 100644 --- a/test/CSharp/AnalyzeCecil.ps1 +++ b/test/CSharp/AnalyzeCecil.ps1 @@ -4,9 +4,10 @@ $projectDir = "$baseDir\cecil" $logDir = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\log") $logFile = "$logDir\cecil.log" $analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Debug\CodeCracker.CSharp.dll") +$analyzerCommonDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Debug\CodeCracker.Common.dll") $gitPath = "https://github.com/jbevain/cecil.git" -if (Test-Path "C:\proj\cecil") { - $gitPath = "c:\proj\cecil" +if (Test-Path "C:\p\cecil") { + $gitPath = "c:\p\cecil" } echo "Saving to log file $logFile" @@ -56,7 +57,10 @@ foreach($csproj in $csprojs) $itemGroup = $xmlProj.CreateElement("ItemGroup", $xmlProj.Project.xmlns) $analyzer = $xmlProj.CreateElement("Analyzer", $xmlProj.Project.xmlns) $analyzer.SetAttribute("Include", $analyzerDll) + $analyzerCommon = $xmlProj.CreateElement("Analyzer", $xmlProj.Project.xmlns) + $analyzerCommon.SetAttribute("Include", $analyzerCommonDll) $itemGroup.AppendChild($analyzer) | Out-Null + $itemGroup.AppendChild($analyzerCommon) | Out-Null $xmlProj.DocumentElement.AppendChild($itemGroup) | Out-Null $xmlProj.Save($csproj.FullName) } @@ -66,9 +70,9 @@ echo "Building..." foreach($sln in $slns) { echo "Building $($sln.FullName)..." - msbuild $sln.FullName /m /t:rebuild /v:detailed /p:Configuration="net_4_0_Debug" >> $logFile + msbuild $sln.FullName /m /t:rebuild /v:detailed /p:Configuration="net_4_5_Debug" >> $logFile } -$ccBuildErrors = cat $logFile | Select-String "info AnalyzerDriver: The Compiler Analyzer 'CodeCracker" +$ccBuildErrors = cat $logFile | Select-String "info AD0001: The Compiler Analyzer 'CodeCracker" if ($ccBuildErrors -ne $null) { write-host "Errors found (see $logFile):" diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index d967ce575..cc6d4ffc3 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -14,7 +14,7 @@ public async Task WhenCallExtensionMethodAsExtensionHasNoDiagnostics() const string source = @" using System.Linq; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -33,7 +33,7 @@ public async Task WhenCallExtensionMethodAsStaticMenthodTriggerAFix() const string source = @" using System.Linq; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -60,7 +60,7 @@ public async Task WhenCallExtensionMethodWithFullNamespaceAsStaticMenthodTrigger { const string source = @" namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -88,7 +88,7 @@ public async Task WhenCallExtensionMethodAsStaticMenthodShouldFix() const string source = @" using System.Linq; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -102,7 +102,7 @@ public void Bar() const string expected = @" using System.Linq; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -116,6 +116,40 @@ public void Bar() await VerifyCSharpFixAsync(source, expected); } + [Fact] + public async Task WhenCallExtensionMethodAsStaticMenthodShouldFixWithReturnStatement() + { + const string source = @" + using System.Linq; + namespace ConsoleApplication1 + { + public class Foo + { + public bool Bar() + { + var source = new int[] { 1, 2, 3 }; + return Enumerable.Any(source, x => x > 1); + } + } + }"; + + const string expected = @" + using System.Linq; + namespace ConsoleApplication1 + { + public class Foo + { + public bool Bar() + { + var source = new int[] { 1, 2, 3 }; + return source.Any(x => x > 1); + } + } + }"; + + await VerifyCSharpFixAsync(source, expected); + } + [Fact] public async Task WhenCallExtensionMethodWithFullNamespaceAndNotImportedShouldImport() { @@ -125,7 +159,7 @@ public async Task WhenCallExtensionMethodWithFullNamespaceAndNotImportedShouldIm using System.Collections.Generic; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -143,7 +177,7 @@ public void Bar() using System.Linq; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() @@ -179,7 +213,7 @@ public void Bar() using System.Linq; namespace ConsoleApplication1 - { + { public class Foo { public void Bar() From c17277e91e116e73a541111209497550e78b068d Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 6 Nov 2015 19:46:12 -0800 Subject: [PATCH 039/358] Reorganize StringFormatArgsAnalyzer to use the correct severities Fixes #585 StringFormatArgsAnalyzer was always raising an error, when it is not an error to have extra parameters. So we have taken an extra id, CC0111 to use as the warning, when string.Format is being provided more arguments than the format string is requiring. This will now raise a warning: string.Format("{0}", "a", "b"); When string.Format has less arguments than the format string requires, we are still raising CC0056, as an error, as it will generate a runtime error. This will now raise an error: string.Format("{0}{1}", "a"); Other verifications the analyzer was already checking continue as before. --- .../Usage/StringFormatArgsAnalyzer.cs | 23 ++++----- src/Common/CodeCracker.Common/DiagnosticId.cs | 3 +- .../Usage/StringFormatArgsTests.cs | 48 ++++++++++++------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs index cd386b625..db329b332 100644 --- a/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs @@ -17,27 +17,27 @@ public class StringFormatArgsAnalyzer : DiagnosticAnalyzer internal const string Category = SupportedCategories.Usage; const string Description = "The format argument in String.Format determines the number of argument, considering the {} inside. You should pass the correct number of arguments."; - internal static readonly DiagnosticDescriptor IncorrectNumberOfArgs = new DiagnosticDescriptor( - DiagnosticId.StringFormatArgs.ToDiagnosticId(), + internal static readonly DiagnosticDescriptor ExtraArgs = new DiagnosticDescriptor( + DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), Title, IncorrectNumberOfArgsMessage, Category, - DiagnosticSeverity.Error, + DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description, - helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.StringFormatArgs)); + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.StringFormatArgs_ExtraArgs)); - internal static readonly DiagnosticDescriptor InvalidArgsReference = new DiagnosticDescriptor( - DiagnosticId.StringFormatArgs.ToDiagnosticId(), + internal static readonly DiagnosticDescriptor InvalidArgs = new DiagnosticDescriptor( + DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), Title, InvalidArgsReferenceMessage, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description, - helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.StringFormatArgs)); + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.StringFormatArgs_InvalidArgs)); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(IncorrectNumberOfArgs, InvalidArgsReference); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(ExtraArgs, InvalidArgs); public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(Analyzer, SyntaxKind.InvocationExpression); @@ -58,9 +58,9 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var analyzingInterpolation = (InterpolatedStringExpressionSyntax)SyntaxFactory.ParseExpression($"${formatLiteral.Token.Text}"); var allInterpolations = analyzingInterpolation.Contents.Where(c => c.IsKind(SyntaxKind.Interpolation)).Select(c => (InterpolationSyntax)c); var distinctInterpolations = allInterpolations.Select(c => c.Expression.ToString()).Distinct(); - if (distinctInterpolations.Count() != argumentList.Arguments.Count - 1) + if (distinctInterpolations.Count() < argumentList.Arguments.Count - 1) { - var diag = Diagnostic.Create(IncorrectNumberOfArgs, invocationExpression.GetLocation()); + var diag = Diagnostic.Create(ExtraArgs, invocationExpression.GetLocation()); context.ReportDiagnostic(diag); return; } @@ -74,8 +74,9 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) } if (!validIndexReference) { - var diag = Diagnostic.Create(InvalidArgsReference, invocationExpression.GetLocation()); + var diag = Diagnostic.Create(InvalidArgs, invocationExpression.GetLocation()); context.ReportDiagnostic(diag); + return; } } } diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index 537a0a83a..df6250054 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -49,7 +49,7 @@ public enum DiagnosticId SimplifyRedundantBooleanComparisons = 49, ReadonlyField = 52, JsonNet = 54, - StringFormatArgs = 56, + StringFormatArgs_InvalidArgs = 56, UnusedParameters = 57, AbstractClassShouldNotHavePublicCtors = 60, TaskNameAsync = 61, @@ -78,5 +78,6 @@ public enum DiagnosticId ChangeAllToAny = 92, ConsoleWriteLine = 95, NameOf_External = 108, + StringFormatArgs_ExtraArgs = 111, } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs index 8899710b7..8b0be55f3 100644 --- a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs @@ -6,7 +6,7 @@ namespace CodeCracker.Test.CSharp.Usage { - public class StringFormatTests : CodeFixVerifier + public class StringFormatArgsTests : CodeFixVerifier { protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() => new StringFormatArgsAnalyzer(); @@ -79,13 +79,13 @@ public async Task IgnoresMethodsCalledWithIncorrectParameterTypes() } [Fact] - public async Task MethodsWithLessParametersCreatesDiagnostic() + public async Task LessParametersCreatesError() { var source = @"var result = string.Format(""one {0} two {1}"", ""a"");".WrapInCSharpMethod(); var expected = new DiagnosticResult { - Id = DiagnosticId.StringFormatArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, + Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), + Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, Severity = DiagnosticSeverity.Error, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } }; @@ -93,14 +93,14 @@ public async Task MethodsWithLessParametersCreatesDiagnostic() } [Fact] - public async Task MethodsWithMoreParametersCreatesDiagnostic() + public async Task MoreArgumentsCreatesWarning() { var source = @"var result = string.Format(""one {0} two {1}"", ""a"", ""b"", ""c"");".WrapInCSharpMethod(); var expected = new DiagnosticResult { - Id = DiagnosticId.StringFormatArgs.ToDiagnosticId(), + Id = DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, - Severity = DiagnosticSeverity.Error, + Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } }; await VerifyCSharpDiagnosticAsync(source, expected); @@ -128,14 +128,14 @@ public async Task MethodWithParamtersReferencingSingleAndFormatSpecifiersArgumen } [Fact] - public async Task MethodWithMultibleParamtersReferencingSingleArgumentCreatesDiagnostic() + public async Task TwoParametersReferencingSamePlaceholderCreatesWarning() { var source = @"var result = string.Format(""one {0} two {0}"", ""a"", ""b"");".WrapInCSharpMethod(); var expected = new DiagnosticResult { - Id = DiagnosticId.StringFormatArgs.ToDiagnosticId(), + Id = DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, - Severity = DiagnosticSeverity.Error, + Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } }; await VerifyCSharpDiagnosticAsync(source, expected); @@ -163,7 +163,7 @@ public async Task IgnoreVerbatimStringWithCorrectNumberOfHoles() } [Fact] - public async Task VerbatimStringWithIncorrectNumberOfHolesCreatesDiagnostic() + public async Task VerbatimStringWithMissingArgCreatesError() { var source = @" var noun = ""Giovanni""; @@ -171,8 +171,8 @@ public async Task VerbatimStringWithIncorrectNumberOfHolesCreatesDiagnostic() """"{1}""""."", noun);".WrapInCSharpMethod(); var expected = new DiagnosticResult { - Id = DiagnosticId.StringFormatArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, + Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), + Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, Severity = DiagnosticSeverity.Error, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 25) } }; @@ -180,12 +180,12 @@ public async Task VerbatimStringWithIncorrectNumberOfHolesCreatesDiagnostic() } [Fact] - public async Task MethodWithInvalidArgumentReferenceCreatesDiagnostic() + public async Task InvalidArgumentReferenceCreatesError() { var source = @"var result = string.Format(""one {1}"", ""a"");".WrapInCSharpMethod(); var expected = new DiagnosticResult { - Id = DiagnosticId.StringFormatArgs.ToDiagnosticId(), + Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, Severity = DiagnosticSeverity.Error, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } @@ -194,17 +194,31 @@ public async Task MethodWithInvalidArgumentReferenceCreatesDiagnostic() } [Fact] - public async Task MethodWithVeryInvalidArgumentReferenceCreatesDiagnostic() + public async Task NonIntegerPlaceholderCreatesError() { var source = @"var result = string.Format(""one {notZero}"", ""a"");".WrapInCSharpMethod(); var expected = new DiagnosticResult { - Id = DiagnosticId.StringFormatArgs.ToDiagnosticId(), + Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, Severity = DiagnosticSeverity.Error, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task UnusedArgsCreatesWarning() + { + var source = @"string.Format(""{0}{1}{3}{5}"", ""a"", ""b"", ""c"", ""d"", ""e"", ""f"");".WrapInCSharpMethod(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), + Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } \ No newline at end of file From 2af004d0881be674ddb3922fc32f1c7838d51204 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 7 Nov 2015 09:03:05 -0500 Subject: [PATCH 040/358] Make CodeFixVerifier to always check for new diags Before, if a codeFixIndex was supplied, CodeFixVerifier was not verifying if the analyzer had raised new diagnostics. Now this is fixed. When this was enabled, several code fix providers started generating test errors. This commit also fixes all of those. Also, discovered that the DisposablesShouldCallSuppressFinalize is assuming System is imported, added a skipped test to fix that. It was also not working correctly with explicitly implemented interfaces, and this is now fixed, also the tests were fixed. Also, fixed ParameterRefactory which was generating correct code in text, but an incorrect syntax tree. --- .../UseStaticRegexIsMatchCodeFixProvider.cs | 3 + .../ParameterRefactoryCodeFixProvider.cs | 94 ++++----- ...ablesShouldCallSuppressFinalizeAnalyzer.cs | 7 +- .../Design/CatchEmptyTests.cs | 6 +- .../Design/EmptyCatchBlockTests.cs | 11 +- .../Performance/StringBuilderInLoopTests.cs | 4 +- .../Performance/UseStaticRegexIsMatchTests.cs | 7 +- .../Refactoring/ParameterRefectoryTests.cs | 10 +- ...posablesShouldCallSuppressFinalizeTests.cs | 179 ++++++++++-------- .../Usage/RethrowExceptionTests.cs | 10 +- .../Verifiers/CodeFixVerifier.cs | 14 +- 11 files changed, 172 insertions(+), 173 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchCodeFixProvider.cs b/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchCodeFixProvider.cs index 49629f5d5..9dd542c56 100644 --- a/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchCodeFixProvider.cs @@ -45,6 +45,9 @@ private async static Task MakeRegexStaticAsync(Document document, Diag newArgumentList = newArgumentList.Insert(2, SyntaxFactory.Argument(SyntaxFactory.IdentifierName("RegexOptions.Compiled"))); var memberExpression = (MemberAccessExpressionSyntax)invocationDeclaration.Expression; + //todo: use simplification with `.WithAdditionalAnnotations(Simplifier.Annotation)`, like the example below. + //right now it is not working because tests can't find System.Text.RegularExpressions.Regex, we need to fix that + //var isMatchExpression = SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName("System.Text.RegularExpressions.Regex.IsMatch").WithAdditionalAnnotations(Simplifier.Annotation), var isMatchExpression = SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName("Regex.IsMatch"), SyntaxFactory.ArgumentList(newArgumentList)) .WithLeadingTrivia(memberExpression.GetLeadingTrivia()) diff --git a/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.cs index 9bc595e14..27740c976 100644 --- a/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.cs @@ -38,97 +38,69 @@ private async static Task NewClassAsync(Document document, Diagnostic SyntaxNode newRootParameter = null; if (oldNamespace == null) { - var newCompilation = NewCompilationFactory((CompilationUnitSyntax)oldClass.Parent, oldClass, oldMethod); + var newCompilation = AddParameterClassToCompilationUnitAndUpdateClassToUseNamespace((CompilationUnitSyntax)oldClass.Parent, oldClass, oldMethod); newRootParameter = root.ReplaceNode(oldClass.Parent, newCompilation); return document.WithSyntaxRoot(newRootParameter); } - var newNameSpace = NewNameSpaceFactory(oldNamespace, oldClass, oldMethod); - newRootParameter = root.ReplaceNode(oldNamespace, newNameSpace); + var newNamespace = AddParameterClassToNamespaceAndUpdateClassToUseNamespace(oldNamespace, oldClass, oldMethod); + newRootParameter = root.ReplaceNode(oldNamespace, newNamespace).WithAdditionalAnnotations(Formatter.Annotation); return document.WithSyntaxRoot(newRootParameter); } - private static List NewPropertyClassFactory(MethodDeclarationSyntax methodOld) + private static List CreateProperties(MethodDeclarationSyntax method) { var newGetSyntax = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); var newSetSyntax = SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); var acessorSyntax = SyntaxFactory.AccessorList( - SyntaxFactory.Token(SyntaxKind.OpenBraceToken), - SyntaxFactory.List(new[] { newGetSyntax, newSetSyntax }), - SyntaxFactory.Token(SyntaxKind.CloseBraceToken)); + SyntaxFactory.Token(SyntaxKind.OpenBraceToken), + SyntaxFactory.List(new[] { newGetSyntax, newSetSyntax }), + SyntaxFactory.Token(SyntaxKind.CloseBraceToken)); var properties = new List(); - foreach (ParameterSyntax param in methodOld.ParameterList.Parameters) + foreach (ParameterSyntax param in method.ParameterList.Parameters) { - var property = SyntaxFactory.PropertyDeclaration( - default(SyntaxList), - SyntaxFactory.TokenList(new[] { SyntaxFactory.Token(SyntaxKind.PublicKeyword) }), - param.Type, - default(ExplicitInterfaceSpecifierSyntax), - SyntaxFactory.Identifier(FirstLetteToUpper(param.Identifier.Text)), - acessorSyntax); + var property = SyntaxFactory.PropertyDeclaration(param.Type, FirstLetteToUpper(param.Identifier.Text)) + .WithModifiers(SyntaxFactory.TokenList(new[] { SyntaxFactory.Token(SyntaxKind.PublicKeyword) })) + .WithAccessorList(acessorSyntax); properties.Add(property); - } return properties; } - private static ClassDeclarationSyntax NewClassParameterFactory(string newNameClass, List Property) + private static ClassDeclarationSyntax CreateParameterClass(string newNameClass, MethodDeclarationSyntax oldMethod) { + var properties = CreateProperties(oldMethod); return SyntaxFactory.ClassDeclaration(newNameClass) - .WithMembers(SyntaxFactory.List(Property)) - .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) - .WithAdditionalAnnotations(Formatter.Annotation); - + .WithMembers(SyntaxFactory.List(properties)) + .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))); } - private static NamespaceDeclarationSyntax NewNameSpaceFactory(NamespaceDeclarationSyntax OldNameSpace, ClassDeclarationSyntax OldClass, MethodDeclarationSyntax OldMethod) + private static NamespaceDeclarationSyntax AddParameterClassToNamespaceAndUpdateClassToUseNamespace(NamespaceDeclarationSyntax oldNamespace, ClassDeclarationSyntax oldClass, MethodDeclarationSyntax oldMethod) { - var newNameSpace = OldNameSpace; - var className = $"NewClass{OldMethod.Identifier.Text}"; - var memberNameSpaceOld = (from member in OldNameSpace.Members - where member == OldClass - select member).FirstOrDefault(); - newNameSpace = OldNameSpace.ReplaceNode(memberNameSpaceOld, NewClassFactory(className, OldClass, OldMethod)); - var newParameterClass = NewClassParameterFactory(className, NewPropertyClassFactory(OldMethod)); - newNameSpace = newNameSpace - .WithMembers(newNameSpace.Members.Add(newParameterClass)) - .WithAdditionalAnnotations(Formatter.Annotation); - return newNameSpace; + var className = $"NewClass{oldMethod.Identifier.Text}"; + var newParameterClass = CreateParameterClass(className, oldMethod); + var newNamespace = oldNamespace.ReplaceNode(oldClass, UpdateClassToUseNewParameterClass(className, oldClass, oldMethod)) + .AddMembers(newParameterClass); + return newNamespace; } - private static ClassDeclarationSyntax NewClassFactory(string className, ClassDeclarationSyntax classOld, MethodDeclarationSyntax methodOld) + private static ClassDeclarationSyntax UpdateClassToUseNewParameterClass(string className, ClassDeclarationSyntax classOld, MethodDeclarationSyntax methodOld) { - - var newParameter = SyntaxFactory.Parameter(SyntaxFactory.Identifier($"{className} {FirstLetteToLower(className)}")); - - var paremeters = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList().Add(newParameter)) - .WithAdditionalAnnotations(Formatter.Annotation); - - - var newMethod = SyntaxFactory.MethodDeclaration(methodOld.ReturnType, methodOld.Identifier.Text) - .WithModifiers(methodOld.Modifiers) - .WithParameterList(paremeters) - .WithBody(methodOld.Body) - .WithAdditionalAnnotations(Formatter.Annotation); - + var newParameter = SyntaxFactory.Parameter(SyntaxFactory.Identifier(FirstLetteToLower(className))).WithType(SyntaxFactory.ParseTypeName(className)); + var parameters = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList().Add(newParameter)); + var newMethod = methodOld.WithParameterList(parameters); var newClass = classOld.ReplaceNode(methodOld, newMethod); - return newClass; } - private static CompilationUnitSyntax NewCompilationFactory(CompilationUnitSyntax OldCompilation, ClassDeclarationSyntax OldClass, MethodDeclarationSyntax OldMethod) + private static CompilationUnitSyntax AddParameterClassToCompilationUnitAndUpdateClassToUseNamespace(CompilationUnitSyntax oldCompilation, ClassDeclarationSyntax oldClass, MethodDeclarationSyntax oldMethod) { - var newNameSpace = OldCompilation; - var className = $"NewClass{OldMethod.Identifier.Text}"; - var OldMemberNameSpace = (from member in OldCompilation.Members - where member == OldClass - select member).FirstOrDefault(); - newNameSpace = OldCompilation.ReplaceNode(OldMemberNameSpace, NewClassFactory(className, OldClass, OldMethod)); - var newParameterClass = NewClassParameterFactory(className, NewPropertyClassFactory(OldMethod)); - return newNameSpace.WithMembers(newNameSpace.Members.Add(newParameterClass)) - .WithAdditionalAnnotations(Formatter.Annotation); - + var className = $"NewClass{oldMethod.Identifier.Text}"; + var newParameterClass = CreateParameterClass(className, oldMethod); + var newNamespace = oldCompilation.ReplaceNode(oldClass, UpdateClassToUseNewParameterClass(className, oldClass, oldMethod)) + .AddMembers(newParameterClass); + return newNamespace; } private static string FirstLetteToUpper(string text) => diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs index e57e1b769..d0311aa1c 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs @@ -59,8 +59,13 @@ private static void Analyze(SymbolAnalysisContext context) private static ISymbol FindDisposeMethod(INamedTypeSymbol symbol) { - return symbol.GetMembers().Where(x => x.ToString().Contains($"{x.ContainingType.Name}.Dispose(")).Cast() + var disposeSymbol = symbol.GetMembers().Where(x => + x.Kind == SymbolKind.Method + && (x.ToString().Contains($"{x.ContainingType.Name }.Dispose(") + || (((IMethodSymbol)x).ExplicitInterfaceImplementations.Any(i => i.ToString() == "System.IDisposable.Dispose()")))) + .Cast() .FirstOrDefault(m => m.Parameters == null || m.Parameters.Length == 0); + return disposeSymbol; } public static bool ContainsUserDefinedFinalizer(INamedTypeSymbol symbol) diff --git a/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs b/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs index 169cfc7a9..2608bf926 100644 --- a/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs @@ -44,7 +44,7 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public void Foo() { try { @@ -65,7 +65,7 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public void Foo() { try { @@ -78,7 +78,7 @@ public async Task Foo() } } }"; - await VerifyCSharpFixAsync(test, fixtest, 0); + await VerifyCSharpFixAsync(test, fixtest, 0, allowNewCompilerDiagnostics: true); } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs b/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs index 245361631..007f9dec9 100644 --- a/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs @@ -8,6 +8,7 @@ public class EmptyCatchBlockTests : CodeFixVerifier if (!actions.Any()) break; if (codeFixIndex != null) - { document = await ApplyFixAsync(document, actions.ElementAt((int)codeFixIndex)).ConfigureAwait(true); - break; - } - - document = await ApplyFixAsync(document, actions.ElementAt(0)).ConfigureAwait(true); + else + document = await ApplyFixAsync(document, actions.ElementAt(0)).ConfigureAwait(true); var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true)); compilerDiagnostics = (await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true)).ToList(); From da58d2345795a078b9a48bf31c32dae7c73bef13 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 7 Nov 2015 09:06:15 -0500 Subject: [PATCH 041/358] Fix typo --- .../Usage/CallExtensionMethodAsExtensionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index cc6d4ffc3..d951964ae 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -117,7 +117,7 @@ public void Bar() } [Fact] - public async Task WhenCallExtensionMethodAsStaticMenthodShouldFixWithReturnStatement() + public async Task WhenCallExtensionMethodAsStaticMethodShouldFixWithReturnStatement() { const string source = @" using System.Linq; From e78070bb13b780546f581361ae6cd425d76f0659 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 7 Nov 2015 09:17:05 -0500 Subject: [PATCH 042/358] Fix VB tests after updating CodeFixVerifier --- .../Design/EmptyCatchBlockTests.vb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb b/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb index 0b25c0b04..316333a6e 100644 --- a/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Design/EmptyCatchBlockTests.vb @@ -9,12 +9,12 @@ Namespace Design Imports System Namespace ConsoleApplication1 Class TypeName - Public Async Function Foo() As Task + Public Sub Foo() Try Dim a = ""A"" Catch End Try - End Function + End Sub End Class End Namespace" @@ -24,13 +24,13 @@ End Namespace" Imports System Namespace ConsoleApplication1 Class TypeName - Public Async Function Foo() As Task + Public Sub Foo() Try Dim a = ""A"" Catch Throw End Try - End Function + End Sub End Class End Namespace" @@ -43,9 +43,9 @@ End Namespace" Imports System Namespace ConsoleApplication1 Class TypeName - Public Async Function Foo() As Task + Public Sub Foo() Dim a = ""A"" - End Function + End Sub End Class End Namespace" @@ -58,13 +58,13 @@ End Namespace" Imports System Namespace ConsoleApplication1 Class TypeName - Public Async Function Foo() As Task + Public Sub Foo() Try Dim a = ""A"" Catch ex As Exception Throw End Try - End Function + End Sub End Class End Namespace" From 38ec2184d94f7be9b6dbab78e563804433c13919 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 7 Nov 2015 09:46:56 -0500 Subject: [PATCH 043/358] Update changeculture on master --- .../CodeCracker.Test.Common/ChangeCulture.cs | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/test/Common/CodeCracker.Test.Common/ChangeCulture.cs b/test/Common/CodeCracker.Test.Common/ChangeCulture.cs index 635ee1d5d..afa4b3536 100644 --- a/test/Common/CodeCracker.Test.Common/ChangeCulture.cs +++ b/test/Common/CodeCracker.Test.Common/ChangeCulture.cs @@ -1,24 +1,38 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Globalization; +using System.Threading; namespace CodeCracker.Test { public class ChangeCulture : IDisposable { + private readonly CultureInfo originalCulture; + private readonly CultureInfo originalUICulture; + private readonly CultureInfo originalDefaultCulture; + private readonly CultureInfo originalDefaultUICulture; + public ChangeCulture(string cultureName) { - System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(cultureName); - System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(cultureName); + originalCulture = Thread.CurrentThread.CurrentCulture; + originalUICulture = Thread.CurrentThread.CurrentUICulture; + originalDefaultCulture = CultureInfo.DefaultThreadCurrentCulture; + originalDefaultUICulture = CultureInfo.DefaultThreadCurrentUICulture; + + Thread.CurrentThread.CurrentCulture = + Thread.CurrentThread.CurrentUICulture = + CultureInfo.DefaultThreadCurrentCulture = + CultureInfo.DefaultThreadCurrentUICulture = + CultureInfo.GetCultureInfo(cultureName); + } public void Dispose() { - System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; - System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.InvariantCulture; + Thread.CurrentThread.CurrentCulture = originalCulture; + Thread.CurrentThread.CurrentUICulture = originalUICulture; + CultureInfo.DefaultThreadCurrentCulture = originalDefaultCulture; + CultureInfo.DefaultThreadCurrentUICulture = originalDefaultUICulture; GC.SuppressFinalize(this); } } -} +} \ No newline at end of file From e1c71a1b3c7e71f3e4f8e67d8c2b729918c095d6 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Tue, 10 Nov 2015 10:24:27 -0200 Subject: [PATCH 044/358] Moving leading trivia from variable declaration to using statement (fixes #577) --- ...sableVariableNotDisposedCodeFixProvider.cs | 2 +- .../DisposableVariableNotDisposedTests.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs index 303e2da3f..b9910ed6c 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedCodeFixProvider.cs @@ -61,7 +61,7 @@ public static SyntaxNode CreateUsing(SyntaxNode root, ObjectCreationExpressionSy var variableDeclarator = (VariableDeclaratorSyntax)objectCreation.Parent.Parent; var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent; var statement = (LocalDeclarationStatementSyntax)variableDeclaration.Parent; - newRoot = CreateRootWithUsing(root, statement, u => u.WithDeclaration(variableDeclaration)); + newRoot = CreateRootWithUsing(root, statement, u => u.WithDeclaration(variableDeclaration.WithoutLeadingTrivia())); } else if (objectCreation.Parent.IsKind(SyntaxKind.Argument)) { diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index 08d1921d3..ba6e4dad9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -996,6 +996,25 @@ void IDisposable.Dispose() { } await VerifyCSharpFixAsync(source, fixtest); } + [Fact] + public async Task AfterFixCommentsArePreserved() + { + + var source = @" +// comment +var mem = new System.IO.MemoryStream(); +var b = mem.ReadByte(); +".WrapInCSharpMethod(); + + var fixtest = @" +// comment +using (var mem = new System.IO.MemoryStream()) +{ + var b = mem.ReadByte(); +} +".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(source, fixtest); + } [Fact] public async Task ExplicitlyDisposedObjectDoesNotCreateDiagnostic() From c042f062567af8ef6187c89f8a19a4372808612d Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 7 Nov 2015 13:53:15 -0500 Subject: [PATCH 045/358] Remove webforms application lifecicle methods from MakeMethodStaticAnalyzer Closes #451 --- .../Design/MakeMethodStaticAnalyzer.cs | 12 ++++++++ .../Design/MakeMethodStaticTests.cs | 29 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs index d6ad156c9..138a3744c 100644 --- a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs @@ -77,11 +77,23 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) } if (IsTestMethod(method, methodSymbol)) return; + if (IsWebFormsMethod(methodSymbol)) return; var diagnostic = Diagnostic.Create(Rule, method.Identifier.GetLocation(), method.Identifier.ValueText); context.ReportDiagnostic(diagnostic); } + private static readonly string[] webFormsMethods = new string[] { + "Application_AuthenticateRequest", "Application_BeginRequest", + "Application_End", "Application_EndRequest", + "Application_Error", "Application_Start", + "Session_End", "Session_Start" }; + private static bool IsWebFormsMethod(IMethodSymbol methodSymbol) + { + if (!webFormsMethods.Contains(methodSymbol.Name)) return false; + return (methodSymbol.ContainingType.AllBaseTypes().Any(t => t.ToString() == "System.Web.HttpApplication")); + } + private static bool IsTestMethod(MethodDeclarationSyntax method, IMethodSymbol methodSymbol) { var result = false; diff --git a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs index 447160fa6..9b094771b 100644 --- a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs @@ -123,7 +123,7 @@ static void Foo() { } #endregion")] [InlineData(@" ///Method summary -void Foo() { }", +void Foo() { }", @" ///Method summary static void Foo() { }")] @@ -540,5 +540,32 @@ await VerifyCSharpHasNoDiagnosticsAsync(new string[] { nunitWithoutTestFixtureWithTestCaseSourceAttributeAndOtherNonAttributedMethodsSource }); } + + [Theory] + [InlineData(@"void Application_AuthenticateRequest() { }")] + [InlineData(@"void Application_BeginRequest() { }")] + [InlineData(@"void Application_End() { }")] + [InlineData(@"void Application_EndRequest() { }")] + [InlineData(@"void Application_Error() { }")] + [InlineData(@"void Application_Start(object sender, EventArgs e) { }")] + [InlineData(@"void Session_End() { }")] + [InlineData(@"void Session_Start() { }")] + public async Task IgnoreKnownWebFormsMethods(string code) + { + var source = $@" + using System; + namespace System.Web + {{ + public class HttpApplication {{ }} + }} + namespace MyWebApp1 + {{ + public class Global : System.Web.HttpApplication + {{ + {code} + }} + }}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From 0d4320ff0e1345a7868e4c28af21fc54f4fa9ef8 Mon Sep 17 00:00:00 2001 From: carloscds Date: Thu, 12 Nov 2015 22:46:12 -0200 Subject: [PATCH 046/358] fix unused parameters --- .../Usage/UnusedParametersCodeFixProvider.cs | 1 + .../Usage/UnusedParametersTests.cs | 97 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs index 91199debf..9b8baddd2 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixProvider.cs @@ -46,6 +46,7 @@ public async static Task> RemoveParameterAsync(Document var solution = document.Project.Solution; var parameterList = (ParameterListSyntax)parameter.Parent; var parameterPosition = parameterList.Parameters.IndexOf(parameter); + if (parameterList.Parameters.First().ToString().Contains("this")) parameterPosition--; var newParameterList = parameterList.WithParameters(parameterList.Parameters.Remove(parameter)); var foundDocument = false; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index a968e566d..25c3ea625 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -666,5 +666,102 @@ bool TryParse(string input, out int output, out int out2) await VerifyCSharpDiagnosticAsync(source, CreateDiagnosticResult("out2", 4, 49)); } + [Fact] + public async Task CallWithUnusedParameterExtensionMethodNoDiagnostic() + { + const string source = @" +static class C +{ + private static void Bar() + { + """".Foo(); + } + private static void Foo(this string s) + { + s += """"; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task CallWithUnusedParameterExtensionMethodCreateDiagnostic() + { + const string source = @" +static class C +{ + private static void Bar() + { + """".Foo(1); + } + private static void Foo(this string s, int i) + { + s += """"; + } +}"; + await VerifyCSharpDiagnosticAsync(source,CreateDiagnosticResult("i", 8, 44)); + } + + [Fact] + public async Task CallWithUnusedParameterExtensionMethodFix() + { + const string source = @" +static class C +{ + private static void Bar() + { + """".Foo(1); + } + private static void Foo(this string s, int i) + { + s += """"; + } +}"; + + const string fixtest = @" +static class C +{ + private static void Bar() + { + """".Foo(); + } + private static void Foo(this string s) + { + s += """"; + } +}"; + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task CallWithUnusedTwoParameterExtensionMethodFix() + { + const string source = @" +static class C +{ + private static void Bar() + { + """".Foo(1,""a""); + } + private static void Foo(this string s, int i, string j) + { + s += i.ToString(); + } +}"; + + const string fixtest = @" +static class C +{ + private static void Bar() + { + """".Foo(1); + } + private static void Foo(this string s, int i) + { + s += i.ToString(); + } +}"; + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From cb73ffe107942d7f159ef1e0949228f61bfd69c1 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Tue, 17 Nov 2015 10:54:50 -0200 Subject: [PATCH 047/358] Using and accepting 'System.GC.SuppressFinalize' (fix #590) --- ...ablesShouldCallSuppressFinalizeAnalyzer.cs | 12 +++++-- ...ouldCallSuppressFinalizeCodeFixProvider.cs | 34 ++++++++++++++++--- ...posablesShouldCallSuppressFinalizeTests.cs | 22 +++++++++++- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs index d0311aa1c..4c1c50e20 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs @@ -49,9 +49,15 @@ private static void Analyze(SymbolAnalysisContext context) { var invocation = statement.Expression as InvocationExpressionSyntax; var method = invocation?.Expression as MemberAccessExpressionSyntax; - var identifierSyntax = method?.Expression as IdentifierNameSyntax; - if (identifierSyntax != null && identifierSyntax.Identifier.ToString() == "GC" && method.Name.ToString() == "SuppressFinalize") - return; + if (method?.Name.ToString() == "SuppressFinalize") + { + var identifierSyntax = method?.Expression as IdentifierNameSyntax; + if (identifierSyntax?.Identifier.ToString() == "GC") + return; + var simpleMemberAccess = method?.Expression as MemberAccessExpressionSyntax; + if (simpleMemberAccess?.ToString() == "System.GC") + return; + } } } context.ReportDiagnostic(Diagnostic.Create(Rule, disposeMethod.Locations[0], symbol.Name)); diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs index e1c0fabab..a2058987f 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs @@ -28,10 +28,26 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) return Task.FromResult(0); } - private async static Task AddSuppressFinalizeAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + private async static Task AddSuppressFinalizeAsync( + Document document, + Diagnostic diagnostic, + CancellationToken cancellationToken + ) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var method = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + + var startLocation = diagnostic.Location.SourceSpan.Start; + var token = root.FindToken(startLocation); + var method = token.Parent.AncestorsAndSelf().OfType().First(); + + var gc = IsThereUsingSystem(root) + ? (ExpressionSyntax) SyntaxFactory.IdentifierName("GC") + : SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("System"), + SyntaxFactory.IdentifierName("GC") + ); + return document .WithSyntaxRoot(root .ReplaceNode(method, method.AddBodyStatements( @@ -39,10 +55,20 @@ private async static Task AddSuppressFinalizeAsync(Document document, SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, - SyntaxFactory.IdentifierName("GC"), + gc, SyntaxFactory.IdentifierName("SuppressFinalize")), - SyntaxFactory.ArgumentList().AddArguments(SyntaxFactory.Argument(SyntaxFactory.ThisExpression()))))) + SyntaxFactory.ArgumentList().AddArguments( + SyntaxFactory.Argument(SyntaxFactory.ThisExpression()))))) .WithAdditionalAnnotations(Formatter.Annotation))); } + + + public static bool IsThereUsingSystem(SyntaxNode root) + { + return root + .DescendantNodesAndSelf() + .OfType() + .Any(u => u.Name.ToString() == "System"); + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs index 47b3f043e..3238408a6 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs @@ -331,7 +331,7 @@ protected virtual void Dispose(bool disposing) await VerifyCSharpFixAsync(source, fixtest, 0); } - [Fact(Skip = "ToDo")] + [Fact()] public async void AddsSystemGCWhenSystemIsNotImported() { const string source = @" @@ -362,5 +362,25 @@ protected virtual void Dispose(bool disposing) }"; await VerifyCSharpFixAsync(source, fixtest, 0); } + + [Fact()] + public async void CallingSystemGCSupressFinalizeShouldNotGenerateDiags() + { + const string source = @" + public class MyType : System.IDisposable + { + void IDisposable.Dispose() + { + Dispose(true); + System.GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) + { + + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From 376d539f48065b20ba273ac030431f5537a9d692 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 17 Nov 2015 14:04:09 -0200 Subject: [PATCH 048/358] Work with only one argument on StringFormatArgsAnalyzer --- .../Usage/StringFormatArgsAnalyzer.cs | 16 +++++++++------- .../Usage/StringFormatArgsTests.cs | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs index db329b332..397a4961d 100644 --- a/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/StringFormatArgsAnalyzer.cs @@ -49,16 +49,18 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (memberExpresion?.Name?.ToString() != "Format") return; var memberSymbol = context.SemanticModel.GetSymbolInfo(memberExpresion).Symbol; if (memberSymbol == null) return; - if (!memberSymbol.ToString().StartsWith("string.Format(string, ")) return; + var memberSignature = memberSymbol.ToString(); + if (!memberSignature.StartsWith("string.Format(string, ")) return; var argumentList = invocationExpression.ArgumentList as ArgumentListSyntax; - if (argumentList?.Arguments.Count < 2) return; - if (!argumentList.Arguments[0]?.Expression?.IsKind(SyntaxKind.StringLiteralExpression) ?? false) return; - if (memberSymbol.ToString() == "string.Format(string, params object[])" && argumentList.Arguments.Skip(1).Any(a => context.SemanticModel.GetTypeInfo(a.Expression).Type.TypeKind == TypeKind.Array)) return; - var formatLiteral = (LiteralExpressionSyntax)argumentList.Arguments[0].Expression; + if (argumentList == null) return; + var arguments = argumentList.Arguments; + if (!arguments[0]?.Expression?.IsKind(SyntaxKind.StringLiteralExpression) ?? false) return; + if (memberSignature == "string.Format(string, params object[])" && arguments.Count == 2 && context.SemanticModel.GetTypeInfo(arguments[1].Expression).Type.TypeKind == TypeKind.Array) return; + var formatLiteral = (LiteralExpressionSyntax)arguments[0].Expression; var analyzingInterpolation = (InterpolatedStringExpressionSyntax)SyntaxFactory.ParseExpression($"${formatLiteral.Token.Text}"); var allInterpolations = analyzingInterpolation.Contents.Where(c => c.IsKind(SyntaxKind.Interpolation)).Select(c => (InterpolationSyntax)c); var distinctInterpolations = allInterpolations.Select(c => c.Expression.ToString()).Distinct(); - if (distinctInterpolations.Count() < argumentList.Arguments.Count - 1) + if (distinctInterpolations.Count() < arguments.Count - 1) { var diag = Diagnostic.Create(ExtraArgs, invocationExpression.GetLocation()); context.ReportDiagnostic(diag); @@ -70,7 +72,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) int argIndexReference; if (int.TryParse(interpolation, out argIndexReference)) { - validIndexReference = argIndexReference >= 0 && argIndexReference < argumentList.Arguments.Count - 1; + validIndexReference = argIndexReference >= 0 && argIndexReference < arguments.Count - 1; } if (!validIndexReference) { diff --git a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs index 8b0be55f3..5b6cf0257 100644 --- a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs @@ -78,6 +78,20 @@ public async Task IgnoresMethodsCalledWithIncorrectParameterTypes() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task NoParametersCreatesError() + { + var source = @"var result = string.Format(""{0}"");".WrapInCSharpMethod(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), + Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, + Severity = DiagnosticSeverity.Error, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + [Fact] public async Task LessParametersCreatesError() { From 566b989458e1a53b2ec5ef7f674be29bcc7f15e7 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Tue, 17 Nov 2015 15:38:28 -0200 Subject: [PATCH 049/358] Performing semantic analysis to determine if 'System.GC.SuppressFinalize' was used --- ...ablesShouldCallSuppressFinalizeAnalyzer.cs | 66 ++++++++++--------- ...posablesShouldCallSuppressFinalizeTests.cs | 29 +++++++- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs index 4c1c50e20..4ab5b1e3a 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs @@ -1,8 +1,10 @@ -using Microsoft.CodeAnalysis; +using System; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.CSharp; namespace CodeCracker.CSharp.Usage { @@ -28,50 +30,52 @@ public class DisposablesShouldCallSuppressFinalizeAnalyzer : DiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); public override void Initialize(AnalysisContext context) => - context.RegisterSymbolAction(Analyze, SymbolKind.NamedType); + context.RegisterSyntaxNodeAction(LanguageVersion.CSharp6, Analyze, SyntaxKind.MethodDeclaration); - private static void Analyze(SymbolAnalysisContext context) + private static void Analyze(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; - var symbol = (INamedTypeSymbol)context.Symbol; + + var semanticModel = context.SemanticModel; + var method = (MethodDeclarationSyntax)context.Node; + + var methodSymbol = semanticModel.GetDeclaredSymbol(method); + var isImplicitDispose = methodSymbol.ToString().Contains($"{methodSymbol.ContainingType.Name}.Dispose("); + var isExplicitDispose = + methodSymbol.ExplicitInterfaceImplementations.Any(i => i.ToString() == "System.IDisposable.Dispose()"); + + if (!isImplicitDispose && !isExplicitDispose) + return; + + if (methodSymbol.Parameters != null && methodSymbol.Parameters.Length > 0) + return; + + var symbol = methodSymbol.ContainingType; if (symbol.TypeKind != TypeKind.Class) return; if (!symbol.Interfaces.Any(i => i.SpecialType == SpecialType.System_IDisposable)) return; if (symbol.IsSealed && !ContainsUserDefinedFinalizer(symbol)) return; if (!ContainsNonPrivateConstructors(symbol)) return; - var disposeMethod = FindDisposeMethod(symbol); - if (disposeMethod == null) return; - var syntaxTree = disposeMethod.DeclaringSyntaxReferences[0]?.GetSyntax(); - var statements = ((MethodDeclarationSyntax)syntaxTree)?.Body?.Statements.OfType(); + var statements = method.Body?.Statements.OfType(); if (statements != null) { foreach (var statement in statements) { var invocation = statement.Expression as InvocationExpressionSyntax; - var method = invocation?.Expression as MemberAccessExpressionSyntax; - if (method?.Name.ToString() == "SuppressFinalize") - { - var identifierSyntax = method?.Expression as IdentifierNameSyntax; - if (identifierSyntax?.Identifier.ToString() == "GC") - return; - var simpleMemberAccess = method?.Expression as MemberAccessExpressionSyntax; - if (simpleMemberAccess?.ToString() == "System.GC") - return; - } + var suppress = invocation?.Expression as MemberAccessExpressionSyntax; + + if (suppress?.Name.ToString() != "SuppressFinalize") + continue; + + var containingType = semanticModel.GetSymbolInfo(suppress.Expression).Symbol as INamedTypeSymbol; + if (containingType?.ContainingNamespace.Name != "System") + continue; + + if (containingType.Name == "GC") + return; } } - context.ReportDiagnostic(Diagnostic.Create(Rule, disposeMethod.Locations[0], symbol.Name)); - } - - private static ISymbol FindDisposeMethod(INamedTypeSymbol symbol) - { - var disposeSymbol = symbol.GetMembers().Where(x => - x.Kind == SymbolKind.Method - && (x.ToString().Contains($"{x.ContainingType.Name }.Dispose(") - || (((IMethodSymbol)x).ExplicitInterfaceImplementations.Any(i => i.ToString() == "System.IDisposable.Dispose()")))) - .Cast() - .FirstOrDefault(m => m.Parameters == null || m.Parameters.Length == 0); - return disposeSymbol; + context.ReportDiagnostic(Diagnostic.Create(Rule, methodSymbol.Locations[0], symbol.Name)); } public static bool ContainsUserDefinedFinalizer(INamedTypeSymbol symbol) @@ -89,7 +93,7 @@ public static bool ContainsNonPrivateConstructors(INamedTypeSymbol symbol) .Any(m => m.MetadataName == ".ctor" && m.DeclaredAccessibility != Accessibility.Private); } - private static bool IsNestedPrivateType(INamedTypeSymbol symbol) + private static bool IsNestedPrivateType(ISymbol symbol) { if (symbol == null) return false; diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs index 3238408a6..04c9e421d 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs @@ -16,7 +16,7 @@ public class MyType : System.IDisposable { public void Dispose() { - GC.SuppressFinalize(this); + System.GC.SuppressFinalize(this); } }"; await VerifyCSharpHasNoDiagnosticsAsync(source); @@ -62,6 +62,7 @@ public void Dispose() public async Task NoWarningIfClassImplementsDisposableCallsSuppressFinalizeAndCallsDisposeWithThis() { const string source = @" + using System; public class MyType : System.IDisposable { public void Dispose() @@ -78,6 +79,7 @@ public void Dispose() public async Task NoWarningIfClassImplementsDisposableCallsSuppressFinalize() { const string source = @" + using System; public class MyType : System.IDisposable { public void Dispose() @@ -331,7 +333,7 @@ protected virtual void Dispose(bool disposing) await VerifyCSharpFixAsync(source, fixtest, 0); } - [Fact()] + [Fact] public async void AddsSystemGCWhenSystemIsNotImported() { const string source = @" @@ -363,7 +365,7 @@ protected virtual void Dispose(bool disposing) await VerifyCSharpFixAsync(source, fixtest, 0); } - [Fact()] + [Fact] public async void CallingSystemGCSupressFinalizeShouldNotGenerateDiags() { const string source = @" @@ -382,5 +384,26 @@ protected virtual void Dispose(bool disposing) await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async void CallingGCSupressFinalizeWithAliasShouldNotGenerateDiags() + { + const string source = @"using A = System; + public class MyType : System.IDisposable + { + void IDisposable.Dispose() + { + Dispose(true); + A.GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) + { + + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + } } \ No newline at end of file From 166e85f88cf5efc5b4d89daa1dcefeb21845f5b7 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Tue, 17 Nov 2015 16:01:18 -0200 Subject: [PATCH 050/358] Using System.GC whenever System is not imported in the context --- ...ouldCallSuppressFinalizeCodeFixProvider.cs | 57 ++++++++++--------- ...posablesShouldCallSuppressFinalizeTests.cs | 38 +++++++++++++ 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs index a2058987f..78c3bc080 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Simplification; namespace CodeCracker.CSharp.Usage { @@ -40,35 +41,39 @@ CancellationToken cancellationToken var token = root.FindToken(startLocation); var method = token.Parent.AncestorsAndSelf().OfType().First(); - var gc = IsThereUsingSystem(root) - ? (ExpressionSyntax) SyntaxFactory.IdentifierName("GC") - : SyntaxFactory.MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - SyntaxFactory.IdentifierName("System"), - SyntaxFactory.IdentifierName("GC") - ); + var systemGc = SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("System"), + SyntaxFactory.IdentifierName("GC") + ); - return document - .WithSyntaxRoot(root - .ReplaceNode(method, method.AddBodyStatements( - SyntaxFactory.ExpressionStatement( - SyntaxFactory.InvocationExpression( - SyntaxFactory.MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - gc, - SyntaxFactory.IdentifierName("SuppressFinalize")), - SyntaxFactory.ArgumentList().AddArguments( - SyntaxFactory.Argument(SyntaxFactory.ThisExpression()))))) - .WithAdditionalAnnotations(Formatter.Annotation))); - } + var suppressFinalize = SyntaxFactory.IdentifierName("SuppressFinalize"); + var arguments = SyntaxFactory.ArgumentList() + .AddArguments(SyntaxFactory.Argument(SyntaxFactory.ThisExpression())); + + var suppressFinalizeCall = + SyntaxFactory.ExpressionStatement( + SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + systemGc, + suppressFinalize + ), + arguments + )) + .WithAdditionalAnnotations(Simplifier.Annotation) + .WithAdditionalAnnotations(Formatter.Annotation); + + + var modifiedMethod = method.AddBodyStatements( + suppressFinalizeCall + ); + + + return document + .WithSyntaxRoot(root.ReplaceNode(method, modifiedMethod)); - public static bool IsThereUsingSystem(SyntaxNode root) - { - return root - .DescendantNodesAndSelf() - .OfType() - .Any(u => u.Name.ToString() == "System"); } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs index 04c9e421d..c0b7a0b13 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs @@ -405,5 +405,43 @@ protected virtual void Dispose(bool disposing) await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async void UseSystemGCWhenSystemNamespaceWasNotImportedInCurrentContext() + { + const string source = @" + namespace A + { + using System; + } + namespace B + { + class Foo : System.IDisposable + { + public void Dispose() + { + } + } + }"; + + const string fixtest = @" + namespace A + { + using System; + } + namespace B + { + class Foo : System.IDisposable + { + public void Dispose() + { + System.GC.SuppressFinalize(this); + } + } + }"; + + + await VerifyCSharpFixAsync(source, fixtest, 0); + } + } } \ No newline at end of file From 12207de5103f88bed05c40c127a849dc32a988d9 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Tue, 17 Nov 2015 22:29:15 -0500 Subject: [PATCH 051/358] Remove show warnings as errors --- src/CSharp/CodeCracker/CodeCracker.csproj | 2 +- src/Common/CodeCracker.Common/CodeCracker.Common.csproj | 2 +- src/VisualBasic/CodeCracker/CodeCracker.vbproj | 4 ++-- test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj | 2 +- .../CodeCracker.Test.Common/CodeCracker.Test.Common.csproj | 2 +- test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 26fb91930..3b8c67acb 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -23,7 +23,7 @@ prompt 4 ..\..\..\codecrackerandall.ruleset - true + false pdbonly diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index df0772fc8..01ea25c96 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -24,7 +24,7 @@ DEBUG;TRACE prompt 4 - true + false pdbonly diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 9f34be72b..899ec2952 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -26,7 +26,7 @@ 40057 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 ..\..\..\codecrackerandall.ruleset - true + false pdbonly @@ -39,7 +39,7 @@ CodeCracker.VisualBasic.xml 40057 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 - true + false On diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index b4c650860..ae9300a91 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -29,7 +29,7 @@ 4 false ..\..\..\codecrackerandall.test.ruleset - true + false pdbonly diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 748cc5da6..66ee698e9 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -25,7 +25,7 @@ DEBUG;TRACE prompt 4 - true + false pdbonly diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index da9ac7b1f..cedf4a8da 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -27,7 +27,7 @@ CodeCracker.Test.VisualBasic.xml - true + false 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 @@ -39,7 +39,7 @@ CodeCracker.Test.VisualBasic.xml - true + false 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 From daeff359f5aa7ef4e43f91da766c4d8aee536220 Mon Sep 17 00:00:00 2001 From: ReadmeCritic Date: Tue, 17 Nov 2015 20:38:27 -0800 Subject: [PATCH 052/358] Update README URLs based on HTTP redirects --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 35d68f63b..c771fb052 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # Code Cracker -An analyzer library for C# and VB that uses [Roslyn](http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx) to produce refactorings, code analysis, and other niceties. +An analyzer library for C# and VB that uses [Roslyn](https://github.com/dotnet/roslyn) to produce refactorings, code analysis, and other niceties. Check the official project site on [code-cracker.github.io](http://code-cracker.github.io). There you will find information on how to contribute, our task board, definition of done, definition of ready, etc. [![Build status](https://ci.appveyor.com/api/projects/status/h21sli3jkumuswyi?svg=true)](https://ci.appveyor.com/project/code-cracker/code-cracker) -[![Nuget count](http://img.shields.io/nuget/v/codecracker.svg)](https://www.nuget.org/packages/codecracker/) -[![Nuget downloads](http://img.shields.io/nuget/dt/codecracker.svg)](https://www.nuget.org/packages/codecracker/) -[![Issues open](http://img.shields.io/github/issues-raw/code-cracker/code-cracker.svg)](https://huboard.com/code-cracker/code-cracker/) +[![Nuget count](https://img.shields.io/nuget/v/codecracker.svg)](https://www.nuget.org/packages/codecracker/) +[![Nuget downloads](https://img.shields.io/nuget/dt/codecracker.svg)](https://www.nuget.org/packages/codecracker/) +[![Issues open](https://img.shields.io/github/issues-raw/code-cracker/code-cracker.svg)](https://huboard.com/code-cracker/code-cracker/) [![Coverage Status](https://img.shields.io/coveralls/code-cracker/code-cracker/master.svg)](https://coveralls.io/r/code-cracker/code-cracker?branch=master) [![Source Browser](https://img.shields.io/badge/Browse-Source-green.svg)](http://ccref.azurewebsites.net) @@ -177,7 +177,7 @@ unless they are meaningful. For most analyzers and code fixes a single commit sh prefer to work with a lot commits at the end squash them. Make your first commit lines mean something, specially the first one. -[Here](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message) and +[Here](https://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message) and [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) are some tips on a good commit first line/message. @@ -245,9 +245,9 @@ Small code changes or updates outside code files will eventually be made by the ## Maintainers/Core team -* [Giovanni Bassi](http://blog.lambda3.com.br/L3/giovannibassi/), aka Giggio, [Lambda3](http://www.lambda3.com.br), [@giovannibassi](http://twitter.com/giovannibassi) -* [Elemar Jr.](http://elemarjr.net/), [Promob](http://promob.com/), [@elemarjr](http://twitter.com/elemarjr) -* [Carlos dos Santos](http://carloscds.net/), [CDS Informática](http://www.cds-software.com.br/), [@cdssoftware](http://twitter.com/cdssoftware) +* [Giovanni Bassi](http://blog.lambda3.com.br/L3/giovannibassi/), aka Giggio, [Lambda3](http://www.lambda3.com.br), [@giovannibassi](https://twitter.com/giovannibassi) +* [Elemar Jr.](http://elemarjr.net/), [Promob](http://promob.com/), [@elemarjr](https://twitter.com/elemarjr) +* [Carlos dos Santos](http://carloscds.net/), [CDS Informática](http://www.cds-software.com.br/), [@cdssoftware](https://twitter.com/cdssoftware) Contributors can be found at the [contributors](https://github.com/code-cracker/code-cracker/graphs/contributors) page on Github. From e0ec4c60684cebceed596cc2c823d59eaeb9eab2 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 18 Nov 2015 17:37:19 -0200 Subject: [PATCH 053/358] Fix warnings as per CC recommendations --- .../Style/AlwaysUseVarCodeFixProvider.cs | 4 ++-- .../Style/TernaryOperatorCodeFixProvider.cs | 14 ++++++-------- ...lesShouldCallSuppressFinalizeCodeFixProvider.cs | 6 +++--- .../Style/SwitchToAutoPropTests.cs | 4 ++-- .../Usage/IPAddressAnalyzerTests.cs | 4 ++-- .../Verifiers/CodeFixVerifier.cs | 14 ++++++-------- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs index b44987caa..1df4bd4b0 100644 --- a/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs @@ -31,7 +31,7 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) private async static Task UseVarAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - + var diagnosticSpan = diagnostic.Location.SourceSpan; var localDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); var variableDeclaration = localDeclaration.Declaration; @@ -46,7 +46,7 @@ private async static Task UseVarAsync(Document document, Diagnostic di { var originalVariable = variableDeclaration.Variables[i]; var newLeadingTrivia = originalVariable.GetLeadingTrivia(); - + //Get the trivia from the separator as well if (i != 0) { diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 0bc6bd886..cae303ff2 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -114,10 +114,9 @@ private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionS if (ifConvertedType?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { var constValue = semanticModel.GetConstantValue(ifExpression); - if (constValue.HasValue && constValue.Value == null) - trueExpression = SyntaxFactory.CastExpression(typeSyntax, ifExpression); - else - trueExpression = ifExpression; + trueExpression = constValue.HasValue && constValue.Value == null + ? SyntaxFactory.CastExpression(typeSyntax, ifExpression) + : ifExpression; isNullable = true; } else @@ -127,10 +126,9 @@ private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionS if (elseConvertedType?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { var constValue = semanticModel.GetConstantValue(elseExpression); - if (constValue.HasValue && constValue.Value == null) - falseExpression = SyntaxFactory.CastExpression(typeSyntax, elseExpression); - else - falseExpression = elseExpression; + falseExpression = constValue.HasValue && constValue.Value == null + ? SyntaxFactory.CastExpression(typeSyntax, elseExpression) + : elseExpression; isNullable = true; } else diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs index 78c3bc080..74b735cd1 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.cs @@ -30,8 +30,8 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) } private async static Task AddSuppressFinalizeAsync( - Document document, - Diagnostic diagnostic, + Document document, + Diagnostic diagnostic, CancellationToken cancellationToken ) { @@ -64,7 +64,7 @@ CancellationToken cancellationToken )) .WithAdditionalAnnotations(Simplifier.Annotation) .WithAdditionalAnnotations(Formatter.Annotation); - + var modifiedMethod = method.AddBodyStatements( suppressFinalizeCall diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index 346432605..39ab004ea 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -496,7 +496,7 @@ public void Foo() [Fact] public async Task FixPropIntoAutoPropAndFixKeepingXMLComments() { - var source = @" + const string source = @" public class Foo { private int x = 10; @@ -510,7 +510,7 @@ public int X } }"; - var expected = @" + const string expected = @" public class Foo { /// diff --git a/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs index c0ee1d28a..ccf94d7e4 100644 --- a/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs @@ -62,14 +62,14 @@ public async Task IfIsOtherTypeParseMethodDoesNotCreateDiagnostic() } [Fact] - public async Task IfParseIdentifierFoundAndParameterIsNotStringLiteralDoesNotCreatesDiagnostic() + public async Task IfParseIdentifierFoundAndParameterIsNotStringLiteralDoesNotCreatesDiagnostic() { var test = string.Format(TestCode, @"var ip = ""; ""System.Net.IPAddress.Parse(ip)"); await VerifyCSharpHasNoDiagnosticsAsync(test); } [Fact] - public async Task IfAbbreviateParseIdentifierFoundAndParameterIsNotStringLiteralDoesNotCreatesDiagnostic() + public async Task IfAbbreviateParseIdentifierFoundAndParameterIsNotStringLiteralDoesNotCreatesDiagnostic() { var test = string.Format(TestCode, @"var ip = ""; ""IPAddress.Parse(ip)"); await VerifyCSharpHasNoDiagnosticsAsync(test); diff --git a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs index 2dd81aa14..92a423897 100644 --- a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs +++ b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs @@ -111,10 +111,9 @@ private async static Task VerifyFixAsync(string language, DiagnosticAnalyzer ana if (!actions.Any()) break; - if (codeFixIndex != null) - document = await ApplyFixAsync(document, actions.ElementAt((int)codeFixIndex)).ConfigureAwait(true); - else - document = await ApplyFixAsync(document, actions.ElementAt(0)).ConfigureAwait(true); + document = codeFixIndex != null + ? await ApplyFixAsync(document, actions.ElementAt((int)codeFixIndex)).ConfigureAwait(true) + : await ApplyFixAsync(document, actions.ElementAt(0)).ConfigureAwait(true); analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzer, new[] { document }).ConfigureAwait(true); @@ -154,10 +153,9 @@ private async static Task VerifyFixAsync(string language, ImmutableArray if (!actions.Any()) break; - if (codeFixIndex != null) - document = await ApplyFixAsync(document, actions.ElementAt((int)codeFixIndex)).ConfigureAwait(true); - else - document = await ApplyFixAsync(document, actions.ElementAt(0)).ConfigureAwait(true); + document = codeFixIndex != null + ? await ApplyFixAsync(document, actions.ElementAt((int)codeFixIndex)).ConfigureAwait(true) + : await ApplyFixAsync(document, actions.ElementAt(0)).ConfigureAwait(true); var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true)); compilerDiagnostics = (await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true)).ToList(); From acdf44a9549aa6bd48c22930c8484f78f6e16100 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 18 Nov 2015 20:50:14 -0200 Subject: [PATCH 054/358] Update CC to rc4-0937 --- src/CSharp/CodeCracker/CodeCracker.csproj | 4 ++-- src/CSharp/CodeCracker/packages.config | 2 +- src/Common/CodeCracker.Common/CodeCracker.Common.csproj | 4 ++-- src/Common/CodeCracker.Common/packages.config | 2 +- src/VisualBasic/CodeCracker/CodeCracker.vbproj | 4 ++-- src/VisualBasic/CodeCracker/packages.config | 2 +- test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj | 4 ++-- test/CSharp/CodeCracker.Test/packages.config | 2 +- .../CodeCracker.Test.Common/CodeCracker.Test.Common.csproj | 4 ++-- test/Common/CodeCracker.Test.Common/packages.config | 2 +- test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj | 4 ++-- test/VisualBasic/CodeCracker.Test/packages.config | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 26fb91930..7ed341fb5 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -220,8 +220,8 @@ - - + + diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index 647ea2d01..b1d6589d7 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index caca05700..1f9da6ad1 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -69,8 +69,8 @@ - - + + diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index 8e389d917..4cac7a531 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 9f34be72b..5f6a6cb48 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -159,8 +159,8 @@ - - + + diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index d9c4e3f3c..79646a42c 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index b4c650860..9125e159a 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -233,8 +233,8 @@ - - + + diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index b087a68cb..48057ebe2 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 748cc5da6..328c8050f 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -141,8 +141,8 @@ - - + + diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index cc4f16c52..de79a4784 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index da9ac7b1f..8d5067bf7 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -226,8 +226,8 @@ - - + + diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config index e50654a79..a3482fea0 100644 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ b/test/VisualBasic/CodeCracker.Test/packages.config @@ -1,6 +1,6 @@  - + From 178c4b30f3b9af70b52cf93da28bb39cc506822a Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Wed, 18 Nov 2015 18:02:45 -0500 Subject: [PATCH 055/358] Resetting treat warnings as errors --- src/CSharp/CodeCracker/CodeCracker.csproj | 2 +- src/Common/CodeCracker.Common/CodeCracker.Common.csproj | 2 +- src/VisualBasic/CodeCracker/CodeCracker.vbproj | 4 ++-- test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj | 2 +- .../CodeCracker.Test.Common/CodeCracker.Test.Common.csproj | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 3b8c67acb..26fb91930 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -23,7 +23,7 @@ prompt 4 ..\..\..\codecrackerandall.ruleset - false + true pdbonly diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 8d1845e7a..caca05700 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -24,7 +24,7 @@ DEBUG;TRACE prompt 4 - false + true pdbonly diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 899ec2952..9f34be72b 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -26,7 +26,7 @@ 40057 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 ..\..\..\codecrackerandall.ruleset - false + true pdbonly @@ -39,7 +39,7 @@ CodeCracker.VisualBasic.xml 40057 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 - false + true On diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index ae9300a91..b4c650860 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -29,7 +29,7 @@ 4 false ..\..\..\codecrackerandall.test.ruleset - false + true pdbonly diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 66ee698e9..748cc5da6 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -25,7 +25,7 @@ DEBUG;TRACE prompt 4 - false + true pdbonly From c4fe57b8970c4778864cc2a3d442c7f1d70bd5c0 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Wed, 18 Nov 2015 18:32:14 -0500 Subject: [PATCH 056/358] Fix treat warnings as errors on vb test project to reset it to on. --- test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index cedf4a8da..da9ac7b1f 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -27,7 +27,7 @@ CodeCracker.Test.VisualBasic.xml - false + true 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 @@ -39,7 +39,7 @@ CodeCracker.Test.VisualBasic.xml - false + true 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 From 9b191b534948b2040257c4d661fcfe8d9f4a3391 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Thu, 19 Nov 2015 09:58:53 -0200 Subject: [PATCH 057/358] Fix should get the right expression to process (fixes #597) --- ...undantBooleanComparisonsCodeFixProvider.cs | 32 +++++++++++++------ ...implifyRedundantBooleanComparisonsTests.cs | 26 +++++++++++++++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs index 68a402570..a840d90a3 100644 --- a/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs @@ -1,14 +1,14 @@ -using Microsoft.CodeAnalysis; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +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.Immutable; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace CodeCracker.CSharp.Usage { @@ -31,7 +31,11 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) private static async Task RemoveRedundantComparisonAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var comparison = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var comparison = root.FindToken(diagnostic.Location.SourceSpan.Start) + .Parent.AncestorsAndSelf() + .OfType() + .First(bes => !bes.IsKind(SyntaxKind.IsExpression)); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); bool constValue; ExpressionSyntax replacer; @@ -49,9 +53,19 @@ private static async Task RemoveRedundantComparisonAsync(Document docu } - if ((!constValue && comparison.IsKind(SyntaxKind.EqualsExpression)) || (constValue && comparison.IsKind(SyntaxKind.NotEqualsExpression))) + if ((!constValue && comparison.IsKind(SyntaxKind.EqualsExpression)) || + (constValue && comparison.IsKind(SyntaxKind.NotEqualsExpression))) + { + if (comparison.Left is BinaryExpressionSyntax) + { + replacer = SyntaxFactory.ParenthesizedExpression(replacer); + } replacer = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, replacer); - replacer = replacer.WithAdditionalAnnotations(Formatter.Annotation); + } + + replacer = replacer + .WithAdditionalAnnotations(Formatter.Annotation); + var newRoot = root.ReplaceNode(comparison, replacer); var newDocument = document.WithSyntaxRoot(newRoot); diff --git a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs index 7b0f25909..3b57bea31 100644 --- a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs @@ -42,6 +42,7 @@ public async Task WhenComparingWithBoolAnalyzerCreatesDiagnostic(string sample, await VerifyCSharpDiagnosticAsync(test, expected); } + [Theory] [InlineData("if (foo == 0) {}")] @@ -102,5 +103,30 @@ public async Task FixRemovesRedundantComparisons(string original, string result) await VerifyCSharpFixAsync(test, fixtest); } + + [Fact] + public async Task FixWithoutThrowingAnyException() + { + var test = @" +struct ProjectCompilation {} +class Foo +{ + public void Comp(bool obj) + { + if (obj is ProjectCompilation == false) return false; + } +}"; + + var fixtest = @" +struct ProjectCompilation {} +class Foo +{ + public void Comp(bool obj) + { + if (!(obj is ProjectCompilation)) return false; + } +}"; + await VerifyCSharpFixAsync(test, fixtest); + } } } \ No newline at end of file From dbb0c6dfd9c796989e8a3385c0f5c93dbeba929d Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Thu, 19 Nov 2015 10:22:58 -0200 Subject: [PATCH 058/358] Ooops! fixing the test method returning type --- .../Usage/SimplifyRedundantBooleanComparisonsTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs index 3b57bea31..0a0351a59 100644 --- a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs @@ -111,7 +111,7 @@ public async Task FixWithoutThrowingAnyException() struct ProjectCompilation {} class Foo { - public void Comp(bool obj) + public bool Comp(bool obj) { if (obj is ProjectCompilation == false) return false; } @@ -121,7 +121,7 @@ public void Comp(bool obj) struct ProjectCompilation {} class Foo { - public void Comp(bool obj) + public bool Comp(bool obj) { if (!(obj is ProjectCompilation)) return false; } From 8cab8f6db7d95ef224b034f9893df056b27fa072 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Thu, 19 Nov 2015 11:19:43 -0200 Subject: [PATCH 059/358] Ooops! I did it again. Now every path returns a value --- .../Usage/SimplifyRedundantBooleanComparisonsTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs index 0a0351a59..ba6076219 100644 --- a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs @@ -114,6 +114,7 @@ class Foo public bool Comp(bool obj) { if (obj is ProjectCompilation == false) return false; + return true; } }"; @@ -124,6 +125,7 @@ class Foo public bool Comp(bool obj) { if (!(obj is ProjectCompilation)) return false; + return true; } }"; await VerifyCSharpFixAsync(test, fixtest); From 9ab75155fa546f14e2e643cd4392d26ba98cc92a Mon Sep 17 00:00:00 2001 From: mirhagk Date: Thu, 19 Nov 2015 17:14:28 -0500 Subject: [PATCH 060/358] Added failing test case to demonstrate bug #594 --- test/CSharp/CodeCracker.Test/Design/NameOfTests.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs b/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs index c6d3e5e4e..75169acf7 100644 --- a/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs @@ -417,12 +417,13 @@ public class @class : BaseTypeName public @class() : base(""SomeDelegate"") { } - void Foo3(string a) + void Foo3(string a, BaseTypeName d) { Dictionary dict = new Dictionary { { ""b"", ""readonlyField"" }, - { ""xyz"", ""ParticularEvent"" } + { ""xyz"", ""ParticularEvent"" }, + { ""c"", ""Foo3""}, }; } @@ -452,7 +453,8 @@ public int Property CreateNameofDiagnosticResult("readonlyField", 27, 49), CreateNameofDiagnosticResult("SomeDelegate", 29, 36), CreateNameofDiagnosticResult("readonlyField", 35, 28), - CreateNameofDiagnosticResult("ParticularEvent", 36, 30) + CreateNameofDiagnosticResult("ParticularEvent", 36, 30), + CreateNameofDiagnosticResult("Foo3", 37, 28) }; await VerifyCSharpDiagnosticAsync(source, expected); From cc0505c718993f628783164656f3f00f7e3758ba Mon Sep 17 00:00:00 2001 From: mirhagk Date: Thu, 19 Nov 2015 17:54:54 -0500 Subject: [PATCH 061/358] When grabbing the display parts use a special format display to exclude uneeded pieces --- src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs index 8f98c156e..9e94e2589 100644 --- a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs @@ -88,7 +88,7 @@ private static string GetProgramElementNameThatMatchStringLiteral(LiteralExpress return null; } - programElementName = symbol.ToDisplayParts().LastOrDefault(AnalyzerExtensions.IsName).ToString(); + programElementName = symbol.ToDisplayParts(NameOfSymbolDisplayForamt).LastOrDefault(AnalyzerExtensions.IsName).ToString(); } return programElementName; @@ -124,5 +124,7 @@ private static string GetParameterNameThatMatchStringLiteral(LiteralExpressionSy private static ParameterSyntax GetParameterWithIdentifierEqualToStringLiteral(LiteralExpressionSyntax stringLiteral, SeparatedSyntaxList parameters) => parameters.FirstOrDefault(m => string.Equals(m.Identifier.ValueText, stringLiteral.Token.ValueText, StringComparison.Ordinal)); + + private static SymbolDisplayFormat NameOfSymbolDisplayForamt = new SymbolDisplayFormat(memberOptions: SymbolDisplayMemberOptions.None, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers); } } \ No newline at end of file From 0f61cf6ae93886fa9d8c94b03db997a0b115b6f3 Mon Sep 17 00:00:00 2001 From: Jim Wooley Date: Thu, 19 Nov 2015 23:57:06 -0500 Subject: [PATCH 062/358] Update VB code fixes to reduce work done in register code fix method (issue #348) --- .../Design/CatchEmptyCodeFixProvider.vb | 14 +++++----- .../Design/EmptyCatchBlockCodeFixProvider.vb | 24 +++++++++------- .../Design/NameOfCodeFixProvider.vb | 19 +++++++------ ...aticConstructorExceptionCodeFixProvider.vb | 12 ++++---- ...ariableConstWhenPossibleCodeFixProvider.vb | 16 +++++------ .../RemoveWhereWhenItIsPossibleAnalyzer.vb | 4 +-- ...oveWhereWhenItIsPossibleCodeFixProvider.vb | 16 ++++++----- .../SealedAttributeCodeFixProvider.vb | 9 ++++-- .../StringBuilderInLoopAnalyzer.vb | 4 ++- .../StringBuilderInLoopCodeFixProvider.vb | 24 ++++++++-------- .../ParameterRefactoryCodeFixProvider.vb | 28 +++++++++---------- .../UseConfigureAwaitFalseCodeFixProvider.vb | 19 +++++++------ .../Style/InterfaceNameCodeFixProvider.vb | 16 ++++++----- .../Usage/ArgumentExceptionAnalyzer.vb | 10 ++++--- .../Usage/ArgumentExceptionCodeFixProvider.vb | 19 +++++++------ .../DisposableFieldNotDisposedAnalyzer.vb | 9 ++++-- ...sposableFieldNotDisposedCodeFixProvider.vb | 18 ++++++------ ...ouldCallSuppressFinalizeCodeFixProvider.vb | 14 ++++++---- ...otHavePublicConstructorsCodeFixProvider.vb | 17 +++++------ .../RemovePrivateMethodNeverUsedAnalyzer.vb | 3 +- ...vePrivateMethodNeverUsedCodeFixProvider.vb | 13 +++++---- 21 files changed, 169 insertions(+), 139 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Design/CatchEmptyCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/CatchEmptyCodeFixProvider.vb index 909a8adb9..ecbb7a6ca 100644 --- a/src/VisualBasic/CodeCracker/Design/CatchEmptyCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/CatchEmptyCodeFixProvider.vb @@ -18,15 +18,16 @@ Namespace Design Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diag = context.Diagnostics.First() - Dim diagSpan = diag.Location.SourceSpan - Dim declaration = root.FindToken(diagSpan.Start).Parent.AncestorsAndSelf.OfType(Of CatchBlockSyntax).First() - context.RegisterCodeFix(CodeAction.Create("Add an Exception class", Function(c) MakeCatchEmptyAsync(context.Document, declaration, c), NameOf(CatchEmptyCodeFixProvider)), diag) + context.RegisterCodeFix(CodeAction.Create("Add an Exception class", Function(c) MakeCatchEmptyAsync(context.Document, diag, c), NameOf(CatchEmptyCodeFixProvider)), diag) + Return Task.FromResult(0) End Function - Private Async Function MakeCatchEmptyAsync(document As Document, catchStatement As CatchBlockSyntax, cancellationtoken As CancellationToken) As Task(Of Document) + Private Async Function MakeCatchEmptyAsync(document As Document, diag As Diagnostic, cancellationtoken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationtoken).ConfigureAwait(False) + Dim diagSpan = diag.Location.SourceSpan + Dim catchStatement = root.FindToken(diagSpan.Start).Parent.AncestorsAndSelf.OfType(Of CatchBlockSyntax).First() Dim semanticModel = Await document.GetSemanticModelAsync(cancellationtoken) Dim newCatch = SyntaxFactory.CatchBlock( @@ -39,7 +40,6 @@ Namespace Design WithTrailingTrivia(catchStatement.GetTrailingTrivia). WithAdditionalAnnotations(Formatter.Annotation) - Dim root = Await document.GetSyntaxRootAsync() Dim newRoot = root.ReplaceNode(catchStatement, newCatch) Dim newDoc = document.WithSyntaxRoot(newRoot) Return newDoc diff --git a/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb index 150d6bd0c..674922f04 100644 --- a/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/EmptyCatchBlockCodeFixProvider.vb @@ -18,19 +18,20 @@ Namespace Design Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diag = context.Diagnostics.First - Dim diagSpan = diag.Location.SourceSpan - Dim declaration = root.FindToken(diagSpan.Start).Parent.AncestorsAndSelf.OfType(Of CatchBlockSyntax).First - context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", Function(c) RemoveTry(context.Document, declaration, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(RemoveTry)), diag) - context.RegisterCodeFix(CodeAction.Create("Insert Exception class to Catch", Function(c) InsertExceptionClassCommentAsync(context.Document, declaration, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(InsertExceptionClassCommentAsync)), diag) + context.RegisterCodeFix(CodeAction.Create("Remove Empty Catch Block", Function(c) RemoveTry(context.Document, diag, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(RemoveTry)), diag) + context.RegisterCodeFix(CodeAction.Create("Insert Exception class to Catch", Function(c) InsertExceptionClassCommentAsync(context.Document, diag, c), NameOf(EmptyCatchBlockCodeFixProvider) & NameOf(InsertExceptionClassCommentAsync)), diag) + Return Task.FromResult(0) End Function - Private Async Function RemoveTry(document As Document, catchBlock As CatchBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function RemoveTry(document As Document, diag As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim diagSpan = diag.Location.SourceSpan + Dim catchBlock = root.FindToken(diagSpan.Start).Parent.FirstAncestorOrSelfOfType(Of CatchBlockSyntax) + Dim tryBlock = DirectCast(catchBlock.Parent, TryBlockSyntax) Dim statements = tryBlock.Statements - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim newRoot = root.ReplaceNode(catchBlock.Parent, statements.Select(Function(s) s. @@ -41,7 +42,11 @@ Namespace Design Return newDocument End Function - Private Async Function InsertExceptionClassCommentAsync(document As Document, catchBlock As CatchBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function InsertExceptionClassCommentAsync(document As Document, diag As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim diagSpan = diag.Location.SourceSpan + Dim catchBlock = root.FindToken(diagSpan.Start).Parent.FirstAncestorOrSelfOfType(Of CatchBlockSyntax) + Dim statements = New SyntaxList(Of SyntaxNode)().Add(SyntaxFactory.ThrowStatement()) Dim catchStatement = SyntaxFactory.CatchStatement( @@ -54,7 +59,6 @@ Namespace Design WithTrailingTrivia(catchBlock.GetTrailingTrivia). WithAdditionalAnnotations(Formatter.Annotation) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim newRoot = root.ReplaceNode(catchBlock, catchClause) Dim newDocument = document.WithSyntaxRoot(newRoot) Return newDocument diff --git a/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb index a7f875abf..41d633b51 100644 --- a/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/NameOfCodeFixProvider.vb @@ -1,4 +1,5 @@ -Imports System.Collections.Immutable +Imports CodeCracker.Properties +Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions @@ -18,24 +19,24 @@ Namespace Design Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First + context.RegisterCodeFix(CodeAction.Create(Resources.NameOfAnalyzer_Title, Function(c) MakeNameOf(context.Document, diagnostic, c), NameOf(NameOfCodeFixProvider)), diagnostic) + Return Task.FromResult(0) + End Function + + Private Async Function MakeNameOf(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim diagnosticspan = diagnostic.Location.SourceSpan Dim stringLiteral = root.FindToken(diagnosticspan.Start).Parent.AncestorsAndSelf.OfType(Of LiteralExpressionSyntax).FirstOrDefault - If stringLiteral IsNot Nothing Then - context.RegisterCodeFix(CodeAction.Create("use NameOf()", Function(c) MakeNameOf(context.Document, stringLiteral, root), NameOf(NameOfCodeFixProvider)), diagnostic) - End If - End Function - Private Function MakeNameOf(document As Document, stringLiteral As LiteralExpressionSyntax, root As SyntaxNode) As Task(Of Document) Dim newNameof = SyntaxFactory.ParseExpression($"NameOf({stringLiteral.Token.ToString().Replace("""", "")})"). WithLeadingTrivia(stringLiteral.GetLeadingTrivia). WithTrailingTrivia(stringLiteral.GetTrailingTrivia). WithAdditionalAnnotations(Formatter.Annotation) Dim newRoot = root.ReplaceNode(stringLiteral, newNameof) - Return Task.FromResult(document.WithSyntaxRoot(newRoot)) + Return document.WithSyntaxRoot(newRoot) End Function End Class diff --git a/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.vb index 8feb23984..5293269e7 100644 --- a/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.vb @@ -16,15 +16,17 @@ Namespace Design Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First + context.RegisterCodeFix(CodeAction.Create("Remove this exception", Function(ct) RemoveThrow(context.Document, diagnostic, ct), NameOf(StaticConstructorExceptionCodeFixProvider)), diagnostic) + Return Task.FromResult(0) + End Function + + Private Async Function RemoveThrow(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim sourceSpan = diagnostic.Location.SourceSpan Dim throwBlock = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf.OfType(Of ThrowStatementSyntax).First - context.RegisterCodeFix(CodeAction.Create("Remove this exception", Function(ct) RemoveThrow(context.Document, throwBlock, ct), NameOf(StaticConstructorExceptionCodeFixProvider)), diagnostic) - End Function - Private Async Function RemoveThrow(document As Document, throwBlock As ThrowStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document) Return document.WithSyntaxRoot((Await document.GetSyntaxRootAsync(cancellationToken)).RemoveNode(throwBlock, SyntaxRemoveOptions.KeepNoTrivia)) End Function End Class diff --git a/src/VisualBasic/CodeCracker/Performance/MakeLocalVariableConstWhenPossibleCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Performance/MakeLocalVariableConstWhenPossibleCodeFixProvider.vb index 31ced6241..4d2d4e094 100644 --- a/src/VisualBasic/CodeCracker/Performance/MakeLocalVariableConstWhenPossibleCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Performance/MakeLocalVariableConstWhenPossibleCodeFixProvider.vb @@ -18,17 +18,18 @@ Namespace Performance Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First() - Dim diagnosticSpan = diagnostic.Location.SourceSpan - Dim localDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType(Of LocalDeclarationStatementSyntax).First() Const message = "Make constant" - context.RegisterCodeFix(CodeAction.Create(message, Function(c) MakeConstantAsync(context.Document, localDeclaration, c), NameOf(MakeLocalVariableConstWhenPossibleCodeFixProvider)), diagnostic) - + context.RegisterCodeFix(CodeAction.Create(message, Function(c) MakeConstantAsync(context.Document, diagnostic, c), NameOf(MakeLocalVariableConstWhenPossibleCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function - Public Async Function MakeConstantAsync(document As Document, localDeclaration As LocalDeclarationStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Public Async Function MakeConstantAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim diagnosticSpan = diagnostic.Location.SourceSpan + Dim localDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType(Of LocalDeclarationStatementSyntax).First() + Dim declaration = localDeclaration.Declarators.First Dim dimModifier = localDeclaration.Modifiers.First() @@ -46,7 +47,6 @@ Namespace Performance WithTrailingTrivia(localDeclaration.GetTrailingTrivia()). WithAdditionalAnnotations(Formatter.Annotation) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken) Dim newRoot = root.ReplaceNode(localDeclaration, newLocalDeclaration) Return document.WithSyntaxRoot(newRoot) End Function diff --git a/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.vb b/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.vb index 0da0cf67c..584604eb5 100644 --- a/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.vb @@ -43,8 +43,8 @@ Namespace Performance If Not supportedMethods.Contains(candidate) Then Exit Sub If nextMethodInvoke.ArgumentList.Arguments.Any Then Return - - Dim diag = Diagnostic.Create(Rule, GetNameExpressionOfTheInvokedMethod(whereInvoke).GetLocation(), candidate) + Dim props = New Dictionary(Of String, String) From {{"methodName", candidate}}.ToImmutableDictionary() + Dim diag = Diagnostic.Create(Rule, GetNameExpressionOfTheInvokedMethod(whereInvoke).GetLocation(), props, candidate) context.ReportDiagnostic(diag) End Sub diff --git a/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleCodeFixProvider.vb index 0887c0dbb..dc5eb5fd3 100644 --- a/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Performance/RemoveWhereWhenItIsPossibleCodeFixProvider.vb @@ -17,18 +17,20 @@ Namespace Performance Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First + Dim name = diagnostic.Properties!methodName + Dim message = $"Remove 'Where' moving predicate to '{name}'" + context.RegisterCodeFix(CodeAction.Create(message, Function(c) RemoveWhere(context.Document, diagnostic, c), NameOf(RemoveWhereWhenItIsPossibleCodeFixProvider)), diagnostic) + Return Task.FromResult(0) + End Function + + Private Async Function RemoveWhere(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim diagnosticSpan = diagnostic.Location.SourceSpan Dim whereInvoke = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType(Of InvocationExpressionSyntax)().First() Dim nextMethodInvoke = whereInvoke.Parent.FirstAncestorOrSelf(Of InvocationExpressionSyntax)() - Dim message = "Remove 'Where' moving predicate to '" + RemoveWhereWhenItIsPossibleAnalyzer.GetNameOfTheInvokeMethod(nextMethodInvoke) + "'" - context.RegisterCodeFix(CodeAction.Create(message, Function(c) RemoveWhere(context.Document, whereInvoke, nextMethodInvoke, c), NameOf(RemoveWhereWhenItIsPossibleCodeFixProvider)), diagnostic) - End Function - Private Async Function RemoveWhere(document As Document, whereInvoke As InvocationExpressionSyntax, nextMethodInvoke As InvocationExpressionSyntax, cancellationToken As CancellationToken) As Task(Of Document) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim whereMemberAccess = whereInvoke.ChildNodes.OfType(Of MemberAccessExpressionSyntax)().FirstOrDefault() Dim nextMethodMemberAccess = nextMethodInvoke.ChildNodes.OfType(Of MemberAccessExpressionSyntax)().FirstOrDefault() diff --git a/src/VisualBasic/CodeCracker/Performance/SealedAttributeCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Performance/SealedAttributeCodeFixProvider.vb index 7f312ee93..966b28bca 100644 --- a/src/VisualBasic/CodeCracker/Performance/SealedAttributeCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Performance/SealedAttributeCodeFixProvider.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports System.Threading Namespace Performance @@ -21,10 +22,14 @@ Namespace Performance Dim diag = context.Diagnostics.First() Dim sourceSpan = diag.Location.SourceSpan Dim type = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType(Of Microsoft.CodeAnalysis.VisualBasic.Syntax.ClassStatementSyntax)().First() - context.RegisterCodeFix(CodeAction.Create("Mark as NotInheritable", Function(ct) MarkClassAsSealed(context.Document, type, ct), NameOf(SealedAttributeCodeFixProvider)), diag) + context.RegisterCodeFix(CodeAction.Create("Mark as NotInheritable", Function(ct) MarkClassAsSealed(context.Document, diag, ct), NameOf(SealedAttributeCodeFixProvider)), diag) End Function - Private Async Function MarkClassAsSealed(document As Document, type As ClassStatementSyntax, cancellationToken As Threading.CancellationToken) As Task(Of Document) + Private Async Function MarkClassAsSealed(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim sourceSpan = diagnostic.Location.SourceSpan + Dim type = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType(Of Microsoft.CodeAnalysis.VisualBasic.Syntax.ClassStatementSyntax)().First() + Return document. WithSyntaxRoot((Await document.GetSyntaxRootAsync(cancellationToken)). ReplaceNode(type, diff --git a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb index 054feb557..e00b20f13 100644 --- a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb @@ -65,7 +65,9 @@ Namespace Performance Exit Sub End If - Dim diag = Diagnostic.Create(Rule, assignmentExpression.GetLocation(), assignmentExpression.Left.ToString()) + Dim assignmentExpressionLeft = assignmentExpression.Left.ToString() + Dim props = New Dictionary(Of String, String) From {{NameOf(assignmentExpressionLeft), assignmentExpressionLeft}}.ToImmutableDictionary() + Dim diag = Diagnostic.Create(Rule, assignmentExpression.GetLocation(), props, assignmentExpression.Left.ToString()) context.ReportDiagnostic(diag) End Sub End Class diff --git a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopCodeFixProvider.vb index 47317fbcd..7475456dd 100644 --- a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopCodeFixProvider.vb @@ -19,27 +19,28 @@ Namespace Performance Return Nothing End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First + context.RegisterCodeFix(CodeAction.Create($"Use StringBuilder to create a value for '{diagnostic.Properties!assignmentExpressionLeft}'", Function(c) UseStringBuilder(context.Document, diagnostic, c), NameOf(StringBuilderInLoopCodeFixProvider)), diagnostic) + Return Task.FromResult(0) + End Function + + Private Async Function UseStringBuilder(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim diagosticSpan = diagnostic.Location.SourceSpan - Dim assignmentExpression = root.FindToken(diagosticSpan.Start).Parent.AncestorsAndSelf.OfType(Of AssignmentStatementSyntax).First - context.RegisterCodeFix(CodeAction.Create("Use StringBuilder to create a value for " & assignmentExpression.Left.ToString(), Function(c) UseStringBuilder(context.Document, assignmentExpression, c), NameOf(StringBuilderInLoopCodeFixProvider)), diagnostic) + Dim expressionStatement = root.FindToken(diagosticSpan.Start).Parent.AncestorsAndSelf.OfType(Of AssignmentStatementSyntax).First - End Function - Private Async Function UseStringBuilder(document As Document, assignmentStatement As AssignmentStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document) - Dim expressionStatement = assignmentStatement Dim expressionStatementParent = expressionStatement.Parent Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) - Dim builderName = FindAvailableStringBuilderVariableName(assignmentStatement, semanticModel) + Dim builderName = FindAvailableStringBuilderVariableName(expressionStatement, semanticModel) Dim loopStatement = expressionStatement.FirstAncestorOrSelfOfType( GetType(WhileBlockSyntax), GetType(ForBlockSyntax), GetType(ForEachBlockSyntax), GetType(DoLoopBlockSyntax)) - Dim newExpressionStatementParent = ReplaceAddExpressionByStringBuilderAppendExpression(assignmentStatement, expressionStatement, expressionStatementParent, builderName) + Dim newExpressionStatementParent = ReplaceAddExpressionByStringBuilderAppendExpression(expressionStatement, expressionStatement, expressionStatementParent, builderName) Dim newLoopStatement = loopStatement.ReplaceNode(expressionStatementParent, newExpressionStatementParent) Dim stringBuilderType = SyntaxFactory.ParseTypeName("System.Text.StringBuilder").WithAdditionalAnnotations(Simplifier.Annotation) @@ -51,14 +52,13 @@ Namespace Performance Dim stringBuilderDeclaration = SyntaxFactory.LocalDeclarationStatement(SyntaxTokenList.Create(SyntaxFactory.Token(SyntaxKind.DimKeyword)), declarators).NormalizeWhitespace(" ").WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) - Dim appendExpressionOnInitialization = SyntaxFactory.ParseExecutableStatement(builderName & ".Append(" & assignmentStatement.Left.ToString() & ")").WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) '.WithLeadingTrivia(assignmentStatement.GetLeadingTrivia()).WithTrailingTrivia(assignmentStatement.GetTrailingTrivia()) - Dim stringBuilderToString = SyntaxFactory.ParseExecutableStatement(assignmentStatement.Left.ToString() & " = " & builderName & ".ToString()").WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) '.WithLeadingTrivia(assignmentStatement.GetLeadingTrivia()).WithTrailingTrivia(assignmentStatement.GetTrailingTrivia()) + Dim appendExpressionOnInitialization = SyntaxFactory.ParseExecutableStatement(builderName & ".Append(" & expressionStatement.Left.ToString() & ")").WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) + Dim stringBuilderToString = SyntaxFactory.ParseExecutableStatement(expressionStatement.Left.ToString() & " = " & builderName & ".ToString()").WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) Dim loopParent = loopStatement.Parent Dim newLoopParent = loopParent.ReplaceNode(loopStatement, {stringBuilderDeclaration, appendExpressionOnInitialization, newLoopStatement, stringBuilderToString}). WithAdditionalAnnotations(Formatter.Annotation) - Dim root = Await document.GetSyntaxRootAsync() Dim newroot = root.ReplaceNode(loopParent, newLoopParent) Dim newDocument = document.WithSyntaxRoot(newroot) Return newDocument diff --git a/src/VisualBasic/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.vb index 90b83d036..dd259cc03 100644 --- a/src/VisualBasic/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Refactoring/ParameterRefactoryCodeFixProvider.vb @@ -12,15 +12,10 @@ Namespace Refactoring Public Class ParameterRefactoryCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) - + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First() - Dim diagnosticSpan = diagnostic.Location.SourceSpan - Dim declarationClass = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOfType(Of ClassBlockSyntax) - Dim declarationNamespace = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOfType(Of NamespaceBlockSyntax) - Dim declarationMethod = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOfType(Of MethodBlockSyntax) - context.RegisterCodeFix(CodeAction.Create("Change to new Class", Function(c) NewClassAsync(context.Document, declarationNamespace, declarationClass, declarationMethod, c), NameOf(ParameterRefactoryCodeFixProvider)), diagnostic) + context.RegisterCodeFix(CodeAction.Create("Change to new Class", Function(c) NewClassAsync(context.Document, diagnostic, c), NameOf(ParameterRefactoryCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function Public Overrides NotOverridable ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.ParameterRefactory.ToDiagnosticId()) @@ -29,16 +24,21 @@ Namespace Refactoring Return WellKnownFixAllProviders.BatchFixer End Function - Private Async Function NewClassAsync(document As Document, oldNamespace As NamespaceBlockSyntax, oldClass As ClassBlockSyntax, oldMethod As MethodBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function NewClassAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim diagnosticSpan = diagnostic.Location.SourceSpan + Dim declarationClass = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOfType(Of ClassBlockSyntax) + Dim declarationNamespace = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOfType(Of NamespaceBlockSyntax) + Dim declarationMethod = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOfType(Of MethodBlockSyntax) + Dim newRootParameter As SyntaxNode - If oldNamespace Is Nothing Then - Dim newCompilation = NewCompilationFactory(DirectCast(oldClass.Parent, CompilationUnitSyntax), oldClass, oldMethod) - newRootParameter = root.ReplaceNode(oldClass.Parent, newCompilation) + If declarationNamespace Is Nothing Then + Dim newCompilation = NewCompilationFactory(DirectCast(declarationClass.Parent, CompilationUnitSyntax), declarationClass, declarationMethod) + newRootParameter = root.ReplaceNode(declarationClass.Parent, newCompilation) Return document.WithSyntaxRoot(newRootParameter) End If - Dim newNamespace = NewNamespaceFactory(oldNamespace, oldClass, oldMethod) - newRootParameter = root.ReplaceNode(oldNamespace, newNamespace) + Dim newNamespace = NewNamespaceFactory(declarationNamespace, declarationClass, declarationMethod) + newRootParameter = root.ReplaceNode(declarationNamespace, newNamespace) Return document.WithSyntaxRoot(newRootParameter) End Function diff --git a/src/VisualBasic/CodeCracker/Reliability/UseConfigureAwaitFalseCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Reliability/UseConfigureAwaitFalseCodeFixProvider.vb index f2480f0dc..4dbe74275 100644 --- a/src/VisualBasic/CodeCracker/Reliability/UseConfigureAwaitFalseCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Reliability/UseConfigureAwaitFalseCodeFixProvider.vb @@ -1,4 +1,5 @@ Imports System.Collections.Immutable +Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes @@ -17,11 +18,15 @@ Namespace Reliability Return WellKnownFixAllProviders.BatchFixer End Function - Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task + Public NotOverridable Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First() - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + context.RegisterCodeFix(CodeAction.Create("Use ConfigureAwait(False)", Function(c) CreateUseConfigureAwaitAsync(context.Document, diagnostic, c), NameOf(UseConfigureAwaitFalseCodeFixProvider)), diagnostic) + Return Task.FromResult(0) + End Function + Private Shared Async Function CreateUseConfigureAwaitAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim awaitExpression = root.FindNode(diagnostic.Location.SourceSpan).ChildNodes.OfType(Of AwaitExpressionSyntax).FirstOrDefault() - If awaitExpression Is Nothing Then Exit Function + If awaitExpression Is Nothing Then Return document Dim newExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( @@ -35,12 +40,8 @@ Namespace Reliability WithTrailingTrivia(awaitExpression.Expression.GetTrailingTrivia()). WithAdditionalAnnotations(Formatter.Annotation) Dim newRoot = root.ReplaceNode(awaitExpression.Expression, newExpression) - Dim newDocument = context.Document.WithSyntaxRoot(newRoot) - context.RegisterCodeFix(CodeAction.Create("Use ConfigureAwait(False)", - Function(ct) - Return Task.FromResult(newDocument) - End Function, - NameOf(UseConfigureAwaitFalseCodeFixProvider)), diagnostic) + Dim newDocument = document.WithSyntaxRoot(newRoot) + Return newDocument End Function End Class End Namespace \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/Style/InterfaceNameCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Style/InterfaceNameCodeFixProvider.vb index b975cd1a8..a7be8807b 100644 --- a/src/VisualBasic/CodeCracker/Style/InterfaceNameCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Style/InterfaceNameCodeFixProvider.vb @@ -18,17 +18,19 @@ Namespace Style Return WellKnownFixAllProviders.BatchFixer End Function - Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public NotOverridable Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First() - Dim diagnosticSpan = diagnostic.Location.SourceSpan - Dim declaration = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelfOfType(GetType(InterfaceStatementSyntax)) context.RegisterCodeFix(CodeAction.Create("Consider start Interface name with letter 'I'.", - Function(c) ChangeInterfaceNameAsync(context.Document, DirectCast(declaration, InterfaceStatementSyntax), c), NameOf(InterfaceNameCodeFixProvider)), diagnostic) - + Function(c) ChangeInterfaceNameAsync(context.Document, diagnostic, c), NameOf(InterfaceNameCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function - Private Async Function ChangeInterfaceNameAsync(document As Document, interfaceStatement As InterfaceStatementSyntax, cancellationToken As CancellationToken) As Task(Of Solution) + Private Async Function ChangeInterfaceNameAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Solution) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim diagnosticSpan = diagnostic.Location.SourceSpan + Dim declaration = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelfOfType(GetType(InterfaceStatementSyntax)) + Dim interfaceStatement = DirectCast(declaration, InterfaceStatementSyntax) + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) Dim newName = "I" & interfaceStatement.Identifier.Text diff --git a/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionAnalyzer.vb index 30d8022ef..5f44756e4 100644 --- a/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionAnalyzer.vb @@ -50,14 +50,16 @@ It can be either specified directly or using nameof() (VB 14 and above only)." If Not paramNameOpt.HasValue Then Exit Sub Dim paramName = paramNameOpt.Value.ToString() - If IsParamNameCompatibleWithCreatingContext(objectCreationExpression, paramName) Then Exit Sub - Dim diag = Diagnostic.Create(Rule, paramNameLiteral.GetLocation, paramName) + Dim parameters As IEnumerable(Of String) = Nothing + If IsParamNameCompatibleWithCreatingContext(objectCreationExpression, paramName, parameters) Then Exit Sub + Dim props = parameters.ToImmutableDictionary(Function(p) $"param{p}", Function(p) p) + Dim diag = Diagnostic.Create(Rule, paramNameLiteral.GetLocation, props.ToImmutableDictionary(), paramName) context.ReportDiagnostic(diag) End Sub - Private Function IsParamNameCompatibleWithCreatingContext(node As SyntaxNode, paramName As String) As Boolean - Dim parameters = GetParameterNamesFromCreationContext(node) + Private Function IsParamNameCompatibleWithCreatingContext(node As SyntaxNode, paramName As String, ByRef parameters As IEnumerable(Of String)) As Boolean + parameters = GetParameterNamesFromCreationContext(node) If parameters Is Nothing Then Return True Return parameters.Contains(paramName) End Function diff --git a/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionCodeFixProvider.vb index 730fa4d5e..be77760c7 100644 --- a/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/ArgumentExceptionCodeFixProvider.vb @@ -18,20 +18,22 @@ Namespace Usage Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.ArgumentException.ToDiagnosticId()) - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First() - Dim span = diagnostic.Location.SourceSpan - Dim objectCreation = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of ObjectCreationExpressionSyntax) - Dim parameters = ArgumentExceptionAnalyzer.GetParameterNamesFromCreationContext(objectCreation) + Dim parameters = diagnostic.Properties.Where(Function(p) p.Key.StartsWith("param")) For Each param In parameters - Dim message = "Use '" & param & "'" - context.RegisterCodeFix(CodeAction.Create(message, Function(c) FixParamAsync(context.Document, objectCreation, param, c), NameOf(ArgumentExceptionCodeFixProvider)), diagnostic) + Dim message = $"Use '{param}'" + context.RegisterCodeFix(CodeAction.Create(message, Function(c) FixParamAsync(context.Document, diagnostic, param.Value, c), NameOf(ArgumentExceptionCodeFixProvider)), diagnostic) Next + Return Task.FromResult(0) End Function - Private Async Function FixParamAsync(document As Document, objectCreation As ObjectCreationExpressionSyntax, newParamName As String, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function FixParamAsync(document As Document, diagnostic As Diagnostic, newParamName As String, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim span = diagnostic.Location.SourceSpan + Dim objectCreation = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of ObjectCreationExpressionSyntax) + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) Dim argumentList = objectCreation.ArgumentList @@ -40,7 +42,6 @@ Namespace Usage Dim currentParamName = paramNameOpt.Value.ToString() Dim newLiteral = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(newParamName)) - Dim root = Await document.GetSyntaxRootAsync() Dim newRoot = root.ReplaceNode(paramNameLiteral, newLiteral) Dim newDocument = document.WithSyntaxRoot(newRoot) Return newDocument diff --git a/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.vb index 5de9041ac..16ed817be 100644 --- a/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.vb @@ -53,12 +53,15 @@ Namespace Usage Dim variableDeclarator = TryCast(fieldSyntaxRef.GetSyntax().Parent, VariableDeclaratorSyntax) If variableDeclarator Is Nothing Then Exit Sub If ContainingTypeImplementsIDisposableAndCallsItOnTheField(context, fieldSymbol, fieldSymbol.ContainingType) Then Exit Sub + + Dim props = New Dictionary(Of String, String) From {{"variableIdentifier", variableDeclarator.Names.First().Identifier.ValueText}}.ToImmutableDictionary() + If variableDeclarator.AsClause.Kind = SyntaxKind.AsNewClause Then - context.ReportDiagnostic(Diagnostic.Create(RuleForCreated, variableDeclarator.GetLocation(), fieldSymbol.Name)) + context.ReportDiagnostic(Diagnostic.Create(RuleForCreated, variableDeclarator.GetLocation(), props, fieldSymbol.Name)) ElseIf TypeOf (variableDeclarator.Initializer?.Value) Is InvocationExpressionSyntax Then - context.ReportDiagnostic(Diagnostic.Create(RuleForReturned, variableDeclarator.GetLocation(), fieldSymbol.Name)) + context.ReportDiagnostic(Diagnostic.Create(RuleForReturned, variableDeclarator.GetLocation(), props, fieldSymbol.Name)) ElseIf TypeOf (variableDeclarator.Initializer?.Value) Is ObjectCreationExpressionSyntax Then - context.ReportDiagnostic(Diagnostic.Create(RuleForCreated, variableDeclarator.GetLocation(), fieldSymbol.Name)) + context.ReportDiagnostic(Diagnostic.Create(RuleForCreated, variableDeclarator.GetLocation(), props, fieldSymbol.Name)) End If End Sub diff --git a/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedCodeFixProvider.vb index 2205dca82..dd9932546 100644 --- a/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/DisposableFieldNotDisposedCodeFixProvider.vb @@ -14,16 +14,13 @@ Namespace Usage Public Class DisposableFieldNotDisposedCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First - Dim span = diagnostic.Location.SourceSpan - Dim variableDeclarator = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of VariableDeclaratorSyntax)() - context.RegisterCodeFix(CodeAction.Create("Dispose field '" & variableDeclarator.Names.First().ToString(), - Function(c) DisposeField(context.Document, variableDeclarator, c), + context.RegisterCodeFix(CodeAction.Create($"Dispose field '{diagnostic.Properties!variableIdentifier}", + Function(c) DisposeField(context.Document, diagnostic, c), NameOf(DisposableFieldNotDisposedCodeFixProvider)), diagnostic) - + Return Task.FromResult(0) End Function Public Overrides NotOverridable ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId()) @@ -32,13 +29,16 @@ Namespace Usage Return WellKnownFixAllProviders.BatchFixer End Function - Private Async Function DisposeField(document As Document, variableDeclarator As VariableDeclaratorSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function DisposeField(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim span = diagnostic.Location.SourceSpan + Dim variableDeclarator = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of VariableDeclaratorSyntax)() + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken) Dim type = variableDeclarator.FirstAncestorOrSelf(Of ClassBlockSyntax) Dim typeSymbol = semanticModel.GetDeclaredSymbol(type) Dim newTypeImplementingIDisposable = AddIDisposableImplementationToType(type, typeSymbol) Dim newTypeWithDisposeMethod = AddDisposeDeclarationToDisposeMethod(variableDeclarator, newTypeImplementingIDisposable, typeSymbol) - Dim root = Await document.GetSyntaxRootAsync() Dim newRoot = root.ReplaceNode(type, newTypeWithDisposeMethod) Dim newDocument = document.WithSyntaxRoot(newRoot) Return newDocument diff --git a/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.vb index 94c6470c0..1d9cdb587 100644 --- a/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeCodeFixProvider.vb @@ -12,12 +12,10 @@ Namespace Usage Public Class DisposablesShouldCallSuppressFinalizeCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First - Dim span = diagnostic.Location.SourceSpan - Dim method = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MethodBlockSyntax)() - context.RegisterCodeFix(CodeAction.Create("Call GC.SuppressFinalize", Function(ct) AddSuppressFinalizeAsync(context.Document, method, ct), NameOf(DisposablesShouldCallSuppressFinalizeCodeFixProvider)), diagnostic) + context.RegisterCodeFix(CodeAction.Create("Call GC.SuppressFinalize", Function(ct) AddSuppressFinalizeAsync(context.Document, diagnostic, ct), NameOf(DisposablesShouldCallSuppressFinalizeCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function Public NotOverridable Overrides Function GetFixAllProvider() As FixAllProvider @@ -26,7 +24,11 @@ Namespace Usage Public Overrides NotOverridable ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId()) - Public Async Function AddSuppressFinalizeAsync(document As Document, method As MethodBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Public Async Function AddSuppressFinalizeAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim span = diagnostic.Location.SourceSpan + Dim method = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MethodBlockSyntax)() + Dim suppressInvocation = SyntaxFactory.ExpressionStatement( SyntaxFactory.InvocationExpression( diff --git a/src/VisualBasic/CodeCracker/Usage/MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider.vb index 16ff5569c..f91d7255f 100644 --- a/src/VisualBasic/CodeCracker/Usage/MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider.vb @@ -11,13 +11,10 @@ Namespace Usage Public Class MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider Inherits CodeFixProvider - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diag = context.Diagnostics.First() - Dim span = diag.Location.SourceSpan - - Dim constructor = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of SubNewStatementSyntax) - context.RegisterCodeFix(CodeAction.Create("Use 'Protected' in stead of 'Public'", Function(c) ReplacePublicWithProtectedAsync(context.Document, constructor, c), NameOf(MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider)), diag) + context.RegisterCodeFix(CodeAction.Create("Use 'Friend' instead of 'Public'", Function(c) ReplacePublicWithProtectedAsync(context.Document, diag, c), NameOf(MustInheritClassShouldNotHavePublicConstructorsCodeFixProvider)), diag) + Return Task.FromResult(0) End Function @@ -27,13 +24,17 @@ Namespace Usage Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(DiagnosticId.AbstractClassShouldNotHavePublicCtors.ToDiagnosticId()) - Private Async Function ReplacePublicWithProtectedAsync(document As Document, constructor As SubNewStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document) + Private Async Function ReplacePublicWithProtectedAsync(document As Document, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim span = diagnostic.Location.SourceSpan + + Dim constructor = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of SubNewStatementSyntax) + Dim [public] = constructor.Modifiers.First(Function(m) m.IsKind(SyntaxKind.PublicKeyword)) Dim [protected] = SyntaxFactory.Token([public].LeadingTrivia, SyntaxKind.ProtectedKeyword, [public].TrailingTrivia) Dim newModifiers = constructor.Modifiers.Replace([public], [protected]) Dim newConstructor = constructor.WithModifiers(newModifiers) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim newRoot = root.ReplaceNode(constructor, newConstructor) Dim newDocumnent = document.WithSyntaxRoot(newRoot) Return newDocumnent diff --git a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb index 1be347d85..c273ef808 100644 --- a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb @@ -39,7 +39,8 @@ Namespace Usage If methodStatement.HandlesClause IsNot Nothing Then Exit Sub If Not methodStatement.Modifiers.Any(Function(a) a.ValueText = SyntaxFactory.Token(SyntaxKind.PrivateKeyword).ValueText) Then Exit Sub If IsMethodUsed(methodStatement, context.SemanticModel) Then Exit Sub - Dim diag = Diagnostic.Create(Rule, methodStatement.GetLocation()) + Dim props = New Dictionary(Of String, String) From {{"identifier", methodStatement.Identifier.Text}}.ToImmutableDictionary() + Dim diag = Diagnostic.Create(Rule, methodStatement.GetLocation(), props) context.ReportDiagnostic(diag) End Sub diff --git a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedCodeFixProvider.vb b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedCodeFixProvider.vb index 9f0289cb7..ca0e5eb55 100644 --- a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedCodeFixProvider.vb +++ b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedCodeFixProvider.vb @@ -15,16 +15,17 @@ Namespace Usage Return WellKnownFixAllProviders.BatchFixer End Function - Public Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False) + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task Dim diagnostic = context.Diagnostics.First() - Dim span = diagnostic.Location.SourceSpan - Dim methodNotUsed = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MethodStatementSyntax) - context.RegisterCodeFix(CodeAction.Create("Remove unused private method: " & methodNotUsed.Identifier.ValueText, Function(c) RemoveMethodAsync(context.Document, methodNotUsed, c), NameOf(RemovePrivateMethodNeverUsedCodeFixProvider)), diagnostic) + context.RegisterCodeFix(CodeAction.Create($"Remove unused private method: {diagnostic.Properties!identifier}", Function(c) RemoveMethodAsync(context.Document, diagnostic, c), NameOf(RemovePrivateMethodNeverUsedCodeFixProvider)), diagnostic) + Return Task.FromResult(0) End Function - Private Async Function RemoveMethodAsync(document As Document, methodNotUsed As MethodStatementSyntax, cancellationToken As Threading.CancellationToken) As Task(Of Document) + Private Async Function RemoveMethodAsync(document As Document, diagnostic As Diagnostic, cancellationToken As Threading.CancellationToken) As Task(Of Document) Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) + Dim span = diagnostic.Location.SourceSpan + Dim methodNotUsed = root.FindToken(span.Start).Parent.FirstAncestorOrSelf(Of MethodStatementSyntax) + Dim newRoot = root.RemoveNode(methodNotUsed.Parent, SyntaxRemoveOptions.KeepNoTrivia) Return document.WithSyntaxRoot(newRoot) End Function From 4411c7b1c6bee7b5c956c2cc653f8729c3855490 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Tue, 24 Nov 2015 15:40:47 -0200 Subject: [PATCH 063/358] changing the way CC verifies if parameter is used (closes #562) --- .../Usage/UnusedParametersAnalyzer.cs | 51 ++++++++++++++++--- .../Usage/UnusedParametersTests.cs | 24 +++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs index 823ea9d1c..8be0b8636 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs @@ -42,6 +42,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (!IsCandidateForRemoval(methodOrConstructor, semanticModel)) return; var parameters = methodOrConstructor.ParameterList.Parameters.ToDictionary(p => p, p => semanticModel.GetDeclaredSymbol(p)); var ctor = methodOrConstructor as ConstructorDeclarationSyntax; + if (ctor?.Initializer != null) { var symbolsTouched = new List(); @@ -56,25 +57,61 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) foreach (var parameter in parametersToRemove) parameters.Remove(parameter.Key); } + if (methodOrConstructor.Body.Statements.Any()) { - var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(methodOrConstructor.Body.Statements.First(), methodOrConstructor.Body.Statements.Last()); - if (!dataFlowAnalysis.Succeeded) return; foreach (var parameter in parameters) { - var parameterSymbol = parameter.Value; - if (parameterSymbol == null) continue; - if (!dataFlowAnalysis.ReadInside.Contains(parameterSymbol) && !dataFlowAnalysis.WrittenInside.Contains(parameterSymbol)) - context = ReportDiagnostic(context, parameter.Key); + var used = methodOrConstructor.Body + .DescendantNodesAndSelf() + .OfType() + .Any(iName => IdentifierRefersToParam(iName, parameter.Key)); + + if (!used) + { + ReportDiagnostic(context, parameter.Key); + } } + // + // THIS IS THE RIGHT WAY TO DO THIS VERIFICATION. + // BUT, WE HAVE TO WAIT FOR A "BUGFIX" FROM ROSLYN TEAM + // IN DataFlowAnalysis + // + // https://github.com/dotnet/roslyn/issues/6967 + // + //var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(methodOrConstructor.Body); + //if (!dataFlowAnalysis.Succeeded) return; + //foreach (var parameter in parameters) + //{ + + // var parameterSymbol = parameter.Value; + // if (parameterSymbol == null) continue; + // if (!dataFlowAnalysis.ReadInside.Contains(parameterSymbol) && + // !dataFlowAnalysis.WrittenInside.Contains(parameterSymbol)) + // { + // ReportDiagnostic(context, parameter.Key); + // } + //} } else { foreach (var parameter in parameters.Keys) - context = ReportDiagnostic(context, parameter); + ReportDiagnostic(context, parameter); } } + private static bool IdentifierRefersToParam(IdentifierNameSyntax iName, ParameterSyntax param) + { + if (iName.Identifier.ToString() != param.Identifier.ToString()) + return false; + + var mae = iName.Parent as MemberAccessExpressionSyntax; + if (mae == null) + return true; + + return mae.DescendantNodes().FirstOrDefault() == iName; + } + private static bool IsCandidateForRemoval(BaseMethodDeclarationSyntax methodOrConstructor, SemanticModel semanticModel) { if (methodOrConstructor.Modifiers.Any(m => m.ValueText == "partial" || m.ValueText == "override") diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 25c3ea625..f2d71c341 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -20,6 +20,30 @@ public void Foo() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task UsedParameterDoesNotCreateDiagnostic2() + { + const string source = @" +using System.Globalization; +using System.Reflection; + +namespace ClassLibrary1 +{ + public class Class1 + { + protected Class1() { } + + public static void SetDefaultThreadCulture(CultureInfo currentCulture, CultureInfo currentUICulture) + { + typeof(CultureInfo).InvokeMember(""s_userDefaultCulture"", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.SetField, null, null, new object[] { currentCulture }, CultureInfo.InvariantCulture); + typeof(CultureInfo).InvokeMember(""s_userDefaultUICulture"", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.SetField, null, null, new object[] { currentUICulture }, CultureInfo.InvariantCulture); + } + } +} +"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task UsedParameterDoesNotCreateDiagnostic() { From ca18464f00ac357b31684733422e0f6105e19b28 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 26 Nov 2015 01:15:29 +0100 Subject: [PATCH 064/358] Fixes #407 CC0001 no longer applies to primitives CC0105 is now raised for primitives --- .../CodeCracker/Style/AlwaysUseVarAnalyzer.cs | 42 +++++++++++++++++-- .../Style/AlwaysUseVarCodeFixProvider.cs | 2 +- src/Common/CodeCracker.Common/DiagnosticId.cs | 1 + .../Style/AlwaysUseVarTests.cs | 40 ++++++++++++++++-- 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs b/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs index a320a29fb..5a2c98282 100644 --- a/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs @@ -16,7 +16,7 @@ public class AlwaysUseVarAnalyzer : DiagnosticAnalyzer const string Description = "Usage of an implicit type improve readability of the code.\r\n" + "Code depending on types for their readability should be refactored with better variable " + "names or by introducing well-named methods."; - internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + internal static readonly DiagnosticDescriptor RuleNonPrimitives = new DiagnosticDescriptor( DiagnosticId.AlwaysUseVar.ToDiagnosticId(), Title, MessageFormat, @@ -26,7 +26,18 @@ public class AlwaysUseVarAnalyzer : DiagnosticAnalyzer description:Description, helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.AlwaysUseVar)); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + internal static readonly DiagnosticDescriptor RulePrimitives = new DiagnosticDescriptor( + DiagnosticId.AlwaysUseVarOnPrimitives.ToDiagnosticId(), + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.AlwaysUseVarOnPrimitives)); + + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(RuleNonPrimitives, RulePrimitives); public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.LocalDeclarationStatement); @@ -54,8 +65,33 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) if (!conversion.IsIdentity) return; } - var diagnostic = Diagnostic.Create(Rule, variableDeclaration.Type.GetLocation()); + var rule = IsPrimitvie(variableType) ? RulePrimitives : RuleNonPrimitives; + var diagnostic = Diagnostic.Create(rule, variableDeclaration.Type.GetLocation()); context.ReportDiagnostic(diagnostic); } + + private static bool IsPrimitvie(ITypeSymbol typeSymbol) + { + switch (typeSymbol.SpecialType) + { + case SpecialType.System_Boolean: + case SpecialType.System_Byte: + case SpecialType.System_SByte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_IntPtr: + case SpecialType.System_UIntPtr: + case SpecialType.System_Char: + case SpecialType.System_Double: + case SpecialType.System_Single: + return true; + default: + return false; + } + } } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs index 1df4bd4b0..664cf3b40 100644 --- a/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/AlwaysUseVarCodeFixProvider.cs @@ -17,7 +17,7 @@ namespace CodeCracker.CSharp.Style public class AlwaysUseVarCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticId.AlwaysUseVar.ToDiagnosticId()); + ImmutableArray.Create(DiagnosticId.AlwaysUseVar.ToDiagnosticId(), DiagnosticId.AlwaysUseVarOnPrimitives.ToDiagnosticId()); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index df6250054..b3e757224 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -79,5 +79,6 @@ public enum DiagnosticId ConsoleWriteLine = 95, NameOf_External = 108, StringFormatArgs_ExtraArgs = 111, + AlwaysUseVarOnPrimitives = 105, } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs b/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs index e192d7eae..96d332850 100644 --- a/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs @@ -7,6 +7,7 @@ namespace CodeCracker.Test.CSharp.Style { public class AlwaysUseVarTests : CodeFixVerifier { + [Fact] public async Task IgnoresConstantDeclarations() { @@ -93,10 +94,12 @@ class Fee: IFee {} } - [Fact] - public async Task CreateDiagnosticsWhenAssigningValueWithSameDeclaringType() + [Theory] + [InlineData("int")] + [InlineData("System.Int32")] + public async Task CreateDiagnosticsWhenAssigningValueWithSameDeclaringTypePrimitive(string value) { - const string test = @" + var test = @" using System; namespace ConsoleApplication1 @@ -105,7 +108,36 @@ class TypeName { public async Task Foo() { - int a = 10; + " + value + @" a = 10; + } + } + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.AlwaysUseVarOnPrimitives.ToDiagnosticId(), + Message = "Use 'var' instead of specifying the type name.", + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Theory] + [InlineData("string a = \"10\";")] + [InlineData("DateTime date1 = new DateTime(2013, 6, 1, 12, 32, 30);")] + public async Task CreateDiagnosticsWhenAssigningValueWithSameDeclaringTypeNonPrimitive(string value) + { + var test = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + " + value + @" } } }"; From f767d631f18aea0a940da2f8370796a417c724b7 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 2 Dec 2015 01:32:47 -0200 Subject: [PATCH 065/358] Make AD0001 a warning instead of an error --- src/CSharp/CodeCracker/CodeCracker.csproj | 1 + src/Common/CodeCracker.Common/CodeCracker.Common.csproj | 1 + src/VisualBasic/CodeCracker/CodeCracker.vbproj | 1 + test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj | 1 + .../CodeCracker.Test.Common/CodeCracker.Test.Common.csproj | 1 + test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj | 1 + 6 files changed, 6 insertions(+) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 7ed341fb5..f1417b406 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -24,6 +24,7 @@ 4 ..\..\..\codecrackerandall.ruleset true + AD0001 pdbonly diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 1f9da6ad1..2927e9ff9 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -25,6 +25,7 @@ prompt 4 true + AD0001 pdbonly diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 5f6a6cb48..db041b097 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -27,6 +27,7 @@ 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 ..\..\..\codecrackerandall.ruleset true + AD0001 pdbonly diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 9125e159a..45c3eff72 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -30,6 +30,7 @@ false ..\..\..\codecrackerandall.test.ruleset true + AD0001 pdbonly diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 328c8050f..45c86bdfd 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -26,6 +26,7 @@ prompt 4 true + AD0001 pdbonly diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 8d5067bf7..745344595 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -29,6 +29,7 @@ true 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 + AD0001 pdbonly From 3619b07ded508eaa6c91215692e9d2ead622a883 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 2 Dec 2015 01:56:29 -0200 Subject: [PATCH 066/358] Fix UseInvokeMethodToFireEvent to work with expression bodied methods Closes #611 --- .../UseInvokeMethodToFireEventAnalyzer.cs | 2 +- .../Design/UseInvokeMethodToFireEventTests.cs | 46 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index 546dfec2f..6d6b9f0c4 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -57,7 +57,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) private static bool HasCheckForNull(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) { var method = invocation.FirstAncestorOfKind(SyntaxKind.MethodDeclaration) as MethodDeclarationSyntax; - if (method != null) + if (method != null && method.Body != null) { var ifs = method.Body.Statements.OfKind(SyntaxKind.IfStatement); foreach (IfStatementSyntax @if in ifs) diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index 6b6f976fe..ed532d7d6 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -31,6 +31,47 @@ public void Execute() await VerifyCSharpDiagnosticAsync(test, expected); } + [Fact] + public async void AcceptExpressionBodiedMethods() + { + const string test = @" + public class MyClass + { + public event System.EventHandler MyEvent; + public void Execute() => + MyEvent(this, System.EventArgs.Empty); + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } + }; + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void FixExpressionBodiedMethods() + { + const string source = @" + public class MyClass + { + public event System.EventHandler MyEvent; + public void Execute() => + MyEvent(this, System.EventArgs.Empty); + }"; + const string fixtest = @" + public class MyClass + { + public event System.EventHandler MyEvent; + public void Execute() => + MyEvent?.Invoke(this, System.EventArgs.Empty); + }"; + + await VerifyCSharpFixAsync(source, fixtest); + } + [Fact] public async void WarningIfCustomEventIsFiredDirectly() { @@ -268,7 +309,7 @@ public void Execute() } }"; - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] @@ -295,8 +336,7 @@ public void Execute() MyEvent?.Invoke(this, System.EventArgs.Empty); //Some Comment } }"; - - await VerifyCSharpFixAsync(source, fixtest, 0); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] From 86cff2358bd1ca770338fdb9075c0c0a97778ef0 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 2 Dec 2015 11:49:16 -0200 Subject: [PATCH 067/358] Change var to const string --- .../SimplifyRedundantBooleanComparisonsCodeFixProvider.cs | 2 +- .../Usage/SimplifyRedundantBooleanComparisonsTests.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs index a840d90a3..8c9ba5209 100644 --- a/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/SimplifyRedundantBooleanComparisonsCodeFixProvider.cs @@ -65,7 +65,7 @@ private static async Task RemoveRedundantComparisonAsync(Document docu replacer = replacer .WithAdditionalAnnotations(Formatter.Annotation); - + var newRoot = root.ReplaceNode(comparison, replacer); var newDocument = document.WithSyntaxRoot(newRoot); diff --git a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs index ba6076219..714e2bc3c 100644 --- a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs @@ -42,7 +42,7 @@ public async Task WhenComparingWithBoolAnalyzerCreatesDiagnostic(string sample, await VerifyCSharpDiagnosticAsync(test, expected); } - + [Theory] [InlineData("if (foo == 0) {}")] @@ -107,7 +107,7 @@ public async Task FixRemovesRedundantComparisons(string original, string result) [Fact] public async Task FixWithoutThrowingAnyException() { - var test = @" + const string test = @" struct ProjectCompilation {} class Foo { @@ -118,7 +118,7 @@ public bool Comp(bool obj) } }"; - var fixtest = @" + const string fixtest = @" struct ProjectCompilation {} class Foo { From 029bf1d4ed0567dbbc403a85743d98dc55516907 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 2 Dec 2015 11:55:26 -0200 Subject: [PATCH 068/358] Update NoPrivateReadonlyFieldAnalyzer to do not work on generated code Fixes #609 --- .../Usage/NoPrivateReadonlyFieldAnalyzer.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs index e1a2bbd90..f87394915 100644 --- a/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/NoPrivateReadonlyFieldAnalyzer.cs @@ -36,11 +36,19 @@ public override void Initialize(AnalysisContext analysisContext) var assignedFields = new List(); compilationStartContext.RegisterSyntaxNodeAction( - syntaxNodeAnalysisContext => CaptureCandidateFields(syntaxNodeAnalysisContext.Node as FieldDeclarationSyntax, syntaxNodeAnalysisContext.SemanticModel, candidateFields), + syntaxNodeAnalysisContext => + { + if (syntaxNodeAnalysisContext.IsGenerated()) return; + CaptureCandidateFields(syntaxNodeAnalysisContext.Node as FieldDeclarationSyntax, syntaxNodeAnalysisContext.SemanticModel, candidateFields); + }, SyntaxKind.FieldDeclaration); compilationStartContext.RegisterSyntaxNodeAction( - syntaxNodeAnalysisContext => CaptureAssignedFields(syntaxNodeAnalysisContext.Node as TypeDeclarationSyntax, syntaxNodeAnalysisContext.SemanticModel, assignedFields), + syntaxNodeAnalysisContext => + { + if (syntaxNodeAnalysisContext.IsGenerated()) return; + CaptureAssignedFields(syntaxNodeAnalysisContext.Node as TypeDeclarationSyntax, syntaxNodeAnalysisContext.SemanticModel, assignedFields); + }, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration); compilationStartContext.RegisterCompilationEndAction(compilationEndContext => From 1a82b4c82fd24f435c931491c8808af05cd5b04e Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 2 Dec 2015 12:44:55 -0200 Subject: [PATCH 069/358] Update testing infrastructure --- build.targets.ps1 | 4 +-- runTestsCS.ps1 | 2 +- runTestsVB.ps1 | 2 +- .../CodeCracker.Test/CodeCracker.Test.csproj | 30 +++++++++---------- test/CSharp/CodeCracker.Test/packages.config | 13 ++++---- .../CodeCracker.Test.Common.csproj | 26 ++++++++-------- .../CodeCracker.Test.Common/packages.config | 15 +++++----- .../CodeCracker.Test/CodeCracker.Test.vbproj | 28 ++++++++--------- .../CodeCracker.Test/packages.config | 13 ++++---- 9 files changed, 68 insertions(+), 65 deletions(-) diff --git a/build.targets.ps1 b/build.targets.ps1 index ab668b7e4..d40bb9b6f 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -15,7 +15,7 @@ Properties { $nupkgPathCS = "$rootDir\src\CSharp\CodeCracker.CSharp.{0}.nupkg" $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" $nupkgPathJoint = "$rootDir\CodeCracker.{0}.nupkg" - $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.0.0\tools\xunit.console.x86.exe" + $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" $openCoverExe = "$packagesDir\OpenCover.4.6.166\tools\OpenCover.Console.exe" $testDllCS = "CodeCracker.Test.CSharp.dll" $testDllVB = "CodeCracker.Test.VisualBasic.dll" @@ -23,7 +23,7 @@ Properties { $testDirVB = "$testDir\VisualBasic\CodeCracker.Test\bin\Debug" $logDir = "$rootDir\log" $outputXml = "$logDir\CodeCoverageResults.xml" - $reportGeneratorExe = "$packagesDir\ReportGenerator.2.1.8.0\tools\ReportGenerator.exe" + $reportGeneratorExe = "$packagesDir\ReportGenerator.2.3.5.0\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" $converallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" $isRelease = $isAppVeyor -and ($env:APPVEYOR_REPO_BRANCH -eq "release") diff --git a/runTestsCS.ps1 b/runTestsCS.ps1 index 324d6ed85..622e9718e 100644 --- a/runTestsCS.ps1 +++ b/runTestsCS.ps1 @@ -3,7 +3,7 @@ $Global:lastRun = $lastRun = [System.DateTime]::Now $testDllDirPath = "$PSScriptRoot\test\CSharp\CodeCracker.Test\bin\Debug\" $testDllFileName = "CodeCracker.Test.CSharp.dll" $Global:testDllFullFileName = "$testDllDirPath$testDllFileName" -$Global:xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.0.0\tools\xunit.console.x86.exe" +$Global:xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" if ($testClass -eq "now"){ . $Global:xunitConsole "$Global:testDllFullFileName" diff --git a/runTestsVB.ps1 b/runTestsVB.ps1 index 0e21f458a..53e5730ea 100644 --- a/runTestsVB.ps1 +++ b/runTestsVB.ps1 @@ -3,7 +3,7 @@ $Global:lastRun = $lastRun = [System.DateTime]::Now $testDllDirPath = "$PSScriptRoot\test\VisualBasic\CodeCracker.Test\bin\Debug\" $testDllFileName = "CodeCracker.Test.VisualBasic.dll" $Global:testDllFullFileName = "$testDllDirPath$testDllFileName" -$Global:xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.0.0\tools\xunit.console.x86.exe" +$Global:xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" if ($testClass -eq "now"){ . $Global:xunitConsole "$Global:testDllFullFileName" diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 45c3eff72..a6563e108 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -1,8 +1,6 @@  - - - + Debug AnyCPU @@ -42,12 +40,12 @@ false - - ..\..\..\packages\FluentAssertions.3.4.1\lib\net45\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll True - - ..\..\..\packages\FluentAssertions.3.4.1\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll True @@ -113,12 +111,16 @@ ..\..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll True - - ..\..\..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll + + ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll True - - ..\..\..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll + + ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + True + + + ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll True @@ -244,9 +246,7 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + - \ No newline at end of file + diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index 48057ebe2..a0dee04b2 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -1,7 +1,7 @@  - + @@ -11,10 +11,11 @@ - + - - - - + + + + + \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 45c86bdfd..7cd7dba5b 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -1,7 +1,5 @@  - - Debug @@ -37,12 +35,12 @@ 4 - - ..\..\..\packages\FluentAssertions.3.4.1\lib\net45\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll True - - ..\..\..\packages\FluentAssertions.3.4.1\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll True @@ -116,12 +114,16 @@ ..\..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll True - - ..\..\..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll + + ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll True - - ..\..\..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll + + ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + True + + + ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll True @@ -152,8 +154,6 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - \ No newline at end of file + diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index de79a4784..162e91055 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -2,7 +2,7 @@ - + @@ -13,13 +13,14 @@ - + - + - - - - + + + + + \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 745344595..edc9e8b66 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -1,8 +1,6 @@  - - - + Debug @@ -56,12 +54,12 @@ On - - ..\..\..\packages\FluentAssertions.3.4.1\lib\net45\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll True - - ..\..\..\packages\FluentAssertions.3.4.1\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll True @@ -124,12 +122,16 @@ ..\..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll True - - ..\..\..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll + + ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll True - - ..\..\..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll + + ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + True + + + ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll True @@ -237,9 +239,7 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + - + + Designer + PreserveNewest @@ -160,8 +162,8 @@ - - + + diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index 79646a42c..be0fe2547 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 47647d0a9..0cac11358 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -236,8 +236,8 @@ - - + + @@ -255,4 +255,4 @@ --> - + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs index 5b2704a82..5413edb7e 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs @@ -261,7 +261,7 @@ class TypeName [InlineData("!xs.All(i => i != 1)", "xs.Any(i => i == 1)")] public async Task FixesExpressionBodiedMember(string code, string fixedCode) { - var source = @" + const string source = @" using System; using System.Linq; class TypeName diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index 75f638a82..60a80b3d0 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -82,7 +82,7 @@ public async Task IgnoresDisposableObjectsCreatedDirectParentIsNotAnUsingStateme [Fact] public async Task IgnoresDisposableObjectsBeingCreatedWithTernaryInUsingStatement() { - var source = @" + const string source = @" namespace CSharpNamespace { public class DisposableClass : System.IDisposable { } diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index a0dee04b2..953d54e58 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 8f7bee13b..5ca8c8ccc 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -144,8 +144,8 @@ - - + + @@ -162,4 +162,4 @@ --> - + \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs b/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs index c01eee989..6163123c2 100644 --- a/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs +++ b/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs @@ -97,8 +97,8 @@ protected async Task VerifyCSharpDiagnosticAsync(string[] sources, DiagnosticRes /// An array of strings to create source documents from to run the analyzers on /// DiagnosticResults that should appear after the analyzer is run on the sources /// The VB language version, defaults to the latest stable version. - protected async Task VerifyBasicDiagnosticAsync(string[] sources, DiagnosticResult[] expected, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersion) => - await VerifyDiagnosticsAsync(sources, LanguageNames.VisualBasic, GetDiagnosticAnalyzer(), expected, LanguageVersion.CSharp6, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic14).ConfigureAwait(true); + protected async Task VerifyBasicDiagnosticAsync(string[] sources, DiagnosticResult[] expected, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersion = Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic14) => + await VerifyDiagnosticsAsync(sources, LanguageNames.VisualBasic, GetDiagnosticAnalyzer(), expected, LanguageVersion.CSharp6, languageVersion).ConfigureAwait(true); /// /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index 162e91055..f1bc5d8d5 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 2b9ba435c..9648c8dbb 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -229,8 +229,8 @@ - - + + diff --git a/test/VisualBasic/CodeCracker.Test/PlaceholderTest.vb b/test/VisualBasic/CodeCracker.Test/PlaceholderTest.vb deleted file mode 100644 index 759adf72f..000000000 --- a/test/VisualBasic/CodeCracker.Test/PlaceholderTest.vb +++ /dev/null @@ -1,10 +0,0 @@ -Imports Xunit -Imports CodeCracker -Public Class PlaceholderTest - - Public Sub PleaseRemove() - Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic12.RunWithVB14OrGreater(Sub() - End Sub) - End Sub - -End Class diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config index 9cbe03d8c..2739aafad 100644 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ b/test/VisualBasic/CodeCracker.Test/packages.config @@ -1,6 +1,6 @@  - + From 4b788b3850543fd1b83aae1913e87489b3e50b53 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 29 Jan 2016 18:22:55 -0200 Subject: [PATCH 119/358] Update nuget to 3.3 and psake to 4.5 --- .gitignore | 1 + .nuget/packages.config | 6 ++-- build.ps1 | 63 ++++++++++++++++++++++++++++++++++++++++-- build.targets.ps1 | 4 ++- nuget.config | 2 ++ psake.ps1 | 4 +-- 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index a3172ad67..3da239e30 100644 --- a/.gitignore +++ b/.gitignore @@ -191,3 +191,4 @@ ModelManifest.xml log/ .vs +nuget.exe diff --git a/.nuget/packages.config b/.nuget/packages.config index a571bd134..5e0ac7672 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,5 +1,5 @@  - - - \ No newline at end of file + + + diff --git a/build.ps1 b/build.ps1 index 028d74306..c51dd0bf9 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,11 +1,68 @@ -if ((Test-Path $PSScriptRoot\packages\psake.4.4.2\tools\psake.psm1) -ne $true) { - nuget restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot +$ErrorActionPreference = "Stop" +# functions: + +function IsNugetVersion3($theNugetExe) { + try { + $nugetText = . $theNugetExe | Out-String + } catch { + return false + } + [regex]$regex = '^NuGet Version: (.*)\n' + $match = $regex.Match($nugetText) + $version = $match.Groups[1].Value + return $version.StartsWith(3) } -Import-Module $PSScriptRoot\packages\psake.4.4.2\tools\psake.psm1 -force + +function Get-Nuget { + if (gcm nuget -ErrorAction SilentlyContinue) { + if (IsNugetVersion3 'nuget') { + return 'nuget' + } else { + Download-Nuget + return $localNuget + } + } else { + Download-Nuget + return $localNuget + } +} + +function Download-Nuget { + $tempNuget = "$env:TEMP\codecracker\nuget.exe" + if (!(Test-Path "$env:TEMP\codecracker\")) { + md "$env:TEMP\codecracker\" + } + if (Test-Path $localNuget) { + if (IsNugetVersion3($localNuget)) { return } + } + if (Test-Path $tempNuget) { + if (IsNugetVersion3($tempNuget)) { + cp $tempNuget $localNuget + return + } + } + wget "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile $tempNuget + cp $tempNuget $localNuget +} + +function Import-Psake { + $psakeModule = "$PSScriptRoot\packages\psake.4.5.0\tools\psake.psm1" + if ((Test-Path $psakeModule) -ne $true) { + . $nugetExe restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot + } + Import-Module $psakeModule -force +} + +# statements: + +$localNuget = "$PSScriptRoot\.nuget\nuget.exe" +$nugetExe = Get-Nuget +Import-Psake if ($MyInvocation.UnboundArguments.Count -ne 0) { . $PSScriptRoot\psake.ps1 -taskList ($MyInvocation.UnboundArguments -join " ") } else { . $PSScriptRoot\build.ps1 Build } + exit !($psake.build_success) \ No newline at end of file diff --git a/build.targets.ps1 b/build.targets.ps1 index 4b8dd93fa..2e7030fc0 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -11,7 +11,7 @@ Properties { $nuspecPathCS = "$rootDir\src\CSharp\CodeCracker\CodeCracker.nuspec" $nuspecPathVB = "$rootDir\src\VisualBasic\CodeCracker\CodeCracker.nuspec" $nuspecPathJoint = "$rootDir\src\CodeCracker.nuspec" - $nugetExe = "$packagesDir\NuGet.CommandLine.2.8.5\tools\NuGet.exe" + $nugetExe = "$packagesDir\NuGet.CommandLine.3.3.0\tools\NuGet.exe" $nupkgPathCS = "$rootDir\src\CSharp\CodeCracker.CSharp.{0}.nupkg" $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" $nupkgPathJoint = "$rootDir\CodeCracker.{0}.nupkg" @@ -121,6 +121,8 @@ Task Pack-Nuget-VB -precondition { return $isAppVeyor } { PackNuget "VB" "$rootDir\src\VisualBasic" $nuspecPathVB $nupkgPathVB } +Task Echo { echo echo } + function PackNuget($language, $dir, $nuspecFile, $nupkgFile) { Write-Host "Packing nuget for $language..." [xml]$xml = cat $nuspecFile diff --git a/nuget.config b/nuget.config index 35c4d89a8..ffae90ba7 100644 --- a/nuget.config +++ b/nuget.config @@ -1,10 +1,12 @@  + + diff --git a/psake.ps1 b/psake.ps1 index ac4218572..de6e34a2d 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -1,3 +1,3 @@ -Import-Module $PSScriptRoot\packages\psake.4.4.2\tools\psake.psm1 -force -Invoke-Expression("Invoke-psake -framework '4.5.1' build.targets.ps1 " + $MyInvocation.UnboundArguments -join " ") +Import-Module $PSScriptRoot\packages\psake.4.5.0\tools\psake.psm1 -force +Invoke-Expression("Invoke-psake -framework '4.5.2' build.targets.ps1 " + $MyInvocation.UnboundArguments -join " ") exit !($psake.build_success) \ No newline at end of file From ff26fdeef521068d9a0a7d2c7e20d3fa2cf9bc0c Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 29 Jan 2016 23:09:22 -0200 Subject: [PATCH 120/358] Fix make static analyzer w/ structs Fixes #681 --- .../Design/MakeMethodStaticAnalyzer.cs | 3 +- .../Design/MakeMethodStaticTests.cs | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs index 138a3744c..eb128c92a 100644 --- a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs @@ -73,7 +73,8 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) { var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(method.Body); if (!dataFlowAnalysis.Succeeded) return; - if (dataFlowAnalysis.DataFlowsIn.Any(inSymbol => inSymbol.Name == "this")) return; + if (dataFlowAnalysis.DataFlowsIn.Any(inSymbol => inSymbol.Name == "this") + || dataFlowAnalysis.WrittenInside.Any(inSymbol => inSymbol.Name == "this")) return; } if (IsTestMethod(method, methodSymbol)) return; diff --git a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs index 00adacc39..cc980214d 100644 --- a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs @@ -985,5 +985,43 @@ static void M() }"; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task IgnoreInStructs() + { + const string source = @" +struct Foo +{ + private int x; + + public void M(int x) + { + this.x = x; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task ReportInStructs() + { + const string source = @" +struct Foo +{ + public void M() + { + N(); + } + public static void N() { } +}"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.MakeMethodStatic.ToDiagnosticId(), + Message = string.Format(MakeMethodStaticAnalyzer.MessageFormat, "M"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } \ No newline at end of file From 568bc6bb244a06f2a4b86e02f0ce78ab5f2831ea Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 30 Jan 2016 12:08:40 -0200 Subject: [PATCH 121/358] Fix change to for when there was an assignment Closes #683 --- .../CodeCracker/Style/ForInArrayAnalyzer.cs | 2 ++ .../CodeCracker.Test/Style/ForInArrayTests.cs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs index 5ef048995..43bc440b6 100644 --- a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs @@ -55,6 +55,8 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (t.Text != forVariable.Identifier.Text) return false; var elementAccess = t.GetAncestor(); if (elementAccess == null) return true; + var assignment = elementAccess.Parent as AssignmentExpressionSyntax; + if (assignment != null && assignment.Left == elementAccess) return true; var accessIdentifier = elementAccess.Expression as IdentifierNameSyntax; if (accessIdentifier == null) return true; var identifierSymbol = semanticModel.GetSymbolInfo(accessIdentifier).Symbol; diff --git a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs index 227773cad..e7caab9e9 100644 --- a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs @@ -594,5 +594,24 @@ public int Foo(int[] array) }"; await VerifyCSharpFixAsync(source, fixtest, 0); } + + [Fact] + public async Task WhenThereIsAnAssignmentDoesNotCreateDiagnostic() + { + var source = @" +class Baz +{ + void Foo() + { + var buffer = new[] { 1 }; + for (int i = 0; i < buffer.Length; i++) + { + var temp = buffer[i]; + buffer[i] = 1; + } + } +}".WrapInCSharpMethod(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From 97e3123595b04a27421f6d665a1ac099c48b1375 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 30 Jan 2016 19:14:19 -0200 Subject: [PATCH 122/358] Add check to for analyzer to verify if is enumerable Closes #684 --- .../CodeCracker/Style/ForInArrayAnalyzer.cs | 24 ++- .../CodeCracker.Test/Style/ForInArrayTests.cs | 150 +++++++++++++++++- 2 files changed, 169 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs index 43bc440b6..300462f5e 100644 --- a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs @@ -11,7 +11,7 @@ namespace CodeCracker.CSharp.Style public class ForInArrayAnalyzer : DiagnosticAnalyzer { internal const string Title = "Use foreach"; - internal const string MessageFormat = "{0}"; + internal const string MessageFormat = "You can use foreach instead of for."; internal const string Category = SupportedCategories.Style; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( @@ -45,6 +45,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var semanticModel = context.SemanticModel; var arrayId = semanticModel.GetSymbolInfo(arrayAccessor.Expression).Symbol; if (arrayId == null) return; + if (!IsEnumerable(arrayId)) return; var forVariable = forStatement.Declaration.Variables.First(); var literalExpression = forVariable.Initializer.Value as LiteralExpressionSyntax; if (literalExpression == null || !literalExpression.IsKind(SyntaxKind.NumericLiteralExpression)) return; @@ -76,8 +77,27 @@ where controlVarId.Equals(initSymbol) where arrayId.Equals(someArrayInit) select arrayId).ToList(); if (!arrayAccessorSymbols.Any()) return; - var diagnostic = Diagnostic.Create(Rule, forStatement.ForKeyword.GetLocation(), "You can use foreach instead of for."); + var diagnostic = Diagnostic.Create(Rule, forStatement.ForKeyword.GetLocation()); context.ReportDiagnostic(diagnostic); } + + private static bool IsEnumerable(ISymbol arrayId) + { + var type = (arrayId as ILocalSymbol)?.Type + ?? (arrayId as IParameterSymbol)?.Type + ?? (arrayId as IPropertySymbol)?.Type + ?? (arrayId as IFieldSymbol)?.Type; + if (type == null) return false; + if (type.AllInterfaces.Any(i => i.ToString() == "System.Collections.IEnumerable")) return true; + var allReturnTypes = type.GetMembers("GetEnumerator") + .Select(m => m as IMethodSymbol) + .Where(m => m != null) + .Select(m => m.ReturnType).ToList(); + if (allReturnTypes.Any(t => t.ToString() == "System.Collections.IEnumerator")) return true; + var hasGetEnumerator = allReturnTypes.SelectMany(t => t.AllInterfaces) + .Distinct() + .Any(i => i.ToString() == "System.Collections.IEnumerator"); + return hasGetEnumerator; + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs index e7caab9e9..6d1afa994 100644 --- a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs @@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis; using System.Threading.Tasks; using Xunit; +using System; namespace CodeCracker.Test.CSharp.Style { @@ -569,7 +570,6 @@ public int Foo(int[] array) } } }"; - const string fixtest = @" namespace ConsoleApplication1 { @@ -598,7 +598,7 @@ public int Foo(int[] array) [Fact] public async Task WhenThereIsAnAssignmentDoesNotCreateDiagnostic() { - var source = @" + const string source = @" class Baz { void Foo() @@ -610,8 +610,152 @@ void Foo() buffer[i] = 1; } } -}".WrapInCSharpMethod(); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoreIfNotEnumerable() + { + const string source = @" +class Foo +{ + void Bar() + { + var list = new MyList(); + for (int i = 0; i < list.Count; i++) + { + var item = list[i]; + } + } +} +class MyList +{ + public int Count => 1; + public int this[int index] => 1; +}"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task IfHasMethodGetEnumeratorReturningIEnumeratorCreatesDiagnostic() + { + const string source = @" +class Foo +{ + void Bar() + { + var list = new MyList(); + for (int i = 0; i < list.Count; i++) + { + var item = list[i]; + } + } +} +class MyList +{ + public int Count => 1; + public int this[int index] => 1; + public System.Collections.IEnumerator GetEnumerator() + { + yield return 1; + } +}"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.ForInArray.ToDiagnosticId(), + Message = ForInArrayAnalyzer.MessageFormat, + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 9) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task IfHasMethodGetEnumeratorReturningClassThatImplementsIEnumeratorCreatesDiagnostic() + { + const string source = @" +class Foo +{ + void Bar() + { + var list = new MyList(); + for (int i = 0; i < list.Count; i++) + { + var item = list[i]; + } + } +} +public class MyEnumerator : System.Collections.IEnumerator +{ + public object Current => 1; + public bool MoveNext() { } + public void Reset() { } +} +class MyList +{ + public int Count => 1; + public int this[int index] => 1; + public MyEnumerator GetEnumerator() + { + yield return 1; + } +}"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.ForInArray.ToDiagnosticId(), + Message = ForInArrayAnalyzer.MessageFormat, + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 9) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task WithFieldCreatesDiagnostic() + { + var source = @" +private int[] array = new [] {1}; +public int Foo() +{ + for (var i = 0; i < array.Length; i++) + { + var item = array[i]; + } +}".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.ForInArray.ToDiagnosticId(), + Message = "You can use foreach instead of for.", + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 5) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task WithPropertyCreatesDiagnostic() + { + var source = @" +public int[] Foo +{ + set + { + for (var i = 0; i < value.Length; i++) + { + var item = value[i]; + } + } +} +}".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.ForInArray.ToDiagnosticId(), + Message = "You can use foreach instead of for.", + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 9) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } \ No newline at end of file From f0492a362f220a982069e3792d82ffd569047b68 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 1 Feb 2016 01:13:03 -0200 Subject: [PATCH 123/358] Fix explicit property when making autoprop Closes #687 --- .../Extensions/CSharpAnalyzerExtensions.cs | 30 +- .../Style/SwitchToAutoPropCodeFixProvider.cs | 64 +++- .../Extensions/AnalyzerExtensions.cs | 19 ++ .../Style/SwitchToAutoPropTests.cs | 305 ++++++++++++++++++ 4 files changed, 415 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index e0ea39836..0d82e7692 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -459,6 +459,9 @@ public static SyntaxNode FirstAncestorOfKind(this SyntaxNode node, params Syntax return null; } + public static TNode FirstAncestorOfKind(this SyntaxNode node, params SyntaxKind[] kinds) where TNode : SyntaxNode => + (TNode)FirstAncestorOfKind(node, kinds); + public static IEnumerable OfKind(this IEnumerable nodes, SyntaxKind kind) where TNode : SyntaxNode { foreach (var node in nodes) @@ -679,5 +682,30 @@ public static SyntaxToken WithoutTrivia(this SyntaxToken token) var newToken = token.ReplaceTrivia(trivia, (o, _) => default(SyntaxTrivia)); return newToken; } + + private static readonly SyntaxTokenList publicToken = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); + private static readonly SyntaxTokenList privateToken = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)); + private static readonly SyntaxTokenList protectedToken = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)); + private static readonly SyntaxTokenList protectedInternalToken = SyntaxFactory.TokenList( + SyntaxFactory.Token(SyntaxKind.ProtectedKeyword), SyntaxFactory.Token(SyntaxKind.InternalKeyword)); + private static readonly SyntaxTokenList internalToken = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.InternalKeyword)); + public static SyntaxTokenList GetTokens(this Accessibility accessibility) + { + switch (accessibility) + { + case Accessibility.Public: + return publicToken; + case Accessibility.Private: + return privateToken; + case Accessibility.Protected: + return protectedToken; + case Accessibility.Internal: + return internalToken; + case Accessibility.ProtectedAndInternal: + return protectedInternalToken; + default: + throw new NotSupportedException(); + } + } } -} \ No newline at end of file +} diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs index 3b0eb03dc..093b9e7de 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs @@ -4,8 +4,10 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Simplification; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -44,16 +46,30 @@ public async static Task MakeAutoPropertyAsync(Document document, Synt var returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; var variableDeclarator = (VariableDeclaratorSyntax)returnIdentifierSymbol.DeclaringSyntaxReferences.First().GetSyntax(); var fieldDeclaration = variableDeclarator.FirstAncestorOfType(); + var fieldSymbol = (IFieldSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator); + var propertySymbol = semanticModel.GetDeclaredSymbol(property); root = root.TrackNodes(returnIdentifier, fieldDeclaration, property); document = document.WithSyntaxRoot(root); root = await document.GetSyntaxRootAsync(cancellationToken); semanticModel = await document.GetSemanticModelAsync(cancellationToken); returnIdentifier = root.GetCurrentNode(returnIdentifier); returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; - var newProperty = GetSimpleProperty(property, variableDeclarator) + var newProperty = GetSimpleProperty(property, variableDeclarator); + Solution newSolution; + if (!propertySymbol.ExplicitInterfaceImplementations.Any()) + { + newProperty = newProperty.WithModifiers(propertySymbol.DeclaredAccessibility + .GetMinimumCommonAccessibility(fieldSymbol.DeclaredAccessibility) + .GetTokens()); + newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, returnIdentifierSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); + } + else + { + newSolution = await RenameSymbolAndKeepExplicitPropertiesBoundAsync(document.Project.Solution, property.Identifier.ValueText, returnIdentifierSymbol, propertySymbol, cancellationToken); + } + newProperty = newProperty .WithTriviaFrom(property) .WithAdditionalAnnotations(Formatter.Annotation); - var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, returnIdentifierSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken); document = newSolution.GetDocument(document.Id); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); root = root.InsertNodesAfter(root.GetCurrentNode(property), new[] { newProperty }); @@ -72,6 +88,50 @@ public async static Task MakeAutoPropertyAsync(Document document, Synt return document.Project.Solution; } + private static async Task RenameSymbolAndKeepExplicitPropertiesBoundAsync(Solution solution, string propertyName, ISymbol returnIdentifierSymbol, IPropertySymbol propertySymbol, CancellationToken cancellationToken) + { + var interfaceType = propertySymbol.ExplicitInterfaceImplementations.First().ContainingType; + var references = await SymbolFinder.FindReferencesAsync(returnIdentifierSymbol, solution, cancellationToken).ConfigureAwait(false); + var documentGroups = references.SelectMany(r => r.Locations).GroupBy(loc => loc.Document); + var newSolution = solution; + var propertyIdentifier = SyntaxFactory.IdentifierName(propertyName); + foreach (var documentGroup in documentGroups) + { + var referencingDocument = documentGroup.Key; + referencingDocument = newSolution.GetDocument(referencingDocument.Id); + var referencingDocRoot = await referencingDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var diagnosticNodes = documentGroup.Select(referenceLocation => referencingDocRoot.FindNode(referenceLocation.Location.SourceSpan)).ToList(); + referencingDocRoot = referencingDocRoot.TrackNodes(diagnosticNodes); + foreach (var diagnosticNode in diagnosticNodes) + { + var trackedNode = referencingDocRoot.GetCurrentNode(diagnosticNode); + var identifierName = (IdentifierNameSyntax)trackedNode; + var memberAccess = identifierName.FirstAncestorOfKind(SyntaxKind.SimpleMemberAccessExpression); + if (memberAccess != null && memberAccess.Name == identifierName) + { + var newMemberAccess = memberAccess.WithExpression( + SyntaxFactory.ParenthesizedExpression( + SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(interfaceType.ToString()), memberAccess.Expression))) + .WithName(propertyIdentifier) + .WithAdditionalAnnotations(Simplifier.Annotation); + referencingDocRoot = referencingDocRoot.ReplaceNode(memberAccess, newMemberAccess); + } + else + { + var newMemberAccess = SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.ParenthesizedExpression( + SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(interfaceType.ToString()), SyntaxFactory.ParseExpression("this"))), + propertyIdentifier) + .WithAdditionalAnnotations(Simplifier.Annotation); + referencingDocRoot = referencingDocRoot.ReplaceNode(trackedNode, newMemberAccess); + } + } + newSolution = newSolution.WithDocumentSyntaxRoot(referencingDocument.Id, referencingDocRoot); + } + return newSolution; + } + private static PropertyDeclarationSyntax GetSimpleProperty(PropertyDeclarationSyntax property, VariableDeclaratorSyntax variableDeclarator) { var simpleGetSetPropetie = property.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { diff --git a/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs b/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs index 8842af323..af2272c40 100644 --- a/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs +++ b/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs @@ -147,5 +147,24 @@ public static IEnumerable GetAllContainingTypes(this ISymbol s symbol = symbol.ContainingType; } } + + public static Accessibility GetMinimumCommonAccessibility(this Accessibility accessibility, Accessibility otherAccessibility) + { + if (accessibility == otherAccessibility || otherAccessibility == Accessibility.Private) return accessibility; + if (otherAccessibility == Accessibility.Public) return Accessibility.Public; + switch (accessibility) + { + case Accessibility.Private: + return otherAccessibility; + case Accessibility.ProtectedAndInternal: + case Accessibility.Protected: + case Accessibility.Internal: + return Accessibility.ProtectedAndInternal; + case Accessibility.Public: + return Accessibility.Public; + default: + throw new NotSupportedException(); + } + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index 5cac1162d..da9886e5b 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -568,5 +568,310 @@ public string Text ".WrapInCSharpClass(); await VerifyCSharpFixAllAsync(source, expected); } + + [Fact] + public async Task FixExplicitPropertyWithReferenceOnSameTime() + { + const string source = @" +interface IFoo +{ + int P { get; set; } +} +class Foo : IFoo +{ + public Foo() + { + p = 1; + } + private int p; + int IFoo.P + { + get + { + return p; + } + set + { + p = value; + } + } +}"; + const string expected = @" +interface IFoo +{ + int P { get; set; } +} +class Foo : IFoo +{ + public Foo() + { + ((IFoo)this).P = 1; + } + int IFoo.P { get; set; } +}"; + await VerifyCSharpFixAllAsync(source, expected); + } + + [Fact] + public async Task FixExplicitPropertyWithReferenceOnDifferentType() + { + const string source = @" +interface IFoo +{ + int P { get; set; } +} +class Foo : IFoo +{ + public int p; + int IFoo.P + { + get + { + return p; + } + set + { + p = value; + } + } +} +class Bar +{ + static void Baz() + { + var foo = new Foo(); + foo.p = 1; + } +}"; + const string expected = @" +interface IFoo +{ + int P { get; set; } +} +class Foo : IFoo +{ + int IFoo.P { get; set; } +} +class Bar +{ + static void Baz() + { + var foo = new Foo(); + ((IFoo)foo).P = 1; + } +}"; + await VerifyCSharpFixAllAsync(source, expected); + } + + [Fact] + public async Task FixAllExplicitPropertyWithReferenceOnDifferentNamespace() + { + const string source1 = @" +using Ns1; +namespace Ns1 +{ + interface IFoo + { + int P { get; set; } + } +} +namespace Ns2 +{ + class Foo : IFoo + { + public int p; + int IFoo.P + { + get + { + return p; + } + set + { + p = value; + } + } + } +}"; + const string source2 = @" +using Ns2; +namespace Ns3 +{ + class Bar + { + static void Baz() + { + var foo = new Foo(); + foo.p = 1; + } + } +}"; + const string expected1 = @" +using Ns1; +namespace Ns1 +{ + interface IFoo + { + int P { get; set; } + } +} +namespace Ns2 +{ + class Foo : IFoo + { + int IFoo.P { get; set; } + } +}"; + const string expected2 = @" +using Ns2; +namespace Ns3 +{ + class Bar + { + static void Baz() + { + var foo = new Foo(); + ((Ns1.IFoo)foo).P = 1; + } + } +}"; + await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { expected1, expected2 }); + } + + [Fact] + public async Task FixAllExplicitPropertyWithReferenceOnDifferentNamespaceWithImportedNs() + { + const string source1 = @" +using Ns1; +namespace Ns1 +{ + interface IFoo + { + int P { get; set; } + } +} +namespace Ns2 +{ + class Foo : IFoo + { + public int p; + int IFoo.P + { + get + { + return p; + } + set + { + p = value; + } + } + } +}"; + const string source2 = @" +using Ns1; +using Ns2; +namespace Ns3 +{ + class Bar + { + static void Baz() + { + var foo = new Foo(); + foo.p = 1; + } + } +}"; + const string expected1 = @" +using Ns1; +namespace Ns1 +{ + interface IFoo + { + int P { get; set; } + } +} +namespace Ns2 +{ + class Foo : IFoo + { + int IFoo.P { get; set; } + } +}"; + const string expected2 = @" +using Ns1; +using Ns2; +namespace Ns3 +{ + class Bar + { + static void Baz() + { + var foo = new Foo(); + ((IFoo)foo).P = 1; + } + } +}"; + await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { expected1, expected2 }); + } + + [Fact] + public async Task FixAllWithNonPublicProperty() + { + const string source1 = @" +namespace Ns1 +{ + class Foo + { + public int p; + private int P + { + get + { + return p; + } + set + { + p = value; + } + } + } +}"; + const string source2 = @" +using Ns1; +namespace Ns2 +{ + class Bar + { + static void Baz() + { + var foo = new Foo(); + foo.p = 1; + } + } +}"; + const string expected1 = @" +namespace Ns1 +{ + class Foo + { + public int P { get; set; } + } +}"; + const string expected2 = @" +using Ns1; +namespace Ns2 +{ + class Bar + { + static void Baz() + { + var foo = new Foo(); + foo.P = 1; + } + } +}"; + await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { expected1, expected2 }); + } } } \ No newline at end of file From 1ff1b66cb96fb2e3d14850699c2919f7ee44238d Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 1 Feb 2016 14:54:06 -0200 Subject: [PATCH 124/358] Bump version to 1.0.0-rc6 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 78ace280a..8c461be91 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index c0c9fc48f..d248171e9 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.0-rc5 + 1.0.0-rc6 CodeCracker giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index 2ed1b4409..9bbcf16e1 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.12")] +[assembly: AssemblyFileVersion("1.0.0.13")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index bfafb3f36..9de77c8de 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.0-rc5 + 1.0.0-rc6 CodeCracker giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index 26ab9c79c..ae8fadbe6 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.12")] +[assembly: AssemblyFileVersion("1.0.0.13")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] [assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index bb59f4019..baa76ca16 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index ace4918c5..6571d3534 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.0-rc5 + 1.0.0-rc6 CodeCracker giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 81d6155cc..533dd3d92 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - + diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index d5f57151e..0440a3f4b 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.12")] +[assembly: AssemblyFileVersion("1.0.0.13")] diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index 13fdcd813..9b9d5375b 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.12")] +[assembly: AssemblyFileVersion("1.0.0.13")] diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index 4780e9294..cb4bb031a 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - + From e71dac0fe8ef80c7c39097d56117281decf17078 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 1 Feb 2016 15:17:48 -0200 Subject: [PATCH 125/358] Update changelog to 1.0.0-rc6 --- CHANGELOG.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 252682423..b3b084bcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,58 @@ # Change Log +## [v1.0.0-rc6](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc6) (2016-02-01) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc5...v1.0.0-rc6) + +**Implemented enhancements:** + +- CC0031 must not fire when Null-check is outside of a try block [\#672](https://github.com/code-cracker/code-cracker/issues/672) +- Add exceptions to CC0068 depending on the method attribute [\#526](https://github.com/code-cracker/code-cracker/issues/526) + +**Fixed bugs:** + +- BUG: CC0048 \(string interpolation\) when string is split into multiple lines [\#689](https://github.com/code-cracker/code-cracker/issues/689) +- CC0017 wrong change with explicitly implemented properties, but can be fixed [\#687](https://github.com/code-cracker/code-cracker/issues/687) +- CC0006 should be checking if for-looped array is enumerable by foreach [\#684](https://github.com/code-cracker/code-cracker/issues/684) +- BUG: CC0006 wrongly tries to convert for into foreach when there would be an assignment to the iteration variable [\#683](https://github.com/code-cracker/code-cracker/issues/683) +- CC0091 MakeMethodStaticCodeFixProvider crashing [\#682](https://github.com/code-cracker/code-cracker/issues/682) +- CC0091 wrongly tries to make static methods in structs [\#681](https://github.com/code-cracker/code-cracker/issues/681) +- BUG: CC0091 \(make static\) changes references incorrectly when used as a method group and in conjunction with another method invocation [\#680](https://github.com/code-cracker/code-cracker/issues/680) +- CC0091 on method Foo does not replace occurences like this.Foo used in delegates [\#677](https://github.com/code-cracker/code-cracker/issues/677) +- ObjectInitializerCodeFixProvider crashes [\#676](https://github.com/code-cracker/code-cracker/issues/676) +- Bug CC0084 should not generate string empty in parameter list in constructor or method [\#669](https://github.com/code-cracker/code-cracker/issues/669) +- CC0022 when theer is ternary operator in using [\#665](https://github.com/code-cracker/code-cracker/issues/665) +- CC0031 should not copy the variable with readonly members [\#663](https://github.com/code-cracker/code-cracker/issues/663) +- BUG on CC0047 \(PropertyPrivateSet\) suggests to make a property set private when the property is already private [\#658](https://github.com/code-cracker/code-cracker/issues/658) +- With more than one constructor, IntroduceFieldFromConstructorCodeFixProvider can replace wrong constructor [\#650](https://github.com/code-cracker/code-cracker/issues/650) +- BUG on CC0057 \(unused parameter\) with named parameters [\#649](https://github.com/code-cracker/code-cracker/issues/649) +- CC0057: Should not try to remove parameters meant to fulfill a delegate contract [\#646](https://github.com/code-cracker/code-cracker/issues/646) +- CC0016 should not copy the variable with readonly members [\#645](https://github.com/code-cracker/code-cracker/issues/645) +- BUG on CC0091 \(MakeMethodStatic\) when a reference to method is used as a method group [\#644](https://github.com/code-cracker/code-cracker/issues/644) +- BUG on CC0043 and CC0092 \(ChangeAnyToAll\) when invocation is negated [\#642](https://github.com/code-cracker/code-cracker/issues/642) +- BUG on CC0043 and CC0092 \(ChangeAnyToAll\) when invocation is in an expression bodied member [\#641](https://github.com/code-cracker/code-cracker/issues/641) +- AD0001 Crash [\#638](https://github.com/code-cracker/code-cracker/issues/638) +- BUG on CC0022 \(disposable not disposed\) fix when there is method chaining [\#630](https://github.com/code-cracker/code-cracker/issues/630) +- New word 'Foramt' in NameOfSymbolDisplayForamt [\#627](https://github.com/code-cracker/code-cracker/issues/627) +- CC0003 is shown even for catches which end with throw [\#626](https://github.com/code-cracker/code-cracker/issues/626) +- CC0001 is shown for variables with type dynamic and object [\#625](https://github.com/code-cracker/code-cracker/issues/625) +- CC0090 when using /// \ [\#624](https://github.com/code-cracker/code-cracker/issues/624) +- Bug: CC0017 not raised when using this [\#623](https://github.com/code-cracker/code-cracker/issues/623) +- CC0052 false positives [\#621](https://github.com/code-cracker/code-cracker/issues/621) +- Bug on CC0029 \(Call GC.SuppressFinalize on dispose\) with expression based methods [\#618](https://github.com/code-cracker/code-cracker/issues/618) +- Removing Option Parameter causes crash [\#617](https://github.com/code-cracker/code-cracker/issues/617) +- BUG on CC0043 and CC0092 \(ChangeAnyToAll\) when invocation has elvis operator [\#613](https://github.com/code-cracker/code-cracker/issues/613) +- When the dispose pattern is used do not raise CC0033 [\#603](https://github.com/code-cracker/code-cracker/issues/603) +- Suggested Nameof fix incorrectly suggests wrong type [\#594](https://github.com/code-cracker/code-cracker/issues/594) + ## [v1.0.0-rc5](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc5) (2015-12-03) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc4...v1.0.0-rc5) +**Implemented enhancements:** + +- CC0091 Know APIs [\#451](https://github.com/code-cracker/code-cracker/issues/451) +- Change CC0001 so that it does not apply to primitives [\#407](https://github.com/code-cracker/code-cracker/issues/407) +- Update all existing code fixes that are doing too much work on RegisterCodeFixesAsync \(VB\) [\#348](https://github.com/code-cracker/code-cracker/issues/348) + **Fixed bugs:** - BUG: UseInvokeMethodToFireEventAnalyzer throwing when method body is null [\#611](https://github.com/code-cracker/code-cracker/issues/611) @@ -22,11 +72,6 @@ - Bug with CC0009 when using the created object in the initialization [\#525](https://github.com/code-cracker/code-cracker/issues/525) - CC0013 Should check for a common type and cast is necessary. [\#521](https://github.com/code-cracker/code-cracker/issues/521) -**Implemented enhancements:** - -- Change CC0001 so that it does not apply to primitives [\#407](https://github.com/code-cracker/code-cracker/issues/407) -- Update all existing code fixes that are doing too much work on RegisterCodeFixesAsync \(VB\) [\#348](https://github.com/code-cracker/code-cracker/issues/348) - ## [v1.0.0-rc4](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc4) (2015-11-02) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc3...v1.0.0-rc4) From a553d66b5503066084438784fad2deacab91c966 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 1 Feb 2016 18:47:39 -0200 Subject: [PATCH 126/358] Update package names to solve error 500 This the error we were getting: Failed to process request. 'The title of your package, 'CodeCracker', is similar to the ID of an existing package, which can cause confusion with our users. Please modify the title of your package and try uploading again.'. The remote server returned an error: (500) Internal Server Error.. --- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index d248171e9..fb1a57fee 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -3,7 +3,7 @@ codecracker.CSharp 1.0.0-rc6 - CodeCracker + CodeCracker for C# giggio,elemarjr,carloscds giggio,elemarjr,carloscds https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index 9de77c8de..e34681210 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -3,7 +3,7 @@ codecracker 1.0.0-rc6 - CodeCracker + CodeCracker for C# and VB giggio,elemarjr,carloscds giggio,elemarjr,carloscds https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 6571d3534..4245b4eeb 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -3,7 +3,7 @@ codecracker.VisualBasic 1.0.0-rc6 - CodeCracker + CodeCracker for Visual Basic giggio,elemarjr,carloscds giggio,elemarjr,carloscds https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt From bb585e29b90e5ca753f3d974a71722644a55ba63 Mon Sep 17 00:00:00 2001 From: carloscds Date: Mon, 1 Feb 2016 18:51:36 -0200 Subject: [PATCH 127/358] Fix #701 --- .../CodeCracker/Usage/UnusedParametersAnalyzer.cs | 2 +- .../Usage/RemoveUnusedVariablesTest.cs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs index 9f1071190..a0fdedc2f 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs @@ -122,7 +122,7 @@ private static bool IdentifierRefersToParam(IdentifierNameSyntax iName, Paramete private static bool IsCandidateForRemoval(BaseMethodDeclarationSyntax methodOrConstructor, SemanticModel semanticModel) { - if (methodOrConstructor.Modifiers.Any(m => m.ValueText == "partial" || m.ValueText == "override" || m.ValueText == "abstract") + if (methodOrConstructor.Modifiers.Any(m => m.ValueText == "partial" || m.ValueText == "override" || m.ValueText == "abstract" || m.ValueText == "extern") || !methodOrConstructor.ParameterList.Parameters.Any()) return false; var method = methodOrConstructor as MethodDeclarationSyntax; diff --git a/test/CSharp/CodeCracker.Test/Usage/RemoveUnusedVariablesTest.cs b/test/CSharp/CodeCracker.Test/Usage/RemoveUnusedVariablesTest.cs index 7d9c05d16..7732bb536 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RemoveUnusedVariablesTest.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RemoveUnusedVariablesTest.cs @@ -9,6 +9,20 @@ public class RemoveUnusedVariablesTest : CodeFixVerifier { protected override CodeFixProvider GetCodeFixProvider() => new RemoveUnusedVariablesCodeFixProvider(); + public async Task UsingExternNoDiagnostics() + { + const string source = @" + using System; + using System.Runtime.InteropServices; + + class TypeName + { + [DllImport(""wininet.dll"", SetLastError = true)] + public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength); + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WhenVariableIsAssignedButItsValueIsNeverUsedShouldCreateDiagnostics() { From 85fdf23f714e12f12f0e9786bb96407b70f95e73 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 29 Jan 2016 23:19:25 -0200 Subject: [PATCH 128/358] Fix nested interpolations Closes #690 --- src/CSharp/CodeCracker/CodeCracker.csproj | 1 + .../Style/ConsoleWriteLineCodeFixProvider.cs | 2 +- .../Style/StringFormatCodeFixProvider.cs | 17 +++-- .../Style/StringFormatFixAllProvider.cs | 67 +++++++++++++++++++ .../Style/StringFormatTests.cs | 30 +++++++++ 5 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index ebbcb04d4..3a914dbb4 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -81,6 +81,7 @@ + diff --git a/src/CSharp/CodeCracker/Style/ConsoleWriteLineCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/ConsoleWriteLineCodeFixProvider.cs index e84754466..a77edc2b5 100644 --- a/src/CSharp/CodeCracker/Style/ConsoleWriteLineCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/ConsoleWriteLineCodeFixProvider.cs @@ -31,7 +31,7 @@ private async static Task MakeStringInterpolationAsync(Document docume { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var invocationExpression = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var newStringInterpolation = await StringFormatCodeFixProvider.CreateNewStringInterpolationAsync(document, invocationExpression, cancellationToken); + var newStringInterpolation = StringFormatCodeFixProvider.CreateNewStringInterpolation(invocationExpression); var newArgumentList = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList().Add(SyntaxFactory.Argument(newStringInterpolation))); var newRoot = root.ReplaceNode(invocationExpression.ArgumentList, newArgumentList); var newDocument = document.WithSyntaxRoot(newRoot); diff --git a/src/CSharp/CodeCracker/Style/StringFormatCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/StringFormatCodeFixProvider.cs index 0c7df73b1..9772b3a3a 100644 --- a/src/CSharp/CodeCracker/Style/StringFormatCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/StringFormatCodeFixProvider.cs @@ -19,7 +19,7 @@ public class StringFormatCodeFixProvider : CodeFixProvider public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.StringFormat.ToDiagnosticId()); - public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => StringFormatFixAllProvider.Instance; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -32,16 +32,21 @@ private async static Task MakeStringInterpolationAsync(Document docume { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var invocationExpression = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var newStringInterpolation = await CreateNewStringInterpolationAsync(document, invocationExpression, cancellationToken); - var newRoot = root.ReplaceNode(invocationExpression, newStringInterpolation); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); + var newRoot = CreateNewStringInterpolation(root, invocationExpression); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; } - public static async Task CreateNewStringInterpolationAsync(Document document, InvocationExpressionSyntax invocationExpression, CancellationToken cancellationToken) + public static SyntaxNode CreateNewStringInterpolation(SyntaxNode root, InvocationExpressionSyntax invocationExpression) + { + var newStringInterpolation = CreateNewStringInterpolation(invocationExpression); + var newRoot = root.ReplaceNode(invocationExpression, newStringInterpolation); + return newRoot; + } + + public static InterpolatedStringExpressionSyntax CreateNewStringInterpolation(InvocationExpressionSyntax invocationExpression) { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var memberSymbol = semanticModel.GetSymbolInfo(invocationExpression.Expression).Symbol; var argumentList = invocationExpression.ArgumentList; var arguments = argumentList.Arguments; var formatLiteral = (LiteralExpressionSyntax)arguments[0].Expression; diff --git a/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs b/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs new file mode 100644 index 000000000..1c3416c81 --- /dev/null +++ b/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs @@ -0,0 +1,67 @@ +using CodeCracker.Properties; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; +using System.Threading.Tasks; + +namespace CodeCracker.CSharp.Style +{ + public sealed class StringFormatFixAllProvider : FixAllProvider + { + private static readonly SyntaxAnnotation stringFormatAnnotation = new SyntaxAnnotation(nameof(StringFormatFixAllProvider)); + private StringFormatFixAllProvider() { } + public static readonly StringFormatFixAllProvider Instance = new StringFormatFixAllProvider(); + public override Task GetFixAsync(FixAllContext fixAllContext) + { + switch (fixAllContext.Scope) + { + case FixAllScope.Document: + return Task.FromResult(CodeAction.Create(Resources.StringFormatCodeFixProvider_Title, + async ct => fixAllContext.Document.WithSyntaxRoot(await GetFixedDocumentAsync(fixAllContext, fixAllContext.Document).ConfigureAwait(false)))); + case FixAllScope.Project: + return Task.FromResult(CodeAction.Create(Resources.StringFormatCodeFixProvider_Title, + ct => GetFixedProjectAsync(fixAllContext, fixAllContext.Project))); + case FixAllScope.Solution: + return Task.FromResult(CodeAction.Create(Resources.StringFormatCodeFixProvider_Title, + ct => GetFixedSolutionAsync(fixAllContext))); + } + return null; + } + + private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) + { + var newSolution = fixAllContext.Solution; + foreach (var projectId in newSolution.ProjectIds) + newSolution = await GetFixedProjectAsync(fixAllContext, newSolution.GetProject(projectId)).ConfigureAwait(false); + return newSolution; + } + + private async static Task GetFixedProjectAsync(FixAllContext fixAllContext, Project project) + { + var solution = project.Solution; + var newDocuments = project.Documents.ToDictionary(d => d.Id, d => GetFixedDocumentAsync(fixAllContext, d)); + await Task.WhenAll(newDocuments.Values).ConfigureAwait(false); + foreach (var newDoc in newDocuments) + solution = solution.WithDocumentSyntaxRoot(newDoc.Key, newDoc.Value.Result); + return solution; + } + + private async static Task GetFixedDocumentAsync(FixAllContext fixAllContext, Document document) + { + var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); + var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var nodes = diagnostics.Select(d => root.FindNode(d.Location.SourceSpan, getInnermostNodeForTie: true).FirstAncestorOrSelfOfType()).Where(n => !n.IsMissing).ToList(); + var newRoot = root.ReplaceNodes(nodes, (original, rewritten) => rewritten.WithAdditionalAnnotations(stringFormatAnnotation)); + while (true) + { + var annotatedNodes = newRoot.GetAnnotatedNodes(stringFormatAnnotation); + var node = annotatedNodes.FirstOrDefault(); + if (node == null) break; + newRoot = StringFormatCodeFixProvider.CreateNewStringInterpolation(newRoot, (InvocationExpressionSyntax)node); + } + return newRoot; + } + } +} \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs b/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs index b1e31397d..76ccf4a94 100644 --- a/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs @@ -636,5 +636,35 @@ public async Task FixWithLineBreaksAndStringConcat() var baz = $""{foo + ""baz"" + ""boo""}"";".WrapInCSharpMethod(); await VerifyCSharpFixAsync(source, expected); } + + [Fact] + public async Task NestedStringFormatCreatesDiagnostic() + { + var source = @"var foo = string.Format(""{0}"", string.Format(""{0}"", 1 ) );".WrapInCSharpMethod(); + var expected1 = new DiagnosticResult + { + Id = DiagnosticId.StringFormat.ToDiagnosticId(), + Message = StringFormatAnalyzer.MessageFormat.ToString(), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 27) } + }; + var expected2 = new DiagnosticResult + { + Id = DiagnosticId.StringFormat.ToDiagnosticId(), + Message = StringFormatAnalyzer.MessageFormat.ToString(), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 48) } + }; + await VerifyCSharpDiagnosticAsync(source, expected1, expected2); + } + + [Fact] + public async Task FixAllStringInterpolations() + { +var foo = $"{$"{1}"}"; + var source = @"var foo = string.Format(""{0}"", string.Format(""{0}"", 1 ) );".WrapInCSharpMethod(); + var expected = @"var foo = $""{$""{1}""}"";".WrapInCSharpMethod(); + await VerifyCSharpFixAllAsync(source, expected); + } } } \ No newline at end of file From 21208c047cedab28a05d98d22982f7b2e6cf6b3b Mon Sep 17 00:00:00 2001 From: Vossekop Date: Tue, 2 Feb 2016 21:39:45 +0100 Subject: [PATCH 129/358] GetEnumerator method returning an IEnumerator is now ignored in CC00091 --- .../Design/MakeMethodStaticAnalyzer.cs | 8 +++- .../Design/MakeMethodStaticTests.cs | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs index eb128c92a..d8dc98556 100644 --- a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs @@ -79,12 +79,13 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) if (IsTestMethod(method, methodSymbol)) return; if (IsWebFormsMethod(methodSymbol)) return; + if (IsGetEnumerator(methodSymbol)) return; var diagnostic = Diagnostic.Create(Rule, method.Identifier.GetLocation(), method.Identifier.ValueText); context.ReportDiagnostic(diagnostic); } - private static readonly string[] webFormsMethods = new string[] { + private static readonly string[] webFormsMethods = { "Application_AuthenticateRequest", "Application_BeginRequest", "Application_End", "Application_EndRequest", "Application_Error", "Application_Start", @@ -95,6 +96,11 @@ private static bool IsWebFormsMethod(IMethodSymbol methodSymbol) return (methodSymbol.ContainingType.AllBaseTypes().Any(t => t.ToString() == "System.Web.HttpApplication")); } + private static bool IsGetEnumerator(IMethodSymbol methodSymbol) + { + return methodSymbol.Name == "GetEnumerator" && methodSymbol.ReturnType.Name == "IEnumerator"; + } + private static bool IsTestMethod(MethodDeclarationSyntax method, IMethodSymbol methodSymbol) { var result = false; diff --git a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs index cc980214d..cafcd4950 100644 --- a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs @@ -1023,5 +1023,44 @@ public static void N() { } }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task IgnoreForGetEnumerator() + { + const string source = @" +class Foo +{ + public System.Collections.IEnumerator GetEnumerator() + { + yield return 1; + yield return 2; + } +}"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task ReportForGetEnumeratorNotReturningIEnumerator() + { + const string source = @" +class Foo +{ + public void GetEnumerator() + { + N(); + } + + public static void N() { } +}"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.MakeMethodStatic.ToDiagnosticId(), + Message = string.Format(MakeMethodStaticAnalyzer.MessageFormat, "GetEnumerator"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } \ No newline at end of file From 33b02e080146da34001b160a4aaa7b659c2d3103 Mon Sep 17 00:00:00 2001 From: "coolrunr@drautage.com" Date: Sat, 6 Feb 2016 18:44:20 -0600 Subject: [PATCH 130/358] Test accessibility when determining if field can be read only. --- .../Usage/ReadonlyFieldAnalyzer.cs | 9 +++++ .../Usage/ReadonlyFieldTests.cs | 34 ++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index cf4e39b76..97d3ebd64 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -96,6 +96,7 @@ private static void VerifyVariable(Dictionary GetTypesInRoot(SyntaxNode root) { var types = new List(); diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index ec7e2aaf8..b7fb708b6 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -804,10 +804,10 @@ public void Foo() await VerifyCSharpHasNoDiagnosticsAsync(source1, source2); } - [Fact] - public async Task FieldsAssignedOnLambdaDoesNotCreateDiagnostic() - { - const string source = @" + [Fact] + public async Task FieldsAssignedOnLambdaDoesNotCreateDiagnostic() + { + const string source = @" namespace ConsoleApplication1 { internal class Test @@ -820,7 +820,31 @@ public Test() } } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task VariableInitializerDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class A + { + public int X; + + public A() + { + X = 5; + } + } + + static void B() + { + var c = new A { X = 7 }; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); } } } From 96249db8506eb9c60a1b2cece7c6598bcbbab05e Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 8 Feb 2016 17:39:50 -0200 Subject: [PATCH 131/358] Keep existing modifiers when making an autoprop Closes #699 --- .../Style/SwitchToAutoPropAnalyzer.cs | 6 +- .../Style/SwitchToAutoPropCodeFixProvider.cs | 70 +++++++++++++------ .../Style/SwitchToAutoPropTests.cs | 28 ++++++++ 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs index 87dd2f577..a51c2dff6 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropAnalyzer.cs @@ -56,13 +56,13 @@ private static void AnalyzeProperty(SyntaxNodeAnalysisContext context, bool canH ((MemberAccessExpressionSyntax)getterReturn.Expression).Expression is ThisExpressionSyntax ? ((MemberAccessExpressionSyntax)getterReturn.Expression).Name : getterReturn.Expression) as IdentifierNameSyntax; if (returnIdentifier == null) return; var semanticModel = context.SemanticModel; - var returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; - if (returnIdentifierSymbol == null) return; + var fieldSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; + if (fieldSymbol == null) return; var assignmentLeftIdentifier = (setterAssignmentExpression.Left is MemberAccessExpressionSyntax && ((MemberAccessExpressionSyntax)setterAssignmentExpression.Left).Expression is ThisExpressionSyntax ? ((MemberAccessExpressionSyntax)setterAssignmentExpression.Left).Name : setterAssignmentExpression.Left) as IdentifierNameSyntax; if (assignmentLeftIdentifier == null) return; var assignmentLeftIdentifierSymbol = semanticModel.GetSymbolInfo(assignmentLeftIdentifier).Symbol; - if (!assignmentLeftIdentifierSymbol.Equals(returnIdentifierSymbol)) return; + if (!assignmentLeftIdentifierSymbol.Equals(fieldSymbol)) return; var assignmentRightIdentifier = setterAssignmentExpression.Right as IdentifierNameSyntax; if (assignmentRightIdentifier == null) return; if (assignmentRightIdentifier.Identifier.Text != "value") return; diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs index 093b9e7de..025187f54 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs @@ -42,47 +42,41 @@ public async static Task MakeAutoPropertyAsync(Document document, Synt { var semanticModel = await document.GetSemanticModelAsync(cancellationToken); var getterReturn = (ReturnStatementSyntax)property.AccessorList.Accessors.First(a => a.Keyword.ValueText == "get").Body.Statements.First(); - var returnIdentifier = (IdentifierNameSyntax)(getterReturn.Expression is MemberAccessExpressionSyntax ? ((MemberAccessExpressionSyntax)getterReturn.Expression).Name : getterReturn.Expression); - var returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; - var variableDeclarator = (VariableDeclaratorSyntax)returnIdentifierSymbol.DeclaringSyntaxReferences.First().GetSyntax(); + var returnIdentifier = (IdentifierNameSyntax)(getterReturn.Expression is MemberAccessExpressionSyntax + ? ((MemberAccessExpressionSyntax)getterReturn.Expression).Name + : getterReturn.Expression); + var fieldSymbol = (IFieldSymbol)semanticModel.GetSymbolInfo(returnIdentifier).Symbol; + var variableDeclarator = (VariableDeclaratorSyntax)fieldSymbol.DeclaringSyntaxReferences.First().GetSyntax(); var fieldDeclaration = variableDeclarator.FirstAncestorOfType(); - var fieldSymbol = (IFieldSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator); var propertySymbol = semanticModel.GetDeclaredSymbol(property); root = root.TrackNodes(returnIdentifier, fieldDeclaration, property); document = document.WithSyntaxRoot(root); root = await document.GetSyntaxRootAsync(cancellationToken); semanticModel = await document.GetSemanticModelAsync(cancellationToken); returnIdentifier = root.GetCurrentNode(returnIdentifier); - returnIdentifierSymbol = semanticModel.GetSymbolInfo(returnIdentifier).Symbol; - var newProperty = GetSimpleProperty(property, variableDeclarator); + fieldSymbol = (IFieldSymbol)semanticModel.GetSymbolInfo(returnIdentifier).Symbol; + var newProperty = CreateAutoProperty(property, variableDeclarator, fieldSymbol, propertySymbol); Solution newSolution; - if (!propertySymbol.ExplicitInterfaceImplementations.Any()) + if (IsExplicityImplementation(propertySymbol)) { - newProperty = newProperty.WithModifiers(propertySymbol.DeclaredAccessibility - .GetMinimumCommonAccessibility(fieldSymbol.DeclaredAccessibility) - .GetTokens()); - newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, returnIdentifierSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); + newSolution = await RenameSymbolAndKeepExplicitPropertiesBoundAsync(document.Project.Solution, property.Identifier.ValueText, fieldSymbol, propertySymbol, cancellationToken); } else { - newSolution = await RenameSymbolAndKeepExplicitPropertiesBoundAsync(document.Project.Solution, property.Identifier.ValueText, returnIdentifierSymbol, propertySymbol, cancellationToken); + newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, fieldSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); } - newProperty = newProperty - .WithTriviaFrom(property) - .WithAdditionalAnnotations(Formatter.Annotation); document = newSolution.GetDocument(document.Id); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - root = root.InsertNodesAfter(root.GetCurrentNode(property), new[] { newProperty }); + root = root.ReplaceNode(root.GetCurrentNode(property), newProperty); var multipleVariableDeclaration = fieldDeclaration.Declaration.Variables.Count > 1; if (multipleVariableDeclaration) { var newfieldDeclaration = fieldDeclaration.WithDeclaration(fieldDeclaration.Declaration.RemoveNode(variableDeclarator, SyntaxRemoveOptions.KeepNoTrivia)); - root = root.RemoveNode(root.GetCurrentNode(property), SyntaxRemoveOptions.KeepNoTrivia); root = root.ReplaceNode(root.GetCurrentNode(fieldDeclaration), newfieldDeclaration); } else { - root = root.RemoveNodes(root.GetCurrentNodes(new SyntaxNode[] { fieldDeclaration, property }), SyntaxRemoveOptions.KeepNoTrivia); + root = root.RemoveNode(root.GetCurrentNode(fieldDeclaration), SyntaxRemoveOptions.KeepNoTrivia); } document = document.WithSyntaxRoot(root); return document.Project.Solution; @@ -132,16 +126,46 @@ private static async Task RenameSymbolAndKeepExplicitPropertiesBoundAs return newSolution; } - private static PropertyDeclarationSyntax GetSimpleProperty(PropertyDeclarationSyntax property, VariableDeclaratorSyntax variableDeclarator) + private static PropertyDeclarationSyntax CreateAutoProperty(PropertyDeclarationSyntax property, VariableDeclaratorSyntax variableDeclarator, + IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol) { - var simpleGetSetPropetie = property.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { + var newProperty = property.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) }))); - return variableDeclarator.Initializer == null ? - simpleGetSetPropetie : - simpleGetSetPropetie.WithInitializer(variableDeclarator.Initializer) + newProperty = variableDeclarator.Initializer == null ? + newProperty : + newProperty.WithInitializer(variableDeclarator.Initializer) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + newProperty = CreatePropertyWithCorrectAccessibility(newProperty, fieldSymbol, propertySymbol); + newProperty = newProperty + .WithTriviaFrom(property) + .WithAdditionalAnnotations(Formatter.Annotation); + return newProperty; } + + private static PropertyDeclarationSyntax CreatePropertyWithCorrectAccessibility(PropertyDeclarationSyntax property, IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol) + { + if (IsExplicityImplementation(propertySymbol)) + return property; + var existingModifiers = property.Modifiers.Where(m => + { + var modifierText = m.ValueText; + return modifierText != "private" + && modifierText != "protected" + && modifierText != "public" + && modifierText != "internal"; + }); + var newAccessibilityModifiers = propertySymbol.DeclaredAccessibility + .GetMinimumCommonAccessibility(fieldSymbol.DeclaredAccessibility) + .GetTokens() + .Aggregate(existingModifiers, (ts, t) => + ts.Any(tt => tt.ValueText == t.ValueText) ? ts : ts.Union(new[] { t }).ToArray()) + .OrderBy(t => t.ValueText); + var newProperty = property.WithModifiers(SyntaxFactory.TokenList(newAccessibilityModifiers)); + return newProperty; + } + + private static bool IsExplicityImplementation(IPropertySymbol propertySymbol) => propertySymbol.ExplicitInterfaceImplementations.Any(); } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index da9886e5b..e1417913f 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -873,5 +873,33 @@ static void Baz() }"; await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { expected1, expected2 }); } + + [Fact] + public async Task FixKeepsStaticModifier() + { + const string source = @" + private int y; + public virtual int Y + { + get { return y; } + set { y = value; } + }"; + const string expected = @"public virtual int Y { get; set; }"; + await VerifyCSharpFixAsync(source.WrapInCSharpClass(), expected.WrapInCSharpClass()); + } + + [Fact] + public async Task FixKeepsVirtualModifier() + { + const string source = @" + private static int y; + public static int Y + { + get { return y; } + set { y = value; } + }"; + const string expected = @"public static int Y { get; set; }"; + await VerifyCSharpFixAsync(source.WrapInCSharpClass(), expected.WrapInCSharpClass()); + } } } \ No newline at end of file From 9128acd4e60ef0451f141ddc0fd58db5fff8cbf6 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 8 Feb 2016 18:39:52 -0200 Subject: [PATCH 132/358] Fix switch to autoprop with self references Closes #702 --- .../Style/SwitchToAutoPropCodeFixProvider.cs | 90 ++++++++++++++----- .../Style/SwitchToAutoPropTests.cs | 35 ++++++++ 2 files changed, 102 insertions(+), 23 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs index 025187f54..b5a2bdfd6 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixProvider.cs @@ -49,40 +49,68 @@ public async static Task MakeAutoPropertyAsync(Document document, Synt var variableDeclarator = (VariableDeclaratorSyntax)fieldSymbol.DeclaringSyntaxReferences.First().GetSyntax(); var fieldDeclaration = variableDeclarator.FirstAncestorOfType(); var propertySymbol = semanticModel.GetDeclaredSymbol(property); - root = root.TrackNodes(returnIdentifier, fieldDeclaration, property); - document = document.WithSyntaxRoot(root); - root = await document.GetSyntaxRootAsync(cancellationToken); - semanticModel = await document.GetSemanticModelAsync(cancellationToken); - returnIdentifier = root.GetCurrentNode(returnIdentifier); - fieldSymbol = (IFieldSymbol)semanticModel.GetSymbolInfo(returnIdentifier).Symbol; + var newRoot = root.TrackNodes(returnIdentifier, fieldDeclaration, property, variableDeclarator); + //cycle + var newDocument = document.WithSyntaxRoot(newRoot); + newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken); var newProperty = CreateAutoProperty(property, variableDeclarator, fieldSymbol, propertySymbol); Solution newSolution; if (IsExplicityImplementation(propertySymbol)) { - newSolution = await RenameSymbolAndKeepExplicitPropertiesBoundAsync(document.Project.Solution, property.Identifier.ValueText, fieldSymbol, propertySymbol, cancellationToken); + semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken); + returnIdentifier = newRoot.GetCurrentNode(returnIdentifier); + fieldSymbol = (IFieldSymbol)semanticModel.GetSymbolInfo(returnIdentifier).Symbol; + newSolution = await RenameSymbolAndKeepExplicitPropertiesBoundAsync(newDocument.Project.Solution, property.Identifier.ValueText, fieldSymbol, propertySymbol, cancellationToken); + newDocument = newSolution.GetDocument(newDocument.Id); + newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(property), newProperty); + newSolution = newSolution.WithDocumentSyntaxRoot(newDocument.Id, newRoot); } else { - newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, fieldSymbol, property.Identifier.ValueText, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); + var currentProperty = newRoot.GetCurrentNode(property); + var type = (TypeDeclarationSyntax)currentProperty.Parent; + var propertyIndex = type.Members.IndexOf(currentProperty); + //Remove the property: this is needed otherwise the rename that happens bellow will not be able to + //correctly redirect the references to the field, as the property will conflict with the name. + //The conflict is specially troublesome for circular references, such as the one that caused the bug #702. + newRoot = newRoot.ReplaceNode(type, type.RemoveNode(currentProperty, SyntaxRemoveOptions.KeepNoTrivia)); + //cycle + newDocument = newDocument.WithSyntaxRoot(newRoot); + newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken); + semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken); + fieldSymbol = (IFieldSymbol)semanticModel.GetDeclaredSymbol(newRoot.GetCurrentNode(variableDeclarator)); + //rename the field: + newSolution = await Renamer.RenameSymbolAsync(newDocument.Project.Solution, fieldSymbol, property.Identifier.ValueText, newDocument.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); + //cycle + newDocument = newSolution.GetDocument(newDocument.Id); + newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + //add the property back: + var currentType = (TypeDeclarationSyntax)newRoot.GetCurrentNode(fieldDeclaration).Parent; + var newMembers = currentType.Members.Insert(propertyIndex, newProperty); + var newType = WithMembers(currentType, newMembers); + newRoot = newRoot.ReplaceNode(currentType, newType); + newSolution = newSolution.WithDocumentSyntaxRoot(newDocument.Id, newRoot); } - document = newSolution.GetDocument(document.Id); - root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - root = root.ReplaceNode(root.GetCurrentNode(property), newProperty); + newDocument = newSolution.GetDocument(newDocument.Id); + newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + newRoot = RemoveField(newRoot, variableDeclarator, fieldDeclaration); + return newSolution.WithDocumentSyntaxRoot(newDocument.Id, newRoot); + } + + private static SyntaxNode RemoveField(SyntaxNode root, VariableDeclaratorSyntax variableDeclarator, FieldDeclarationSyntax fieldDeclaration) + { + var currentField = root.GetCurrentNode(fieldDeclaration); var multipleVariableDeclaration = fieldDeclaration.Declaration.Variables.Count > 1; - if (multipleVariableDeclaration) - { - var newfieldDeclaration = fieldDeclaration.WithDeclaration(fieldDeclaration.Declaration.RemoveNode(variableDeclarator, SyntaxRemoveOptions.KeepNoTrivia)); - root = root.ReplaceNode(root.GetCurrentNode(fieldDeclaration), newfieldDeclaration); - } - else - { - root = root.RemoveNode(root.GetCurrentNode(fieldDeclaration), SyntaxRemoveOptions.KeepNoTrivia); - } - document = document.WithSyntaxRoot(root); - return document.Project.Solution; + root = multipleVariableDeclaration + ? root.ReplaceNode(currentField, fieldDeclaration + .WithDeclaration(fieldDeclaration.Declaration.RemoveNode(variableDeclarator, SyntaxRemoveOptions.KeepNoTrivia))) + : root.RemoveNode(currentField, SyntaxRemoveOptions.KeepNoTrivia); + return root; } - private static async Task RenameSymbolAndKeepExplicitPropertiesBoundAsync(Solution solution, string propertyName, ISymbol returnIdentifierSymbol, IPropertySymbol propertySymbol, CancellationToken cancellationToken) + private static async Task RenameSymbolAndKeepExplicitPropertiesBoundAsync(Solution solution, string propertyName, + ISymbol returnIdentifierSymbol, IPropertySymbol propertySymbol, CancellationToken cancellationToken) { var interfaceType = propertySymbol.ExplicitInterfaceImplementations.First().ContainingType; var references = await SymbolFinder.FindReferencesAsync(returnIdentifierSymbol, solution, cancellationToken).ConfigureAwait(false); @@ -167,5 +195,21 @@ private static PropertyDeclarationSyntax CreatePropertyWithCorrectAccessibility( } private static bool IsExplicityImplementation(IPropertySymbol propertySymbol) => propertySymbol.ExplicitInterfaceImplementations.Any(); + + private static TypeDeclarationSyntax WithMembers(TypeDeclarationSyntax type, SyntaxList newMembers) + { + TypeDeclarationSyntax newType; + var classDeclaration = type as ClassDeclarationSyntax; + if (classDeclaration != null) + { + newType = classDeclaration.WithMembers(newMembers); + } + else + { + var structDeclaration = (StructDeclarationSyntax)type; + newType = structDeclaration.WithMembers(newMembers); + } + return newType; + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs index e1417913f..157d86c37 100644 --- a/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/SwitchToAutoPropTests.cs @@ -901,5 +901,40 @@ public static int Y const string expected = @"public static int Y { get; set; }"; await VerifyCSharpFixAsync(source.WrapInCSharpClass(), expected.WrapInCSharpClass()); } + + [Fact] + public async Task FixUpdatesDerivedClassesCorrectly() + { + const string source = @" +class Point +{ + protected int x; + public virtual int X + { + get + { + return x; + } + set + { + x = value; + } + } +} +class NewPoint : Point +{ + public override int X => (x - 15); +}"; + const string expected = @" +class Point +{ + public virtual int X { get; set; } +} +class NewPoint : Point +{ + public override int X => (base.X - 15); +}"; + await VerifyCSharpFixAsync(source, expected); + } } } \ No newline at end of file From 16d58ee379185986d9e59e4f143716e740e19b40 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 8 Feb 2016 19:46:05 -0200 Subject: [PATCH 133/358] Fix DisposableFieldNotDisposedAnalyzer to ignore static fields Closes #710 --- .../Usage/DisposableFieldNotDisposedAnalyzer.cs | 1 + .../Usage/DisposableFieldNotDisposedTests.cs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs index 3632de804..e38d7959d 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs @@ -43,6 +43,7 @@ private static void AnalyzeField(SymbolAnalysisContext context) { if (context.IsGenerated()) return; var fieldSymbol = (IFieldSymbol)context.Symbol; + if (fieldSymbol.IsStatic) return; if (!fieldSymbol.Type.AllInterfaces.Any(i => i.ToString() == "System.IDisposable") && fieldSymbol.Type.ToString() != "System.IDisposable") return; var fieldSyntaxRef = fieldSymbol.DeclaringSyntaxReferences.FirstOrDefault(); var variableDeclarator = fieldSyntaxRef.GetSyntax() as VariableDeclaratorSyntax; diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs index b66e1f327..123a05cb5 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs @@ -772,6 +772,21 @@ class TypeName : System.IDisposable public void Dispose() => field.Dispose(); } class D : System.IDisposable +{ + public void Dispose() { } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task StaticFieldDoesNotCreateDiagnostic() + { + const string source = @" +static class TypeName +{ + private static D d = new D(); +} +class D : System.IDisposable { public void Dispose() { } }"; From 05cab438e6a1079fcbf2f1512ea17067b59d0599 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 8 Feb 2016 20:15:22 -0200 Subject: [PATCH 134/358] Fixes VirtualMethodOnConstructorAnalyzer to check params Closes #712 Also fixes tests that had incorrect {{ or }}. --- .../VirtualMethodOnConstructorAnalyzer.cs | 20 ++-- .../Usage/VirtualMethodOnConstructorTests.cs | 94 ++++++++++--------- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs b/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs index ce6cfa2eb..f0d2becef 100644 --- a/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/VirtualMethodOnConstructorAnalyzer.cs @@ -40,13 +40,21 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) var ctor = (ConstructorDeclarationSyntax)context.Node; if (ctor.Body == null) return; var methodInvocations = ctor.Body.DescendantNodes().OfType(); - foreach (var method in methodInvocations) + var semanticModel = context.SemanticModel; + foreach (var invocation in methodInvocations) { - var identifier = method.Expression as IdentifierNameSyntax; - if (identifier == null && !method.ToString().StartsWith("this")) return; - var methodDeclaration = context.SemanticModel.GetSymbolInfo(method).Symbol; - if (methodDeclaration == null || !methodDeclaration.IsVirtual) return; - var diagnostic = Diagnostic.Create(Rule, method.GetLocation()); + var identifier = invocation.Expression as IdentifierNameSyntax; + if (identifier == null) + { + if (!invocation.ToString().StartsWith("this.")) return; + } + else + { + if (semanticModel.GetSymbolInfo(identifier).Symbol is IParameterSymbol) return; + } + var methodSymbol = semanticModel.GetSymbolInfo(invocation).Symbol; + if (methodSymbol == null || !methodSymbol.IsVirtual) return; + var diagnostic = Diagnostic.Create(Rule, invocation.GetLocation()); context.ReportDiagnostic(diagnostic); } } diff --git a/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs b/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs index fd76931c3..eb2775560 100644 --- a/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs @@ -11,16 +11,16 @@ public class VirtualMethodOnConstructorTests : DiagnosticVerifier { public async Task IfVirtualMethodFoundInConstructorCreatesDiagnostic() { const string test = @" public class Person -{{ +{ public Person(string foo) - {{ + { DoFoo(foo); - }} + } public virtual void DoFoo(string foo) - {{ - }} -}}"; + { + } +}"; var expected = new DiagnosticResult { Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), Message = VirtualMethodOnConstructorAnalyzer.Message, @@ -35,16 +35,16 @@ public virtual void DoFoo(string foo) public async Task IfVirtualMethodWithThisFoundInConstructorCreatesDiagnostic() { const string test = @" public class Person -{{ +{ public Person(string foo) - {{ + { this.DoFoo(foo); - }} + } public virtual void DoFoo(string foo) - {{ - }} -}}"; + { + } +}"; var expected = new DiagnosticResult { Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), Message = VirtualMethodOnConstructorAnalyzer.Message, @@ -60,20 +60,19 @@ public virtual void DoFoo(string foo) public async Task IfVirtualMethodFoundFromOtherClassInConstructorDoNotCreateDiagnostic() { const string test = @" public class Book -{{ +{ public virtual void DoFoo(string foo) - {{ - }} -}} + { + } +} public class Person -{{ +{ public Person(string foo) - {{ + { var b = new Book(); b.DoFoo(foo); - }} -}} -"; + } +}"; await VerifyCSharpHasNoDiagnosticsAsync(test); } @@ -81,16 +80,15 @@ public Person(string foo) public async Task IfVirtualMethodNotFoundInConstructorDoNotCreateDiagnostic() { const string test = @" public class Person -{{ +{ public Person(string foo) - {{ + { DoFoo(foo); - }} - + } public void DoFoo(string foo) - {{ - }} -}}"; + { + } +}"; await VerifyCSharpHasNoDiagnosticsAsync(test); } @@ -98,20 +96,20 @@ public void DoFoo(string foo) public async Task IfManyVirtualMethodFoundInConstructorCreatesDiagnostics() { const string test = @" public class Person -{{ +{ public Person(string foo) - {{ + { DoFoo(foo); DoFoo2(foo); - }} + } public virtual void DoFoo(string foo) - {{ - }} + { + } public virtual void DoFoo2(string foo) - {{ - }} -}}"; + { + } +}"; var expected = new DiagnosticResult { Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), Message = VirtualMethodOnConstructorAnalyzer.Message, @@ -124,8 +122,6 @@ public virtual void DoFoo2(string foo) Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 3) } }; - - await VerifyCSharpDiagnosticAsync(test, expected, expected2); } @@ -137,12 +133,26 @@ protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() { public async Task IfNameOfFoundInConstructorDoesNotCreateDiagnostic() { const string test = @" public class Person -{{ +{ public Person(string name) - {{ + { throw new System.ArgumentOutOfRangeException(nameof(name), """"); - }} -}}"; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async Task IgnoreParameters() { + var test = @" +using System; +class Foo +{ + public Foo(Func bar) + { + bar(); + } +}"; await VerifyCSharpHasNoDiagnosticsAsync(test); } } From 174cecb2c703394dad38639643de10b35058d837 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 17 Feb 2016 16:26:28 -0200 Subject: [PATCH 135/358] Fix object initializer fix to not delete statements Fixes #717 --- .../Style/ObjectInitializerCodeFixProvider.cs | 2 +- .../Style/ObjectInitializerTests.cs | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs index 11da2a447..258d8975a 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerCodeFixProvider.cs @@ -131,7 +131,7 @@ private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, Seman .WithTrailingTrivia(statement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); newBlockParent = newBlockParent.AddStatements(newLocalDeclarationStatement); - i += initializationExpressions.Count; + i += assignmentExpressions.Count; } else { diff --git a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs index 98f66c406..b4e1b5ddb 100644 --- a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs @@ -183,6 +183,50 @@ public int Foo() await VerifyCSharpFixAsync(source, fixtest, 0); } + [Fact] + public async Task FixDoesNotRemoveNextStatement() + { + const string source = @" +class DataObject +{ + public int MyInt { get; set; } + public double MyDouble { get; set; } +} + +class Program +{ + static void Main() + { + var data = new DataObject + { + MyInt = 5 + }; + data.MyDouble = 5.6; + var a = 1; + } +}"; + const string fixtest = @" +class DataObject +{ + public int MyInt { get; set; } + public double MyDouble { get; set; } +} + +class Program +{ + static void Main() + { + var data = new DataObject + { + MyInt = 5, + MyDouble = 5.6 + }; + var a = 1; + } +}"; + await VerifyCSharpFixAsync(source, fixtest, 0); + } + [Fact] public async Task ObjectCreationWithoutConstructorDoesNotCreateDiagnostic() { From d9884575ccaf5ab8c369db0d54fa7173132f2f19 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 17 Feb 2016 23:32:03 -0200 Subject: [PATCH 136/358] Add PR and issue templates, move CONTRIBUTING --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 0 .github/ISSUE_TEMPLATE.md | 46 ++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 16 ++++++++ 3 files changed, 62 insertions(+) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..0f17d7434 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +#New analyzer: + +Input your analyzer description. + +Before: + +````csharp +//your code that triggers the diagnostic +```` + +After: + +````csharp +//your code after the fix has been applied +```` + +You can add more information here, e.g. conditions under which a diagnostic should not trigger, etc. + +Diagnostic Id: `CC0000` (take a number and update the [wiki](https://github.com/code-cracker/code-cracker/wiki/DiagnosticIds)) +Category: `` (see [supported categories](https://github.com/code-cracker/code-cracker/blob/master/src/Common/CodeCracker.Common/SupportedCategories.cs) and their [descriptions](https://github.com/code-cracker/code-cracker/issues/97)) +Severity: `Hidden | Info | Warning | Error` (see the [descriptions](https://github.com/code-cracker/code-cracker/#severity-levels)) + +#Bug + +Input your bug description. Make sure you describe the steps to reproduce, +that you are working with the latest version, and the issue has not been reported yet. + +Example: (don't use your project code, use a sample that anyone could use to verify the bug, +so, for example, +don't use classes that are not part of the BCL or declared on your sample.) + +````csharp +//the code that reproduces the bug +```` + +Current output after fix applied (if it is a code fix bug): + +````csharp +//code fixed incorrectly +```` + +Expected output after fix applied (if it is a code fix bug): + +````csharp +//code fixed incorrectly +```` \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..f1fc8739d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,16 @@ +#Info (delete this section) +Please see the [contributing guide](https://github.com/code-cracker/code-cracker/blob/master/README.md#contributing), on the contributing section. + +You should notify the maintainers on the issue you are working on before you send a PR. + +[Rebase](http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html) and +[squash](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) your commits. +Submit one commit only, on top of the branch you are working on, `master` for bug fixes to the +stable version, `vnext` to new analyzers and fixers. + +Verify if you pass the [definition of done](https://github.com/code-cracker/code-cracker#definition-of-done). + +Always reference issue you are fixing (see bellow, e.g. `Fixes #123`) + +#Start your PR description here (delete this line too) +Fixes # . \ No newline at end of file From ac90db1d071b367bf7ff4e447f65a865d60d51bf Mon Sep 17 00:00:00 2001 From: float4 <> Date: Fri, 19 Feb 2016 09:49:56 +0200 Subject: [PATCH 137/358] Fixed introduce field from constructor for struct --- .../Extensions/CSharpAnalyzerExtensions.cs | 15 ++++ .../IntroduceFieldFromConstructorAnalyzer.cs | 4 ++ ...duceFieldFromConstructorCodeFixProvider.cs | 17 ++--- .../IntroduceFieldFromConstructorTest.cs | 70 +++++++++++++++++++ 4 files changed, 98 insertions(+), 8 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 0d82e7692..095b7991c 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -707,5 +707,20 @@ public static SyntaxTokenList GetTokens(this Accessibility accessibility) throw new NotSupportedException(); } } + public static TypeDeclarationSyntax WithMembers(this TypeDeclarationSyntax typeDeclarationSyntax, SyntaxList members) + { + if (typeDeclarationSyntax is ClassDeclarationSyntax) + { + return (typeDeclarationSyntax as ClassDeclarationSyntax).WithMembers(members); + } + else if (typeDeclarationSyntax is StructDeclarationSyntax) + { + return (typeDeclarationSyntax as StructDeclarationSyntax).WithMembers(members); + } + else + { + throw new NotSupportedException(); + } + } } } diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs index aada36ec3..91562e3db 100644 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs @@ -34,6 +34,10 @@ private static void AnalyzeConstructor(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; var constructorMethod = (ConstructorDeclarationSyntax)context.Node; + + var type = constructorMethod.FirstAncestorOrSelf(); + if (type == null || !(type is ClassDeclarationSyntax || type is StructDeclarationSyntax)) return; + var parameters = constructorMethod.ParameterList.Parameters; if (constructorMethod.Body == null) return; diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs index ed2730ca6..085196f21 100644 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs @@ -42,11 +42,12 @@ public async static Task IntroduceFieldFromConstructorDocumentAsync(Do public static SyntaxNode IntroduceFieldFromConstructor(SyntaxNode root, ConstructorDeclarationSyntax constructorStatement, ParameterSyntax parameter) { - var oldClass = constructorStatement.FirstAncestorOrSelf(); - var newClass = oldClass; + // There are no constructors in interfaces, therefore all types remaining type (class and struct) are fine. + var oldType = constructorStatement.FirstAncestorOrSelf(); + var newType = oldType; var fieldName = parameter.Identifier.ValueText; var fieldType = parameter.Type; - var members = ExtractMembersFromClass(oldClass.Members); + var members = ExtractMembersFromClass(oldType.Members); var addMember = false; if (!members.Any(p => p.Key == fieldName && p.Value == fieldType.ToString())) @@ -62,7 +63,7 @@ public static SyntaxNode IntroduceFieldFromConstructor(SyntaxNode root, Construc SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(fieldName)), SyntaxFactory.IdentifierName(parameter.Identifier.ValueText))); var newConstructor = constructorStatement.WithBody(constructorStatement.Body.AddStatements(assignmentField)); - newClass = newClass.ReplaceNode(constructorStatement, newConstructor); + newType = newType.ReplaceNode(constructorStatement, newConstructor); if (addMember) { @@ -70,16 +71,16 @@ public static SyntaxNode IntroduceFieldFromConstructor(SyntaxNode root, Construc .WithVariables(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(fieldName))))) .WithModifiers(SyntaxFactory.TokenList(new[] { SyntaxFactory.Token(SyntaxKind.PrivateKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword) })) .WithAdditionalAnnotations(Formatter.Annotation); - newClass = newClass.WithMembers(newClass.Members.Insert(0, newField)).WithoutAnnotations(Formatter.Annotation); + newType = newType.WithMembers(newType.Members.Insert(0, newField)).WithoutAnnotations(Formatter.Annotation); } - var newRoot = root.ReplaceNode(oldClass, newClass); + var newRoot = root.ReplaceNode(oldType, newType); return newRoot; } - private static Dictionary ExtractMembersFromClass(SyntaxList classMembers) + private static Dictionary ExtractMembersFromClass(SyntaxList typeMembers) { var members = new Dictionary(); - foreach (var m in classMembers) + foreach (var m in typeMembers) { var name = ""; if (m.IsKind(SyntaxKind.MethodDeclaration)) diff --git a/test/CSharp/CodeCracker.Test/Refactoring/IntroduceFieldFromConstructorTest.cs b/test/CSharp/CodeCracker.Test/Refactoring/IntroduceFieldFromConstructorTest.cs index fe1b72bf7..e0bac6a01 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/IntroduceFieldFromConstructorTest.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/IntroduceFieldFromConstructorTest.cs @@ -27,6 +27,76 @@ public TypeName(int par) await VerifyCSharpHasNoDiagnosticsAsync(test); } + [Fact] + public async Task WhenConstructorInMidlleOfNoWhere() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + public TypeName(int par) + { + this.par = par; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + + [Fact] + public async Task WhenConstructorOfStruct() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + struct TypeName + { + public TypeName(int par) + { + } + } + }"; + + const string expected = @" + using System; + + namespace ConsoleApplication1 + { + struct TypeName + { + private readonly int par; + + public TypeName(int par) + { + this.par = par; + } + } + }"; + await VerifyCSharpFixAsync(test, expected); + } + + [Fact] + public async Task WhenConstructorOfInterface() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + interface TypeName + { + public TypeName(int par) + { + this.par = par; + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + [Fact] public async Task WhenConstructorParameterHasPrivateReadOnlyField() { From 4f272bc6ac472bfcf2f66138a0cb3b669ca303dd Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 20 Feb 2016 08:45:55 -0200 Subject: [PATCH 138/358] Fix to do not run CC0090 on generated files Fixes #720 --- .../CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs index 7da0fa90a..f4da96669 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs @@ -29,6 +29,7 @@ public sealed class XmlDocumentationAnalyzer : DiagnosticAnalyzer private static void Analyzer(SyntaxNodeAnalysisContext context) { + if (context.IsGenerated()) return; var documentationNode = (DocumentationCommentTriviaSyntax)context.Node; var method = GetMethodFromXmlDocumentation(documentationNode); if (method == null) return; From 596ba55240a5ab90fad1deff3fd6f779572faacb Mon Sep 17 00:00:00 2001 From: carloscds Date: Mon, 1 Feb 2016 22:44:04 -0200 Subject: [PATCH 139/358] Fix #698 Fix error when ValueType Intermediate commit Fix final --- .../CodeCracker/Style/ForInArrayAnalyzer.cs | 23 ++++++- .../CodeCracker.Test/Style/ForInArrayTests.cs | 60 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs index 300462f5e..f8f56457b 100644 --- a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs @@ -65,7 +65,6 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) return !identifierSymbol.Equals(arrayId); }); if (otherUsesOfIndexToken != 0) return; - var arrayAccessorSymbols = (from s in forBlock.Statements.OfType() where s.Declaration.Variables.Count == 1 let declaration = s.Declaration.Variables.First() @@ -77,6 +76,28 @@ where controlVarId.Equals(initSymbol) where arrayId.Equals(someArrayInit) select arrayId).ToList(); if (!arrayAccessorSymbols.Any()) return; + var valueTypeVariable = (from s in forBlock.Statements.OfType() + where s.Declaration.Variables.Count == 1 + let symbol = semanticModel.GetDeclaredSymbol(s.Declaration.Variables.First()) as ISymbol + where ((ILocalSymbol)symbol).Type.IsValueType + select s).ToList(); + + foreach (var statement in forBlock.Statements.OfType()) + { + var left = (statement.Expression as AssignmentExpressionSyntax)?.Left; + var memberAccess = (left as MemberAccessExpressionSyntax)?.Expression; + var identifier = ""; + if (memberAccess?.GetType()?.Name == "IdentifierNameSyntax") + { + identifier = (memberAccess as IdentifierNameSyntax)?.Identifier.Text ?? ""; + } + else + { + var element = (memberAccess as ElementAccessExpressionSyntax)?.Expression; + identifier = (element as IdentifierNameSyntax)?.Identifier.Text ?? ""; + } + if (identifier == arrayId.Name && valueTypeVariable.Any()) return; + } var diagnostic = Diagnostic.Create(Rule, forStatement.ForKeyword.GetLocation()); context.ReportDiagnostic(diagnostic); } diff --git a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs index 6d1afa994..0aa1ede2b 100644 --- a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs @@ -757,5 +757,65 @@ public int[] Foo }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task WithValueTypeNoDiagnostic() + { + var source = @" + using System; + using System.Collections.Generic; + + namespace Test + { + struct Foo + { + public int X; + } + + public class bar + { + static void Goo() + { + var array = new Foo[1]; + for (int i = 0; i < array.Length; i++) + { + var actual = array[i]; + array[i].X = 5; + } + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task WithValueTypeListNoDiagnostic() + { + var source = @" + using System; + using System.Collections.Generic; + + namespace Test + { + struct Foo + { + public int X; + } + + public class bar + { + static void Goo() + { + var array = new List(); + for (int i = 0; i < array.Length; i++) + { + var actual = array[i]; + array[i].X = 5; + } + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From 2a7b3fa6109e445b83230dbd656c91b1d5c08ef1 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 22 Feb 2016 10:48:43 -0300 Subject: [PATCH 140/358] Verify value types in for analyzer Closes #698 --- .../CodeCracker/Style/AlwaysUseVarAnalyzer.cs | 26 +-------------- .../CodeCracker/Style/ForInArrayAnalyzer.cs | 25 ++------------- .../Extensions/AnalyzerExtensions.cs | 24 ++++++++++++++ .../CodeCracker.Test/Style/ForInArrayTests.cs | 32 +++++++++++++++++++ 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs b/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs index dc412018c..7e5c5aab2 100644 --- a/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/AlwaysUseVarAnalyzer.cs @@ -71,33 +71,9 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) } } - var rule = IsPrimitvie(variableType) ? RulePrimitives : RuleNonPrimitives; + var rule = variableType.IsPrimitive() ? RulePrimitives : RuleNonPrimitives; var diagnostic = Diagnostic.Create(rule, variableDeclaration.Type.GetLocation()); context.ReportDiagnostic(diagnostic); } - - private static bool IsPrimitvie(ITypeSymbol typeSymbol) - { - switch (typeSymbol.SpecialType) - { - case SpecialType.System_Boolean: - case SpecialType.System_Byte: - case SpecialType.System_SByte: - case SpecialType.System_Int16: - case SpecialType.System_UInt16: - case SpecialType.System_Int32: - case SpecialType.System_UInt32: - case SpecialType.System_Int64: - case SpecialType.System_UInt64: - case SpecialType.System_IntPtr: - case SpecialType.System_UIntPtr: - case SpecialType.System_Char: - case SpecialType.System_Double: - case SpecialType.System_Single: - return true; - default: - return false; - } - } } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs index f8f56457b..1a95477bf 100644 --- a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs @@ -69,6 +69,9 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) where s.Declaration.Variables.Count == 1 let declaration = s.Declaration.Variables.First() where declaration?.Initializer?.Value is ElementAccessExpressionSyntax + let iterableSymbol = semanticModel.GetDeclaredSymbol(declaration) + let iterableType = ((ILocalSymbol)iterableSymbol).Type + where !(iterableType.IsPrimitive() ^ iterableType.IsValueType) let init = (ElementAccessExpressionSyntax)declaration.Initializer.Value let initSymbol = semanticModel.GetSymbolInfo(init.ArgumentList.Arguments.First().Expression).Symbol where controlVarId.Equals(initSymbol) @@ -76,28 +79,6 @@ where controlVarId.Equals(initSymbol) where arrayId.Equals(someArrayInit) select arrayId).ToList(); if (!arrayAccessorSymbols.Any()) return; - var valueTypeVariable = (from s in forBlock.Statements.OfType() - where s.Declaration.Variables.Count == 1 - let symbol = semanticModel.GetDeclaredSymbol(s.Declaration.Variables.First()) as ISymbol - where ((ILocalSymbol)symbol).Type.IsValueType - select s).ToList(); - - foreach (var statement in forBlock.Statements.OfType()) - { - var left = (statement.Expression as AssignmentExpressionSyntax)?.Left; - var memberAccess = (left as MemberAccessExpressionSyntax)?.Expression; - var identifier = ""; - if (memberAccess?.GetType()?.Name == "IdentifierNameSyntax") - { - identifier = (memberAccess as IdentifierNameSyntax)?.Identifier.Text ?? ""; - } - else - { - var element = (memberAccess as ElementAccessExpressionSyntax)?.Expression; - identifier = (element as IdentifierNameSyntax)?.Identifier.Text ?? ""; - } - if (identifier == arrayId.Name && valueTypeVariable.Any()) return; - } var diagnostic = Diagnostic.Create(Rule, forStatement.ForKeyword.GetLocation()); context.ReportDiagnostic(diagnostic); } diff --git a/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs b/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs index af2272c40..b7bd2ee4f 100644 --- a/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs +++ b/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs @@ -166,5 +166,29 @@ public static Accessibility GetMinimumCommonAccessibility(this Accessibility acc throw new NotSupportedException(); } } + + public static bool IsPrimitive(this ITypeSymbol typeSymbol) + { + switch (typeSymbol.SpecialType) + { + case SpecialType.System_Boolean: + case SpecialType.System_Byte: + case SpecialType.System_SByte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_IntPtr: + case SpecialType.System_UIntPtr: + case SpecialType.System_Char: + case SpecialType.System_Double: + case SpecialType.System_Single: + return true; + default: + return false; + } + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs index 0aa1ede2b..7b333410e 100644 --- a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs @@ -788,6 +788,38 @@ static void Goo() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task WithValueTypeAndIEnumeratorDoesNotCreateDiagnostic() + { + var source = @" +class Foo +{ + void Bar() + { + var list = new MyList(); + for (int i = 0; i < list.Count; i++) + { + var actual = list[i]; + actual.X = 5; + } + } +} +struct Struct +{ + public int X { get; set; } +} +class MyList +{ + public int Count => 1; + public Struct this[int index] => new Struct(); + public System.Collections.Generic.IEnumerator GetEnumerator() + { + yield return new Struct(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WithValueTypeListNoDiagnostic() { From 25516071b9512433c9d373667067ba955968a2ac Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 26 Feb 2016 00:11:53 -0300 Subject: [PATCH 141/358] Ignore Disposable Variable when object could live longer Passed to methods. Assigned to properties. Fixes #465 --- .../DisposableVariableNotDisposedAnalyzer.cs | 26 ++++-- .../DisposableVariableNotDisposedTests.cs | 80 ++++++++++++++----- 2 files changed, 82 insertions(+), 24 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index fc3cbe6d9..9901b2114 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -107,16 +107,30 @@ private static bool IsDisposedOrAssigned(SemanticModel semanticModel, StatementS var method = statement.FirstAncestorOrSelf(); if (method == null) return false; if (IsReturned(method, statement, semanticModel, identitySymbol)) return true; - foreach (var childStatements in method.Body.DescendantNodes().OfType()) + foreach (var childStatement in method.Body.DescendantNodes().OfType()) { - if (childStatements.SpanStart > statement.SpanStart - && (IsCorrectDispose(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol) - || IsAssignedToField(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol))) + if (childStatement.SpanStart > statement.SpanStart + && (IsCorrectDispose(childStatement as ExpressionStatementSyntax, semanticModel, identitySymbol) + || IsPassedAsArgument(childStatement, semanticModel, identitySymbol) + || IsAssignedToFieldOrProperty(childStatement as ExpressionStatementSyntax, semanticModel, identitySymbol))) return true; } return false; } + private static bool IsPassedAsArgument(StatementSyntax statement, SemanticModel semanticModel, ILocalSymbol identitySymbol) + { + if (statement == null) return false; + var args = statement.DescendantNodes().OfKind(SyntaxKind.Argument); + foreach (var arg in args) + { + var argSymbol = semanticModel.GetSymbolInfo(arg.Expression).Symbol; + if (identitySymbol.Equals(argSymbol)) return true; + } + return false; + } + + private static bool IsReturned(MethodDeclarationSyntax method, StatementSyntax statement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { var anonymousFunction = statement.FirstAncestorOfKind(SyntaxKind.ParenthesizedLambdaExpression, @@ -147,13 +161,13 @@ private static bool IsReturned(MethodDeclarationSyntax method, StatementSyntax s return isReturning; } - private static bool IsAssignedToField(ExpressionStatementSyntax expressionStatement, SemanticModel semanticModel, ILocalSymbol identitySymbol) + private static bool IsAssignedToFieldOrProperty(ExpressionStatementSyntax expressionStatement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { if (expressionStatement == null) return false; if (!expressionStatement.Expression.IsKind(SyntaxKind.SimpleAssignmentExpression)) return false; var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression; var assignmentTarget = semanticModel.GetSymbolInfo(assignment.Left).Symbol; - if (assignmentTarget?.Kind != SymbolKind.Field) return false; + if (assignmentTarget?.Kind != SymbolKind.Field && assignmentTarget?.Kind != SymbolKind.Property) return false; var assignmentSource = semanticModel.GetSymbolInfo(assignment.Right).Symbol; return (identitySymbol.Equals(assignmentSource)); } diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index 60a80b3d0..ba53e0a9b 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -595,10 +595,10 @@ public async Task FixADisposableDeclarationWithoutDispose() public async Task FixADisposableDeclarationWithoutDisposeWithStatementsAfter() { var source = @"var m = new System.IO.MemoryStream(); -Console.WriteLine(m);".WrapInCSharpMethod(); +m.Flush();".WrapInCSharpMethod(); var fixtest = @"using (var m = new System.IO.MemoryStream()) { - Console.WriteLine(m); + m.Flush(); }".WrapInCSharpMethod(); await VerifyCSharpFixAsync(source, fixtest); } @@ -609,14 +609,14 @@ public async Task FixADisposableDeclarationWithoutDisposeInsideBlock() var source = @"if (DateTime.Now.Second % 2 == 0) { var m = new System.IO.MemoryStream(); - Console.WriteLine(m); + m.Flush(); } Console.WriteLine(1);".WrapInCSharpMethod(); var fixtest = @"if (DateTime.Now.Second % 2 == 0) { using (var m = new System.IO.MemoryStream()) { - Console.WriteLine(m); + m.Flush(); } } Console.WriteLine(1);".WrapInCSharpMethod(); @@ -682,11 +682,11 @@ public async Task FixAssignmentWithStatementsAfter() { var source = @"System.IO.MemoryStream m; m = new System.IO.MemoryStream(); -Console.WriteLine(m);".WrapInCSharpMethod(); +m.Flush();".WrapInCSharpMethod(); var fixtest = @"System.IO.MemoryStream m; using (m = new System.IO.MemoryStream()) { - Console.WriteLine(m); + m.Flush(); }".WrapInCSharpMethod(); await VerifyCSharpFixAsync(source, fixtest); } @@ -932,7 +932,7 @@ public async Task FixAssignmentInsideBlock() { System.IO.MemoryStream m; m = new System.IO.MemoryStream(); - Console.WriteLine(m); + m.Flush(); } Console.WriteLine(1);".WrapInCSharpMethod(); var fixtest = @"if (DateTime.Now.Second % 2 == 0) @@ -940,7 +940,7 @@ public async Task FixAssignmentInsideBlock() System.IO.MemoryStream m; using (m = new System.IO.MemoryStream()) { - Console.WriteLine(m); + m.Flush(); } } Console.WriteLine(1);".WrapInCSharpMethod(); @@ -954,7 +954,7 @@ public async Task FixAssignmentInsideBlockWithDifferentScopeInDeclarationAndAssi if (DateTime.Now.Second % 2 == 0) { m = new System.IO.MemoryStream(); - Console.WriteLine(m); + m.Flush(); } Console.WriteLine(1);".WrapInCSharpMethod(); var fixtest = @"System.IO.MemoryStream m; @@ -962,7 +962,7 @@ public async Task FixAssignmentInsideBlockWithDifferentScopeInDeclarationAndAssi { using (m = new System.IO.MemoryStream()) { - Console.WriteLine(m); + m.Flush(); } } Console.WriteLine(1);".WrapInCSharpMethod(); @@ -976,7 +976,7 @@ public async Task FixAssignmentInsideBlockWithDifferentScopeInDeclarationAndAssi if (DateTime.Now.Second % 2 == 0) { m = new System.IO.MemoryStream(); - Console.WriteLine(m); + m.Flush(); } m.Flush(); Console.WriteLine(1);".WrapInCSharpMethod(); @@ -984,7 +984,7 @@ public async Task FixAssignmentInsideBlockWithDifferentScopeInDeclarationAndAssi if (DateTime.Now.Second % 2 == 0) { m = new System.IO.MemoryStream(); - Console.WriteLine(m); + m.Flush(); } m.Flush(); Console.WriteLine(1); @@ -1005,7 +1005,7 @@ void Foo() if (DateTime.Now.Second % 2 == 0) { m = new Disposable(); - Console.WriteLine(m); + m.Push(); } m.Flush(); Console.WriteLine(1); @@ -1015,6 +1015,7 @@ class Disposable : IDisposable { void IDisposable.Dispose() { } public void Flush() { } + public void Push() { } } "; const string fixtest = @" @@ -1027,7 +1028,7 @@ void Foo() if (DateTime.Now.Second % 2 == 0) { m = new Disposable(); - Console.WriteLine(m); + m.Push(); } m.Flush(); Console.WriteLine(1); @@ -1038,6 +1039,7 @@ class Disposable : IDisposable { void IDisposable.Dispose() { } public void Flush() { } + public void Push() { } } "; await VerifyCSharpFixAsync(source, fixtest); @@ -1147,7 +1149,7 @@ void Foo() if (DateTime.Now.Second % 2 == 0) { m = new Disposable(); - Console.WriteLine(m); + m.Push(); } m.Flush(); if (DateTime.Now.Second % 3 == 0) @@ -1160,6 +1162,7 @@ class Disposable : IDisposable { void IDisposable.Dispose() { } public void Flush() { } + public void Push() { } } "; const string fixtest = @" @@ -1172,7 +1175,7 @@ void Foo() if (DateTime.Now.Second % 2 == 0) { m = new Disposable(); - Console.WriteLine(m); + m.Push(); } m.Flush(); if (DateTime.Now.Second % 3 == 0) @@ -1185,6 +1188,7 @@ class Disposable : IDisposable { void IDisposable.Dispose() { } public void Flush() { } + public void Push() { } } "; await VerifyCSharpFixAsync(source, fixtest); @@ -1205,7 +1209,7 @@ void Foo() if (DateTime.Now.Second % 4 == 0) { m = new Disposable(); - Console.WriteLine(m); + m.Push(); } m.Flush(); } @@ -1219,6 +1223,7 @@ class Disposable : IDisposable { void IDisposable.Dispose() { } public void Flush() { } + public void Push() { } } "; const string fixtest = @" @@ -1233,7 +1238,7 @@ void Foo() if (DateTime.Now.Second % 4 == 0) { m = new Disposable(); - Console.WriteLine(m); + m.Push(); } m.Flush(); } @@ -1247,6 +1252,7 @@ class Disposable : IDisposable { void IDisposable.Dispose() { } public void Flush() { } + public void Push() { } } "; await VerifyCSharpFixAsync(source, fixtest); @@ -1493,5 +1499,43 @@ static void Baz() }"; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task IgnoreWhenPassedIntoMethod() + { + const string source = @" +using System.IO; +class Foo +{ + void Bar() + { + var m = new MemoryStream(); + Baz(m); + } + void Baz(MemoryStream m) { } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoreWhenAssignedToField() + { + const string source = @" +using System.IO; +class HoldsDisposable +{ + public MemoryStream Ms { get; set; } +} +class Foo +{ + void Bar() + { + var m = new MemoryStream(); + var h = new HoldsDisposable(); + h.Ms = m; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From b34e02edebd2f958f9563c45e89df6f7d2265a33 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 27 Feb 2016 12:08:32 -0300 Subject: [PATCH 142/358] Use nodemon to watch files --- runTestsCS.ps1 | 51 +++++++++++++------------------------------------- runTestsVB.ps1 | 51 +++++++++++++------------------------------------- 2 files changed, 26 insertions(+), 76 deletions(-) diff --git a/runTestsCS.ps1 b/runTestsCS.ps1 index 622e9718e..4a24efe74 100644 --- a/runTestsCS.ps1 +++ b/runTestsCS.ps1 @@ -1,33 +1,20 @@ param([String]$testClass) -$Global:lastRun = $lastRun = [System.DateTime]::Now $testDllDirPath = "$PSScriptRoot\test\CSharp\CodeCracker.Test\bin\Debug\" $testDllFileName = "CodeCracker.Test.CSharp.dll" -$Global:testDllFullFileName = "$testDllDirPath$testDllFileName" -$Global:xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" +$testDllFullFileName = "$testDllDirPath$testDllFileName" +$xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" -if ($testClass -eq "now"){ - . $Global:xunitConsole "$Global:testDllFullFileName" +if (!(gcm nodemon -ErrorAction Ignore)) { + Write-Host -ForegroundColor DarkRed 'Nodemon not found, install it with npm: `npm i -g nodemon`' return } -function global:DebounceXunit { - try { - if (([System.DateTime]::Now - $script:lastRun).TotalMilliseconds -lt 2000) { - return - } - $Global:lastRun = [System.DateTime]::Now - If ($Global:testClass) { - Start-Process $Global:xunitConsole -ArgumentList "`"$Global:testDllFullFileName`" -class $Global:testClass" -NoNewWindow - } Else { - Start-Process $Global:xunitConsole -ArgumentList "`"$Global:testDllFullFileName`"" -NoNewWindow - } - } - catch - { - Write-Host $_.Exception.Message - } +if ($testClass -eq "now"){ + . $xunitConsole "$testDllFullFileName" + return } + Write-Host "Watching $testDllDirPath" If ($testClass) { If ($testClass.StartsWith("CodeCracker.Test") -eq $false) { @@ -35,21 +22,9 @@ If ($testClass) { } Write-Host "Only for $testClass" } -$Global:testClass = $testClass -try { - $watcher = New-Object System.IO.FileSystemWatcher - $watcher.Path = $testDllDirPath - $watcher.Filter = $testDllFileName - $watcher.IncludeSubdirectories = $false - $watcher.EnableRaisingEvents = $true - $watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite - $changed = Register-ObjectEvent $watcher "Changed" -Action { DebounceXunit } -} -catch { - Write-Host $_.Exception.Message -} -#if we do that, then we don't get any console output: -#Write-Host "Press any key to continue ..." -#[System.Console]::ReadKey() -#Unregister-Event $changed.Id +If ($testClass) { + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" --verbose +} Else { + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" --verbose +} \ No newline at end of file diff --git a/runTestsVB.ps1 b/runTestsVB.ps1 index 53e5730ea..30ecc0e14 100644 --- a/runTestsVB.ps1 +++ b/runTestsVB.ps1 @@ -1,33 +1,20 @@ param([String]$testClass) -$Global:lastRun = $lastRun = [System.DateTime]::Now $testDllDirPath = "$PSScriptRoot\test\VisualBasic\CodeCracker.Test\bin\Debug\" $testDllFileName = "CodeCracker.Test.VisualBasic.dll" -$Global:testDllFullFileName = "$testDllDirPath$testDllFileName" -$Global:xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" +$testDllFullFileName = "$testDllDirPath$testDllFileName" +$xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" -if ($testClass -eq "now"){ - . $Global:xunitConsole "$Global:testDllFullFileName" +if (!(gcm nodemon -ErrorAction Ignore)) { + Write-Host -ForegroundColor DarkRed 'Nodemon not found, install it with npm: `npm i -g nodemon`' return } -function global:DebounceXunit { - try { - if (([System.DateTime]::Now - $script:lastRun).TotalMilliseconds -lt 2000) { - return - } - $Global:lastRun = [System.DateTime]::Now - If ($Global:testClass) { - Start-Process $Global:xunitConsole -ArgumentList "`"$Global:testDllFullFileName`" -class $Global:testClass" -NoNewWindow - } Else { - Start-Process $Global:xunitConsole -ArgumentList "`"$Global:testDllFullFileName`"" -NoNewWindow - } - } - catch - { - Write-Host $_.Exception.Message - } +if ($testClass -eq "now"){ + . $xunitConsole "$testDllFullFileName" + return } + Write-Host "Watching $testDllDirPath" If ($testClass) { If ($testClass.StartsWith("CodeCracker.Test") -eq $false) { @@ -35,21 +22,9 @@ If ($testClass) { } Write-Host "Only for $testClass" } -$Global:testClass = $testClass -try { - $watcher = New-Object System.IO.FileSystemWatcher - $watcher.Path = $testDllDirPath - $watcher.Filter = $testDllFileName - $watcher.IncludeSubdirectories = $false - $watcher.EnableRaisingEvents = $true - $watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite - $changed = Register-ObjectEvent $watcher "Changed" -Action { DebounceXunit } -} -catch { - Write-Host $_.Exception.Message -} -#if we do that, then we don't get any console output: -#Write-Host "Press any key to continue ..." -#[System.Console]::ReadKey() -#Unregister-Event $changed.Id +If ($testClass) { + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" --verbose +} Else { + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" --verbose +} \ No newline at end of file From 5bef7bdd824b3522f45afb6c3057a5893b6412b0 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 27 Feb 2016 13:28:21 -0300 Subject: [PATCH 143/358] Do not make a method static if it takes RoutedEventArgs --- .../Design/MakeMethodStaticAnalyzer.cs | 8 ++++++++ .../Design/MakeMethodStaticTests.cs | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs index d8dc98556..b5c5a60b4 100644 --- a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using System.Linq; using System.Collections.Immutable; +using System; namespace CodeCracker.CSharp.Design { @@ -80,11 +81,18 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) if (IsTestMethod(method, methodSymbol)) return; if (IsWebFormsMethod(methodSymbol)) return; if (IsGetEnumerator(methodSymbol)) return; + if (HasRoutedEventArgs(methodSymbol)) return; var diagnostic = Diagnostic.Create(Rule, method.Identifier.GetLocation(), method.Identifier.ValueText); context.ReportDiagnostic(diagnostic); } + private static bool HasRoutedEventArgs(IMethodSymbol methodSymbol) + { + var routedEventArgsParameters = methodSymbol.Parameters.Where(p => p.Type.ToString() == "System.Windows.RoutedEventArgs"); + return routedEventArgsParameters.Any(); + } + private static readonly string[] webFormsMethods = { "Application_AuthenticateRequest", "Application_BeginRequest", "Application_End", "Application_EndRequest", diff --git a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs index cafcd4950..9a1590393 100644 --- a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs @@ -1062,5 +1062,22 @@ public static void N() { } }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task IgnoreMethodsWithRoutedEventArgs() + { + const string source = @" +public class MainWindow +{ + void Window_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + } +} +namespace System.Windows +{ + public class RoutedEventArgs : System.EventArgs { } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From e6e2fcca556b57dc5e34e44605c52d439e984853 Mon Sep 17 00:00:00 2001 From: carloscds Date: Sun, 28 Feb 2016 22:18:54 -0300 Subject: [PATCH 144/358] Fix #724 --- .../Style/TernaryOperatorCodeFixProviders.vb | 15 ++++++--- .../Style/TernaryOperatorTests.vb | 31 +++++++++++++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 6b24f9e72..2bb07719c 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -111,6 +111,15 @@ Namespace Style EnsureNothingAsType(semanticModel, type, typeSyntax). ConvertToBaseType(elseType, type) + If ifAssign.OperatorToken.Text <> "=" Then + trueExpression = ifAssign.Right. + EnsureNothingAsType(semanticModel, type, typeSyntax). + ConvertToBaseType(ifType, type) + + falseExpression = elseAssign.Right. + EnsureNothingAsType(semanticModel, type, typeSyntax). + ConvertToBaseType(elseType, type) + End If Dim leadingTrivia = ifBlock.GetLeadingTrivia. AddRange(ifAssign.GetLeadingTrivia()). @@ -122,13 +131,11 @@ Namespace Style InsertRange(0, elseAssign.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))). InsertRange(0, ifAssign.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))) - Dim ternary = SyntaxFactory.TernaryConditionalExpression(ifBlock.IfStatement.Condition.WithoutTrailingTrivia(), trueExpression.WithoutTrailingTrivia(), - falseExpression.WithoutTrailingTrivia()). - WithAdditionalAnnotations(Formatter.Annotation) + falseExpression.WithoutTrailingTrivia()) - Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left.WithLeadingTrivia(leadingTrivia), ternary). + Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left.WithLeadingTrivia(leadingTrivia), ifAssign.OperatorToken, ternary). WithTrailingTrivia(trailingTrivia). WithAdditionalAnnotations(Formatter.Annotation) diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index ef72d758e..1ebcd9273 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -432,6 +432,34 @@ End Class" Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) End Function + + Public Async Function WhenUsingAssignmentOperatorReturnSameAssignment() As Task + Const source = " +Class MyType + Public Sub x2() + Dim output As String = String.Empty + Dim test As Boolean + test = True + If test Then + output += ""True"" + Else + output += ""False"" + End If + End Sub +End Class" + + Const fix = " +Class MyType + Public Sub x2() + Dim output As String = String.Empty + Dim test As Boolean + test = True + output += If(test, ""True"", ""False"") + End Sub +End Class" + + Await VerifyBasicFixAsync(source, fix, formatBeforeCompare:=True) + End Function End Class @@ -671,6 +699,7 @@ End Namespace" Await VerifyBasicFixAllAsync(New String() {sourceReturn, sourceReturn.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) End Function + End Class Public Class TernaryOperatorFromIifTests @@ -804,7 +833,5 @@ End Class" Await VerifyBasicHasNoDiagnosticsAsync(source) End Function - - End Class From 1c69d6b3e05ce041189a26874a755edf980666a9 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 3 Mar 2016 11:56:32 -0300 Subject: [PATCH 145/358] Remove verbose from nodemon --- runTestsCS.ps1 | 4 ++-- runTestsVB.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runTestsCS.ps1 b/runTestsCS.ps1 index 4a24efe74..bc640573f 100644 --- a/runTestsCS.ps1 +++ b/runTestsCS.ps1 @@ -24,7 +24,7 @@ If ($testClass) { } If ($testClass) { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" --verbose + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" } Else { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" --verbose + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" } \ No newline at end of file diff --git a/runTestsVB.ps1 b/runTestsVB.ps1 index 30ecc0e14..d2fe0644e 100644 --- a/runTestsVB.ps1 +++ b/runTestsVB.ps1 @@ -24,7 +24,7 @@ If ($testClass) { } If ($testClass) { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" --verbose + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" } Else { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" --verbose + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" } \ No newline at end of file From 7fb90f40edbd450b40db7f8b861c4912287f0ab0 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 15 Mar 2016 01:02:36 -0300 Subject: [PATCH 146/358] Fix Make Ternary for VB when it has comments Closes #725 for CC0013 --- .../Style/TernaryOperatorCodeFixProviders.vb | 4 +- .../Style/TernaryOperatorTests.vb | 549 ++++++++++-------- 2 files changed, 308 insertions(+), 245 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 2bb07719c..11d68892c 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -49,8 +49,8 @@ Namespace Style EnsureNothingAsType(semanticModel, type, typeSyntax) Dim leadingTrivia = ifBlock.GetLeadingTrivia() - leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, ifReturn.GetLeadingTrivia().Where(Function(trivia) trivia.IsKind(SyntaxKind.CommentTrivia))) - leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, elseReturn.GetLeadingTrivia().Where(Function(trivia) trivia.IsKind(SyntaxKind.CommentTrivia))) + leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, ifReturn.GetLeadingTrivia()) + leadingTrivia = leadingTrivia.InsertRange(leadingTrivia.Count - 1, elseReturn.GetLeadingTrivia()) Dim trailingTrivia = ifBlock.GetTrailingTrivia. InsertRange(0, elseReturn.GetTrailingTrivia().Where(Function(trivia) Not trivia.IsKind(SyntaxKind.EndOfLineTrivia))). diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 1ebcd9273..89c3787a8 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -1,11 +1,12 @@ Imports CodeCracker.VisualBasic.Style Imports Xunit -Public Class TernaryOperatorWithAssignmentTests - Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorWithAssignmentCodeFixProvider) +Namespace Style + Public Class TernaryOperatorWithAssignmentTests + Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorWithAssignmentCodeFixProvider) - Public Async Function WhenUsingIfWithoutElseAnalyzerDoesNotCreateDiagnostic() As Task - Const sourceWithoutElse = " + Public Async Function WhenUsingIfWithoutElseAnalyzerDoesNotCreateDiagnostic() As Task + Const sourceWithoutElse = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -17,12 +18,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithoutElse) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithoutElse) + End Function - - Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnIfAnalyzerDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnIfAnalyzerDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -37,12 +38,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnElseAnalyzerDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnElseAnalyzerDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -57,12 +58,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfWithElseButWithoutReturnOnElseDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButWithoutReturnOnElseDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -77,12 +78,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfWithElseButIfBlockWithoutReturnDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButIfBlockWithoutReturnDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -97,12 +98,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIElseIfDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIElseIfDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -117,12 +118,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfElseIfElseDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfElseIfElseDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -137,21 +138,21 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task - Dim expected As New DiagnosticResult With { - .Id = DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), - .Message = "You can use a ternary operator.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 8, 13)} - } - Await VerifyBasicDiagnosticAsync(sourceAssign, expected) - End Function + + Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task + Dim expected As New DiagnosticResult With { + .Id = DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), + .Message = "You can use a ternary operator.", + .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, + .Locations = {New DiagnosticResultLocation("Test0.vb", 8, 13)} + } + Await VerifyBasicDiagnosticAsync(sourceAssign, expected) + End Function - Private Const sourceAssign = " + Private Const sourceAssign = " Imports System Namespace ConsoleApplication1 Class MyType @@ -167,9 +168,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - - Public Async Function WhenUsingIfAndElseWithAssignmentChangeToTernaryFix() As Task - Const fix = " + + Public Async Function WhenUsingIfAndElseWithAssignmentChangeToTernaryFix() As Task + Const fix = " Imports System Namespace ConsoleApplication1 Class MyType @@ -180,12 +181,21 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicFixAsync(sourceAssign, fix) - End Function + Await VerifyBasicFixAsync(sourceAssign, fix) + End Function + Sub Foo() + Dim v As Boolean + If True Then + ' a comment + v = False + Else + v = True + End If + End Sub - - Public Async Function WhenUsingIfAndElseWithAssignmentChangeToTernaryFixAll() As Task - Const fix = " + + Public Async Function WhenUsingIfAndElseWithAssignmentChangeToTernaryFixAll() As Task + Const fix = " Imports System Namespace ConsoleApplication1 Class MyType @@ -196,12 +206,12 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicFixAllAsync(New String() {sourceAssign, sourceAssign.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) - End Function + Await VerifyBasicFixAllAsync(New String() {sourceAssign, sourceAssign.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function - - Public Async Function WhenTernaryWithObjectDoesApplyFix() As Task - Const source = " + + Public Async Function WhenTernaryWithObjectDoesApplyFix() As Task + Const source = " Class MyCustomer Public Property Value As String End Class @@ -221,7 +231,7 @@ Class Tester End Sub End Class" - Const fix = " + Const fix = " Class MyCustomer Public Property Value As String End Class @@ -237,13 +247,13 @@ Class Tester End Sub End Class" - Await VerifyBasicFixAsync(source, fix) + Await VerifyBasicFixAsync(source, fix) - End Function + End Function - - Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFix() As Task - Const source = " + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFix() As Task + Const source = " Public Class MyType Public Sub Foo() Dim a As Integer? @@ -255,7 +265,7 @@ Public Class MyType End Sub End Class" - Const fix = " + Const fix = " Public Class MyType Public Sub Foo() Dim a As Integer? @@ -263,13 +273,13 @@ Public Class MyType End Sub End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function - - Public Async Function FixConsidersBaseTypeAssignent() As Task - Const source = " + + Public Async Function FixConsidersBaseTypeAssignent() As Task + Const source = " Public Class Base End Class Public Class B @@ -286,7 +296,7 @@ Public Class MyType End Sub End Class" - Const fix = " + Const fix = " Public Class Base End Class Public Class B @@ -299,12 +309,12 @@ Public Class MyType End Sub End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function - - Public Async Function WhenUsingCommentsConcatenateAtEndOfTernary() As Task - Const source = " + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + Public Async Function WhenUsingCommentsConcatenateAtEndOfTernary() As Task + Const source = " Public Class MyType Public Sub Foo() Dim a As Integer @@ -316,7 +326,7 @@ Public Class MyType End Sub End Class" - Const fix = " + Const fix = " Public Class MyType Public Sub Foo() Dim a As Integer @@ -324,13 +334,13 @@ Public Class MyType End Sub End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function - - Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFixAll() As Task - Const source = " + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeAssignmentChangeToTernaryFixAll() As Task + Const source = " Public Class MyType Public Sub Foo() Dim a As Integer? @@ -342,7 +352,7 @@ Public Class MyType End Sub End Class" - Const fix = " + Const fix = " Public Class MyType Public Sub Foo() Dim a As Integer? @@ -350,24 +360,24 @@ Public Class MyType End Sub End Class" - Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) - End Function + Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function - - Public Async Function WhenUsingConcatenationAssignmentExpandsToConcatenateAtEndOfTernary() As Task - Const source = " + + Public Async Function WhenUsingConcatenationAssignmentExpandsToConcatenateAtEndOfTernary() As Task + Const source = " Public Class MyType Public Sub Foo() Dim x = ""test"" If True Then - x = ""1"" + x = ""1"" Else x &= ""2"" End If End Sub End Class" - Const fix = " + Const fix = " Public Class MyType Public Sub Foo() Dim x = ""test"" @@ -375,14 +385,14 @@ Public Class MyType End Sub End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function - - Public Async Function WhenUsingAddAssiginmentExpandsOperationProperly() As Task - Const source = " + + Public Async Function WhenUsingAddAssiginmentExpandsOperationProperly() As Task + Const source = " Public Class MyType Public Sub Foo() Dim x = 0 @@ -394,7 +404,7 @@ Public Class MyType End Sub End Class" - Const fix = " + Const fix = " Public Class MyType Public Sub Foo() Dim x = 0 @@ -402,13 +412,13 @@ Public Class MyType End Sub End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function - - Public Async Function WhenUsingSubtractAssiginmentExpandsOperationProperly() As Task - Const source = " + + Public Async Function WhenUsingSubtractAssiginmentExpandsOperationProperly() As Task + Const source = " Public Class MyType Public Sub Foo() Dim x = 0 @@ -420,7 +430,7 @@ Public Class MyType End Sub End Class" - Const fix = " + Const fix = " Public Class MyType Public Sub Foo() Dim x = 0 @@ -428,13 +438,13 @@ Public Class MyType End Sub End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function - - Public Async Function WhenUsingAssignmentOperatorReturnSameAssignment() As Task - Const source = " + + Public Async Function WhenUsingAssignmentOperatorReturnSameAssignment() As Task + Const source = " Class MyType Public Sub x2() Dim output As String = String.Empty @@ -448,7 +458,7 @@ Class MyType End Sub End Class" - Const fix = " + Const fix = " Class MyType Public Sub x2() Dim output As String = String.Empty @@ -458,18 +468,16 @@ Class MyType End Sub End Class" - Await VerifyBasicFixAsync(source, fix, formatBeforeCompare:=True) - End Function - - -End Class + Await VerifyBasicFixAsync(source, fix, formatBeforeCompare:=True) + End Function + End Class -Public Class TernaryOperatorWithReturnTests - Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorWithReturnCodeFixProvider) + Public Class TernaryOperatorWithReturnTests + Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorWithReturnCodeFixProvider) - - Public Async Function WhenUsingIfWithoutElseAnalyzerDoesNotCreateDiagnostic() As Task - Const sourceWithoutElse = " + + Public Async Function WhenUsingIfWithoutElseAnalyzerDoesNotCreateDiagnostic() As Task + Const sourceWithoutElse = " Namespace ConsoleApplication1 Class TypeName Public Function Foo() As Integer @@ -480,12 +488,12 @@ Namespace ConsoleApplication1 End Function End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithoutElse) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithoutElse) + End Function - - Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnIfAnalyzerDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnIfAnalyzerDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Function Foo() As Integer @@ -499,12 +507,12 @@ Namespace ConsoleApplication1 End Function End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnElseAnalyzerDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButWithBlockWith2StatementsOnElseAnalyzerDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Function Foo() As Integer @@ -518,12 +526,12 @@ Namespace ConsoleApplication1 End Function End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfWithElseButWithoutReturnOnElseDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButWithoutReturnOnElseDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Function Foo() As Integer @@ -536,12 +544,12 @@ Namespace ConsoleApplication1 End Function End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfWithElseButIfBlockWithoutReturnDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfWithElseButIfBlockWithoutReturnDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Function Foo() As Integer @@ -554,12 +562,12 @@ Namespace ConsoleApplication1 End Function End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIElseIfDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIElseIfDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Function Foo() As Integer @@ -573,13 +581,13 @@ Namespace ConsoleApplication1 End Function End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFix() As Task - Const source = " + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFix() As Task + Const source = " Public Class MyType Public Function Foo() As Integer? If True Then @@ -590,20 +598,20 @@ Public Class MyType End Function End Class" - Const fix = " + Const fix = " Public Class MyType Public Function Foo() As Integer? Return If(True, 1, DirectCast(Nothing, Integer?)) End Function End Class" - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) - End Function + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function - - Public Async Function WhenUsingIfElseIfElseDoesNotCreate() As Task - Const sourceWithMultipleStatements = " + + Public Async Function WhenUsingIfElseIfElseDoesNotCreate() As Task + Const sourceWithMultipleStatements = " Namespace ConsoleApplication1 Class TypeName Public Sub Foo() @@ -617,13 +625,13 @@ Namespace ConsoleApplication1 End Sub End Class End Namespace" - Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(sourceWithMultipleStatements) + End Function - - Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFixAll() As Task - Const source = " + + Public Async Function WhenUsingIfAndElseWithNullableValueTypeDirectReturnChangeToTernaryFixAll() As Task + Const source = " Public Class MyType Public Function Foo() As Integer? If True Then @@ -634,17 +642,17 @@ Public Class MyType End Function End Class" - Const fix = " + Const fix = " Public Class MyType Public Function Foo() As Integer? Return If(True, 1, DirectCast(Nothing, Integer?)) End Function End Class" - Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) - End Function + Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function - Private Const sourceReturn = " + Private Const sourceReturn = " Namespace ConsoleApplication1 Class MyType Public Function Foo() As Integer @@ -658,20 +666,20 @@ Namespace ConsoleApplication1 End Class End Namespace" - - Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task - Dim expected As New DiagnosticResult With { - .Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), - .Message = "You can use a ternary operator.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 13)} - } - Await VerifyBasicDiagnosticAsync(sourceReturn, expected) - End Function + + Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task + Dim expected As New DiagnosticResult With { + .Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), + .Message = "You can use a ternary operator.", + .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, + .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 13)} + } + Await VerifyBasicDiagnosticAsync(sourceReturn, expected) + End Function - - Public Async Function WhenUsingIfAndElseWithDirectReturnCreatesFix() As Task - Const fix = " + + Public Async Function WhenUsingIfAndElseWithDirectReturnCreatesFix() As Task + Const fix = " Namespace ConsoleApplication1 Class MyType Public Function Foo() As Integer @@ -681,12 +689,12 @@ Namespace ConsoleApplication1 End Class End Namespace" - Await VerifyBasicFixAsync(sourceReturn, fix) - End Function + Await VerifyBasicFixAsync(sourceReturn, fix) + End Function - - Public Async Function WhenUsingIfAndElseWithDirectReturnCreatesFixAll() As Task - Const fix = " + + Public Async Function WhenUsingIfAndElseWithDirectReturnCreatesFixAll() As Task + Const fix = " Namespace ConsoleApplication1 Class MyType Public Function Foo() As Integer @@ -696,18 +704,73 @@ Namespace ConsoleApplication1 End Class End Namespace" - Await VerifyBasicFixAllAsync(New String() {sourceReturn, sourceReturn.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) - End Function + Await VerifyBasicFixAllAsync(New String() {sourceReturn, sourceReturn.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function + + Public Async Function FixCanWorkWithCommentsOnIf() As Task + Const source = " +Function s() As Boolean + If True Then + ' a comment + Return False 'b comment + Else + Return True + End If +End Function" + Const fix = " +Function s() As Boolean + ' a comment + Return If(True, False, True) 'b comment +End Function" + Await VerifyBasicFixAsync(source, fix) + End Function -End Class + Public Async Function FixCanWorkWithCommentsOnElse() As Task + Const source = " +Function s() As Boolean + If True Then + Return False + Else + ' a comment + Return True 'b comment + End If +End Function" + Const fix = " +Function s() As Boolean + ' a comment + Return If(True, False, True) 'b comment +End Function" + Await VerifyBasicFixAsync(source, fix) + End Function + + Public Async Function FixCanWorkWithCommentsOnIfAndElse() As Task + Const source = " +Function s() As Boolean + If True Then + ' a comment + Return False 'b comment + Else + ' c comment + Return True 'd comment + End If +End Function" + Const fix = " +Function s() As Boolean + ' a comment + ' c comment + Return If(True, False, True) 'b comment 'd comment +End Function" + Await VerifyBasicFixAsync(source, fix) + End Function + End Class -Public Class TernaryOperatorFromIifTests - Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorFromIifCodeFixProvider) + Public Class TernaryOperatorFromIifTests + Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorFromIifCodeFixProvider) - - Public Async Function WhenUsingIifAndSimpleAssignmentCreatesFix() As Task - Const source = " + + Public Async Function WhenUsingIifAndSimpleAssignmentCreatesFix() As Task + Const source = " Class TypeName Public Sub Foo() Dim x = 1 @@ -715,7 +778,7 @@ Class TypeName End Sub End Class" - Const fix = " + Const fix = " Class TypeName Public Sub Foo() Dim x = 1 @@ -723,12 +786,12 @@ Class TypeName End Sub End Class" - Await VerifyBasicFixAsync(source, fix) - End Function + Await VerifyBasicFixAsync(source, fix) + End Function - - Public Async Function WhenUsingIifAndSimpleAssignmentCreatesFixAll() As Task - Const source = " + + Public Async Function WhenUsingIifAndSimpleAssignmentCreatesFixAll() As Task + Const source = " Class MyType Public Sub Foo() Dim x = 1 @@ -736,7 +799,7 @@ Class MyType End Sub End Class" - Const fix = " + Const fix = " Class MyType Public Sub Foo() Dim x = 1 @@ -744,12 +807,12 @@ Class MyType End Sub End Class" - Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) - End Function + Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function - - Public Async Function WhenUsingIifAndReturnCreatesFix() As Task - Const source = " + + Public Async Function WhenUsingIifAndReturnCreatesFix() As Task + Const source = " Class MyType Public Function Foo() As Integer Dim x = 1 @@ -757,7 +820,7 @@ Class MyType End Function End Class" - Const fix = " + Const fix = " Class MyType Public Function Foo() As Integer Dim x = 1 @@ -765,20 +828,20 @@ Class MyType End Function End Class" - Dim expected As New DiagnosticResult With { - .Id = DiagnosticId.TernaryOperator_Iif.ToDiagnosticId(), - .Message = "You can use a ternary operator.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 16)} - } + Dim expected As New DiagnosticResult With { + .Id = DiagnosticId.TernaryOperator_Iif.ToDiagnosticId(), + .Message = "You can use a ternary operator.", + .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, + .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 16)} + } - Await VerifyBasicDiagnosticAsync(source, expected) - Await VerifyBasicFixAsync(source, fix) - End Function + Await VerifyBasicDiagnosticAsync(source, expected) + Await VerifyBasicFixAsync(source, fix) + End Function - - Public Async Function WhenUsingIifAndReturnCreatesFixAll() As Task - Const source = " + + Public Async Function WhenUsingIifAndReturnCreatesFixAll() As Task + Const source = " Class MyType Public Function Foo() As Integer Dim x = 1 @@ -786,7 +849,7 @@ Class MyType End Function End Class" - Const fix = " + Const fix = " Class MyType Public Function Foo() As Integer Dim x = 1 @@ -794,44 +857,44 @@ Class MyType End Function End Class" - Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) - End Function + Await VerifyBasicFixAllAsync(New String() {source, source.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) + End Function - - Public Async Function WhenNotUsingIifDoesNotCreateAnalyzer() As Task - Const source = " + + Public Async Function WhenNotUsingIifDoesNotCreateAnalyzer() As Task + Const source = " Class TypeName Public Sub Foo() Dim x = 1 End Sub End Class" - Await VerifyBasicHasNoDiagnosticsAsync(source) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(source) + End Function - - Public Async Function WhenIifWithTooManyParametersDoesNotCreateAnalyzer() As Task - Const source = " + + Public Async Function WhenIifWithTooManyParametersDoesNotCreateAnalyzer() As Task + Const source = " Class TypeName Public Sub Foo() Dim x = Iif(true, 1, 2, 3) End Sub End Class" - Await VerifyBasicHasNoDiagnosticsAsync(source) - End Function + Await VerifyBasicHasNoDiagnosticsAsync(source) + End Function - - Public Async Function WhenIifWithTooFewParametersDoesNotCreateAnalyzer() As Task - Const source = " + + Public Async Function WhenIifWithTooFewParametersDoesNotCreateAnalyzer() As Task + Const source = " Class TypeName Public Sub Foo() Dim x = Iif(true, 1) End Sub End Class" - Await VerifyBasicHasNoDiagnosticsAsync(source) - End Function - -End Class + Await VerifyBasicHasNoDiagnosticsAsync(source) + End Function + End Class +End Namespace From 9258e181ee4a7101837d2f19a65119097334ee70 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 15 Mar 2016 01:05:35 -0300 Subject: [PATCH 147/358] Enable Make Ternary for VB when it has leading comments Similar as #725, but for CC0014 --- .../CodeCracker/Style/TernaryOperatorAnalyzer.vb | 8 +++++--- .../CodeCracker.Test/Style/TernaryOperatorTests.vb | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb index 7b498b661..81602adea 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorAnalyzer.vb @@ -67,7 +67,6 @@ Namespace Style If TypeOf (ifClauseStatement) Is ReturnStatementSyntax AndAlso TypeOf (elseStatement) Is ReturnStatementSyntax Then - Dim diag = Diagnostic.Create(RuleForIfWithReturn, ifStatement.IfKeyword.GetLocation, "You can use a ternary operator.") context.ReportDiagnostic(diag) Exit Sub @@ -76,7 +75,10 @@ Namespace Style Dim ifAssignment = TryCast(ifClauseStatement, AssignmentStatementSyntax) Dim elseAssignment = TryCast(elseStatement, AssignmentStatementSyntax) If ifAssignment Is Nothing OrElse elseAssignment Is Nothing Then Exit Sub - If Not ifAssignment?.Left.IsEquivalentTo(elseAssignment?.Left) Then Exit Sub + Dim semanticModel = context.SemanticModel + Dim ifSymbol = semanticModel.GetSymbolInfo(ifAssignment.Left).Symbol + Dim elseSymbol = semanticModel.GetSymbolInfo(elseAssignment.Left).Symbol + If ifSymbol Is Nothing OrElse elseSymbol Is Nothing OrElse ifSymbol.Equals(elseSymbol) = False Then Exit Sub Dim assignDiag = Diagnostic.Create(RuleForIfWithAssignment, ifStatement.IfKeyword.GetLocation(), "You can use a ternary operator.") context.ReportDiagnostic(assignDiag) End Sub @@ -95,4 +97,4 @@ Namespace Style End If End Sub End Class -End Namespace +End Namespace \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 89c3787a8..b363d18ba 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -319,8 +319,10 @@ Public Class MyType Public Sub Foo() Dim a As Integer If True Then + ' a a = 1 ' One Thing Else + ' b a = 2 ' Another End If End Sub @@ -330,6 +332,8 @@ End Class" Public Class MyType Public Sub Foo() Dim a As Integer + ' a + ' b a = If(True, 1, 2) ' One Thing ' Another End Sub End Class" From 847553ad153ff14490e9f3dea37095419caba729 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 27 Mar 2016 14:25:09 -0300 Subject: [PATCH 148/358] Allows verbatim identifiers with UnusedParametersAnalyzer Closes #741 --- .../Usage/UnusedParametersAnalyzer.cs | 8 +++-- .../Usage/UnusedParametersTests.cs | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs index a0fdedc2f..cec3e43ea 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs @@ -110,13 +110,15 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) private static bool IdentifierRefersToParam(IdentifierNameSyntax iName, ParameterSyntax param) { - if (iName.Identifier.ToString() != param.Identifier.ToString()) + var identifierName = iName.Identifier.ToString(); + if (!identifierName.StartsWith("@")) identifierName = $"@{identifierName}"; + var parameterName = param.Identifier.ToString(); + if (!parameterName.StartsWith("@")) parameterName = $"@{parameterName}"; + if (identifierName != parameterName) return false; - var mae = iName.Parent as MemberAccessExpressionSyntax; if (mae == null) return true; - return mae.DescendantNodes().FirstOrDefault() == iName; } diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 8402298ac..44cf5f2b9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -58,6 +58,39 @@ public int Foo(int a) await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task UsedParameterWithVerbatimIdentifierDoesNotCreateDiagnostic() + { + var source = @" +public int Foo(int @a) +{ + return a; +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task UsedParameterUsedWithVerbatimIdentifierDoesNotCreateDiagnostic() + { + var source = @" +public int Foo(int a) +{ + return @a; +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task UsedParameterWithVerbatimIdentifierUsedWithVerbatimIdentifierDoesNotCreateDiagnostic() + { + var source = @" +public int Foo(int @a) +{ + return @a; +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task MethodWithoutStatementsCreatesDiagnostic() { From 5c2fb201fb4d1a2013c5cde2cbe6d307c4a101a3 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 27 Mar 2016 21:30:03 -0300 Subject: [PATCH 149/358] Enable to change to ternary with primitive numeric types Fixes #748 Also fixes for type Object --- .../Extensions/CSharpAnalyzerExtensions.cs | 148 +++++++++++++++++- .../Style/TernaryOperatorCodeFixProvider.cs | 10 +- .../Style/TernaryOperatorTests.cs | 123 +++++++++++++++ 3 files changed, 279 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 095b7991c..818a5b276 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -644,7 +644,7 @@ private static InitializerState DoesBlockContainCertainInitializer(this IEnumera var ifResult = ifStatement.Statement.DoesBlockContainCertainInitializer(context, symbol); if (ifStatement.Else != null) { - var elseResult = ifStatement.Else.Statement .DoesBlockContainCertainInitializer(context, symbol); + var elseResult = ifStatement.Else.Statement.DoesBlockContainCertainInitializer(context, symbol); if (ifResult == InitializerState.Initializer && elseResult == InitializerState.Initializer) currentState = InitializerState.Initializer; @@ -722,5 +722,151 @@ public static TypeDeclarationSyntax WithMembers(this TypeDeclarationSyntax typeD throw new NotSupportedException(); } } + + /// + /// According to the C# Language Spec, item 6.4 + /// See online. + /// + /// The type to convert from + /// The type to convert to + public static bool HasImplicitNumericConversion(this ITypeSymbol from, ITypeSymbol to) + { + if (from == null || to == null) return false; + switch (from.SpecialType) + { + case SpecialType.System_SByte: + switch (to.SpecialType) + { + case SpecialType.System_SByte: + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_Byte: + switch (to.SpecialType) + { + case SpecialType.System_Byte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_Int16: + switch (to.SpecialType) + { + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_UInt16: + switch (to.SpecialType) + { + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_Int32: + switch (to.SpecialType) + { + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_UInt32: + switch (to.SpecialType) + { + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_Int64: + switch (to.SpecialType) + { + case SpecialType.System_Int64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_UInt64: + switch (to.SpecialType) + { + case SpecialType.System_UInt64: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_Char: + switch (to.SpecialType) + { + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Char: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + return true; + default: + return false; + } + case SpecialType.System_Single: + switch (to.SpecialType) + { + case SpecialType.System_Single: + case SpecialType.System_Double: + return true; + default: + return false; + } + default: + return false; + } + } } } diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index cae303ff2..97ebd2e3f 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -135,13 +135,20 @@ private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionS { falseExpression = elseExpression; } - if (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType)) + if (!elseType.HasImplicitNumericConversion(ifType) + && !IsEnumAndZero(ifType, elseExpression) + && !IsEnumAndZero(elseType, ifExpression) + && (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType))) trueExpression = CastToBaseType(ifExpression, ifType, elseType, trueExpression); } + private static bool IsEnumAndZero(ITypeSymbol type, ExpressionSyntax expression) => + type?.BaseType?.SpecialType == SpecialType.System_Enum && expression?.ToString() == "0"; + private static ExpressionSyntax CastToBaseType(ExpressionSyntax ifExpression, ITypeSymbol ifType, ITypeSymbol elseType, ExpressionSyntax trueExpression) { var commonBaseType = ifType.GetCommonBaseType(elseType); + if (commonBaseType.Equals(ifType)) return trueExpression; if (commonBaseType != null) trueExpression = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(commonBaseType.Name).WithAdditionalAnnotations(Simplifier.Annotation), ifExpression); return trueExpression; @@ -152,6 +159,7 @@ private static bool CanBeAssignedTo(this ITypeSymbol type, ITypeSymbol possibleB if (type == null || possibleBaseType == null) return true; if (type.Kind == SymbolKind.ErrorType || possibleBaseType.Kind == SymbolKind.ErrorType) return true; if (type == null || possibleBaseType == null) return true; + if (type.SpecialType == SpecialType.System_Object) return true; var baseType = type; while (baseType != null && baseType.SpecialType != SpecialType.System_Object) { diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 73ca6e47c..946cc60f1 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -406,6 +406,129 @@ class TypeName await VerifyCSharpFixAsync(source, fixtest, allowNewCompilerDiagnostics: true); } + [Fact] + public async Task FixWhenThereIsNumericImplicitConversion() + { + var source = @" +static double OnReturn() +{ + var condition = true; + double aDouble = 2; + var bInteger = 3; + if (condition) + return aDouble; + else + return bInteger; +}".WrapInCSharpClass(); + var fixtest = @" +static double OnReturn() +{ + var condition = true; + double aDouble = 2; + var bInteger = 3; + return condition ? aDouble : bInteger; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenThereIsImplicitConversionWithZeroAndEnum() + { + var source = @" +enum FooBar +{ + one, two +} +static FooBar OnReturn() +{ + var condition = true; + var fooBar = FooBar.one; + if (condition) + return 0; + else + return fooBar; +}".WrapInCSharpClass(); + var fixtest = @" +enum FooBar +{ + one, two +} +static FooBar OnReturn() +{ + var condition = true; + var fooBar = FooBar.one; + return condition ? 0 : fooBar; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenThereIsImplicitConversionWithEnumAndZero() + { + var source = @" +enum FooBar +{ + one, two +} +static FooBar OnReturn() +{ + var condition = true; + var fooBar = FooBar.one; + if (condition) + return fooBar; + else + return 0; +}".WrapInCSharpClass(); + var fixtest = @" +enum FooBar +{ + one, two +} +static FooBar OnReturn() +{ + var condition = true; + var fooBar = FooBar.one; + return condition ? fooBar : 0; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningAnObject() + { + var source = @" +static object OnReturn() +{ + var condition = true; + var aInt = 2; + var anObj = new object(); + if (condition) + return anObj; + else + return aInt; +}".WrapInCSharpClass(); + var fixtest = @" +static object OnReturn() +{ + var condition = true; + var aInt = 2; + var anObj = new object(); + return condition ? anObj : aInt; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + static object OnReturn() + { + var condition = true; + var aInt = 2; + var anObj = new object(); + if (condition) + return anObj; + else + return aInt; + } + [Fact] public async Task WhenUsingIfAndElseWithDirectReturnChangeToTernaryFixAll() { From 4d0bac116d4055288b0632b53bbf6b7fc62f98ef Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 27 Mar 2016 21:32:52 -0300 Subject: [PATCH 150/358] Pass exit code 1 to nodemon always Nodemon fails with some exit codes, this way we avoid that. --- runTestsCS.ps1 | 4 ++-- runTestsVB.ps1 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/runTestsCS.ps1 b/runTestsCS.ps1 index bc640573f..2131ad77c 100644 --- a/runTestsCS.ps1 +++ b/runTestsCS.ps1 @@ -24,7 +24,7 @@ If ($testClass) { } If ($testClass) { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass || exit 1" } Else { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" || exit 1" } \ No newline at end of file diff --git a/runTestsVB.ps1 b/runTestsVB.ps1 index d2fe0644e..2da22c936 100644 --- a/runTestsVB.ps1 +++ b/runTestsVB.ps1 @@ -24,7 +24,7 @@ If ($testClass) { } If ($testClass) { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass" + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" -class $testClass || exit 1" } Else { - nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`"" -} \ No newline at end of file + nodemon --watch $testDllFullFileName --exec "`"$xunitConsole`" `"$testDllFullFileName`" || exit 1" +} From f18dfe8d56af89ae52ffb19d6ec54110ad7b9de6 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 28 Mar 2016 23:45:30 -0300 Subject: [PATCH 151/358] Respect precendence rules when nesting if statements Closes #740 Fixing for Logical OR, Conditional and Coalescing. --- .../MergeNestedIfCodeFixProvider.cs | 5 +- .../Refactoring/MergeNestedIfTest.cs | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Refactoring/MergeNestedIfCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/MergeNestedIfCodeFixProvider.cs index 872ca8a8b..ec24113a7 100644 --- a/src/CSharp/CodeCracker/Refactoring/MergeNestedIfCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/MergeNestedIfCodeFixProvider.cs @@ -40,8 +40,11 @@ private async static Task MergeIfsAsync(Document document, Location di private static SyntaxNode MergeIfs(IfStatementSyntax ifStatement, SyntaxNode root) { var nestedIf = (IfStatementSyntax)ifStatement.Statement.GetSingleStatementFromPossibleBlock(); + var nestedCondition = nestedIf.Condition; + if (nestedCondition.IsAnyKind(SyntaxKind.LogicalOrExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CoalesceExpression)) + nestedCondition = SyntaxFactory.ParenthesizedExpression(nestedCondition); var newIf = ifStatement - .WithCondition(SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, ifStatement.Condition, nestedIf.Condition)) + .WithCondition(SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, ifStatement.Condition, nestedCondition)) .WithStatement(nestedIf.Statement) .WithLeadingTrivia(ifStatement.GetLeadingTrivia().AddRange(nestedIf.GetLeadingTrivia())) .WithAdditionalAnnotations(Formatter.Annotation); diff --git a/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs b/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs index 3adee8668..1bcda1b72 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs @@ -185,5 +185,70 @@ public async Task IfWithoutBlockWithNestedIfWithoutBlockFixed() var a = 1;//comment2".WrapInCSharpMethod(); await VerifyCSharpFixAsync(test, fixtest); } + + [Fact] + public async Task FixAddsParenthesisWhenSecondConditionHasLogicalORExpression() + { + var test = @" +var conditionA = false; +var conditionB = false; +var conditionC = false; +if (conditionA) + if (conditionB || conditionC) + System.Console.WriteLine(); +".WrapInCSharpMethod(); + var fixtest = @" +var conditionA = false; +var conditionB = false; +var conditionC = false; +if (conditionA && (conditionB || conditionC)) + System.Console.WriteLine(); +".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task FixAddsParenthesisWhenSecondConditionHasConditionalExpression() + { + var test = @" +var conditionA = false; +var conditionB = false; +var conditionC = false; +var conditionD = false; +if (conditionA) + if (conditionB ? conditionC : conditionD) + System.Console.WriteLine(); +".WrapInCSharpMethod(); + var fixtest = @" +var conditionA = false; +var conditionB = false; +var conditionC = false; +var conditionD = false; +if (conditionA && (conditionB ? conditionC : conditionD)) + System.Console.WriteLine(); +".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task FixAddsParenthesisWhenSecondConditionHasCoalescingExpression() + { + var test = @" +var conditionA = false; +bool? conditionB = false; +var conditionC = false; +if (conditionA) + if (conditionB ?? conditionC) + System.Console.WriteLine(); +".WrapInCSharpMethod(); + var fixtest = @" +var conditionA = false; +bool? conditionB = false; +var conditionC = false; +if (conditionA && (conditionB ?? conditionC)) + System.Console.WriteLine(); +".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(test, fixtest); + } } } \ No newline at end of file From 76f893baf3ceec9ba6896ae808f4561b5f486baa Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 29 Mar 2016 00:18:00 -0300 Subject: [PATCH 152/358] Skip removing Where method when it is called with indexer Closes #752 --- .../RemoveWhereWhenItIsPossibleAnalyzer.cs | 38 +++++++++---------- .../RemoveWhereWhenItIsPossibleTests.cs | 19 ++++++---- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs index 6ddf3bb23..aa7fbda5e 100644 --- a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs @@ -46,40 +46,36 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; var whereInvoke = (InvocationExpressionSyntax)context.Node; - if (GetNameOfTheInvokedMethod(whereInvoke) != "Where") return; + var nameOfWhereInvoke = GetNameOfTheInvokedMethod(whereInvoke); + if (nameOfWhereInvoke?.ToString() != "Where") return; + if (ArgumentsDoNotMatch(whereInvoke)) return; var nextMethodInvoke = whereInvoke.Parent. FirstAncestorOrSelf(); + if (nextMethodInvoke == null) return; - var candidate = GetNameOfTheInvokedMethod(nextMethodInvoke); + var candidate = GetNameOfTheInvokedMethod(nextMethodInvoke)?.ToString(); if (!supportedMethods.Contains(candidate)) return; if (nextMethodInvoke.ArgumentList.Arguments.Any()) return; var properties = new Dictionary { { "methodName", candidate } }.ToImmutableDictionary(); - var diagnostic = Diagnostic.Create(Rule, GetNameExpressionOfTheInvokedMethod(whereInvoke).GetLocation(), properties, candidate); + var diagnostic = Diagnostic.Create(Rule, nameOfWhereInvoke.GetLocation(), properties, candidate); context.ReportDiagnostic(diagnostic); } - internal static string GetNameOfTheInvokedMethod(InvocationExpressionSyntax invoke) + private static bool ArgumentsDoNotMatch(InvocationExpressionSyntax whereInvoke) { - if (invoke == null) return null; - - var memberAccess = invoke.ChildNodes() - .OfType() - .FirstOrDefault(); - - return GetNameExpressionOfTheInvokedMethod(invoke)?.ToString(); + var arguments = whereInvoke.ArgumentList.Arguments; + if (arguments.Count != 1) return true; + var expression = arguments.First()?.Expression; + if (expression == null) return true; + if (expression is SimpleLambdaExpressionSyntax) return false; + var parenthesizedLambda = expression as ParenthesizedLambdaExpressionSyntax; + if (parenthesizedLambda == null) return true; + return parenthesizedLambda.ParameterList.Parameters.Count != 1; } - internal static SimpleNameSyntax GetNameExpressionOfTheInvokedMethod(InvocationExpressionSyntax invoke) - { - if (invoke == null) return null; - - var memberAccess = invoke.ChildNodes() - .OfType() - .FirstOrDefault(); - - return memberAccess?.Name; - } + private static SimpleNameSyntax GetNameOfTheInvokedMethod(InvocationExpressionSyntax invoke) => + invoke.ChildNodes().OfType().FirstOrDefault()?.Name; } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs index dc64b6c7b..c6e4b622a 100644 --- a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs @@ -69,11 +69,19 @@ public async Task DoSomething() } } }"; - await VerifyCSharpHasNoDiagnosticsAsync(test); - } + [Fact] + public async Task DoNotCreateDiagnosticWhenWhereUsesIndexer() + { + var test = @" +var first = Enumerable.Range(1, 10).ToList(); +var second = Enumerable.Range(1, 10); +var isNotMatch = second.Where((t, i) => first[i] != t).Any(); +".WrapInCSharpMethod(usings: "using System.Linq;"); + await VerifyCSharpHasNoDiagnosticsAsync(test); + } [Theory] [InlineData("First")] @@ -96,11 +104,10 @@ public class Foo public async Task DoSomething() { var a = new int[10]; - var f = a.Where(item => item > 10)." + method + @"(); + var f = a.Where((item) => item > 10)." + method + @"(); } } }"; - var expected = @" using System.Linq; @@ -111,13 +118,11 @@ public class Foo public async Task DoSomething() { var a = new int[10]; - var f = a." + method + @"(item => item > 10); + var f = a." + method + @"((item) => item > 10); } } }"; - await VerifyCSharpFixAsync(test, expected); - } [Theory] From 2cdd64299b578c37efbcb1af099e6735c6b1aa46 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 29 Mar 2016 01:08:01 -0300 Subject: [PATCH 153/358] Enable attributes when ignoring private methods in VB Fixes #744 Also, fixes on C# when qualified names were not verified Also, check for entry points in VB (already worked, only tests) --- .../RemovePrivateMethodNeverUsedAnalyzer.cs | 12 ++++- .../RemovePrivateMethodNeverUsedAnalyzer.vb | 27 +++++++++++ ...emovePrivateMethodNeverUsedAnalyzerTest.cs | 1 + ...emovePrivateMethodNeverUsedAnalyzerTest.vb | 47 +++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs index 335173ed5..40b86f79d 100644 --- a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs @@ -58,7 +58,17 @@ private static bool IsMethodAttributeAnException(MethodDeclarationSyntax methodD foreach (var attribute in attributeList.Attributes) { var identifierName = attribute.Name as IdentifierNameSyntax; - var nameText = identifierName?.Identifier.Text; + string nameText = null; + if (identifierName != null) + { + nameText = identifierName?.Identifier.Text; + } + else + { + var qualifiedName = attribute.Name as QualifiedNameSyntax; + if (qualifiedName != null) + nameText = qualifiedName.Right?.Identifier.Text; + } if (nameText == null) continue; if (IsExcludedAttributeName(nameText)) return true; } diff --git a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb index c273ef808..e1ecd9068 100644 --- a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb @@ -38,12 +38,39 @@ Namespace Usage Dim methodStatement = DirectCast(context.Node, MethodStatementSyntax) If methodStatement.HandlesClause IsNot Nothing Then Exit Sub If Not methodStatement.Modifiers.Any(Function(a) a.ValueText = SyntaxFactory.Token(SyntaxKind.PrivateKeyword).ValueText) Then Exit Sub + If (IsMethodAttributeAnException(methodStatement)) Then Return If IsMethodUsed(methodStatement, context.SemanticModel) Then Exit Sub Dim props = New Dictionary(Of String, String) From {{"identifier", methodStatement.Identifier.Text}}.ToImmutableDictionary() Dim diag = Diagnostic.Create(Rule, methodStatement.GetLocation(), props) context.ReportDiagnostic(diag) End Sub + Private Function IsMethodAttributeAnException(methodStatement As MethodStatementSyntax) As Boolean + For Each attributeList In methodStatement.AttributeLists + For Each attribute In attributeList.Attributes + Dim identifierName = TryCast(attribute.Name, IdentifierNameSyntax) + Dim nameText As String = Nothing + If (identifierName IsNot Nothing) Then + nameText = identifierName?.Identifier.Text + Else + Dim qualifiedName = TryCast(attribute.Name, QualifiedNameSyntax) + If (qualifiedName IsNot Nothing) Then + nameText = qualifiedName.Right?.Identifier.Text + End If + End If + If (nameText Is Nothing) Then Continue For + If (IsExcludedAttributeName(nameText)) Then Return True + Next + Next + Return False + End Function + + Private Shared ReadOnly excludedAttributeNames As String() = {"Fact", "ContractInvariantMethod", "DataMember"} + + Private Shared Function IsExcludedAttributeName(attributeName As String) As Boolean + Return excludedAttributeNames.Contains(attributeName) + End Function + Private Function IsMethodUsed(methodTarget As MethodStatementSyntax, semanticModel As SemanticModel) As Boolean Dim typeDeclaration = TryCast(methodTarget.Parent.Parent, ClassBlockSyntax) If typeDeclaration Is Nothing Then Return True diff --git a/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs b/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs index c866a17b0..abc0c6e97 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs @@ -9,6 +9,7 @@ public class RemovePrivateMethodNeverUsedAnalyzerTest : CodeFixVerifier + + + + + Public Async Function DoesNotGenerateDiagnosticsWhenMethodAttributeIsAnException(value As String) As Task + Dim source = " +Class Foo + <" + value + "> + Private Sub PrivateFoo() + End Sub +End Class" + Await VerifyBasicHasNoDiagnosticsAsync(source) + End Function + + + Public Async Function MainMethodEntryPointReturningVoidDoesNotCreateDiagnostic() As Task + Const test = " +Module Foo + Sub Main(args as String()) + End Sub +End Module" + Await VerifyBasicHasNoDiagnosticsAsync(test) + End Function + + + Public Async Function MainMethodEntryPointReturningIntegerDoesNotCreateDiagnostic() As Task + Const test = " +Module Foo + Function Main(args as String()) as Integer + Return 0 + End Function +End Module" + Await VerifyBasicHasNoDiagnosticsAsync(test) + End Function + + + Public Async Function MainMethodEntryPointWithoutParameterDoesNotCreateDiagnostic() As Task + Const test = " +Module Foo + Function Main() as Integer + Return 0 + End Function +End Module" + Await VerifyBasicHasNoDiagnosticsAsync(test) + End Function + Public Async Function DoesNotGenerateDiagnostics() As Task Const test = " From e83d55b1535f52c958d630d90d4529a1bde34b98 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 31 Mar 2016 01:00:36 -0300 Subject: [PATCH 154/358] Enable to change to ternary with primitive numeric types Fixes #745 --- .../Extensions/VBAnalyzerExtensions.vb | 20 ++++++- .../Style/TernaryOperatorCodeFixProviders.vb | 3 +- .../Helpers/Extensions.cs | 14 +++++ .../Style/TernaryOperatorTests.vb | 53 +++++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb b/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb index 9b3ed1894..d7fe23787 100644 --- a/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb +++ b/src/VisualBasic/CodeCracker/Extensions/VBAnalyzerExtensions.vb @@ -42,10 +42,28 @@ Public Module VBAnalyzerExtensions Public Function ConvertToBaseType(source As ExpressionSyntax, sourceType As ITypeSymbol, targetType As ITypeSymbol) As ExpressionSyntax - If targetType?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then Return source + If (sourceType?.IsNumeric() AndAlso targetType?.IsNumeric()) OrElse + (sourceType?.BaseType?.SpecialType = SpecialType.System_Enum AndAlso targetType?.IsNumeric()) OrElse + (targetType?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T) Then Return source Return If(sourceType IsNot Nothing AndAlso sourceType.Name = targetType.Name, source, SyntaxFactory.DirectCastExpression(source.WithoutTrailingTrivia, SyntaxFactory.ParseTypeName(targetType.Name))).WithTrailingTrivia(source.GetTrailingTrivia()) End Function + + Public Function IsNumeric(typeSymbol As ITypeSymbol) As Boolean + Return typeSymbol.SpecialType = SpecialType.System_Byte OrElse + typeSymbol.SpecialType = SpecialType.System_SByte OrElse + typeSymbol.SpecialType = SpecialType.System_Int16 OrElse + typeSymbol.SpecialType = SpecialType.System_UInt16 OrElse + typeSymbol.SpecialType = SpecialType.System_Int16 OrElse + typeSymbol.SpecialType = SpecialType.System_UInt32 OrElse + typeSymbol.SpecialType = SpecialType.System_Int32 OrElse + typeSymbol.SpecialType = SpecialType.System_UInt64 OrElse + typeSymbol.SpecialType = SpecialType.System_Int64 OrElse + typeSymbol.SpecialType = SpecialType.System_Decimal OrElse + typeSymbol.SpecialType = SpecialType.System_Single OrElse + typeSymbol.SpecialType = SpecialType.System_Double + End Function + Public Function EnsureNothingAsType(expression As ExpressionSyntax, semanticModel As SemanticModel, type As ITypeSymbol, typeSyntax As TypeSyntax) As ExpressionSyntax If type?.OriginalDefinition.SpecialType = SpecialType.System_Nullable_T Then diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 11d68892c..4b60a321e 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -62,7 +62,8 @@ Namespace Style Dim returnStatement = SyntaxFactory.ReturnStatement(ternary). WithLeadingTrivia(leadingTrivia). - WithTrailingTrivia(trailingTrivia) + WithTrailingTrivia(trailingTrivia). + WithAdditionalAnnotations(Formatter.Annotation) Dim newRoot = root.ReplaceNode(ifBlock, returnStatement) Dim newDocument = document.WithSyntaxRoot(newRoot) diff --git a/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs b/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs index 514ab1e6b..082843818 100644 --- a/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs +++ b/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs @@ -32,6 +32,20 @@ class {typeName} }} }}"; } + + public static string WrapInVBClass(this string code, + string typeName = "TypeName", + string imports = "") + { + return $@" +Imports System{imports} +Namespace ConsoleApplication1 + Class {typeName} + {code} + End Class +End Namespace"; + } + public static string WrapInVBMethod(this string code, bool isAsync = false, string typeName = "TypeName", diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index b363d18ba..80a039a2a 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -5,6 +5,7 @@ Namespace Style Public Class TernaryOperatorWithAssignmentTests Inherits CodeFixVerifier(Of TernaryOperatorAnalyzer, TernaryOperatorWithAssignmentCodeFixProvider) + Public Async Function WhenUsingIfWithoutElseAnalyzerDoesNotCreateDiagnostic() As Task Const sourceWithoutElse = " Namespace ConsoleApplication1 @@ -711,6 +712,58 @@ End Namespace" Await VerifyBasicFixAllAsync(New String() {sourceReturn, sourceReturn.Replace("MyType", "MyType1")}, New String() {fix, fix.Replace("MyType", "MyType1")}) End Function + + Public Async Function FixWhenThereIsNumericImplicitConversion() As Task + Dim source = " +Function OnReturn() As Double + Dim condition = True + Dim aDouble As Double = 2 + Dim bInteger = 3 + If condition Then + Return aDouble + Else + Return bInteger + End If +End Function".WrapInVBClass() + Dim fix = " +Function OnReturn() As Double + Dim condition = True + Dim aDouble As Double = 2 + Dim bInteger = 3 + Return If(condition, aDouble, bInteger) +End Function".WrapInVBClass() + Await VerifyBasicFixAsync(source, fix, formatBeforeCompare:=True) + End Function + + + Public Async Function FixWhenThereIsEnumImplicitConversionToNumeric() As Task + Dim source = " +Enum Values + Value +End Enum +Function OnReturn() As Double + Dim condition = True + Dim anEnum As Values = Values.Value + Dim bInteger = 3 + If condition Then + Return anEnum + Else + Return bInteger + End If +End Function".WrapInVBClass() + Dim fix = " +Enum Values + Value +End Enum +Function OnReturn() As Double + Dim condition = True + Dim anEnum As Values = Values.Value + Dim bInteger = 3 + Return If(condition, anEnum, bInteger) +End Function".WrapInVBClass() + Await VerifyBasicFixAsync(source, fix, formatBeforeCompare:=True) + End Function + Public Async Function FixCanWorkWithCommentsOnIf() As Task Const source = " From 4ac0f32700ee4cc1fbaa651f6492b8e8cd702111 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 30 Mar 2016 23:01:27 -0300 Subject: [PATCH 155/358] Can copy evento to variable without crashing when inside a statement Fixes #735 --- ...ventToVariableBeforeFireCodeFixProvider.cs | 18 +++--- .../Extensions/CSharpAnalyzerExtensions.cs | 11 +++- .../CopyEventToVariableBeforeFireTests.cs | 58 +++++++++++++++++++ 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs index 88380df5b..7dd79aa7c 100644 --- a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs @@ -30,12 +30,13 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) return Task.FromResult(0); } - private async static Task CreateVariableAsync(Document document, Diagnostic diagnostic, CancellationToken ct) + private async static Task CreateVariableAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(ct).ConfigureAwait(false); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var sourceSpan = diagnostic.Location.SourceSpan; var invocation = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - const string handlerName = "handler"; + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); + var handlerName = semanticModel.FindAvailableIdentifierName(sourceSpan.Start, "handler"); var variable = SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( @@ -49,18 +50,17 @@ private async static Task CreateVariableAsync(Document document, Diagn SyntaxFactory.EqualsValueClause(invocation.Expression.WithoutLeadingTrivia().WithoutTrailingTrivia())) }))) .WithLeadingTrivia(invocation.Parent.GetLeadingTrivia()); + var statement = invocation.Expression.FirstAncestorOrSelfThatIsAStatement(); + var newStatement = statement.ReplaceNode(invocation.Expression, SyntaxFactory.IdentifierName(handlerName)); var newInvocation = SyntaxFactory.IfStatement( SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, SyntaxFactory.IdentifierName(handlerName), SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)), - SyntaxFactory.ExpressionStatement( - SyntaxFactory.InvocationExpression( - SyntaxFactory.IdentifierName(handlerName), - invocation.ArgumentList))) + newStatement) .WithTrailingTrivia(invocation.Parent.GetTrailingTrivia()); - var oldNode = invocation.Parent; - var newNode = invocation.Parent.WithAdditionalAnnotations(new SyntaxAnnotation(SyntaxAnnotatinKind)); + var oldNode = statement; + var newNode = newStatement.WithAdditionalAnnotations(new SyntaxAnnotation(SyntaxAnnotatinKind)); if (oldNode.Parent.IsEmbeddedStatementOwner()) newNode = SyntaxFactory.Block((StatementSyntax)newNode); var newRoot = root.ReplaceNode(oldNode, newNode); diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 818a5b276..358b3fc6c 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -868,5 +868,14 @@ public static bool HasImplicitNumericConversion(this ITypeSymbol from, ITypeSymb return false; } } + + public static string FindAvailableIdentifierName(this SemanticModel semanticModel, int position, string baseName) + { + var name = baseName; + var inscrementer = 1; + while (semanticModel.LookupSymbols(position, name: name).Any()) + name = baseName + inscrementer++; + return name; + } } -} +} \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs b/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs index 706874d4a..e681b3057 100644 --- a/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs @@ -765,5 +765,63 @@ public int FuncCalc(int p1, int p2) }"; await VerifyCSharpHasNoDiagnosticsAsync(test); } + + [Fact] + public async void FixWhenInsideExpression() + { + var code = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + var fix = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + var handler = AllowInteraction; + if (handler != null) + if (!handler("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(code, fix); + } + + [Fact] + public async void FixWhenInsideExpressionAndNameAlreadyExists() + { + var code = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + var handler = 1; + if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + var fix = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + var handler = 1; + var handler1 = AllowInteraction; + if (handler1 != null) + if (!handler1("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(code, fix); + } } } \ No newline at end of file From c3866fffc57dcab7b72e909aad625b176bb6753d Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 1 Apr 2016 17:29:24 -0300 Subject: [PATCH 156/358] Detect dispose when using elvis operator on CC0022 Closes #761 --- .../DisposableVariableNotDisposedAnalyzer.cs | 34 ++++++++++++++----- .../DisposableVariableNotDisposedTests.cs | 10 ++++++ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index 9901b2114..e53f40891 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -176,17 +176,35 @@ private static bool IsCorrectDispose(ExpressionStatementSyntax expressionStateme { if (expressionStatement == null) return false; var invocation = expressionStatement.Expression as InvocationExpressionSyntax; - if (invocation?.ArgumentList.Arguments.Any() ?? true) return false; - var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; - if (memberAccess == null) return false; + ExpressionSyntax expressionAccessed; + IdentifierNameSyntax memberAccessed; + if (invocation == null) + { + var conditionalAccessExpression = expressionStatement.Expression as ConditionalAccessExpressionSyntax; + if (conditionalAccessExpression == null) return false; + invocation = conditionalAccessExpression.WhenNotNull as InvocationExpressionSyntax; + var memberBinding = invocation?.Expression as MemberBindingExpressionSyntax; + if (memberBinding == null) return false; + expressionAccessed = conditionalAccessExpression.Expression; + memberAccessed = memberBinding.Name as IdentifierNameSyntax; + } + else + { + var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; + if (memberAccess == null) return false; + expressionAccessed = memberAccess.Expression; + memberAccessed = memberAccess.Name as IdentifierNameSyntax; + } + if (memberAccessed == null) return false; + if (invocation.ArgumentList.Arguments.Any()) return false; ISymbol memberSymbol; - if (memberAccess.Expression.IsKind(SyntaxKind.IdentifierName)) + if (expressionAccessed.IsKind(SyntaxKind.IdentifierName)) { - memberSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol; + memberSymbol = semanticModel.GetSymbolInfo(expressionAccessed).Symbol; } - else if (memberAccess.Expression.IsKind(SyntaxKind.ParenthesizedExpression)) + else if (expressionAccessed is ParenthesizedExpressionSyntax) { - var parenthesizedExpression = (ParenthesizedExpressionSyntax)memberAccess.Expression; + var parenthesizedExpression = (ParenthesizedExpressionSyntax)expressionAccessed; var cast = parenthesizedExpression.Expression as CastExpressionSyntax; if (cast == null) return false; var catTypeSymbol = semanticModel.GetTypeInfo(cast.Type).Type; @@ -195,8 +213,6 @@ private static bool IsCorrectDispose(ExpressionStatementSyntax expressionStateme } else return false; if (memberSymbol == null || !memberSymbol.Equals(identitySymbol)) return false; - var memberAccessed = memberAccess.Name as IdentifierNameSyntax; - if (memberAccessed == null) return false; if (memberAccessed.Identifier.Text != "Dispose" || memberAccessed.Arity != 0) return false; var methodSymbol = semanticModel.GetSymbolInfo(memberAccessed).Symbol as IMethodSymbol; if (methodSymbol == null) return false; diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index ba53e0a9b..a07c13405 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -72,6 +72,16 @@ public async Task FixADisposableDeclarationWithoutDisposeWithParenthese() await VerifyCSharpFixAsync(source, fixtest); } + [Fact] + public async Task IgnoreWhenDisposedWithElvisOperator() + { + var source = @" +var m = new System.IO.MemoryStream(); +m?.Dispose(); +".WrapInCSharpMethod(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task IgnoresDisposableObjectsCreatedDirectParentIsNotAnUsingStatement() { From fe0fd387a6bdfc20ee31ca50da388c1f06f18254 Mon Sep 17 00:00:00 2001 From: carloscds Date: Sat, 2 Apr 2016 19:56:07 -0300 Subject: [PATCH 157/358] Fix #733 --- .../CodeCracker/Usage/UnusedParametersAnalyzer.vb | 1 + .../CodeCracker.Test/Usage/UnusedParametersTests.vb | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb index 5e338294a..eccfc6a13 100644 --- a/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/UnusedParametersAnalyzer.vb @@ -65,6 +65,7 @@ You should delete the parameter in such cases." Private Shared Function IsCandidateForRemoval(methodOrConstructor As MethodBlockBaseSyntax, semanticModel As SemanticModel) As Boolean If methodOrConstructor.BlockStatement.Modifiers.Any(Function(m) m.ValueText = "Partial" OrElse m.ValueText = "Overrides") OrElse Not methodOrConstructor.BlockStatement.ParameterList?.Parameters.Any() Then Return False + If methodOrConstructor.HasAttributeOnAncestorOrSelf("DllImport") Then Return False Dim method = TryCast(methodOrConstructor, MethodBlockSyntax) If method IsNot Nothing Then diff --git a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb index f8e0e5bc9..e6c044c9c 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb @@ -464,6 +464,19 @@ End Class Await VerifyBasicDiagnosticAsync(source, CreateDiagnosticResult("out2", 3, 77)) End Function + + Public Async Function CallWithDllImport() As Task + Const source = " +Imports System.Runtime.InteropServices +Class Base + + Private Shared Function y(ByRef message As IntPtr) As Integer + End Function +End Class +" + Await VerifyBasicHasNoDiagnosticsAsync(source) + End Function + Public Async Function CallWithRefAndEnumerableDoesNotCreateDiagnostic() As Task Const source = " From 742b2bee0a00be9746eb0c80a7bc06e69c24df68 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 2 Apr 2016 22:35:56 -0300 Subject: [PATCH 158/358] Update XmlDocumentation to raise 2 different diagnostic ids Use CC0090 for incorrect params (params that exist in the docs but not on code) and CC0097 for missing parameters (params that exist on code, but not on docs). Make 90 an Info, and 97 a Warning. Closes #488 --- src/CSharp/CodeCracker/CodeCracker.csproj | 4 ++-- .../XmlDocumentationAnalyzer.cs | 23 ++++++++++++------- .../XmlDocumentationCodeFixProvider.cs | 2 -- ...entationMissingInCSharpCodeFixProvider.cs} | 14 ++++++----- ...cumentationMissingInXmlCodeFixProvider.cs} | 22 +++++++++--------- src/Common/CodeCracker.Common/DiagnosticId.cs | 3 ++- .../Maintainability/XmlDocumentationTests.cs | 12 +++++----- 7 files changed, 44 insertions(+), 36 deletions(-) rename src/CSharp/CodeCracker/Maintainability/{XmlDocumentationRemoveNonExistentParametersCodeFixProvider.cs => XmlDocumentationMissingInCSharpCodeFixProvider.cs} (77%) rename src/CSharp/CodeCracker/Maintainability/{XmlDocumentationCreateMissingParametersCodeFixProvider.cs => XmlDocumentationMissingInXmlCodeFixProvider.cs} (89%) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 3a914dbb4..c7701d03d 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -75,8 +75,8 @@ - - + + diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs index f4da96669..5f987fddb 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationAnalyzer.cs @@ -14,16 +14,25 @@ public sealed class XmlDocumentationAnalyzer : DiagnosticAnalyzer { internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.XmlDocumentationAnalyzer_Title), Resources.ResourceManager, typeof(Resources)); - internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - DiagnosticId.XmlDocumentation.ToDiagnosticId(), + internal static readonly DiagnosticDescriptor RuleMissingInCSharp = new DiagnosticDescriptor( + DiagnosticId.XmlDocumentation_MissingInCSharp.ToDiagnosticId(), + Title, + Title, + SupportedCategories.Maintainability, + DiagnosticSeverity.Info, + isEnabledByDefault: true, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.XmlDocumentation_MissingInCSharp)); + + internal static readonly DiagnosticDescriptor RuleMissingInXml = new DiagnosticDescriptor( + DiagnosticId.XmlDocumentation_MissingInXml.ToDiagnosticId(), Title, Title, SupportedCategories.Maintainability, DiagnosticSeverity.Warning, isEnabledByDefault: true, - helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.XmlDocumentation)); + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.XmlDocumentation_MissingInXml)); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(RuleMissingInCSharp, RuleMissingInXml); public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(Analyzer, SyntaxKind.SingleLineDocumentationCommentTrivia); @@ -55,15 +64,13 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (parameterWithDocParameter.Any(p => p.Parameter == null)) { - var properties = new Dictionary { ["kind"] = "nonexistentParam" }.ToImmutableDictionary(); - var diagnostic = Diagnostic.Create(Rule, documentationNode.GetLocation(), properties); + var diagnostic = Diagnostic.Create(RuleMissingInCSharp, documentationNode.GetLocation()); context.ReportDiagnostic(diagnostic); } if (parameterWithDocParameter.Any(p => p.DocParameter == null)) { - var properties = new Dictionary { ["kind"] = "missingDoc" }.ToImmutableDictionary(); - var diagnostic = Diagnostic.Create(Rule, documentationNode.GetLocation(), properties); + var diagnostic = Diagnostic.Create(RuleMissingInXml, documentationNode.GetLocation()); context.ReportDiagnostic(diagnostic); } } diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationCodeFixProvider.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationCodeFixProvider.cs index 06e7b5cc7..60cf4f0aa 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationCodeFixProvider.cs @@ -12,8 +12,6 @@ namespace CodeCracker.CSharp.Maintainability { public abstract class XmlDocumentationCodeFixProvider : CodeFixProvider { - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.XmlDocumentation.ToDiagnosticId()); - public abstract SyntaxNode FixParameters(MethodDeclarationSyntax method, SyntaxNode root); protected async Task FixParametersAsync(Document document, Diagnostic diagnostic, CancellationToken c) diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationRemoveNonExistentParametersCodeFixProvider.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs similarity index 77% rename from src/CSharp/CodeCracker/Maintainability/XmlDocumentationRemoveNonExistentParametersCodeFixProvider.cs rename to src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs index 04e3e3e01..232533605 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationRemoveNonExistentParametersCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs @@ -1,19 +1,22 @@ -using Microsoft.CodeAnalysis; +using CodeCracker.Properties; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading.Tasks; -using CodeCracker.Properties; namespace CodeCracker.CSharp.Maintainability { [ExportCodeFixProvider(LanguageNames.CSharp, nameof(XmlDocumentationCodeFixProvider)), Shared] - public sealed class XmlDocumentationRemoveNonExistentParametersCodeFixProvider : XmlDocumentationCodeFixProvider + public sealed class XmlDocumentationMissingInCSharpCodeFixProvider : XmlDocumentationCodeFixProvider { + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.XmlDocumentation_MissingInCSharp.ToDiagnosticId()); + public override SyntaxNode FixParameters(MethodDeclarationSyntax method, SyntaxNode root) { var documentationNode = method.GetLeadingTrivia().Select(x => x.GetStructure()).OfType().First(); @@ -39,9 +42,8 @@ private static IEnumerable GetAllNodesToRemove(IEnumerable FixParametersAsync(context.Document, diagnostic, c)), diagnostic); + context.RegisterCodeFix(CodeAction.Create(Resources.XmlDocumentationRemoveNonExistentParametersCodeFixProvider_Title, c => FixParametersAsync(context.Document, diagnostic, c)), diagnostic); return Task.FromResult(0); } } -} +} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationCreateMissingParametersCodeFixProvider.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs similarity index 89% rename from src/CSharp/CodeCracker/Maintainability/XmlDocumentationCreateMissingParametersCodeFixProvider.cs rename to src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs index b9012de39..be54bc846 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationCreateMissingParametersCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs @@ -1,19 +1,22 @@ -using System.Composition; -using System.Linq; -using System.Threading.Tasks; -using CodeCracker.Properties; +using CodeCracker.Properties; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading.Tasks; using static Microsoft.CodeAnalysis.CSharp.SyntaxKind; namespace CodeCracker.CSharp.Maintainability { [ExportCodeFixProvider(LanguageNames.CSharp, nameof(XmlDocumentationCodeFixProvider)), Shared] - public sealed class XmlDocumentationCreateMissingParametersCodeFixProvider : XmlDocumentationCodeFixProvider + public sealed class XmlDocumentationMissingInXmlCodeFixProvider : XmlDocumentationCodeFixProvider { + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.XmlDocumentation_MissingInXml.ToDiagnosticId()); + private const string WHITESPACE = @" "; public override SyntaxNode FixParameters(MethodDeclarationSyntax method, SyntaxNode root) @@ -23,7 +26,7 @@ public override SyntaxNode FixParameters(MethodDeclarationSyntax method, SyntaxN var methodParameterWithDocParameter = GetMethodParametersWithDocParameters(method, documentationNode); var newFormation = newDocumentationNode.Content.OfType(); - + var nodesToAdd = methodParameterWithDocParameter.Where(p => p.Item2 == null) .Select(x => CreateParamenterXmlDocumentation(x.Item1.Identifier.ValueText, method.Identifier.ValueText)) .Union(newFormation) @@ -83,11 +86,8 @@ private static SyntaxList CreateXmlAttributes(string paramen public override sealed Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); - if (diagnostic.Properties["kind"] == "missingDoc") - context.RegisterCodeFix(CodeAction.Create(Resources.XmlDocumentationCreateMissingParametersCodeFixProvider_Title, c => FixParametersAsync(context.Document, diagnostic, c)), diagnostic); + context.RegisterCodeFix(CodeAction.Create(Resources.XmlDocumentationCreateMissingParametersCodeFixProvider_Title, c => FixParametersAsync(context.Document, diagnostic, c)), diagnostic); return Task.FromResult(0); } } - - -} +} \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index b3e757224..cad9ad940 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -73,10 +73,11 @@ public enum DiagnosticId UseStringEmpty = 84, UseEmptyString = 88, RemoveRedundantElseClause = 89, - XmlDocumentation = 90, + XmlDocumentation_MissingInCSharp = 90, MakeMethodStatic = 91, ChangeAllToAny = 92, ConsoleWriteLine = 95, + XmlDocumentation_MissingInXml = 97, NameOf_External = 108, StringFormatArgs_ExtraArgs = 111, AlwaysUseVarOnPrimitives = 105, diff --git a/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs b/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs index 83ca47b91..4e060ac36 100644 --- a/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs +++ b/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs @@ -5,7 +5,7 @@ namespace CodeCracker.Test.CSharp.Maintainability { - public class XmlDocumentationAnalyzerTests : CodeFixVerifier + public class XmlDocumentationAnalyzerTests : CodeFixVerifier { [Fact] public async Task IgnoresClassDocs() @@ -112,9 +112,9 @@ protected async static Task GetSortedDiagnosticsFromDocumentsAsync var expected = new DiagnosticResult { - Id = DiagnosticId.XmlDocumentation.ToDiagnosticId(), + Id = DiagnosticId.XmlDocumentation_MissingInCSharp.ToDiagnosticId(), Message = "You have missing/unexistent parameters in Xml Docs", - Severity = DiagnosticSeverity.Warning, + Severity = DiagnosticSeverity.Info, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 16) } }; @@ -143,7 +143,7 @@ public static Project CreateProject(string[] sources, out AdhocWorkspace workspa var expected = new DiagnosticResult { - Id = DiagnosticId.XmlDocumentation.ToDiagnosticId(), + Id = DiagnosticId.XmlDocumentation_MissingInXml.ToDiagnosticId(), Message = "You have missing/unexistent parameters in Xml Docs", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 16) } @@ -192,7 +192,7 @@ public int Foo(int value) } } - public class XmlDocumentationRemoveUnexistentParametersCodeFixTests : CodeFixVerifier + public class XmlDocumentationRemoveUnexistentParametersCodeFixTests : CodeFixVerifier { [Fact] public async Task FixRemoveParameterDoc() @@ -278,7 +278,7 @@ protected async static Task GetSortedDiagnosticsFromDocumentsAsync } - public class XmlDocumentationCreateMissingParametersCodeFixTests : CodeFixVerifier + public class XmlDocumentationCreateMissingParametersCodeFixTests : CodeFixVerifier { [Fact] public async Task FixCreateOneParameterDoc() From effcd89592b2c4f1502c4986eb1a2defc61d25b2 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 00:59:34 -0300 Subject: [PATCH 159/358] Unify CC0016 and CC0031 Closes #662 --- src/CSharp/CodeCracker/CodeCracker.csproj | 2 - .../CopyEventToVariableBeforeFireAnalyzer.cs | 54 -- ...ventToVariableBeforeFireCodeFixProvider.cs | 75 -- .../UseInvokeMethodToFireEventAnalyzer.cs | 15 +- ...eInvokeMethodToFireEventCodeFixProvider.cs | 89 +- src/Common/CodeCracker.Common/DiagnosticId.cs | 1 - .../Extensions/AnalyzerExtensions.cs | 2 + .../CodeCracker.Test/CodeCracker.Test.csproj | 1 - .../CopyEventToVariableBeforeFireTests.cs | 827 ------------------ .../Design/UseInvokeMethodToFireEventTests.cs | 622 ++++++++++++- .../Verifiers/CodeFixVerifier.cs | 39 + 11 files changed, 757 insertions(+), 970 deletions(-) delete mode 100644 src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs delete mode 100644 src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs delete mode 100644 test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index c7701d03d..0f1d5e220 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -115,8 +115,6 @@ - - diff --git a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs b/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs deleted file mode 100644 index 9194eecf2..000000000 --- a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireAnalyzer.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using System; -using System.Collections.Immutable; - -namespace CodeCracker.CSharp.Design -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class CopyEventToVariableBeforeFireAnalyzer : DiagnosticAnalyzer - { - internal const string Title = "Copy Event To Variable Before Fire"; - internal const string MessageFormat = "Copy the '{0}' event to a variable before firing it."; - internal const string Category = SupportedCategories.Design; - const string Description = "Events should always be checked for null before being invoked.\r\n" - + "As in a multi-threading context it is possible for an event to be unsubscribed between " - + "the moment where it is checked to be non-null and the moment it is raised the event must " - + "be copied to a temporary variable before the check."; - internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Title, - MessageFormat, - Category, - DiagnosticSeverity.Warning, - true, - description: Description, - helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.CopyEventToVariableBeforeFire)); - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); - - public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(Analyzer, SyntaxKind.InvocationExpression); - - private static void Analyzer(SyntaxNodeAnalysisContext context) - { - if (context.IsGenerated()) return; - var invocation = (InvocationExpressionSyntax)context.Node; - var identifier = invocation.Expression as IdentifierNameSyntax; - if (identifier == null) return; - if (context.Node.Parent.GetType().Name == nameof(ArrowExpressionClauseSyntax)) return; - - var typeInfo = context.SemanticModel.GetTypeInfo(identifier, context.CancellationToken); - - if (typeInfo.ConvertedType?.BaseType == null) return; - - var symbol = context.SemanticModel.GetSymbolInfo(identifier).Symbol; - - if (typeInfo.ConvertedType.BaseType.Name != typeof(MulticastDelegate).Name || - symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Parameter || symbol.IsReadOnlyAndInitializedForCertain(context)) return; - - context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation(), identifier.Identifier.Text)); - } - } -} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs deleted file mode 100644 index 7dd79aa7c..000000000 --- a/src/CSharp/CodeCracker/Design/CopyEventToVariableBeforeFireCodeFixProvider.cs +++ /dev/null @@ -1,75 +0,0 @@ -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.Immutable; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace CodeCracker.CSharp.Design -{ - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CopyEventToVariableBeforeFireCodeFixProvider)), Shared] - public class CopyEventToVariableBeforeFireCodeFixProvider : CodeFixProvider - { - private const string SyntaxAnnotatinKind = "CC-CopyEvent"; - - public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId()); - - public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - - public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) - { - var diagnostic = context.Diagnostics.First(); - context.RegisterCodeFix( - CodeAction.Create("Copy event reference to a variable", ct => CreateVariableAsync(context.Document, diagnostic, ct), nameof(CopyEventToVariableBeforeFireCodeFixProvider)), diagnostic); - return Task.FromResult(0); - } - - private async static Task CreateVariableAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) - { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var sourceSpan = diagnostic.Location.SourceSpan; - var invocation = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var handlerName = semanticModel.FindAvailableIdentifierName(sourceSpan.Start, "handler"); - var variable = - SyntaxFactory.LocalDeclarationStatement( - SyntaxFactory.VariableDeclaration( - SyntaxFactory.ParseTypeName("var"), - SyntaxFactory.SeparatedList( - new[] - { - SyntaxFactory.VariableDeclarator( - SyntaxFactory.Identifier(handlerName), - null, - SyntaxFactory.EqualsValueClause(invocation.Expression.WithoutLeadingTrivia().WithoutTrailingTrivia())) - }))) - .WithLeadingTrivia(invocation.Parent.GetLeadingTrivia()); - var statement = invocation.Expression.FirstAncestorOrSelfThatIsAStatement(); - var newStatement = statement.ReplaceNode(invocation.Expression, SyntaxFactory.IdentifierName(handlerName)); - var newInvocation = - SyntaxFactory.IfStatement( - SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, - SyntaxFactory.IdentifierName(handlerName), - SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)), - newStatement) - .WithTrailingTrivia(invocation.Parent.GetTrailingTrivia()); - var oldNode = statement; - var newNode = newStatement.WithAdditionalAnnotations(new SyntaxAnnotation(SyntaxAnnotatinKind)); - if (oldNode.Parent.IsEmbeddedStatementOwner()) - newNode = SyntaxFactory.Block((StatementSyntax)newNode); - var newRoot = root.ReplaceNode(oldNode, newNode); - newRoot = newRoot.InsertNodesAfter(GetMark(newRoot), new SyntaxNode[] { variable, newInvocation }); - newRoot = newRoot.RemoveNode(GetMark(newRoot), SyntaxRemoveOptions.KeepNoTrivia); - return document.WithSyntaxRoot(newRoot.WithAdditionalAnnotations(Formatter.Annotation)); - } - - private static SyntaxNode GetMark(SyntaxNode node) => - node.DescendantNodes().First(n => n.GetAnnotations(SyntaxAnnotatinKind).Any()); - } -} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index ceba7ca00..33163652d 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -11,11 +11,12 @@ namespace CodeCracker.CSharp.Design [DiagnosticAnalyzer(LanguageNames.CSharp)] public class UseInvokeMethodToFireEventAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Use Invoke Method To call on delegate"; - internal const string MessageFormat = "Use ?.Invoke operator and method to call on '{0}' delegate."; + internal const string Title = "Check for null before calling a delegate"; + internal const string MessageFormat = "Verify if delegate '{0}' is null before invoking it."; internal const string Category = SupportedCategories.Design; const string Description = "In C#6 a delegate can be invoked using the null-propagating operator (?.) and it's" - + " invoke method to avoid throwing a NullReference exception when there is no method attached to the delegate."; + + " invoke method to avoid throwing a NullReference exception when there is no method attached to the delegate. " + + "Or you can check for null before calling the delegate."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), @@ -30,7 +31,7 @@ public class UseInvokeMethodToFireEventAnalyzer : DiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); public override void Initialize(AnalysisContext context) => - context.RegisterSyntaxNodeAction(LanguageVersion.CSharp6, Analyzer, SyntaxKind.InvocationExpression); + context.RegisterSyntaxNodeAction(Analyzer, SyntaxKind.InvocationExpression); private static void Analyzer(SyntaxNodeAnalysisContext context) { @@ -48,11 +49,15 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var invokedMethodSymbol = (typeInfo.ConvertedType as INamedTypeSymbol)?.DelegateInvokeMethod; if (invokedMethodSymbol == null) return; - if (!invokedMethodSymbol.ReturnsVoid && !invokedMethodSymbol.ReturnType.IsReferenceType) return; + //var cantFixWithElvis = false; + //if (!invokedMethodSymbol.ReturnsVoid && !invokedMethodSymbol.ReturnType.IsReferenceType) + // cantFixWithElvis = true; if (HasCheckForNullThatReturns(invocation, context.SemanticModel, symbol)) return; if (IsInsideANullCheck(invocation, context.SemanticModel, symbol)) return; if (symbol.IsReadOnlyAndInitializedForCertain(context)) return; + + //var properties = new Dictionary { { nameof(cantFixWithElvis), cantFixWithElvis.ToString() } }.ToImmutableDictionary(); context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation(), identifier.Identifier.Text)); } diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs index a4a62017c..b3fbbfbee 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventCodeFixProvider.cs @@ -4,6 +4,8 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; +using System; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -15,17 +17,26 @@ namespace CodeCracker.CSharp.Design [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseInvokeMethodToFireEventCodeFixProvider)), Shared] public class UseInvokeMethodToFireEventCodeFixProvider : CodeFixProvider { + private const string SyntaxAnnotatinKind = "CC-CopyEvent"; + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId()); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); + var compilation = (CSharpCompilation)await context.Document.Project.GetCompilationAsync(); + if (compilation.LanguageVersion >= LanguageVersion.CSharp6) + context.RegisterCodeFix( + CodeAction.Create("Change to ?.Invoke to call a delegate", + ct => UseInvokeAsync(context.Document, diagnostic, ct), + nameof(UseInvokeMethodToFireEventCodeFixProvider) + "_Elvis"), diagnostic); context.RegisterCodeFix( - CodeAction.Create("Change to ?.Invoke to call a delegate", ct => UseInvokeAsync(context.Document, diagnostic, ct), nameof(UseInvokeMethodToFireEventCodeFixProvider)), diagnostic); - return Task.FromResult(0); + CodeAction.Create("Copy delegate reference to a variable", + ct => CreateVariableAsync(context.Document, diagnostic, ct), + nameof(UseInvokeMethodToFireEventCodeFixProvider) + "_CopyToVariable"), diagnostic); } private async static Task UseInvokeAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) @@ -42,8 +53,78 @@ private async static Task UseInvokeAsync(Document document, Diagnostic SyntaxFactory.Token(SyntaxKind.DotToken), SyntaxFactory.IdentifierName("Invoke")), invocation.ArgumentList)) + .WithAdditionalAnnotations(Formatter.Annotation) + .WithTrailingTrivia(invocation.GetTrailingTrivia()); + var identifier = (IdentifierNameSyntax)invocation.Expression; + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); + var typeInfo = semanticModel.GetTypeInfo(identifier, cancellationToken); + var symbol = semanticModel.GetSymbolInfo(identifier).Symbol; + var invokedMethodSymbol = ((INamedTypeSymbol)typeInfo.ConvertedType).DelegateInvokeMethod; + ExpressionSyntax newNode = newInvocation; + if (!invokedMethodSymbol.ReturnsVoid && !invokedMethodSymbol.ReturnType.IsReferenceType && !(invocation.Parent is ExpressionStatementSyntax)) + { + var typeName = invokedMethodSymbol.ReturnType.GetFullName(false); + var defaultValue = SyntaxFactory.DefaultExpression(SyntaxFactory.ParseName(typeName) + .WithAdditionalAnnotations(Simplifier.Annotation)); + newNode = SyntaxFactory.BinaryExpression(SyntaxKind.CoalesceExpression, newInvocation, defaultValue) .WithAdditionalAnnotations(Formatter.Annotation); - return document.WithSyntaxRoot(root.ReplaceNode(invocation, newInvocation).WithTrailingTrivia(invocation.GetTrailingTrivia())); + if (invocation.Parent is BinaryExpressionSyntax) + { + var binary = (BinaryExpressionSyntax)invocation.Parent; + if (binary.Right.Equals(invocation.Parent) + && (binary.IsKind(SyntaxKind.BitwiseAndExpression) + || binary.IsKind(SyntaxKind.ExclusiveOrExpression) + || binary.IsKind(SyntaxKind.BitwiseOrExpression) + || binary.IsKind(SyntaxKind.LogicalAndExpression)) + || binary.IsKind(SyntaxKind.LogicalOrExpression) + || binary.IsKind(SyntaxKind.CoalesceExpression)) + newNode = SyntaxFactory.ParenthesizedExpression(newNode); + } + } + var newRoot = root.ReplaceNode(invocation, newNode); + return document.WithSyntaxRoot(newRoot); } + + private async static Task CreateVariableAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var sourceSpan = diagnostic.Location.SourceSpan; + var invocation = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); + var handlerName = semanticModel.FindAvailableIdentifierName(sourceSpan.Start, "handler"); + var variable = + SyntaxFactory.LocalDeclarationStatement( + SyntaxFactory.VariableDeclaration( + SyntaxFactory.ParseTypeName("var"), + SyntaxFactory.SeparatedList( + new[] + { + SyntaxFactory.VariableDeclarator( + SyntaxFactory.Identifier(handlerName), + null, + SyntaxFactory.EqualsValueClause(invocation.Expression.WithoutLeadingTrivia().WithoutTrailingTrivia())) + }))) + .WithLeadingTrivia(invocation.Parent.GetLeadingTrivia()); + var statement = invocation.Expression.FirstAncestorOrSelfThatIsAStatement(); + var newStatement = statement.ReplaceNode(invocation.Expression, SyntaxFactory.IdentifierName(handlerName)); + var newInvocation = + SyntaxFactory.IfStatement( + SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, + SyntaxFactory.IdentifierName(handlerName), + SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)), + newStatement) + .WithTrailingTrivia(invocation.Parent.GetTrailingTrivia()); + var oldNode = statement; + var newNode = newStatement.WithAdditionalAnnotations(new SyntaxAnnotation(SyntaxAnnotatinKind)); + if (oldNode.Parent.IsEmbeddedStatementOwner()) + newNode = SyntaxFactory.Block((StatementSyntax)newNode); + var newRoot = root.ReplaceNode(oldNode, newNode); + newRoot = newRoot.InsertNodesAfter(GetMark(newRoot), new SyntaxNode[] { variable, newInvocation }); + newRoot = newRoot.RemoveNode(GetMark(newRoot), SyntaxRemoveOptions.KeepNoTrivia); + return document.WithSyntaxRoot(newRoot.WithAdditionalAnnotations(Formatter.Annotation)); + } + + private static SyntaxNode GetMark(SyntaxNode node) => + node.DescendantNodes().First(n => n.GetAnnotations(SyntaxAnnotatinKind).Any()); } } \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index cad9ad940..156dc6285 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -18,7 +18,6 @@ public enum DiagnosticId TernaryOperator_Return = 13, TernaryOperator_Assignment = 14, UnnecessaryParenthesis = 15, - CopyEventToVariableBeforeFire = 16, SwitchToAutoProp = 17, ExistenceOperator = 18, ConvertToSwitch = 19, diff --git a/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs b/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs index b7bd2ee4f..cc3802231 100644 --- a/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs +++ b/src/Common/CodeCracker.Common/Extensions/AnalyzerExtensions.cs @@ -125,6 +125,8 @@ public static string GetLastIdentifierIfQualiedTypeName(this string typeName) public static string GetFullName(this ISymbol symbol, bool addGlobal = true) { + if (symbol.Kind == SymbolKind.TypeParameter) + return symbol.ToString(); var fullName = symbol.Name; var containingSymbol = symbol.ContainingSymbol; while (!(containingSymbol is INamespaceSymbol)) diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 0cac11358..8a756946c 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -162,7 +162,6 @@ - diff --git a/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs b/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs deleted file mode 100644 index e681b3057..000000000 --- a/test/CSharp/CodeCracker.Test/Design/CopyEventToVariableBeforeFireTests.cs +++ /dev/null @@ -1,827 +0,0 @@ -using CodeCracker.CSharp.Design; -using Microsoft.CodeAnalysis; -using Xunit; - -namespace CodeCracker.Test.CSharp.Design -{ - public class CopyEventToVariableBeforeFireTests : CodeFixVerifier - { - [Fact] - public async void WarningIfEventIsFiredDirectly() - { - const string test = @" - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfCustomEventIsFiredDirectly() - { - const string test = @" - public class MyArgs : System.EventArgs - { - public string Info { get; set; } - } - - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - MyEvent(this, new MyArgs() { Info = ""ping"" }); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfCustomEventWithCustomDelegateIsFiredDirectly() - { - const string test = @" - public class MyArgs : System.EventArgs - { - public string Info { get; set; } - } - - public delegate void Executed (object sender, MyArgs args); - - public class MyClass - { - public event Executed MyEvent; - - public void Execute() - { - MyEvent(this, new MyArgs() { Info = ""ping"" }); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 15, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void NotWarningIfEventIsCopiedToLocalVariableBeforeFire() - { - const string test = @" - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - var handler = MyEvent; - if (handler != null) - handler(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void WarningIfEventIsReadOnlyButNotAssignedInConstructor() - { - const string test = @" - public class MyClass - { - readonly int SomeOtherField; - readonly System.EventHandler MyEvent; - - public MyClass() - { - SomeOtherField = 42; - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedInIfInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool shouldAssign) - { - if(shouldAssign) - { - MyEvent = (sender, args) => { }; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedInForeachInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(int[] values) - { - foreach(var value in values) - { - MyEvent = (sender, args) => { }; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedInForInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(int number) - { - for(int i = 0; i < number; i++) - { - MyEvent = (sender, args) => { }; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedInWhileInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(int number) - { - while(number > 0) - { - MyEvent = (sender, args) => { }; - number--; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedAfterReturnInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool returnEarly) - { - if(returnEarly) - { - return; - } - MyEvent = (sender, args) => { }; - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedToNullRegularAssignmentOnFieldDeclaration() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent = null; - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedToNullInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool returnEarly) - { - MyEvent = null; - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedToNullAfterRegularAssignmentInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool returnEarly) - { - MyEvent = (sender, args) => { }; - MyEvent = null; - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedInAllSwitchCasesButNoDefaultInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(int value) - { - switch(value) - { - case 1: MyEvent = (sender, args) => { }; break; - case 2: MyEvent = (sender, args) => { }; break; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndAssignedInASwitchCaseButNotAllInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(int value) - { - switch(value) - { - case 1: MyEvent = (sender, args) => { }; break; - default: break; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - var expected = new DiagnosticResult - { - Id = DiagnosticId.CopyEventToVariableBeforeFire.ToDiagnosticId(), - Message = "Copy the 'MyEvent' event to a variable before firing it.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - } - - [Fact] - public async void NotWarningIfEventIsReadOnlyAndAssignedInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass() - { - MyEvent = (sender, args) => { }; - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfEventIsReadOnlyAndAssignedInBlockInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool shouldAssign) - { - { - MyEvent = (sender, args) => { }; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfEventIsReadOnlyAndAssignedInIfAndElseInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool shouldAssign) - { - if(shouldAssign) - { - MyEvent = (sender, args) => { }; - } - else - { - MyEvent = (sender, args) => { }; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfEventIsReadOnlyAndAssignedInAllSwitchCasesInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(int value) - { - switch(value) - { - case 1: MyEvent = (sender, args) => { }; break; - case 2: MyEvent = (sender, args) => { }; break; - default: MyEvent = (sender, args) => { }; break; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void WarningIfEventIsReadOnlyAndReturnAfterAssignmentInConstructor() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent; - - public MyClass(bool returnEarly) - { - MyEvent = (sender, args) => { }; - if(returnEarly) - { - return; - } - } - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfEventIsReadOnlyAndAssignedOnFieldDeclaration() - { - const string test = @" - public class MyClass - { - readonly System.EventHandler MyEvent = (sender, args) => { }; - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfIsNotAnEvent() - { - const string test = @" - public class MyClass - { - public void Execute() - { - MyClass.Run(null); - } - - public static void Run(object obj) - { - - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfIsAParameter() - { - const string test = @" - public class MyClass - { - public void Execute(Action action) - { - action(); - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void WhenEventIsFiredDirectlyShouldCopyItToVariable() - { - const string source = @" - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - MyEvent(this, System.EventArgs.Empty); - } - }"; - - const string fixtest = @" - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - var handler = MyEvent; - if (handler != null) - handler(this, System.EventArgs.Empty); - } - }"; - - await VerifyCSharpFixAsync(source, fixtest, 0); - } - - [Fact] - public async void KeepCommentsWhenReplacedWithCodeFix() - { - const string source = @" - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - //comment - MyEvent(this, System.EventArgs.Empty); //Some Comment - } - }"; - - const string fixtest = @" - public class MyClass - { - public event System.EventHandler MyEvent; - - public void Execute() - { - //comment - var handler = MyEvent; - if (handler != null) - handler(this, System.EventArgs.Empty); //Some Comment - } - }"; - - await VerifyCSharpFixAsync(source, fixtest, 0); - } - - [Fact] - public async void FixWhenInvocationIsInsideABlockWithoutBraces() - { - const string source = @" - public class MyClass - { - public event System.EventHandler MyEvent; - bool raiseEvents = true; - - public void Execute() - { - if (raiseEvents) MyEvent(this, System.EventArgs.Empty); - } - }"; - - const string fixtest = @" - public class MyClass - { - public event System.EventHandler MyEvent; - bool raiseEvents = true; - - public void Execute() - { - if (raiseEvents) - { - var handler = MyEvent; - if (handler != null) - handler(this, System.EventArgs.Empty); - } - } - }"; - - await VerifyCSharpFixAsync(source, fixtest, 0); - } - - [Fact] - public async void IgnoreMemberAccess() - { - var test = @"var tuple = new Tuple(1, null); -tuple.Item2();".WrapInCSharpMethod(); - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void NotWarningIfExpressionBodied() - { - const string test = @" - public class MyClass - { - public int Foo(int par1, int par2) => FuncCalc(par1,par2); - - public int FuncCalc(int p1, int p2) - { - return p1*p2; - } - - }"; - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - - [Fact] - public async void FixWhenInsideExpression() - { - var code = @" -public System.Func AllowInteraction { get; protected set; } -protected bool AllowedInteraction() -{ - if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) - { - return false; - } - return true; -}".WrapInCSharpClass(); - var fix = @" -public System.Func AllowInteraction { get; protected set; } -protected bool AllowedInteraction() -{ - var handler = AllowInteraction; - if (handler != null) - if (!handler("""") || 1 == System.DateTime.Now.Second) - { - return false; - } - return true; -}".WrapInCSharpClass(); - await VerifyCSharpFixAsync(code, fix); - } - - [Fact] - public async void FixWhenInsideExpressionAndNameAlreadyExists() - { - var code = @" -public System.Func AllowInteraction { get; protected set; } -protected bool AllowedInteraction() -{ - var handler = 1; - if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) - { - return false; - } - return true; -}".WrapInCSharpClass(); - var fix = @" -public System.Func AllowInteraction { get; protected set; } -protected bool AllowedInteraction() -{ - var handler = 1; - var handler1 = AllowInteraction; - if (handler1 != null) - if (!handler1("""") || 1 == System.DateTime.Now.Second) - { - return false; - } - return true; -}".WrapInCSharpClass(); - await VerifyCSharpFixAsync(code, fix); - } - } -} \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index db9e72c7a..810d8a426 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -56,6 +56,350 @@ public void Execute() await VerifyCSharpDiagnosticAsync(test, expected); } + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedInIfInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(bool shouldAssign) + { + if(shouldAssign) + { + MyEvent = (sender, args) => { }; + } + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedInForeachInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(int[] values) + { + foreach(var value in values) + { + MyEvent = (sender, args) => { }; + } + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedInForInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(int number) + { + for(int i = 0; i < number; i++) + { + MyEvent = (sender, args) => { }; + } + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedInWhileInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(int number) + { + while(number > 0) + { + MyEvent = (sender, args) => { }; + number--; + } + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedAfterReturnInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(bool returnEarly) + { + if(returnEarly) + { + return; + } + MyEvent = (sender, args) => { }; + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedToNullRegularAssignmentOnFieldDeclaration() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent = null; + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedToNullInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(bool returnEarly) + { + MyEvent = null; + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedToNullAfterRegularAssignmentInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(bool returnEarly) + { + MyEvent = (sender, args) => { }; + MyEvent = null; + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedInAllSwitchCasesButNoDefaultInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(int value) + { + switch(value) + { + case 1: MyEvent = (sender, args) => { }; break; + case 2: MyEvent = (sender, args) => { }; break; + } + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void WarningIfEventIsReadOnlyAndAssignedInASwitchCaseButNotAllInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass(int value) + { + switch(value) + { + case 1: MyEvent = (sender, args) => { }; break; + default: break; + } + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), + Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async void NotWarningIfEventIsReadOnlyAndAssignedInConstructor() + { + const string test = @" + public class MyClass + { + readonly System.EventHandler MyEvent; + + public MyClass() + { + MyEvent = (sender, args) => { }; + } + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] public async void AcceptExpressionBodiedMethods() { @@ -466,13 +810,289 @@ public static TReturn Method(System.Func getter) where T } [Fact] - public async void WhenMethodInvokedWithNonReferenceTypeHasNoDiagnostic() + public async void WhenMethodInvokedWithNonReferenceTypeHasOnlyIfNullDiagnostic() { var test = @" + public static TReturn Method(System.Func getter) where TReturn : struct + { + return getter?.Invoke(default(T)) ?? default(TReturn); + }".WrapInCSharpClass(); + await VerifyCSharpHasNumberOfCodeActions(test, 1); + } + + public static TReturn Method(System.Func getter) where TReturn : struct + { + getter?.Invoke(default(T)); + return getter?.Invoke(default(T)) ?? default(TReturn); + } + + [Fact] + public async void FixWithInvokeWithNonReferenceType() + { + var source = @" + public static TReturn Method(System.Func getter) where T : System.Attribute where TReturn : struct + { + return getter(default(T)); + }".WrapInCSharpClass(); + var fix = @" + public static TReturn Method(System.Func getter) where T : System.Attribute where TReturn : struct + { + return getter?.Invoke(default(T)) ?? default(TReturn); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fix, codeFixIndex: 0); + } + + [Fact] + public async void FixWithCheckForNullWithNonReferenceType() + { + var source = @" public static TReturn Method(System.Func getter) where T : System.Attribute where TReturn : struct { return getter(default(T)); }".WrapInCSharpClass(); + var fix = @" + public static TReturn Method(System.Func getter) where T : System.Attribute where TReturn : struct + { + var handler = getter; + if (handler != null) + return handler(default(T)); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fix, codeFixIndex: 1, allowNewCompilerDiagnostics: true); + } + + [Fact] + public async void FixWithCheckForNullAndKeepCommentsWhenReplacedWithCodeFix() + { + const string source = @" + public class MyClass + { + public event System.EventHandler MyEvent; + + public void Execute() + { + //comment + MyEvent(this, System.EventArgs.Empty); //Some Comment + } + }"; + + const string fixtest = @" + public class MyClass + { + public event System.EventHandler MyEvent; + + public void Execute() + { + //comment + var handler = MyEvent; + if (handler != null) + handler(this, System.EventArgs.Empty); //Some Comment + } + }"; + await VerifyCSharpFixAsync(source, fixtest, 1); + } + + [Fact] + public async void FixWhenInvocationIsInsideABlockWithoutBraces() + { + const string source = @" + public class MyClass + { + public event System.EventHandler MyEvent; + bool raiseEvents = true; + + public void Execute() + { + if (raiseEvents) MyEvent(this, System.EventArgs.Empty); + } + }"; + + const string fixtest = @" + public class MyClass + { + public event System.EventHandler MyEvent; + bool raiseEvents = true; + + public void Execute() + { + if (raiseEvents) + { + var handler = MyEvent; + if (handler != null) + handler(this, System.EventArgs.Empty); + } + } + }"; + + await VerifyCSharpFixAsync(source, fixtest, 1); + } + + [Fact] + public async void OnlyOneFixIfExpressionBodied() + { + const string test = @" + public class MyClass + { + public int Foo(int par1, int par2) => FuncCalc(par1,par2); + + public int FuncCalc(int p1, int p2) + { + return p1*p2; + } + }"; + await VerifyCSharpHasNumberOfCodeActions(test, 1); + } + + [Fact] + public async void FixWhenInsideExpressionWithInvoke() + { + var code = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + var fix = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + if (!AllowInteraction?.Invoke("""") ?? default(bool) || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(code, fix); + } + + [Fact] + public async void FixWhenInsideABinaryExpressionWithPrecedenceWithInvoke() + { + var code = @" +void Foo(Func f) +{ + var b = true; + if (b || f()) + { + } +}".WrapInCSharpClass(); + var fix = @" +void Foo(Func f) +{ + var b = true; + if (b || (f?.Invoke() ?? default(bool))) + { + } +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(code, fix); + } + + [Fact] + public async void FixWhenInsideExpressionWithCheckForNull() + { + var code = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + var fix = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + var handler = AllowInteraction; + if (handler != null) + if (!handler("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(code, fix, 1); + } + + [Fact] + public async void FixWhenInsideExpressionAndNameAlreadyExists() + { + var code = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + var handler = 1; + if (!AllowInteraction("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + var fix = @" +public System.Func AllowInteraction { get; protected set; } +protected bool AllowedInteraction() +{ + var handler = 1; + var handler1 = AllowInteraction; + if (handler1 != null) + if (!handler1("""") || 1 == System.DateTime.Now.Second) + { + return false; + } + return true; +}".WrapInCSharpClass(); + await VerifyCSharpFixAsync(code, fix, 1); + } + + [Fact] + public async void WhenEventIsFiredDirectlyShouldCopyItToVariable() + { + const string source = @" + public class MyClass + { + public event System.EventHandler MyEvent; + + public void Execute() + { + MyEvent(this, System.EventArgs.Empty); + } + }"; + + const string fixtest = @" + public class MyClass + { + public event System.EventHandler MyEvent; + + public void Execute() + { + var handler = MyEvent; + if (handler != null) + handler(this, System.EventArgs.Empty); + } + }"; + + await VerifyCSharpFixAsync(source, fixtest, 1); + } + + [Fact] + public async void NotWarningIfEventIsCopiedToLocalVariableBeforeFire() + { + const string test = @" + public class MyClass + { + public event System.EventHandler MyEvent; + + public void Execute() + { + var handler = MyEvent; + if (handler != null) + handler(this, System.EventArgs.Empty); + } + }"; await VerifyCSharpHasNoDiagnosticsAsync(test); } diff --git a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs index 92a423897..b6cc7416f 100644 --- a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs +++ b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs @@ -323,6 +323,45 @@ private async static Task VerifyFixAllAsync(string language, DiagnosticAnalyzer } } + /// + /// Called to verify how many code actions a code fix registered + /// Creates a Document from the source string, then gets diagnostics on it and verify if it has x number of code actions registred. + /// It will fail the test if it has a different number of code actions registred to it. + /// + /// A class in the form of a string before the CodeFix was applied to it + /// The codefix to be applied to the code wherever the relevant Diagnostic is found + /// C# language version used for compiling the test project, required unless you inform the VB language version. + /// The expected number of code actions provided by the code fix. + protected async Task VerifyCSharpHasNumberOfCodeActions(string source, int numberOfCodeActions, CodeFixProvider codeFixProvider = null, LanguageVersion languageVersionCSharp = LanguageVersion.CSharp6) => + await VerifyNumberOfCodeActions(LanguageNames.CSharp, GetDiagnosticAnalyzer(), codeFixProvider ?? GetCodeFixProvider(), source, numberOfCodeActions, languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic14).ConfigureAwait(true); + + /// + /// General verifier for a diagnostics that verifies how many code actions a code fix registered. + /// Creates a Document from the source string, then gets diagnostics on it and verify if it has x number of code actions registred. + /// It will fail the test if it has a different number of code actions registred to it. + /// + /// The language the source code is in + /// The analyzer to be applied to the source code + /// The codefix to be applied to the code wherever the relevant Diagnostic is found + /// A class in the form of a string before the CodeFix was applied to it + /// C# language version used for compiling the test project, required unless you inform the VB language version. + /// VB language version used for compiling the test project, required unless you inform the C# language version. + /// The expected number of code actions provided by the code fix. + private async static Task VerifyNumberOfCodeActions(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string source, int numberOfCodeActions, LanguageVersion languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersionVB) + { + var document = CreateDocument(source, language, languageVersionCSharp, languageVersionVB); + var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzer, new[] { document }).ConfigureAwait(true); + + foreach (var analyzerDiagnostic in analyzerDiagnostics) + { + var actions = new List(); + var context = new CodeFixContext(document, analyzerDiagnostic, (a, d) => actions.Add(a), CancellationToken.None); + await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(true); + var numberOfCodeActionsFound = actions.Count(); + Assert.True(numberOfCodeActions == numberOfCodeActionsFound, $"Should have {numberOfCodeActions} code actions registered for diagnostic '{analyzerDiagnostic.Id}' but got {numberOfCodeActionsFound}."); + } + } + /// /// Called to test a C# codefix when it should not had been registered /// From 24f65a83cdb53d7664a682e789945ffa9b596cb0 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 01:41:22 -0300 Subject: [PATCH 160/358] Change from Debug build config to Release --- CodeCracker.CSharp.sln | 12 +++++++++++- appveyor.yml | 2 +- build.targets.ps1 | 18 +++++++++--------- src/CSharp/CodeCracker/CodeCracker.nuspec | 6 +++--- src/CodeCracker.nuspec | 4 ++-- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 6 +++--- test/CSharp/AnalyzeCecil.ps1 | 6 +++--- test/CSharp/AnalyzeCoreFx.ps1 | 4 ++-- test/CSharp/AnalyzeRoslyn.ps1 | 6 +++--- 9 files changed, 37 insertions(+), 27 deletions(-) diff --git a/CodeCracker.CSharp.sln b/CodeCracker.CSharp.sln index 55aa52a2b..2f52cf033 100644 --- a/CodeCracker.CSharp.sln +++ b/CodeCracker.CSharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F5240AD-2B4E-48A4-B9FC-7D19DACEF2CD}" ProjectSection(SolutionItems) = preProject @@ -49,6 +49,7 @@ Global Debug|Any CPU = Debug|Any CPU DebugNoVsix|Any CPU = DebugNoVsix|Any CPU Release|Any CPU = Release|Any CPU + ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -57,29 +58,38 @@ Global {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.Build.0 = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/appveyor.yml b/appveyor.yml index 0eae120fe..c89ed6dff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: 1.0.0.{build} skip_tags: true -configuration: DebugNoVsix +configuration: ReleaseNoVsix init: - git config --global core.autocrlf true diff --git a/build.targets.ps1 b/build.targets.ps1 index 2e7030fc0..59ddf710b 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -19,13 +19,13 @@ Properties { $openCoverExe = "$packagesDir\OpenCover.4.6.166\tools\OpenCover.Console.exe" $testDllCS = "CodeCracker.Test.CSharp.dll" $testDllVB = "CodeCracker.Test.VisualBasic.dll" - $testDirCS = "$testDir\CSharp\CodeCracker.Test\bin\Debug" - $testDirVB = "$testDir\VisualBasic\CodeCracker.Test\bin\Debug" + $testDirCS = "$testDir\CSharp\CodeCracker.Test\bin\Release" + $testDirVB = "$testDir\VisualBasic\CodeCracker.Test\bin\Release" $logDir = "$rootDir\log" $outputXml = "$logDir\CodeCoverageResults.xml" $reportGeneratorExe = "$packagesDir\ReportGenerator.2.3.5.0\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" - $converallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" + $coverallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" $isRelease = $isAppVeyor -and ($env:APPVEYOR_REPO_BRANCH -eq "release") $isPullRequest = $env:APPVEYOR_PULL_REQUEST_NUMBER -ne $null } @@ -51,16 +51,16 @@ Task Build-VB -depends Prepare-Build, Build-Only-VB Task Build-Only -depends Build-Only-CS, Build-Only-VB Task Build-Only-CS { if ($isAppVeyor) { - Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=DebugNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } + Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } } else { - Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=DebugNoVsix } + Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } } } Task Build-Only-VB { if ($isAppVeyor) { - Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=DebugNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } + Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } } else { - Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=DebugNoVsix } + Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } } } @@ -128,7 +128,7 @@ function PackNuget($language, $dir, $nuspecFile, $nupkgFile) { [xml]$xml = cat $nuspecFile $nupkgFile = $nupkgFile -f $xml.package.metadata.version Write-Host "Nupkg path is $nupkgFile" - . $nugetExe pack $nuspecFile -Properties "Configuration=Debug;Platform=AnyCPU" -OutputDirectory $dir + . $nugetExe pack $nuspecFile -OutputDirectory $dir ls $nupkgFile Write-Host "Nuget packed for $language!" Write-Host "Pushing nuget artifact for $language..." @@ -220,6 +220,6 @@ function RunTestWithCoverage($fullTestDllPaths) { Exec { . $reportGeneratorExe -verbosity:Info -reports:$outputXml -targetdir:$coverageReportDir } if ($env:COVERALLS_REPO_TOKEN -ne $null) { Write-Host -ForegroundColor DarkBlue "Uploading coverage report to Coveralls.io" - Exec { . $converallsNetExe --opencover $outputXml --full-sources } + Exec { . $coverallsNetExe --opencover $outputXml --full-sources } } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index fb1a57fee..974df8851 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -13,15 +13,15 @@ A analyzer library for C# that uses Roslyn to produce refactorings, code analysis, and other niceties. This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. - Third alpha release - Copyright CodeCracker 2014-2015 + See https://github.com/code-cracker/code-cracker/blob/master/CHANGELOG.md + Copyright CodeCracker 2014-2016 roslyn, analyzers - + diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index e34681210..9ea132644 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -15,8 +15,8 @@ You probably don't want this package directly, search for the C# or Visual Basic specific packages (codecracker.CSharp and codecracker.VisualBasic). This will install both. This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. - First alpha release - Copyright CodeCracker 2014 + See https://github.com/code-cracker/code-cracker/blob/master/CHANGELOG.md + Copyright CodeCracker 2014-2016 roslyn, analyzers diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 4245b4eeb..d5a8ec65e 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -13,15 +13,15 @@ A analyzer library for Visual Basic that uses Roslyn to produce refactorings, code analysis, and other niceties. This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. - Third alpha release - Copyright CodeCracker 2014-2015 + See https://github.com/code-cracker/code-cracker/blob/master/CHANGELOG.md + Copyright CodeCracker 2014-2016 roslyn, analyzers - + diff --git a/test/CSharp/AnalyzeCecil.ps1 b/test/CSharp/AnalyzeCecil.ps1 index 6f9902b76..a2700956e 100644 --- a/test/CSharp/AnalyzeCecil.ps1 +++ b/test/CSharp/AnalyzeCecil.ps1 @@ -3,8 +3,8 @@ $baseDir = "$([System.IO.Path]::GetTempPath())$([System.Guid]::NewGuid().ToStri $projectDir = "$baseDir\cecil" $logDir = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\log") $logFile = "$logDir\cecil.log" -$analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Debug\CodeCracker.CSharp.dll") -$analyzerCommonDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Debug\CodeCracker.Common.dll") +$analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Release\CodeCracker.CSharp.dll") +$analyzerCommonDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Release\CodeCracker.Common.dll") $gitPath = "https://github.com/jbevain/cecil.git" if (Test-Path "C:\p\cecil") { $gitPath = "c:\p\cecil" @@ -78,7 +78,7 @@ if ($ccBuildErrors -ne $null) write-host "Errors found (see $logFile):" foreach($ccBuildError in $ccBuildErrors) { - Write-Host -ForegroundColor DarkRed "$($ccBuildError.LineNumber) $($ccBuildError.Line)" + Write-Host -ForegroundColor DarkRed "$($ccBuildError.LineNumber) $($ccBuildError.Line)" } throw "Errors found on the cecil analysis" } \ No newline at end of file diff --git a/test/CSharp/AnalyzeCoreFx.ps1 b/test/CSharp/AnalyzeCoreFx.ps1 index e6f28ab9c..c418b147a 100644 --- a/test/CSharp/AnalyzeCoreFx.ps1 +++ b/test/CSharp/AnalyzeCoreFx.ps1 @@ -3,7 +3,7 @@ $baseDir = "$([System.IO.Path]::GetTempPath())$([System.Guid]::NewGuid().ToStri $projectDir = "$baseDir\corefx" $logDir = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\log") $logFile = "$logDir\corefx.log" -$analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Debug\CodeCracker.CSharp.dll") +$analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Release\CodeCracker.CSharp.dll") $gitPath = "https://github.com/dotnet/corefx.git" if (Test-Path "C:\proj\corefx") { $gitPath = "C:\proj\corefx" @@ -69,7 +69,7 @@ if ($ccBuildErrors -ne $null) Write-Host "Errors found (see $logFile):" foreach($ccBuildError in $ccBuildErrors) { - Write-Host -ForegroundColor DarkRed "$($ccBuildError.LineNumber) $($ccBuildError.Line)" + Write-Host -ForegroundColor DarkRed "$($ccBuildError.LineNumber) $($ccBuildError.Line)" } throw "Errors found on the corefx analysis" } diff --git a/test/CSharp/AnalyzeRoslyn.ps1 b/test/CSharp/AnalyzeRoslyn.ps1 index efd208be6..0ac60d2fb 100644 --- a/test/CSharp/AnalyzeRoslyn.ps1 +++ b/test/CSharp/AnalyzeRoslyn.ps1 @@ -3,8 +3,8 @@ $baseDir = "$([System.IO.Path]::GetTempPath())$([System.Guid]::NewGuid().ToStri $projectDir = "$baseDir\roslyn" $logDir = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\log") $logFile = "$logDir\roslyn.log" -$analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Debug\CodeCracker.CSharp.dll") -$analyzerDllVB = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\VisualBasic\CodeCracker\bin\Debug\CodeCracker.VisualBasic.dll") +$analyzerDll = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\CSharp\CodeCracker\bin\Release\CodeCracker.CSharp.dll") +$analyzerDllVB = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\src\VisualBasic\CodeCracker\bin\Release\CodeCracker.VisualBasic.dll") $gitPath = "https://github.com/dotnet/roslyn.git" if (Test-Path "c:\proj\roslyn") { $gitPath = "c:\proj\roslyn" @@ -101,7 +101,7 @@ if ($ccBuildErrors -ne $null) Write-Host "Errors found (see $logFile):" foreach($ccBuildError in $ccBuildErrors) { - Write-Host -ForegroundColor DarkRed "$($ccBuildError.LineNumber) $($ccBuildError.Line)" + Write-Host -ForegroundColor DarkRed "$($ccBuildError.LineNumber) $($ccBuildError.Line)" } throw "Errors found on the roslyn analysis" } \ No newline at end of file From cd121d14f66f5d1836386bfa8272e35ddb8beb29 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 01:48:40 -0300 Subject: [PATCH 161/358] Create ReleaseNoVsix build config for global and vb slns --- CodeCracker.VisualBasic.sln | 12 +++++++++++- CodeCracker.sln | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CodeCracker.VisualBasic.sln b/CodeCracker.VisualBasic.sln index 049aa9a2c..6b903192a 100644 --- a/CodeCracker.VisualBasic.sln +++ b/CodeCracker.VisualBasic.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22609.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" EndProject @@ -45,6 +45,7 @@ Global Debug|Any CPU = Debug|Any CPU DebugNoVsix|Any CPU = DebugNoVsix|Any CPU Release|Any CPU = Release|Any CPU + ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -53,29 +54,38 @@ Global {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CodeCracker.sln b/CodeCracker.sln index 0b2e60b2a..8061066fb 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" EndProject @@ -61,6 +61,7 @@ Global Debug|Any CPU = Debug|Any CPU DebugNoVsix|Any CPU = DebugNoVsix|Any CPU Release|Any CPU = Release|Any CPU + ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -69,46 +70,60 @@ Global {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.Build.0 = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 6a7bd84f00c77a67a1e66693375cb0a9e4f2a594 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 02:28:42 -0300 Subject: [PATCH 162/358] Bump version to 1.0.0 :shipit: --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 4 ++-- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 4 ++-- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 8c461be91..ceaef7c59 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index 974df8851..bd9ae7cc4 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.0-rc6 + 1.0.0 CodeCracker for C# giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index 9bbcf16e1..0b5e5b22a 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.13")] +[assembly: AssemblyFileVersion("1.0.0.14")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index 9ea132644..67e27ad9d 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.0-rc6 + 1.0.0 CodeCracker for C# and VB giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014-2016 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index ae8fadbe6..266a6438b 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.13")] +[assembly: AssemblyFileVersion("1.0.0.14")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] -[assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] +[assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index baa76ca16..3cfea306c 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index d5a8ec65e..3be6daa7e 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.0-rc6 + 1.0.0 CodeCracker for Visual Basic giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 533dd3d92..e1f2b3667 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - - + + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index 0440a3f4b..71eb11924 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.13")] +[assembly: AssemblyFileVersion("1.0.0.14")] \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index 9b9d5375b..587387784 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.13")] +[assembly: AssemblyFileVersion("1.0.0.14")] \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index cb4bb031a..b5de9452d 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - + \ No newline at end of file From 70d3379e475a69b8f4790669063840f2cda4db78 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 02:29:59 -0300 Subject: [PATCH 163/358] Skip generation/publishing of joint nuget package --- build.targets.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.targets.ps1 b/build.targets.ps1 index 59ddf710b..79813258b 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -112,7 +112,8 @@ Task Update-Nuspec-VB -precondition { return $isAppVeyor -and ($isRelease -ne $t Task Pack-Nuget -precondition { return $isAppVeyor } -depends Pack-Nuget-Joint Task Pack-Nuget-Joint -precondition { return $isAppVeyor } -depends Pack-Nuget-Csharp, Pack-Nuget-VB { - PackNuget "Joint package" "$rootDir" $nuspecPathJoint $nupkgPathJoint + #we won't be publishing the common package anymore + #PackNuget "Joint package" "$rootDir" $nuspecPathJoint $nupkgPathJoint } Task Pack-Nuget-CSharp -precondition { return $isAppVeyor } { PackNuget "C#" "$rootDir\src\CSharp" $nuspecPathCS $nupkgPathCS From 3d561402f84724cbe4530405f68345e69caa2c13 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 02:38:52 -0300 Subject: [PATCH 164/358] Use build number as `-z1234` --- build.targets.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.targets.ps1 b/build.targets.ps1 index 79813258b..933398474 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -140,7 +140,7 @@ function PackNuget($language, $dir, $nuspecFile, $nupkgFile) { function UpdateNuspec($nuspecPath, $language) { write-host "Updating version in nuspec file for $language to $buildNumber" [xml]$xml = cat $nuspecPath - $xml.package.metadata.version+="-$buildNumber" + $xml.package.metadata.version+="-z$buildNumber" write-host "Nuspec version will be $($xml.package.metadata.version)" $xml.Save($nuspecPath) write-host "Nuspec saved for $language!" From cfb5aff1108f2beb19a9ec14046d03e3dbefa5aa Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 03:27:27 -0300 Subject: [PATCH 165/358] Update changelog to 1.0.0 --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b084bcf..7753429db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,41 @@ # Change Log +## [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) + +**Implemented enhancements:** + +- CC0016 and CC0031 are doing similar work [\#662](https://github.com/code-cracker/code-cracker/issues/662) +- Update XmlDocumentation to raise 2 different diagnostic ids [\#488](https://github.com/code-cracker/code-cracker/issues/488) + +**Fixed bugs:** + +- BUG: using null propagation foils the analysis for dispose object \(CC0022\) [\#761](https://github.com/code-cracker/code-cracker/issues/761) +- CC0011 incorrect when Where predicate uses index parameter [\#752](https://github.com/code-cracker/code-cracker/issues/752) +- BUG: Change to ternary fails with primitive numeric types \(CC0013 and CC0014\) [\#748](https://github.com/code-cracker/code-cracker/issues/748) +- CC0014 Use ternary tries to DirectCast integer to double [\#745](https://github.com/code-cracker/code-cracker/issues/745) +- BUG: CC0068 'Method is not used' should not apply to methods that have the ContractInvariantMethod attribute [\#744](https://github.com/code-cracker/code-cracker/issues/744) +- BUG: CC0057 UnusedParametersAnalyzer should not be triggered with verbatim identifier \(prefixed with @\) [\#741](https://github.com/code-cracker/code-cracker/issues/741) +- Code fix for CC0075 could break the logic of the code [\#740](https://github.com/code-cracker/code-cracker/issues/740) +- BUG: CC0016 "CopyEventToVariableBeforeFireCodeFixProvider" crashes [\#735](https://github.com/code-cracker/code-cracker/issues/735) +- CC0057 UnusedParametersAnalyzer should not be triggered by DllImport [\#733](https://github.com/code-cracker/code-cracker/issues/733) +- BUG: CC0013 \(Make Ternary\) doesn't handle comments correctly [\#725](https://github.com/code-cracker/code-cracker/issues/725) +- BUG: CC0014: You can use a ternary operator turns a+=b into a=a+b [\#724](https://github.com/code-cracker/code-cracker/issues/724) +- Bug in introduce field from constructor [\#721](https://github.com/code-cracker/code-cracker/issues/721) +- BUG: CC0090 \(xmldoc\) is raised on generated files [\#720](https://github.com/code-cracker/code-cracker/issues/720) +- BUG: CC0008 code fix removes too many lines when constructor already has initializer [\#717](https://github.com/code-cracker/code-cracker/issues/717) +- BUG: CC0067 must not fire when parameter Func\ is called in constructor. [\#712](https://github.com/code-cracker/code-cracker/issues/712) +- BUG: CC0033 \(DisposableFieldNotDisposed\) Should ignore static field [\#710](https://github.com/code-cracker/code-cracker/issues/710) +- CC0017 virtual props can create infinite loops [\#702](https://github.com/code-cracker/code-cracker/issues/702) +- CC0057: extern method parameter unused [\#701](https://github.com/code-cracker/code-cracker/issues/701) +- BUG: CC0052 \(readonly\) flags field that is used in variable initializer, which then gives compile error [\#700](https://github.com/code-cracker/code-cracker/issues/700) +- BUG: CC0017 \(create auto property\) removing modifiers \(static, virtual, etc\) [\#699](https://github.com/code-cracker/code-cracker/issues/699) +- BUG: CC0006 \(foreach\) edge case for non-writable struct field [\#698](https://github.com/code-cracker/code-cracker/issues/698) +- BUG: CC00091 Method `GetEnumerator` should never be made static [\#696](https://github.com/code-cracker/code-cracker/issues/696) +- Bug: CC0048 nested interpolations doesn't fix in one iteration [\#690](https://github.com/code-cracker/code-cracker/issues/690) +- BUG: CC0091 WPF event cannot be static [\#639](https://github.com/code-cracker/code-cracker/issues/639) +- DisposableVariableNotDisposedAnalyzer \(CC0022\) should not raise a diagnostic when returning a type that contains the disposable [\#465](https://github.com/code-cracker/code-cracker/issues/465) + ## [v1.0.0-rc6](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc6) (2016-02-01) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc5...v1.0.0-rc6) @@ -96,10 +132,13 @@ - CC0009 eats pragmas and trivia [\#493](https://github.com/code-cracker/code-cracker/issues/493) - CC0013 \(user ternary\) rule should be more careful with nullable types. \(VB\) [\#468](https://github.com/code-cracker/code-cracker/issues/468) - ## [v1.0.0-rc3](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc3) (2015-10-03) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc2...v1.0.0-rc3) +**Implemented enhancements:** + +- CC0013 Should be Information instead of Warning [\#520](https://github.com/code-cracker/code-cracker/issues/520) + **Fixed bugs:** - CC0017 Change to auto property codefix removes multiple variable declaration. [\#512](https://github.com/code-cracker/code-cracker/issues/512) @@ -120,6 +159,12 @@ ## [v1.0.0-rc2](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc2) (2015-08-19) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-rc1...v1.0.0-rc2) +**Implemented enhancements:** + +- Update VB Allow Members Ordering to work with Modules [\#440](https://github.com/code-cracker/code-cracker/issues/440) +- Provide an equivalence key on all code fix providers [\#417](https://github.com/code-cracker/code-cracker/issues/417) +- Unit test methods raises CC0091 - "Make \ method static" [\#404](https://github.com/code-cracker/code-cracker/issues/404) + **Fixed bugs:** - Erroneous CC0039 message [\#461](https://github.com/code-cracker/code-cracker/issues/461) @@ -138,6 +183,10 @@ ## [v1.0.0-rc1](https://github.com/code-cracker/code-cracker/tree/v1.0.0-rc1) (2015-07-23) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.0-beta1...v1.0.0-rc1) +**Implemented enhancements:** + +- Verify if xml docs have the correct parameters [\#357](https://github.com/code-cracker/code-cracker/issues/357) + **Fixed bugs:** - BUG: CopyEventToVariableBeforeFireCodeFixProvider throwing [\#411](https://github.com/code-cracker/code-cracker/issues/411) @@ -278,6 +327,7 @@ - Update all analyzers to use the supported categories [\#97](https://github.com/code-cracker/code-cracker/issues/97) - Detect read-only private fields and fix adding the "readonly" modifier [\#86](https://github.com/code-cracker/code-cracker/issues/86) - Offer diagnostic to allow for ordering members inside classes and structs [\#76](https://github.com/code-cracker/code-cracker/issues/76) +- Excess parameters in methods [\#44](https://github.com/code-cracker/code-cracker/issues/44) - Suggest use of stringbuilder when you have a while loop [\#34](https://github.com/code-cracker/code-cracker/issues/34) - Private set by default for automatic properties [\#32](https://github.com/code-cracker/code-cracker/issues/32) - Class that has IDisposable fields should implement IDisposable and dispose those fields [\#30](https://github.com/code-cracker/code-cracker/issues/30) @@ -352,4 +402,4 @@ -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file From 4037af5ccdb730bf5e65e22752b1127c06913646 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 3 Apr 2016 03:53:11 -0300 Subject: [PATCH 166/358] Update badges --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c771fb052..1a7259b4d 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ Check the official project site on [code-cracker.github.io](http://code-cracker. our task board, definition of done, definition of ready, etc. [![Build status](https://ci.appveyor.com/api/projects/status/h21sli3jkumuswyi?svg=true)](https://ci.appveyor.com/project/code-cracker/code-cracker) -[![Nuget count](https://img.shields.io/nuget/v/codecracker.svg)](https://www.nuget.org/packages/codecracker/) -[![Nuget downloads](https://img.shields.io/nuget/dt/codecracker.svg)](https://www.nuget.org/packages/codecracker/) +[![Nuget count](https://img.shields.io/nuget/v/codecracker.CSharp.svg)](https://www.nuget.org/packages/codecracker.CSharp/) +[![License](https://img.shields.io/github/license/code-cracker/code-cracker.svg)](https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt) [![Issues open](https://img.shields.io/github/issues-raw/code-cracker/code-cracker.svg)](https://huboard.com/code-cracker/code-cracker/) [![Coverage Status](https://img.shields.io/coveralls/code-cracker/code-cracker/master.svg)](https://coveralls.io/r/code-cracker/code-cracker?branch=master) [![Source Browser](https://img.shields.io/badge/Browse-Source-green.svg)](http://ccref.azurewebsites.net) From d3c536c7286b8c66eceb16b60e32def9fce15d2c Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 11 Apr 2016 22:57:22 -0300 Subject: [PATCH 167/358] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a7259b4d..f3ae91e29 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ changes to source control and share with your team, then you also want the Nuget To install from Nuget, for the C# version: ```powershell -Install-Package CodeCracker.CSharp -Pre +Install-Package CodeCracker.CSharp ``` Or for the Visual Basic version: ```powershell -Install-Package CodeCracker.VisualBasic -Pre +Install-Package CodeCracker.VisualBasic ``` Or use the Package Manager in Visual Studio. From 75a8304725c945d82292c913fa2863d7c408a4b1 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 15 Apr 2016 20:54:22 -0300 Subject: [PATCH 168/358] Update deps and cleanup --- build.targets.ps1 | 4 +-- src/CSharp/CodeCracker/CodeCracker.csproj | 4 +-- .../UseInvokeMethodToFireEventAnalyzer.cs | 4 --- src/CSharp/CodeCracker/packages.config | 2 +- .../CodeCracker.Common.csproj | 4 +-- src/Common/CodeCracker.Common/packages.config | 2 +- .../CodeCracker/CodeCracker.vbproj | 4 +-- src/VisualBasic/CodeCracker/packages.config | 2 +- .../CodeCracker.Test/CodeCracker.Test.csproj | 16 +++++----- .../Design/UseInvokeMethodToFireEventTests.cs | 4 +-- .../CodeCracker.Test/Style/ForInArrayTests.cs | 6 ++-- .../Style/TernaryOperatorTests.cs | 11 ------- .../Usage/JsonNetAnalyzerTests.cs | 30 ++++++++----------- .../Usage/VirtualMethodOnConstructorTests.cs | 2 +- test/CSharp/CodeCracker.Test/packages.config | 6 ++-- .../CodeCracker.Test.Common.csproj | 16 +++++----- .../Helpers/DiagnosticVerifier.Helper.cs | 1 - .../Verifiers/CodeFixVerifier.cs | 6 ++-- .../CodeCracker.Test.Common/packages.config | 10 +++---- .../CodeCracker.Test/CodeCracker.Test.vbproj | 18 +++++------ .../Style/TernaryOperatorTests.vb | 9 ------ ...sonNetTests.vb => JsonNetAnalyzerTests.vb} | 4 +-- .../CodeCracker.Test/packages.config | 6 ++-- 23 files changed, 71 insertions(+), 100 deletions(-) rename test/VisualBasic/CodeCracker.Test/Usage/{JsonNetTests.vb => JsonNetAnalyzerTests.vb} (96%) diff --git a/build.targets.ps1 b/build.targets.ps1 index 933398474..7c7e12a6a 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -16,14 +16,14 @@ Properties { $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" $nupkgPathJoint = "$rootDir\CodeCracker.{0}.nupkg" $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" - $openCoverExe = "$packagesDir\OpenCover.4.6.166\tools\OpenCover.Console.exe" + $openCoverExe = "$packagesDir\OpenCover.4.6.519\tools\OpenCover.Console.exe" $testDllCS = "CodeCracker.Test.CSharp.dll" $testDllVB = "CodeCracker.Test.VisualBasic.dll" $testDirCS = "$testDir\CSharp\CodeCracker.Test\bin\Release" $testDirVB = "$testDir\VisualBasic\CodeCracker.Test\bin\Release" $logDir = "$rootDir\log" $outputXml = "$logDir\CodeCoverageResults.xml" - $reportGeneratorExe = "$packagesDir\ReportGenerator.2.3.5.0\tools\ReportGenerator.exe" + $reportGeneratorExe = "$packagesDir\ReportGenerator.2.4.4.0\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" $coverallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" $isRelease = $isAppVeyor -and ($env:APPVEYOR_REPO_BRANCH -eq "release") diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 0f1d5e220..e8c815a5f 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -221,8 +221,8 @@ - - + + diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index 33163652d..c0d8ef201 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -49,15 +49,11 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var invokedMethodSymbol = (typeInfo.ConvertedType as INamedTypeSymbol)?.DelegateInvokeMethod; if (invokedMethodSymbol == null) return; - //var cantFixWithElvis = false; - //if (!invokedMethodSymbol.ReturnsVoid && !invokedMethodSymbol.ReturnType.IsReferenceType) - // cantFixWithElvis = true; if (HasCheckForNullThatReturns(invocation, context.SemanticModel, symbol)) return; if (IsInsideANullCheck(invocation, context.SemanticModel, symbol)) return; if (symbol.IsReadOnlyAndInitializedForCertain(context)) return; - //var properties = new Dictionary { { nameof(cantFixWithElvis), cantFixWithElvis.ToString() } }.ToImmutableDictionary(); context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation(), identifier.Identifier.Text)); } diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index 776175206..442f37a31 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 109c559bf..1ea38b03f 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -70,8 +70,8 @@ - - + + diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index c412e21be..0265a0254 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 500c6b6eb..5fe35f007 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -162,8 +162,8 @@ - - + + diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index be0fe2547..30ff459a2 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 8a756946c..f474e4208 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -40,12 +40,12 @@ false - - ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.dll True - - ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.Core.dll True @@ -68,8 +68,8 @@ ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll True @@ -235,8 +235,8 @@ - - + + diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index 810d8a426..9f3239e43 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -817,7 +817,7 @@ public static TReturn Method(System.Func getter) where T { return getter?.Invoke(default(T)) ?? default(TReturn); }".WrapInCSharpClass(); - await VerifyCSharpHasNumberOfCodeActions(test, 1); + await VerifyCSharpHasNumberOfCodeActionsAsync(test, 1); } public static TReturn Method(System.Func getter) where TReturn : struct @@ -939,7 +939,7 @@ public int FuncCalc(int p1, int p2) return p1*p2; } }"; - await VerifyCSharpHasNumberOfCodeActions(test, 1); + await VerifyCSharpHasNumberOfCodeActionsAsync(test, 1); } [Fact] diff --git a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs index 7b333410e..780687f64 100644 --- a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs @@ -761,7 +761,7 @@ public int[] Foo [Fact] public async Task WithValueTypeNoDiagnostic() { - var source = @" + const string source = @" using System; using System.Collections.Generic; @@ -791,7 +791,7 @@ static void Goo() [Fact] public async Task WithValueTypeAndIEnumeratorDoesNotCreateDiagnostic() { - var source = @" + const string source = @" class Foo { void Bar() @@ -823,7 +823,7 @@ public System.Collections.Generic.IEnumerator GetEnumerator() [Fact] public async Task WithValueTypeListNoDiagnostic() { - var source = @" + const string source = @" using System; using System.Collections.Generic; diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 946cc60f1..68d90f96d 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -518,17 +518,6 @@ static object OnReturn() await VerifyCSharpFixAsync(source, fixtest); } - static object OnReturn() - { - var condition = true; - var aInt = 2; - var anObj = new object(); - if (condition) - return anObj; - else - return aInt; - } - [Fact] public async Task WhenUsingIfAndElseWithDirectReturnChangeToTernaryFixAll() { diff --git a/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs index aad8d95a6..d94b0be0b 100644 --- a/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs @@ -6,7 +6,7 @@ namespace CodeCracker.Test.CSharp.Usage { - public class JsonNetTests : CodeFixVerifier + public class JsonNetAnalyzerTests : CodeFixVerifier { private const string TestCode = @" using System; @@ -26,86 +26,82 @@ public Person() [Fact] public async Task IfDeserializeObjectIdentifierFoundAndJsonTextIsIncorrectCreatesDiagnostic() { - var test = string.Format(TestCode, @"Newtonsoft.Json.JsonConvert.DeserializeObject(""foo"")"); + var test = string.Format(TestCode, @"Newtonsoft.Json.JsonConvert.DeserializeObject(""foo"");"); await VerifyCSharpDiagnosticAsync(test, CreateDiagnosticResult(11, 67)); } [Fact] public async Task IfAbbreviatedDeserializeObjectIdentifierFoundAndJsonTextIsIncorrectCreatesDiagnostic() { - var test = string.Format(TestCode, @"JsonConvert.DeserializeObject(""foo"")"); + var test = string.Format(TestCode, @"JsonConvert.DeserializeObject(""foo"");"); await VerifyCSharpDiagnosticAsync(test, CreateDiagnosticResult(11,51)); } [Fact] public async Task IfDeserializeObjectIdentifierFoundAndJsonTextIsCorrectDoesNotCreatesDiagnostic() { - var test = string.Format(TestCode, @"Newtonsoft.Json.JsonConvert.DeserializeObject(""{""name"":""foo""}"")"); + var test = string.Format(TestCode, @"Newtonsoft.Json.JsonConvert.DeserializeObject(""{""name"":""foo""}"");"); await VerifyCSharpHasNoDiagnosticsAsync(test); } [Fact] public async Task IfAbbreviateDeserializeObjectIdentifierFoundAndJsonTextIsCorrectDoesNotCreatesDiagnostic() { - var test = string.Format(TestCode, @"JsonConvert.DeserializeObject(""{""name"":""foo""}"")"); + var test = string.Format(TestCode, @"JsonConvert.DeserializeObject(""{""name"":""foo""}"");"); await VerifyCSharpHasNoDiagnosticsAsync(test); } [Fact] public async Task IfJObjectParseIdentifierFoundAndJsonTextIsIncorrectCreatesDiagnostic() { - var test = string.Format(TestCode, @"Newtonsoft.Json.Linq.JObject.Parse(""foo"")"); + var test = string.Format(TestCode, @"Newtonsoft.Json.Linq.JObject.Parse(""foo"");"); await VerifyCSharpDiagnosticAsync(test, CreateDiagnosticResult(11, 48)); } [Fact] public async Task IfAbbreviatedJObjectParseIdentifierFoundAndJsonTextIsIncorrectCreatesDiagnostic() { - var test = string.Format(TestCode, @"JObject.Parse(""foo"")"); + var test = string.Format(TestCode, @"JObject.Parse(""foo"");"); await VerifyCSharpDiagnosticAsync(test, CreateDiagnosticResult(11, 27)); } [Fact] public async Task IfJObjectParseIdentifierFoundAndJsonTextIsCorrectDoesNotCreatesDiagnostic() { - var test = string.Format(TestCode, @"JObject.Parse(""{""name"":""foo""}"")"); + var test = string.Format(TestCode, @"JObject.Parse(""{""name"":""foo""}"");"); await VerifyCSharpHasNoDiagnosticsAsync(test); } // [Fact] public async Task IfJArrayParseIdentifierFoundAndJsonTextIsIncorrectCreatesDiagnostic() { - var test = string.Format(TestCode, @"Newtonsoft.Json.Linq.JArray.Parse(""foo"")"); + var test = string.Format(TestCode, @"Newtonsoft.Json.Linq.JArray.Parse(""foo"");"); await VerifyCSharpDiagnosticAsync(test, CreateDiagnosticResult(11, 47)); } [Fact] public async Task IfAbbreviatedJArrayParseIdentifierFoundAndJsonTextIsIncorrectCreatesDiagnostic() { - var test = string.Format(TestCode, @"JArray.Parse(""foo"")"); + var test = string.Format(TestCode, @"JArray.Parse(""foo"");"); await VerifyCSharpDiagnosticAsync(test, CreateDiagnosticResult(11, 26)); } [Fact] public async Task IfJArrayParseIdentifierFoundAndJsonTextIsCorrectDoesNotCreatesDiagnostic() { - var test = string.Format(TestCode, @"JArray.Parse(""{""name"":""foo""}"")"); + var test = string.Format(TestCode, @"JArray.Parse(""{""name"":""foo""}"");"); await VerifyCSharpHasNoDiagnosticsAsync(test); } private static DiagnosticResult CreateDiagnosticResult(int line, int column) { return new DiagnosticResult { Id = DiagnosticId.JsonNet.ToDiagnosticId(), - Message = "Error parsing boolean value. Path '', line 0, position 0.", + Message = "Unexpected end when reading JSON. Path '', line 1, position 3.", Severity = DiagnosticSeverity.Error, Locations = new[] {new DiagnosticResultLocation("Test0.cs", line, column)} }; } - - protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() - { - return new JsonNetAnalyzer(); - } + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() => new JsonNetAnalyzer(); } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs b/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs index eb2775560..6d55294df 100644 --- a/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs @@ -144,7 +144,7 @@ public Person(string name) [Fact] public async Task IgnoreParameters() { - var test = @" + const string test = @" using System; class Foo { diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index 953d54e58..4fe5396c0 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -1,14 +1,14 @@  - - + + - + diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 5ca8c8ccc..2d74ed808 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -35,12 +35,12 @@ 4 - - ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.dll True - - ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.Core.dll True @@ -71,8 +71,8 @@ ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll True @@ -144,8 +144,8 @@ - - + + diff --git a/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs b/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs index 81a7cfd79..4a40a1eed 100644 --- a/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs +++ b/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticVerifier.Helper.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Threading; using System.Threading.Tasks; namespace CodeCracker.Test diff --git a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs index b6cc7416f..5603da4c6 100644 --- a/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs +++ b/test/Common/CodeCracker.Test.Common/Verifiers/CodeFixVerifier.cs @@ -332,8 +332,8 @@ private async static Task VerifyFixAllAsync(string language, DiagnosticAnalyzer /// The codefix to be applied to the code wherever the relevant Diagnostic is found /// C# language version used for compiling the test project, required unless you inform the VB language version. /// The expected number of code actions provided by the code fix. - protected async Task VerifyCSharpHasNumberOfCodeActions(string source, int numberOfCodeActions, CodeFixProvider codeFixProvider = null, LanguageVersion languageVersionCSharp = LanguageVersion.CSharp6) => - await VerifyNumberOfCodeActions(LanguageNames.CSharp, GetDiagnosticAnalyzer(), codeFixProvider ?? GetCodeFixProvider(), source, numberOfCodeActions, languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic14).ConfigureAwait(true); + protected async Task VerifyCSharpHasNumberOfCodeActionsAsync(string source, int numberOfCodeActions, CodeFixProvider codeFixProvider = null, LanguageVersion languageVersionCSharp = LanguageVersion.CSharp6) => + await VerifyNumberOfCodeActionsAsync(LanguageNames.CSharp, GetDiagnosticAnalyzer(), codeFixProvider ?? GetCodeFixProvider(), source, numberOfCodeActions, languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic14).ConfigureAwait(true); /// /// General verifier for a diagnostics that verifies how many code actions a code fix registered. @@ -347,7 +347,7 @@ protected async Task VerifyCSharpHasNumberOfCodeActions(string source, int numbe /// C# language version used for compiling the test project, required unless you inform the VB language version. /// VB language version used for compiling the test project, required unless you inform the C# language version. /// The expected number of code actions provided by the code fix. - private async static Task VerifyNumberOfCodeActions(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string source, int numberOfCodeActions, LanguageVersion languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersionVB) + private async static Task VerifyNumberOfCodeActionsAsync(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string source, int numberOfCodeActions, LanguageVersion languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersionVB) { var document = CreateDocument(source, language, languageVersionCSharp, languageVersionVB); var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzer, new[] { document }).ConfigureAwait(true); diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index f1bc5d8d5..30cf43a90 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -1,8 +1,8 @@  - + - + @@ -11,9 +11,9 @@ - - - + + + diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 9648c8dbb..5243bd27a 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -54,12 +54,12 @@ On - - ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.dll True - - ..\..\..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.Core.dll True @@ -82,8 +82,8 @@ ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll True @@ -184,7 +184,7 @@ - + @@ -229,8 +229,8 @@ - - + + diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 80a039a2a..d5357ee71 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -184,15 +184,6 @@ Namespace ConsoleApplication1 End Namespace" Await VerifyBasicFixAsync(sourceAssign, fix) End Function - Sub Foo() - Dim v As Boolean - If True Then - ' a comment - v = False - Else - v = True - End If - End Sub Public Async Function WhenUsingIfAndElseWithAssignmentChangeToTernaryFixAll() As Task diff --git a/test/VisualBasic/CodeCracker.Test/Usage/JsonNetTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb similarity index 96% rename from test/VisualBasic/CodeCracker.Test/Usage/JsonNetTests.vb rename to test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb index ea69e25a7..a1b921ef7 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/JsonNetTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb @@ -3,7 +3,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Xunit Namespace Usage - Public Class JsonNetTests + Public Class JsonNetAnalyzerTests Inherits CodeFixVerifier Private Const TestCode = " @@ -21,7 +21,7 @@ End Namespace" Private Shared Function CreateDiagnosticResult(line As Integer, column As Integer) As DiagnosticResult Return New DiagnosticResult With { .Id = DiagnosticId.JsonNet.ToDiagnosticId(), - .Message = "Error parsing boolean value. Path '', line 0, position 0.", + .Message = "Unexpected end when reading JSON. Path '', line 1, position 3.", .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Error, .Locations = {New DiagnosticResultLocation("Test0.vb", line, column)} } diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config index 2739aafad..5e32c07e9 100644 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ b/test/VisualBasic/CodeCracker.Test/packages.config @@ -1,14 +1,14 @@  - - + + - + From cbc32b0c621b0ad4a73d88df0a32e26c442dea6d Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 16 Apr 2016 17:01:06 -0300 Subject: [PATCH 169/358] Update Microsoft.CodeAnalysis.Analyzers to 1.1.0 This had to be done manually, as the other CodeAnalysis packages depend on version =1.0.0 of Microsoft.CodeAnalysis.Analyzers, so, if using VS to do this, it will auto upgrade all Microsoft.CodeAnalysis.* packages to 1.1.0 as well, which will keep the analyzer from working on VS 2015 RTM, only working on Update 1. --- src/CSharp/CodeCracker/CodeCracker.csproj | 4 ++-- src/CSharp/CodeCracker/packages.config | 2 +- src/Common/CodeCracker.Common/CodeCracker.Common.csproj | 4 ++-- src/Common/CodeCracker.Common/packages.config | 2 +- src/VisualBasic/CodeCracker/CodeCracker.vbproj | 4 ++-- src/VisualBasic/CodeCracker/packages.config | 2 +- test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj | 4 ++-- test/CSharp/CodeCracker.Test/packages.config | 2 +- .../CodeCracker.Test.Common/CodeCracker.Test.Common.csproj | 4 ++-- test/Common/CodeCracker.Test.Common/packages.config | 2 +- test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj | 4 ++-- test/VisualBasic/CodeCracker.Test/packages.config | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index e8c815a5f..e1a60a05e 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -223,8 +223,8 @@ - - + + diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index 442f37a31..26624b6d1 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 1ea38b03f..6ecee6f01 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -72,8 +72,8 @@ - - + + diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index 0265a0254..564e6399a 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 5fe35f007..ba1b36a08 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -164,8 +164,8 @@ - - + + diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index 30ff459a2..06a0521ef 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,7 +1,7 @@  - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index f474e4208..b17ba4a79 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -237,8 +237,8 @@ - - + + diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index 4fe5396c0..2796290c0 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -2,7 +2,7 @@ - + diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 2d74ed808..bf88cd107 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -146,8 +146,8 @@ - - + + diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index 30cf43a90..9f3abe748 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -3,7 +3,7 @@ - + diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 5243bd27a..96671272a 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -231,8 +231,8 @@ - - + + diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config index 5e32c07e9..784240f28 100644 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ b/test/VisualBasic/CodeCracker.Test/packages.config @@ -2,7 +2,7 @@ - + From 9bb6062cfc426c3b2cc4ae0606241caecb2233b2 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 17 Apr 2016 02:00:28 -0300 Subject: [PATCH 170/358] Bump version to 1.0.1 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index ceaef7c59..19b4ff34c 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index bd9ae7cc4..f659d5f96 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.0 + 1.0.1 CodeCracker for C# giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index 0b5e5b22a..e73618076 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.14")] +[assembly: AssemblyFileVersion("1.0.1.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index 67e27ad9d..c910e7aba 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.0 + 1.0.1 CodeCracker for C# and VB giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014-2016 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index 266a6438b..8fd31cfbe 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.14")] +[assembly: AssemblyFileVersion("1.0.1.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] [assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 3cfea306c..2292f0dec 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 3be6daa7e..70abb04ba 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.0 + 1.0.1 CodeCracker for Visual Basic giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index e1f2b3667..9f6f2650c 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index 71eb11924..9da58a97d 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.14")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.1.0")] \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index 587387784..8c492b358 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.14")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.1.0")] \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index b5de9452d..2599bd9f5 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - \ No newline at end of file + \ No newline at end of file From cb56328511b10200992cba78d3f07dcaa1e34638 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 17 Apr 2016 02:07:17 -0300 Subject: [PATCH 171/358] Fixes CallExtensionMethodAsExtensionAnalyzer with C# 5 Closes #781 Also allows for same tree extension methods to be detected by comparing by method name instead of symbol equality. --- .../CallExtensionMethodAsExtensionAnalyzer.cs | 11 ++-- .../CallExtensionMethodAsExtensionTests.cs | 54 ++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index 15d9bff32..e949222bd 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -66,12 +66,15 @@ private static bool IsSelectingADifferentMethod(IEnumerable childNod var speculativeRootWithExtensionMethod = tree.GetCompilationUnitRoot() .ReplaceNode(invocationExpression, newInvocationStatement) .AddUsings(extensionMethodNamespaceUsingDirective); - var speculativeModel = compilation.ReplaceSyntaxTree(tree, speculativeRootWithExtensionMethod.SyntaxTree) - .GetSemanticModel(speculativeRootWithExtensionMethod.SyntaxTree); - var speculativeInvocationStatement = speculativeRootWithExtensionMethod.SyntaxTree.GetCompilationUnitRoot().GetAnnotatedNodes(introduceExtensionMethodAnnotation).Single() as InvocationExpressionSyntax; + var speculativeTree = speculativeRootWithExtensionMethod.SyntaxTree; + var speculativeTreeOptions = (CSharpParseOptions)speculativeTree.Options; + var speculativeTreeWithCorrectLanguageVersion = speculativeTree.WithRootAndOptions(speculativeRootWithExtensionMethod, speculativeTreeOptions.WithLanguageVersion(((CSharpParseOptions)tree.Options).LanguageVersion)); + var speculativeModel = compilation.ReplaceSyntaxTree(tree, speculativeTreeWithCorrectLanguageVersion) + .GetSemanticModel(speculativeTreeWithCorrectLanguageVersion); + var speculativeInvocationStatement = speculativeTreeWithCorrectLanguageVersion.GetCompilationUnitRoot().GetAnnotatedNodes(introduceExtensionMethodAnnotation).Single() as InvocationExpressionSyntax; var speculativeExtensionMethodSymbol = speculativeModel.GetSymbolInfo(speculativeInvocationStatement.Expression).Symbol as IMethodSymbol; var speculativeNonExtensionFormOfTheMethodSymbol = speculativeExtensionMethodSymbol?.GetConstructedReducedFrom(); - return speculativeNonExtensionFormOfTheMethodSymbol == null || !speculativeNonExtensionFormOfTheMethodSymbol.Equals(methodSymbol); + return speculativeNonExtensionFormOfTheMethodSymbol == null || speculativeNonExtensionFormOfTheMethodSymbol.ToString() != methodSymbol.ToString();//can't compare equality, as speculative symbol might be different } private static int CountArguments(IEnumerable childNodes) => diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index d951964ae..2b7e06964 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using System.Threading.Tasks; using Xunit; @@ -28,7 +29,7 @@ public void Bar() } [Fact] - public async Task WhenCallExtensionMethodAsStaticMenthodTriggerAFix() + public async Task WhenCallExtensionMethodAsStaticMethodTriggerAFix() { const string source = @" using System.Linq; @@ -55,6 +56,57 @@ public void Bar() await VerifyCSharpDiagnosticAsync(source, expected); } + [Fact] + public async Task WhenCallExtensionMethodAsStaticMethodTriggerAFixWithCSharp5() + { + const string source = @" + using System.Linq; + namespace ConsoleApplication1 + { + public class Foo + { + public void Bar() + { + var source = new int[] { 1, 2, 3 }; + Enumerable.Any(source, x => x > 1); + } + } + }"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), + Message = "Do not call 'Any' method of class 'Enumerable' as a static method", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 33) } + }; + await VerifyCSharpDiagnosticAsync(source, expected, LanguageVersion.CSharp5); + } + + [Fact] + public async Task CreatesDiagnosticWhenExtensionClassInSameTree() + { + const string source = @" +class Foo +{ + public static void Bar() + { + C.M(""""); + } +} +public static class C +{ + public static string M(this string s) => s; +}"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), + Message = "Do not call 'M' method of class 'C' as a static method", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 9) } + }; + await VerifyCSharpDiagnosticAsync(source, expected, LanguageVersion.CSharp5); + } + [Fact] public async Task WhenCallExtensionMethodWithFullNamespaceAsStaticMenthodTriggerAFix() { From a657cab4893859e00571d0cf658acf283e948751 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 17 Apr 2016 02:23:01 -0300 Subject: [PATCH 172/358] Change build and deployment conditions Allow now build from tags. Deploy now from tags not from the release branch anymore. For patches, now deploy to myget any branch that looks like a version number, like: v1.0.x v3.9.x Always ending with an `x`. --- appveyor.yml | 11 ++++++++--- build.targets.ps1 | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c89ed6dff..58c443b5b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,5 @@ version: 1.0.0.{build} -skip_tags: true - configuration: ReleaseNoVsix init: @@ -56,7 +54,7 @@ deploy: secure: s1aIT1sGbIeG5Ccgree7K+k/h7LOSzPfJOrsWcCuzgFGrcuexPZUwX/CfYnU9w4v skip_symbols: true on: - branch: release + appveyor_repo_tag: true - provider: NuGet server: https://www.myget.org/F/codecrackerbuild/api/v2/package api_key: @@ -71,6 +69,13 @@ deploy: skip_symbols: true on: branch: vnext +- provider: NuGet + server: https://www.myget.org/F/codecrackerbuild/api/v2/package + api_key: + secure: 42eslsnaZIIcMVVaeC9Qu5NI9yjzLzHWYUGl0HLhl0YurivQezpMyJOwgSVjiGmj + skip_symbols: true + on: + branch: /v\d\.\d\.x/ notifications: - provider: Email diff --git a/build.targets.ps1 b/build.targets.ps1 index 7c7e12a6a..42ee817bb 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -26,7 +26,7 @@ Properties { $reportGeneratorExe = "$packagesDir\ReportGenerator.2.4.4.0\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" $coverallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" - $isRelease = $isAppVeyor -and ($env:APPVEYOR_REPO_BRANCH -eq "release") + $isRelease = $isAppVeyor -and (($env:APPVEYOR_REPO_BRANCH -eq "release") -or ($env:APPVEYOR_REPO_TAG -eq "true")) $isPullRequest = $env:APPVEYOR_PULL_REQUEST_NUMBER -ne $null } From b38cef381242f3f2306e4e2317ff54a58b368b13 Mon Sep 17 00:00:00 2001 From: ngobzin11 Date: Wed, 20 Apr 2016 14:51:35 -0500 Subject: [PATCH 173/358] Restricted ReadonlyFieldAnalyzer to primitive and reference types, #775 --- .../Usage/ReadonlyFieldAnalyzer.cs | 15 ++- .../Usage/ReadonlyFieldTests.cs | 95 +++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 97d3ebd64..6c031eebd 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -145,8 +145,12 @@ private static Dictionary GetCandidateVa private static Dictionary GetCandidateVariables(SemanticModel semanticModel, FieldDeclarationSyntax fieldDeclaration) { var variablesToMakeReadonly = new Dictionary(); - if (fieldDeclaration == null) return variablesToMakeReadonly; - if (!CanBeMadeReadonly(fieldDeclaration)) return variablesToMakeReadonly; + if (fieldDeclaration == null || + IsComplexValueType(semanticModel, fieldDeclaration) || + !CanBeMadeReadonly(fieldDeclaration)) + { + return variablesToMakeReadonly; + } foreach (var variable in fieldDeclaration.Declaration.Variables) { if (variable.Initializer == null) continue; @@ -167,6 +171,13 @@ private static bool CanBeMadeReadonly(FieldDeclarationSyntax fieldDeclaration) || m.IsKind(SyntaxKind.ConstKeyword)); } + private static bool IsComplexValueType(SemanticModel semanticModel, FieldDeclarationSyntax fieldDeclaration) + { + var fieldTypeName = fieldDeclaration.Declaration.Type; + var fieldType = semanticModel.GetTypeInfo(fieldTypeName).ConvertedType; + return fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + } + private static bool CanBeMadeReadonly(IFieldSymbol fieldSymbol) { return (fieldSymbol.DeclaredAccessibility == Accessibility.NotApplicable diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index b7fb708b6..bd528508c 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -846,5 +846,100 @@ static void B() }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task UserDefinedStructFieldDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct = default(MyStruct); + + private struct MyStruct + { + public int Value; + } + } + } + "; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DateTimeFieldInitializedOnDeclarationDoesNotCreateDiagnostic() + { + const string source = @" + using System; + + namespace ConsoleApplication1 + { + public class MyClass + { + private DateTime date = new DateTime(2008, 5, 1, 8, 30, 52); + } + } + "; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task EnumerationFieldInitializedOnDeclarationCreatesADiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private VehicleType car = VehicleType.Car; + + private enum VehicleType + { + None = 0, + Car = 1, + Truck = 2 + } + } + } + "; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), + Message = string.Format(ReadonlyFieldAnalyzer.Message, "car"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 33) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task ReferenceTypeFieldInitializedInConstructorCreatesADiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class Person + { + private string name; + + public Person(string name) + { + this.name = name; + } + } + } + "; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), + Message = string.Format(ReadonlyFieldAnalyzer.Message, "name"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 28) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } From 0e2adc07c7de3eabed62e82dba60d715d434cc4f Mon Sep 17 00:00:00 2001 From: Hubert Kindermann Date: Tue, 28 Jun 2016 16:49:48 +0200 Subject: [PATCH 174/358] Fixes #773. --- .../CSharpGeneratedCodeAnalysisExtensions.cs | 14 ++-- .../GeneratedCodeAnalysisExtensionsTests.cs | 77 ++++++++----------- 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs index d7386b3c5..339e64ae1 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs @@ -1,8 +1,8 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp; namespace CodeCracker { @@ -48,9 +48,13 @@ public static bool HasAutoGeneratedComment(this SyntaxTree tree) if (!firstToken.HasLeadingTrivia) return false; trivia = firstToken.LeadingTrivia; } - var commentLines = trivia.Where(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia)).Take(2).ToList(); - if (commentLines.Count != 2) return false; - return commentLines[1].ToString() == "// "; + + var comments = trivia.Where(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia) || t.IsKind(SyntaxKind.MultiLineCommentTrivia)); + return comments.Any(t => + { + var s = t.ToString(); + return s.Contains(" GetSymbolAnalysisContext(source).IsGenerated().Should().BeTrue(); - [Fact] - public static void SyntaxNodeAnalysis_WithAutoGeneratedCommentBasedOnWebForms() => - GetSyntaxNodeAnalysisContext( + [Theory] + [InlineData( @"//------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -304,11 +303,8 @@ namespace WebApplication3 public partial class _Default { } -}").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SyntaxTreeAnalysis_WithAutoGeneratedCommentBasedOnWebForms() => - GetSyntaxTreeAnalysisContext( +}", false)] + [InlineData( @"//------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -316,57 +312,46 @@ public static void SyntaxTreeAnalysis_WithAutoGeneratedCommentBasedOnWebForms() // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // -//------------------------------------------------------------------------------ - +//------------------------------------------------------------------------------", true)] + [InlineData( +@"// +// This code was generated by a tool. namespace WebApplication3 { public partial class _Default { } -}").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SyntaxTreeAnalysis_WithAutoGeneratedCommentEmpty() => - GetSyntaxTreeAnalysisContext( -@"//------------------------------------------------------------------------------ -// -// This code was generated by a tool. +}", false)] + [InlineData( +@"// +// This code was generated by a tool.", true)] + [InlineData( +@"// This code was generated by a tool. // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SymbolicAnalysis_WithAutoGeneratedCommentBasedOnWebForms() => - GetSymbolAnalysisContext( -@"//------------------------------------------------------------------------------ // -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - namespace WebApplication3 { public partial class _Default { } -}").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SyntaxNodeAnalysis_WithAutoGeneratedCommentEmpty() => - GetSyntaxNodeAnalysisContext( -@"//------------------------------------------------------------------------------ -// -// This code was generated by a tool. +}", false)] + [InlineData( +@"// This code was generated by a tool. // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------").IsGenerated().Should().BeTrue(); +// ", true)] + public static void SyntaxNodeAnalysis_WithAutoGeneratedComment(string source, bool isEmpty) + { + GetSyntaxTreeAnalysisContext(source).IsGenerated().Should().BeTrue(); + if (isEmpty) + { + GetSyntaxNodeAnalysisContext(source).IsGenerated().Should().BeTrue(); + } + else + { + GetSyntaxNodeAnalysisContext(source).IsGenerated().Should().BeTrue(); + GetSymbolAnalysisContext(source).IsGenerated().Should().BeTrue(); + } + } private static SyntaxNodeAnalysisContext GetSyntaxNodeAnalysisContext(string code, string fileName = baseProjectPath + "a.cs") => GetSyntaxNodeAnalysisContext(code, fileName); From 0af060616a99c4b2dd223ca728cacfb277cf07c9 Mon Sep 17 00:00:00 2001 From: ngobzin11 Date: Wed, 20 Apr 2016 14:51:35 -0500 Subject: [PATCH 175/358] Restricted ReadonlyFieldAnalyzer to primitive and reference types, #775 --- .../Usage/ReadonlyFieldAnalyzer.cs | 15 ++- .../Usage/ReadonlyFieldTests.cs | 95 +++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 97d3ebd64..6c031eebd 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -145,8 +145,12 @@ private static Dictionary GetCandidateVa private static Dictionary GetCandidateVariables(SemanticModel semanticModel, FieldDeclarationSyntax fieldDeclaration) { var variablesToMakeReadonly = new Dictionary(); - if (fieldDeclaration == null) return variablesToMakeReadonly; - if (!CanBeMadeReadonly(fieldDeclaration)) return variablesToMakeReadonly; + if (fieldDeclaration == null || + IsComplexValueType(semanticModel, fieldDeclaration) || + !CanBeMadeReadonly(fieldDeclaration)) + { + return variablesToMakeReadonly; + } foreach (var variable in fieldDeclaration.Declaration.Variables) { if (variable.Initializer == null) continue; @@ -167,6 +171,13 @@ private static bool CanBeMadeReadonly(FieldDeclarationSyntax fieldDeclaration) || m.IsKind(SyntaxKind.ConstKeyword)); } + private static bool IsComplexValueType(SemanticModel semanticModel, FieldDeclarationSyntax fieldDeclaration) + { + var fieldTypeName = fieldDeclaration.Declaration.Type; + var fieldType = semanticModel.GetTypeInfo(fieldTypeName).ConvertedType; + return fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + } + private static bool CanBeMadeReadonly(IFieldSymbol fieldSymbol) { return (fieldSymbol.DeclaredAccessibility == Accessibility.NotApplicable diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index b7fb708b6..bd528508c 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -846,5 +846,100 @@ static void B() }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task UserDefinedStructFieldDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct = default(MyStruct); + + private struct MyStruct + { + public int Value; + } + } + } + "; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DateTimeFieldInitializedOnDeclarationDoesNotCreateDiagnostic() + { + const string source = @" + using System; + + namespace ConsoleApplication1 + { + public class MyClass + { + private DateTime date = new DateTime(2008, 5, 1, 8, 30, 52); + } + } + "; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task EnumerationFieldInitializedOnDeclarationCreatesADiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private VehicleType car = VehicleType.Car; + + private enum VehicleType + { + None = 0, + Car = 1, + Truck = 2 + } + } + } + "; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), + Message = string.Format(ReadonlyFieldAnalyzer.Message, "car"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 33) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task ReferenceTypeFieldInitializedInConstructorCreatesADiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class Person + { + private string name; + + public Person(string name) + { + this.name = name; + } + } + } + "; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), + Message = string.Format(ReadonlyFieldAnalyzer.Message, "name"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 28) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } From f7d2893e8ea03ace30451a553a00f80615553987 Mon Sep 17 00:00:00 2001 From: Hubert Kindermann Date: Tue, 28 Jun 2016 16:49:48 +0200 Subject: [PATCH 176/358] Fixes #773. --- .../CSharpGeneratedCodeAnalysisExtensions.cs | 14 ++-- .../GeneratedCodeAnalysisExtensionsTests.cs | 77 ++++++++----------- 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs index d7386b3c5..339e64ae1 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpGeneratedCodeAnalysisExtensions.cs @@ -1,8 +1,8 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp; namespace CodeCracker { @@ -48,9 +48,13 @@ public static bool HasAutoGeneratedComment(this SyntaxTree tree) if (!firstToken.HasLeadingTrivia) return false; trivia = firstToken.LeadingTrivia; } - var commentLines = trivia.Where(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia)).Take(2).ToList(); - if (commentLines.Count != 2) return false; - return commentLines[1].ToString() == "// "; + + var comments = trivia.Where(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia) || t.IsKind(SyntaxKind.MultiLineCommentTrivia)); + return comments.Any(t => + { + var s = t.ToString(); + return s.Contains(" GetSymbolAnalysisContext(source).IsGenerated().Should().BeTrue(); - [Fact] - public static void SyntaxNodeAnalysis_WithAutoGeneratedCommentBasedOnWebForms() => - GetSyntaxNodeAnalysisContext( + [Theory] + [InlineData( @"//------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -304,11 +303,8 @@ namespace WebApplication3 public partial class _Default { } -}").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SyntaxTreeAnalysis_WithAutoGeneratedCommentBasedOnWebForms() => - GetSyntaxTreeAnalysisContext( +}", false)] + [InlineData( @"//------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -316,57 +312,46 @@ public static void SyntaxTreeAnalysis_WithAutoGeneratedCommentBasedOnWebForms() // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // -//------------------------------------------------------------------------------ - +//------------------------------------------------------------------------------", true)] + [InlineData( +@"// +// This code was generated by a tool. namespace WebApplication3 { public partial class _Default { } -}").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SyntaxTreeAnalysis_WithAutoGeneratedCommentEmpty() => - GetSyntaxTreeAnalysisContext( -@"//------------------------------------------------------------------------------ -// -// This code was generated by a tool. +}", false)] + [InlineData( +@"// +// This code was generated by a tool.", true)] + [InlineData( +@"// This code was generated by a tool. // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SymbolicAnalysis_WithAutoGeneratedCommentBasedOnWebForms() => - GetSymbolAnalysisContext( -@"//------------------------------------------------------------------------------ // -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - namespace WebApplication3 { public partial class _Default { } -}").IsGenerated().Should().BeTrue(); - - [Fact] - public static void SyntaxNodeAnalysis_WithAutoGeneratedCommentEmpty() => - GetSyntaxNodeAnalysisContext( -@"//------------------------------------------------------------------------------ -// -// This code was generated by a tool. +}", false)] + [InlineData( +@"// This code was generated by a tool. // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------").IsGenerated().Should().BeTrue(); +// ", true)] + public static void SyntaxNodeAnalysis_WithAutoGeneratedComment(string source, bool isEmpty) + { + GetSyntaxTreeAnalysisContext(source).IsGenerated().Should().BeTrue(); + if (isEmpty) + { + GetSyntaxNodeAnalysisContext(source).IsGenerated().Should().BeTrue(); + } + else + { + GetSyntaxNodeAnalysisContext(source).IsGenerated().Should().BeTrue(); + GetSymbolAnalysisContext(source).IsGenerated().Should().BeTrue(); + } + } private static SyntaxNodeAnalysisContext GetSyntaxNodeAnalysisContext(string code, string fileName = baseProjectPath + "a.cs") => GetSyntaxNodeAnalysisContext(code, fileName); From 794c05aaedd35f207c6bc9e6c327d0c2df967f36 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 7 Aug 2016 16:22:57 -0300 Subject: [PATCH 177/358] Bump version to 1.1.0 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 19b4ff34c..3a3f50bbe 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index f659d5f96..72744d97a 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.1 + 1.1.0 CodeCracker for C# giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index e73618076..f63d51c3e 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index c910e7aba..f5113b83b 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.1 + 1.1.0 CodeCracker for C# and VB giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014-2016 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index 8fd31cfbe..b57f8b71e 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] [assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 2292f0dec..6cff126bc 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 70abb04ba..326c5ccb4 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.1 + 1.1.0 CodeCracker for Visual Basic giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 9f6f2650c..0758c2287 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index 9da58a97d..4b18b5a68 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.1.0.0")] \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index 8c492b358..d56074edd 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.1.0.0")] \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index 2599bd9f5..8823e3c6f 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - \ No newline at end of file + \ No newline at end of file From 553d402d555144de13a35085f81d3b2f5f2e7229 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 8 Aug 2016 00:07:39 -0300 Subject: [PATCH 178/358] Enhance UseInvokeMethodToFireEventAnalyzer to detect null checks Closes #779 --- .../UseInvokeMethodToFireEventAnalyzer.cs | 48 +++++++++++++------ .../Design/UseInvokeMethodToFireEventTests.cs | 41 ++++++++++++++++ 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index c0d8ef201..1ae8992d4 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -52,6 +52,9 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (HasCheckForNullThatReturns(invocation, context.SemanticModel, symbol)) return; if (IsInsideANullCheck(invocation, context.SemanticModel, symbol)) return; + if (IsPartOfATernaryThatChecksForNull(invocation, context.SemanticModel, symbol)) return; + if (IsPartOfALogicalOrThatChecksForNull(invocation, context.SemanticModel, symbol)) return; + if (IsPartOfALogicalAndThatChecksForNotNull(invocation, context.SemanticModel, symbol)) return; if (symbol.IsReadOnlyAndInitializedForCertain(context)) return; context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation(), identifier.Identifier.Text)); @@ -91,22 +94,37 @@ private static bool HasCheckForNullThatReturns(InvocationExpressionSyntax invoca return false; } - private static bool IsInsideANullCheck(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) + private static bool IsPartOfATernaryThatChecksForNull(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) => + IsConditionThatChecksForNotEqualsNull(invocation.FirstAncestorOfType()?.Condition, semanticModel, symbol); + + private static bool IsPartOfALogicalOrThatChecksForNull(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) => + IsConditionThatChecksForEqualsNull(invocation.FirstAncestorOfKind(SyntaxKind.LogicalOrExpression)?.Left, semanticModel, symbol); + + private static bool IsPartOfALogicalAndThatChecksForNotNull(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) => + IsConditionThatChecksForNotEqualsNull(invocation.FirstAncestorOfKind(SyntaxKind.LogicalAndExpression)?.Left, semanticModel, symbol); + + private static bool IsInsideANullCheck(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) => + invocation.Ancestors().OfType().Any(@if => IsConditionThatChecksForNotEqualsNull(@if.Condition, semanticModel, symbol)); + + private static bool IsConditionThatChecksForNotEqualsNull(ExpressionSyntax condition, SemanticModel semanticModel, ISymbol symbol) => + IsConditionThatChecksForNull(condition, semanticModel, symbol, SyntaxKind.NotEqualsExpression); + + private static bool IsConditionThatChecksForEqualsNull(ExpressionSyntax condition, SemanticModel semanticModel, ISymbol symbol) => + IsConditionThatChecksForNull(condition, semanticModel, symbol, SyntaxKind.EqualsExpression); + + private static bool IsConditionThatChecksForNull(ExpressionSyntax condition, SemanticModel semanticModel, ISymbol symbol, SyntaxKind binarySyntaxKind) { - var ifs = invocation.Ancestors().OfType(); - foreach (IfStatementSyntax @if in ifs) - { - if (!@if.Condition?.IsKind(SyntaxKind.NotEqualsExpression) ?? true) continue; - var equals = (BinaryExpressionSyntax)@if.Condition; - if (equals.Left == null || equals.Right == null) continue; - ISymbol identifierSymbol; - if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName)) - identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol; - else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName)) - identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol; - else continue; - if (symbol.Equals(identifierSymbol)) return true; - } + if (condition == null) return false; + if (!condition.IsKind(binarySyntaxKind)) return false; + var equals = (BinaryExpressionSyntax)condition; + if (equals.Left == null || equals.Right == null) return false; + ISymbol identifierSymbol; + if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName)) + identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol; + else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName)) + identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol; + else return false; + if (symbol.Equals(identifierSymbol)) return true; return false; } } diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index 9f3239e43..0ff013093 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -1096,5 +1096,46 @@ public void Execute() await VerifyCSharpHasNoDiagnosticsAsync(test); } + + [Fact] + public async void IgnoreIfAlreadyCheckedForNull() + { + const string test = @" +public static int Get(Func method) { + return method != null ? method(12345) : 0; +}"; + + await VerifyCSharpHasNoDiagnosticsAsync(test.WrapInCSharpClass()); + } + + [Fact] + public async void IgnoreIfInLogicalOrThatCheckedForNull() + { + const string test = @" +public class Foo +{ + private System.Func _filter; + public void Bar() + { + var b = _filter == null || _filter(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(test.WrapInCSharpClass()); + } + + [Fact] + public async void IgnoreIfInLogicalAndThatCheckedForNotNull() + { + const string test = @" +public class Foo +{ + private System.Func _filter; + public void Bar() + { + var b = _filter != null && _filter(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(test.WrapInCSharpClass()); + } } } \ No newline at end of file From 61545d9b28e8c56b862765e5135acc15b1823733 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 9 Aug 2016 00:56:09 -0300 Subject: [PATCH 179/358] Fix CallExtensionMethodAsExtensionAnalyzer for methods without arguments Fixes #810 --- .../CallExtensionMethodAsExtensionAnalyzer.cs | 1 + .../CallExtensionMethodAsExtensionTests.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs index e949222bd..0a6f14de5 100644 --- a/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/CallExtensionMethodAsExtensionAnalyzer.cs @@ -46,6 +46,7 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, Compila var methodCaller = childNodes.OfType().FirstOrDefault(); if (methodCaller == null) return; var argumentsCount = CountArguments(childNodes); + if (argumentsCount == 0) return; var classSymbol = GetCallerClassSymbol(context.SemanticModel, methodCaller.Expression); if (classSymbol == null || !classSymbol.MightContainExtensionMethods) return; var methodSymbol = GetCallerMethodSymbol(context.SemanticModel, methodCaller.Name, argumentsCount); diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index 2b7e06964..31de8f5c7 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -9,6 +9,25 @@ namespace CodeCracker.Test.CSharp.Usage public class CallExtensionMethodAsExtensionTests : CodeFixVerifier { + [Fact] + public async Task IgnoreWhenMissingArguments() + { + const string source = @" +using System.Linq; +class Foo +{ + public static void N() + { + Exts.M(); + } +} +static class Exts +{ + public static void M(this string s) => s.ToString(); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WhenCallExtensionMethodAsExtensionHasNoDiagnostics() { From bb44e97d90562093d648ff70d97f9104b6c37719 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 9 Aug 2016 01:15:11 -0300 Subject: [PATCH 180/358] Remove ref and out from conditions that allow read only fields Fixes #788 --- .../Usage/ReadonlyFieldAnalyzer.cs | 7 +++++ .../Usage/ReadonlyFieldTests.cs | 28 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 6c031eebd..401e7ef48 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -59,6 +59,13 @@ private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation c ? semanticModel : compilation.GetSemanticModel(syntaxReference.SyntaxTree); var descendants = syntaxReference.GetSyntax().DescendantNodes().ToList(); + var argsWithRefOrOut = descendants.OfType().Where(a => a.RefOrOutKeyword != null); + foreach (var argWithRefOrOut in argsWithRefOrOut) + { + var fieldSymbol = syntaxRefSemanticModel.GetSymbolInfo(argWithRefOrOut.Expression).Symbol as IFieldSymbol; + if (fieldSymbol == null) continue; + variablesToMakeReadonly.Remove(fieldSymbol); + } var assignments = descendants.OfKind(SyntaxKind.SimpleAssignmentExpression, SyntaxKind.AddAssignmentExpression, SyntaxKind.AndAssignmentExpression, SyntaxKind.DivideAssignmentExpression, SyntaxKind.ExclusiveOrAssignmentExpression, SyntaxKind.LeftShiftAssignmentExpression, SyntaxKind.ModuloAssignmentExpression, diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index bd528508c..efbaa8c12 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -19,6 +19,32 @@ class TypeName await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); } + [Fact] + public async Task IgnoreOut() + { + const string source = @" +public class C +{ + private string field = ""; + private static void Foo(out string bar) => bar = ""; + public void Baz() => Foo(out field); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task IgnoreRef() + { + const string source = @" +public class C +{ + private string field = ""; + private static void Foo(ref string bar) => bar = ""; + public void Baz() => Foo(ref field); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + [Fact] public async Task IgnorePostIncrement() { @@ -856,7 +882,7 @@ namespace ConsoleApplication1 public class MyClass { private MyStruct myStruct = default(MyStruct); - + private struct MyStruct { public int Value; From db0df32ad67c46091ed92d77d9d0cf5802193212 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 9 Aug 2016 01:23:50 -0300 Subject: [PATCH 181/358] Enable fields to be disposed when using member access expression Fixes #795 --- .../DisposableFieldNotDisposedAnalyzer.cs | 1 - .../Usage/DisposableFieldNotDisposedTests.cs | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs index e38d7959d..2e625e04d 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs @@ -96,7 +96,6 @@ private static bool CallsDisposeOnField(IFieldSymbol fieldSymbol, MethodDeclarat var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; if (memberAccess?.Name == null) return false; if (memberAccess.Name.Identifier.ToString() != "Dispose" || memberAccess.Name.Arity != 0) return false; - if (!memberAccess.Expression.IsKind(SyntaxKind.IdentifierName)) return false; return fieldSymbol.Equals(semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol); }); return hasDisposeCall; diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs index 123a05cb5..ba84e4bc6 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs @@ -210,6 +210,30 @@ public void Dispose() { } await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task WhenAFieldThatImplementsIDisposableIsDisposedWithThisDoesNotCreateDiagnostic() + { + const string source = @" + using System; + namespace ConsoleApplication1 + { + class TypeName : IDisposable + { + private D field = D.Create(); + public void Dispose() + { + this.field.Dispose(); + } + } + class D : IDisposable + { + public static D Create() => new D(); + public void Dispose() { } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WhenAFieldThatImplementsIDisposableIsDisposedThroughImplicitImplementationDoesNotCreateDiagnostic() { From 719d83566aca05cc7bc650689b19a1e7685007e4 Mon Sep 17 00:00:00 2001 From: Vsevolod Krasnov Date: Thu, 11 Aug 2016 06:32:35 +0300 Subject: [PATCH 182/358] Fix 'GC.SuppressFinalize within the finally block' #776 (#819) --- ...ablesShouldCallSuppressFinalizeAnalyzer.cs | 2 +- ...posablesShouldCallSuppressFinalizeTests.cs | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs index 4ab5b1e3a..c19d84911 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs @@ -56,7 +56,7 @@ private static void Analyze(SyntaxNodeAnalysisContext context) if (symbol.IsSealed && !ContainsUserDefinedFinalizer(symbol)) return; if (!ContainsNonPrivateConstructors(symbol)) return; - var statements = method.Body?.Statements.OfType(); + var statements = method.Body?.DescendantNodes().OfType(); if (statements != null) { foreach (var statement in statements) diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs index e90b46906..f145f40ab 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs @@ -58,6 +58,66 @@ public void Dispose() await VerifyCSharpDiagnosticAsync(test, expected); } + [Fact] + public async void DoNotWarnIfClassImplementsIDisposableWithSuppressFinalizeCallInFinally() + { + const string test = @" + public class MyType : System.IDisposable + { + public void Dispose() + { + try + { + } + finally + { + System.GC.SuppressFinalize(this); + } + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async void DoNotWarnIfClassImplementsIDisposableWithSuppressFinalizeCallInIf() + { + const string test = @" + public class MyType : System.IDisposable + { + public void Dispose() + { + if (true) + { + System.GC.SuppressFinalize(this); + } + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async void DoNotWarnIfClassImplementsIDisposableWithSuppressFinalizeCallInElse() + { + const string test = @" + public class MyType : System.IDisposable + { + public void Dispose() + { + if (true) + { + } + else + { + System.GC.SuppressFinalize(this); + } + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + [Fact] public async Task NoWarningIfClassImplementsDisposableCallsSuppressFinalizeAndCallsDisposeWithThis() { From 7cfff1c99f54fe3000cc93bcb000ad54678fa548 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 9 Aug 2016 00:44:56 -0300 Subject: [PATCH 183/358] Enable CC0029 analyzer to work with arrow methods Fixes #809 --- ...ablesShouldCallSuppressFinalizeAnalyzer.cs | 29 +++++++++---------- ...posablesShouldCallSuppressFinalizeTests.cs | 10 +++++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs index c19d84911..b70f8d735 100644 --- a/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.cs @@ -38,6 +38,7 @@ private static void Analyze(SyntaxNodeAnalysisContext context) var semanticModel = context.SemanticModel; var method = (MethodDeclarationSyntax)context.Node; + if (method.Body == null && method.ExpressionBody == null) return; var methodSymbol = semanticModel.GetDeclaredSymbol(method); var isImplicitDispose = methodSymbol.ToString().Contains($"{methodSymbol.ContainingType.Name}.Dispose("); @@ -56,24 +57,22 @@ private static void Analyze(SyntaxNodeAnalysisContext context) if (symbol.IsSealed && !ContainsUserDefinedFinalizer(symbol)) return; if (!ContainsNonPrivateConstructors(symbol)) return; - var statements = method.Body?.DescendantNodes().OfType(); - if (statements != null) + var expressions = method.Body != null + ? method.Body?.DescendantNodes().OfType().Select(e => e.Expression) + : new[] { method.ExpressionBody.Expression }; + foreach (var expression in expressions) { - foreach (var statement in statements) - { - var invocation = statement.Expression as InvocationExpressionSyntax; - var suppress = invocation?.Expression as MemberAccessExpressionSyntax; + var suppress = (expression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax; - if (suppress?.Name.ToString() != "SuppressFinalize") - continue; + if (suppress?.Name.ToString() != "SuppressFinalize") + continue; - var containingType = semanticModel.GetSymbolInfo(suppress.Expression).Symbol as INamedTypeSymbol; - if (containingType?.ContainingNamespace.Name != "System") - continue; + var containingType = semanticModel.GetSymbolInfo(suppress.Expression).Symbol as INamedTypeSymbol; + if (containingType?.ContainingNamespace.Name != "System") + continue; - if (containingType.Name == "GC") - return; - } + if (containingType.Name == "GC") + return; } context.ReportDiagnostic(Diagnostic.Create(Rule, methodSymbol.Locations[0], symbol.Name)); } @@ -104,4 +103,4 @@ private static bool IsNestedPrivateType(ISymbol symbol) return IsNestedPrivateType(symbol.ContainingType); } } -} \ No newline at end of file +} diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs index f145f40ab..487f2b557 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs @@ -7,6 +7,16 @@ namespace CodeCracker.Test.CSharp.Usage { public class DisposablesShouldCallSuppressFinalizeTests : CodeFixVerifier { + [Fact] + public async void AlreadyCallsSuppressFinalizeWithArrowMethod() + { + const string source = @" + public class MyType : System.IDisposable + { + public void Dispose() => System.GC.SuppressFinalize(this); + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } [Fact] public async void AlreadyCallsSuppressFinalize() From b40843eab577001bcb2ce146df5ff5a6c0abc62e Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 19 Aug 2016 12:09:58 -0300 Subject: [PATCH 184/358] Ignore member order on ReadonlyFieldAnalyzer Fix #812 Add constructor to the top of the list so we add fields with constructors initializers first --- .../Usage/ReadonlyFieldAnalyzer.cs | 14 +++++++++++ .../Usage/ReadonlyFieldTests.cs | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 401e7ef48..d9db192ba 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -36,6 +36,19 @@ private static void AnalyzeCompilation(CompilationStartAnalysisContext compilati compilationStartAnalysisContext.RegisterSyntaxTreeAction(context => AnalyzeTree(context, compilation)); } + private struct MethodKindComparer : IComparer + { + public int Compare(MethodKind x, MethodKind y) => + x - y == 0 + ? 0 + : (x == MethodKind.Constructor + ? 1 + : (y == MethodKind.Constructor + ? -1 + : x - y)); + } + private static readonly MethodKindComparer methodKindComparer = new MethodKindComparer(); + private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation compilation) { if (context.IsGenerated()) return; @@ -51,6 +64,7 @@ private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation c var typeSymbol = semanticModel.GetDeclaredSymbol(type); if (typeSymbol == null) continue; var methods = typeSymbol.GetAllMethodsIncludingFromInnerTypes(); + methods = methods.OrderByDescending(m => m.MethodKind, methodKindComparer).ToList(); foreach (var method in methods) { foreach (var syntaxReference in method.DeclaringSyntaxReferences) diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index efbaa8c12..e4181d876 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -967,5 +967,29 @@ public Person(string name) }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task IgnoreWhenConstructorIsTheLastMember() + { + const string source = @" +class Test +{ + private int value; + public int Value + { + get { return value; } + set { this.value = value; } + } + public void Foo() + { + value = 1; + } + public Test() + { + value = 8; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } From 822f0bfaac570ac60992f7f8288a8c73d5252bf7 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 20 Aug 2016 14:46:54 -0300 Subject: [PATCH 185/358] Ignore methods that implement interface in TaskNameAsync (CC0061) Fix #793 Also, refactor the search for interface members on TaskNameAsyncAnalyzer and MakeMethodStaticAnalyzer. --- .../Design/MakeMethodStaticAnalyzer.cs | 12 +---- .../Extensions/CSharpAnalyzerExtensions.cs | 33 ++++++++++++ .../Style/TaskNameAsyncAnalyzer.cs | 15 +++--- .../Style/TaskNameASyncTests.cs | 54 +++++++++++++++++++ 4 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs index b5c5a60b4..a5fecd666 100644 --- a/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/MakeMethodStaticAnalyzer.cs @@ -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) { diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 358b3fc6c..50065c3d7 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -877,5 +877,38 @@ public static string FindAvailableIdentifierName(this SemanticModel semanticMode name = baseName + inscrementer++; return name; } + + public static bool IsImplementingInterface(this MemberDeclarationSyntax member, SemanticModel semanticModel) => + semanticModel.GetDeclaredSymbol(member).IsImplementingInterface(); + + public static bool IsImplementingInterface(this ISymbol memberSymbol) + { + if (memberSymbol == null) return false; + IMethodSymbol methodSymbol; + IEventSymbol eventSymbol; + IPropertySymbol propertySymbol; + if ((methodSymbol = memberSymbol as IMethodSymbol) != null) + { + if (methodSymbol.ExplicitInterfaceImplementations.Any()) return true; + } + else if ((propertySymbol = memberSymbol as IPropertySymbol) != null) + { + if (propertySymbol.ExplicitInterfaceImplementations.Any()) return true; + } + else if ((eventSymbol = memberSymbol as IEventSymbol) != null) + { + if (eventSymbol.ExplicitInterfaceImplementations.Any()) return true; + } + else return false; + var type = memberSymbol.ContainingType; + if (type == null) return false; + var interfaceMembersWithSameName = type.AllInterfaces.SelectMany(i => i.GetMembers(memberSymbol.Name)); + foreach (var interfaceMember in interfaceMembersWithSameName) + { + var implementation = type.FindImplementationForInterfaceMember(interfaceMember); + if (implementation != null && implementation.Equals(memberSymbol)) return true; + } + return false; + } } } \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs index 5fd40d27c..d90d22915 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Immutable; +using System.Linq; namespace CodeCracker.CSharp.Style { @@ -43,15 +44,15 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(diag); return; } - var returnType = context.SemanticModel.GetSymbolInfo(method.ReturnType).Symbol as INamedTypeSymbol; + var semanticModel = context.SemanticModel; + var returnType = semanticModel.GetSymbolInfo(method.ReturnType).Symbol as INamedTypeSymbol; if (returnType == null) return; - if (returnType.ToString() == "System.Threading.Tasks.Task" || - (returnType.IsGenericType && returnType.ConstructedFrom.ToString() == "System.Threading.Tasks.Task")) - { - context.ReportDiagnostic(diag); - } - + if (returnType.ToString() != "System.Threading.Tasks.Task" && + (!returnType.IsGenericType || returnType.ConstructedFrom.ToString() != "System.Threading.Tasks.Task")) + return; + if (method.IsImplementingInterface(semanticModel)) return; + context.ReportDiagnostic(diag); } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs index 919a54fe6..76107647d 100644 --- a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs @@ -178,5 +178,59 @@ public Task TestAsync() }"; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task IgnoreMethodFromImplicitlyImplementedInterface() + { + const string source = @" +using System.Threading.Tasks; +public interface IBar +{ + Task Foo(); +} +public class Bar : IBar +{ + public Task Foo() + { + throw new System.NotImplementedException(); + } +}"; + //we still get the diagnostic for the interface itself + var expected = new DiagnosticResult + { + Id = DiagnosticId.TaskNameAsync.ToDiagnosticId(), + Message = string.Format(TaskNameAsyncAnalyzer.MessageFormat, "FooAsync"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 5, 10) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task IgnoreMethodFromExplicitlyImplementedInterface() + { + const string source = @" +using System.Threading.Tasks; +public interface IBar +{ + Task Foo(); +} +public class Bar : IBar +{ + Task IBar.Foo() + { + throw new System.NotImplementedException(); + } +}"; + //we still get the diagnostic for the interface itself + var expected = new DiagnosticResult + { + Id = DiagnosticId.TaskNameAsync.ToDiagnosticId(), + Message = string.Format(TaskNameAsyncAnalyzer.MessageFormat, "FooAsync"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 5, 10) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } } } \ No newline at end of file From 17b6b0233a9bc48b774579b756159f3676a7061f Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 20 Aug 2016 19:48:28 -0300 Subject: [PATCH 186/358] Update StringBuilderInLoopAnalyzer to ignore some member accesses If the member access is to a variable declared within the loop, we should not be raising a diagnostic. Fix #797 --- .../StringBuilderInLoopAnalyzer.cs | 16 ++++++++++--- .../Performance/StringBuilderInLoopTests.cs | 24 ++++++++++++++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs index 1ef255876..27427a1f3 100644 --- a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs @@ -36,11 +36,11 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; var assignmentExpression = (AssignmentExpressionSyntax)context.Node; - var whileStatement = assignmentExpression.FirstAncestorOfType(typeof(WhileStatementSyntax), + var loopStatement = assignmentExpression.FirstAncestorOfType(typeof(WhileStatementSyntax), typeof(ForStatementSyntax), typeof(ForEachStatementSyntax), typeof(DoStatementSyntax)); - if (whileStatement == null) return; + if (loopStatement == null) return; var semanticModel = context.SemanticModel; var arrayAccess = assignmentExpression.Left as ElementAccessExpressionSyntax; var symbolForAssignment = arrayAccess != null @@ -58,7 +58,17 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) } else if (type.Name != "String") return; // Do not analyze a string declared within the loop. - if (symbolForAssignment is ILocalSymbol && whileStatement.DescendantTokens(((ILocalSymbol)symbolForAssignment).DeclaringSyntaxReferences[0].Span).Any()) return; + if (symbolForAssignment is ILocalSymbol && loopStatement.DescendantTokens(((ILocalSymbol)symbolForAssignment).DeclaringSyntaxReferences[0].Span).Any()) return; + var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; + if (memberAccess != null) + { + var memberAccessExpressionSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol as ILocalSymbol; + if (memberAccessExpressionSymbol != null) + { + if (loopStatement.DescendantTokens(memberAccessExpressionSymbol.DeclaringSyntaxReferences[0].Span).Any()) + return; + } + } if (assignmentExpression.IsKind(SyntaxKind.SimpleAssignmentExpression)) { if (!(assignmentExpression.Right?.IsKind(SyntaxKind.AddExpression) ?? false)) return; diff --git a/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs b/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs index c31e7ebac..9f14bdcb5 100644 --- a/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs @@ -29,7 +29,6 @@ public void Method() { } await VerifyCSharpHasNoDiagnosticsAsync(source); } - [Fact] public async Task WhileWithoutStringConcatDoesNotCreateDiagnostic() { @@ -631,5 +630,28 @@ public void Looper(ref int a) }".WrapInCSharpClass(); await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task IgnoreWhenVariableInTheLoopContextIsChanged() + { + const string source = @" +class MyObject +{ + public string MyObjectString; +} +class MyClass +{ + private readonly System.Collections.Generic.List items = new System.Collections.Generic.List(); + private void M(string suffix) + { + foreach (MyObject o in items) + { + o.MyObjectString += suffix; + } + } +} + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From 27fd04d11cecb86843626b470da26ca3713841dc Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 22 Aug 2016 08:08:03 -0300 Subject: [PATCH 187/358] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f3ae91e29..f928ce0d9 100644 --- a/README.md +++ b/README.md @@ -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 was downloaded at ([Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). + ## Contributing Questions, comments, bug reports, and pull requests are all welcome. From 194ba06aae5859f9aaf8e69fdb81eba6474458d5 Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 22 Aug 2016 08:08:39 -0300 Subject: [PATCH 188/358] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f928ce0d9..1036a22c1 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Then add a reference to CodeCracker.dll from within the Analyzers node inside Re ## SonarQube Plugin -CodeCracker has a SonarQube Plugin that was downloaded at ([Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). +CodeCracker has a SonarQube Plugin that can downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). ## Contributing From 442eb755a150d4d1fbd1006d47ae2b5bdef62990 Mon Sep 17 00:00:00 2001 From: Lazaro Fernandes Lima Suleiman Date: Sun, 28 Aug 2016 16:51:48 -0300 Subject: [PATCH 189/358] Add support to remove unnecessary '.ToString()' in a string concatenation --- src/CSharp/CodeCracker/CodeCracker.csproj | 2 + ...ryToStringInStringConcatenationAnalyzer.cs | 74 +++++++ ...ingInStringConcatenationCodeFixProvider.cs | 54 +++++ src/Common/CodeCracker.Common/DiagnosticId.cs | 1 + .../CodeCracker.Test/CodeCracker.Test.csproj | 1 + ...ssaryToStringInStringConcatenationTests.cs | 208 ++++++++++++++++++ 6 files changed, 340 insertions(+) create mode 100644 src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs create mode 100644 src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationCodeFixProvider.cs create mode 100644 test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index e1a60a05e..965fba6b7 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -83,6 +83,8 @@ + + diff --git a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs new file mode 100644 index 000000000..fb9a0974a --- /dev/null +++ b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs @@ -0,0 +1,74 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; +using System.Collections.Immutable; +using System.Linq; + +namespace CodeCracker.CSharp.Style +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class UnnecessaryToStringInStringConcatenationAnalyzer : DiagnosticAnalyzer + { + internal const string Title = "Unnecessary '.ToString()' call in string concatenation."; + internal const string MessageFormat = Title; + internal const string Category = SupportedCategories.Style; + const string Description = "The runtime automatically calls '.ToString()' method for" + + " string concatenation operations when there is no parameters. Remove them."; + + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + DiagnosticId.UnnecessaryToStringInStringConcatenation.ToDiagnosticId(), + Title, + MessageFormat, + Category, + DiagnosticSeverity.Info, + customTags: WellKnownDiagnosticTags.Unnecessary, + isEnabledByDefault: true, + description: Description, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.UnnecessaryToStringInStringConcatenation)); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) => + context.RegisterSyntaxNodeAction(Analyzer, SyntaxKind.AddExpression); + + private static void Analyzer(SyntaxNodeAnalysisContext context) + { + if (context.IsGenerated()) return; + var addExpression = context.Node as BinaryExpressionSyntax; + + if (!addExpression.IsKind(SyntaxKind.AddExpression)) return; + + var hasPlusToken = addExpression.ChildNodesAndTokens().Any(x => x.IsKind(SyntaxKind.PlusToken)); + var hasInvocationExpression = addExpression.ChildNodesAndTokens().Any(x => x.IsKind(SyntaxKind.InvocationExpression)); + + //string concatenation must have PlusToken and an InvocationExpression + if (!hasPlusToken || !hasInvocationExpression) return; + var invocationExpressionsThatHaveToStringCall = GetInvocationExpressionsThatHaveToStringCall(addExpression); + + foreach (var expression in invocationExpressionsThatHaveToStringCall) + { + var lastDot = expression.Expression.ChildNodesAndTokens().Last(x => x.IsKind(SyntaxKind.DotToken)); + var argumentList = expression.ChildNodes().Last(x => x.IsKind(SyntaxKind.ArgumentList)); + + //Only default call to ToString method must be accepted + if (expression.ArgumentList.Arguments.Count > 0) + break; + + var tree = expression.SyntaxTree; + var textspan = new TextSpan(lastDot.Span.Start, argumentList.Span.End - lastDot.Span.Start); + + var diagnostic = Diagnostic.Create(Rule, Location.Create(context.Node.SyntaxTree, textspan)); + context.ReportDiagnostic(diagnostic); + } + } + + private static System.Collections.Generic.List GetInvocationExpressionsThatHaveToStringCall(BinaryExpressionSyntax addExpression) + { + return addExpression.ChildNodes().OfType() + .Where(x => x.Expression.ToString().EndsWith(@".ToString")) + .ToList(); + } + } +} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationCodeFixProvider.cs new file mode 100644 index 000000000..4d895d8f5 --- /dev/null +++ b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationCodeFixProvider.cs @@ -0,0 +1,54 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeCracker.CSharp.Style +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UnnecessaryParenthesisCodeFixProvider)), Shared] + public class UnnecessaryToStringInStringConcatenationCodeFixProvider : CodeFixProvider + { + public sealed override ImmutableArray FixableDiagnosticIds => + ImmutableArray.Create(DiagnosticId.UnnecessaryToStringInStringConcatenation.ToDiagnosticId()); + + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = context.Diagnostics.First(); + context.RegisterCodeFix(CodeAction.Create("Remove unnecessary ToString", ct => RemoveUnnecessaryToStringAsync(context.Document, diagnostic, ct), nameof(UnnecessaryToStringInStringConcatenationCodeFixProvider)), diagnostic); + return Task.FromResult(0); + } + private static async Task RemoveUnnecessaryToStringAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var invocationExpression = + root + .FindToken(diagnostic.Location.SourceSpan.Start) + .Parent + .AncestorsAndSelf() + .OfType() + .First(); + + var onlyMemberAccessNode = + invocationExpression + .ChildNodes() + .First() + .ChildNodes() + .First(); + + var newRoot = root.ReplaceNode(invocationExpression, onlyMemberAccessNode); + + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument; + } + + } + +} \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index 156dc6285..7d48257fd 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -80,5 +80,6 @@ public enum DiagnosticId NameOf_External = 108, StringFormatArgs_ExtraArgs = 111, AlwaysUseVarOnPrimitives = 105, + UnnecessaryToStringInStringConcatenation = 118, } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index b17ba4a79..7168f11df 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -146,6 +146,7 @@ + diff --git a/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs b/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs new file mode 100644 index 000000000..077f095e7 --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs @@ -0,0 +1,208 @@ +using CodeCracker.CSharp.Style; +using Microsoft.CodeAnalysis; +using System.Threading.Tasks; +using Xunit; + +namespace CodeCracker.Test.CSharp.Style +{ + public class UnnecessaryToStringInStringConcatenationTests : CodeFixVerifier + { + [Fact] + public async Task InstantiatingAnObjectAndCallToStringInsideAStringConcatenationShouldGenerateDiagnosticResult() + { + const string source = @"var foo = ""a"" + new object().ToString();"; + + var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(1, 29); + + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task InstantiatingAnStringBuilderAndCallToStringInsideAStringConcatenationShouldGenerateDiagnosticResult() + { + const string source = @"var foo = ""a"" + new System.Text.StringBuilder().ToString();"; + + var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(1, 48); + + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task CallToStringForAnInstantiatedObjectInsideAStringConcatenationShouldGenerateDiagnosticResult() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + class AuxClass + { + public override void ToString() + { + return ""Test""; + } + } + + class TypeName + { + public void Foo() + { + var auxClass = new AuxClass(); + + var bar = ""a"" + new AuxClass().ToString(); + var foo = ""a"" + auxClass.ToString(); + var far = ""a"" + new AuxClass().ToString() + auxClass.ToString() + new object().ToString(""C""); + } + } + }"; + + var expected1 = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(20, 47); + var expected2 = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(21, 41); + var expected3 = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(22, 47); + var expected4 = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(22, 69); + + var expected = new DiagnosticResult[] { expected1, expected2, expected3, expected4 }; + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async Task CallToStringInsideAStringConcatenationWithAFormatParameterShouldNotGenerateDiagnosticResult() + { + const string source = @"var salary = ""salary: "" + 1000.ToString(""C"");"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + + [Fact] + public async Task CallToStringOutsideAStringConcatenationWithoutParameterShouldNotGenerateDiagnosticResult() + { + const string source = @"var value = 1000.ToString();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + + private static DiagnosticResult CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(int expectedRow, int expectedColumn) + { + var expected = new DiagnosticResult + { + Id = DiagnosticId.UnnecessaryToStringInStringConcatenation.ToDiagnosticId(), + Message = "Unnecessary '.ToString()' call in string concatenation.", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", expectedRow, expectedColumn) } + }; + + return expected; + } + + [Fact] + public async Task FixReplacesToStringCallInAStringConcatenationWithAVariable() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var text = ""def""; + var a = ""abc"" + text.ToString(); + Console.Log(a); + } + } + }"; + + const string expected = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var text = ""def""; + var a = ""abc"" + text; + Console.Log(a); + } + } + }"; + await VerifyCSharpFixAsync(test, expected); + } + + + [Fact] + public async Task FixReplacesToStringCallInAStringConcatenation() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var a = ""abc"" + ""def"".ToString(); + Console.Log(a); + } + } + }"; + + const string expected = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var a = ""abc"" + ""def""; + Console.Log(a); + } + } + }"; + await VerifyCSharpFixAsync(test, expected); + } + + [Fact] + public async Task FixReplacesToStringCallInAStringConcatenationWithAnObject() + { + const string test = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var foo = ""a"" + new object().ToString(); + Console.Log(foo); + } + } + }"; + + const string expected = @" + using System; + + namespace ConsoleApplication1 + { + class TypeName + { + public async Task Foo() + { + var foo = ""a"" + new object(); + Console.Log(foo); + } + } + }"; + await VerifyCSharpFixAsync(test, expected); + } + } +} \ No newline at end of file From 21dc1da2bce6a7b1690033fd41c36381266fbad4 Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Thu, 25 Aug 2016 17:21:32 -0300 Subject: [PATCH 190/358] Fix #829 --- src/CSharp/CodeCracker/CodeCracker.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index f659d5f96..e08549efe 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -19,6 +19,7 @@ This is a community project, free and open source. Everyone is invited to contri + true From 74853e60ea10e8ee29ac69cc988c0dd1a5016f27 Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Fri, 26 Aug 2016 20:38:49 -0300 Subject: [PATCH 191/358] Fix UseStaticRegexIsMatchAnalyzer when facing a member access expr Fixes #822 --- .../UseStaticRegexIsMatchAnalyzer.cs | 2 +- .../Performance/UseStaticRegexIsMatchTests.cs | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs b/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs index 2ecfa57dc..19c4e2374 100644 --- a/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/UseStaticRegexIsMatchAnalyzer.cs @@ -40,7 +40,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var methodSymbol = context.SemanticModel.GetSymbolInfo(memberExpression).Symbol; if (methodSymbol?.ContainingType.ToString() != "System.Text.RegularExpressions.Regex" || methodSymbol.IsStatic) return; - + if (!(memberExpression.Expression is IdentifierNameSyntax)) return; var variableSymbol = context.SemanticModel.GetSymbolInfo(((IdentifierNameSyntax)memberExpression.Expression).Identifier.Parent).Symbol; if (variableSymbol?.Kind != SymbolKind.Local) return; diff --git a/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs b/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs index 969563a93..c16424c06 100644 --- a/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs @@ -119,5 +119,56 @@ public async Task Foo() }"; await VerifyCSharpFixAsync(test, fixtest, 1, allowNewCompilerDiagnostics: true); //todo: should not need to allow new compiler diagnostic, fix test infrastructure to understand the Regex type } + + [Fact] + public async Task IgnoresIsMatchCallClassMember() + { + const string testStatic = @" + public class RegexTestClass + { + private TestModel testModel; + + private void Test(string text) + { + if (testModel.Regex.IsMatch(text)) + { + return; + } + } + } + + public class TestModel + { + public Regex Regex { get; set; } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(testStatic); + } + + [Fact] + public async Task IgnoresIsMatchCallClassMemberInsideClass() + { + const string testStatic = @" + public class RegexTestClass + { + private C c; + + private void Test(string text) + { + if (c.TestModel.Regex.IsMatch(text)) + { + return; + } + } + } + public class C + { + public TestModel TestModel { get; set; } + } + public class TestModel + { + public System.Text.RegularExpressions.Regex Regex { get; set; } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(testStatic); + } } } \ No newline at end of file From 160d12b834d7522a24807a727b402ba79031f475 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Fri, 26 Aug 2016 01:31:50 -0300 Subject: [PATCH 192/358] Ignore when iteration variable altered in ForInArrayAnalyzer Issued touched assignment, but also checked for pre and post fix unary, ref and out. Closes #814 --- .../CodeCracker/Style/ForInArrayAnalyzer.cs | 58 +++++++++++++---- .../CodeCracker.Test/Style/ForInArrayTests.cs | 65 +++++++++++++++++++ 2 files changed, 109 insertions(+), 14 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs index 1a95477bf..d76eee1d0 100644 --- a/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ForInArrayAnalyzer.cs @@ -4,6 +4,8 @@ using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Immutable; using System.Linq; +using System; +using System.Collections.Generic; namespace CodeCracker.CSharp.Style { @@ -65,24 +67,52 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) return !identifierSymbol.Equals(arrayId); }); if (otherUsesOfIndexToken != 0) return; - var arrayAccessorSymbols = (from s in forBlock.Statements.OfType() - where s.Declaration.Variables.Count == 1 - let declaration = s.Declaration.Variables.First() - where declaration?.Initializer?.Value is ElementAccessExpressionSyntax - let iterableSymbol = semanticModel.GetDeclaredSymbol(declaration) - let iterableType = ((ILocalSymbol)iterableSymbol).Type - where !(iterableType.IsPrimitive() ^ iterableType.IsValueType) - let init = (ElementAccessExpressionSyntax)declaration.Initializer.Value - let initSymbol = semanticModel.GetSymbolInfo(init.ArgumentList.Arguments.First().Expression).Symbol - where controlVarId.Equals(initSymbol) - let someArrayInit = semanticModel.GetSymbolInfo(init.Expression).Symbol - where arrayId.Equals(someArrayInit) - select arrayId).ToList(); - if (!arrayAccessorSymbols.Any()) return; + var iterableSymbols = (from s in forBlock.Statements.OfType() + where s.Declaration.Variables.Count == 1 + let declaration = s.Declaration.Variables.First() + where declaration?.Initializer?.Value is ElementAccessExpressionSyntax + let iterableSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declaration) + let iterableType = iterableSymbol.Type + where !(iterableType.IsPrimitive() ^ iterableType.IsValueType) + let init = (ElementAccessExpressionSyntax)declaration.Initializer.Value + let initSymbol = semanticModel.GetSymbolInfo(init.ArgumentList.Arguments.First().Expression).Symbol + where controlVarId.Equals(initSymbol) + let someArrayInit = semanticModel.GetSymbolInfo(init.Expression).Symbol + where arrayId.Equals(someArrayInit) + select iterableSymbol).ToList(); + if (!iterableSymbols.Any()) return; + if (IsIterationVariableWritten(semanticModel, forBlock, iterableSymbols)) return; var diagnostic = Diagnostic.Create(Rule, forStatement.ForKeyword.GetLocation()); context.ReportDiagnostic(diagnostic); } + private static bool IsIterationVariableWritten(SemanticModel semanticModel, BlockSyntax forBlock, List iterableSymbols) + { + var forDescendants = forBlock.DescendantNodes(); + var assignments = (from assignmentExpression in forDescendants.OfType() + let assignmentLeftSymbol = semanticModel.GetSymbolInfo(assignmentExpression.Left).Symbol + where iterableSymbols.Any(i => i.Equals(assignmentLeftSymbol)) + select assignmentExpression).ToList(); + if (assignments.Any()) return true; + var refs = (from argument in forDescendants.OfType() + where argument.RefOrOutKeyword != null + let argumentExpressionSymbol = semanticModel.GetSymbolInfo(argument.Expression).Symbol + where iterableSymbols.Any(i => i.Equals(argumentExpressionSymbol)) + select argument).ToList(); + if (refs.Any()) return true; + var postfixUnaries = (from postfixUnaryExpression in forDescendants.OfType() + let operandSymbol = semanticModel.GetSymbolInfo(postfixUnaryExpression.Operand).Symbol + where iterableSymbols.Any(i => i.Equals(operandSymbol)) + select postfixUnaryExpression).ToList(); + if (postfixUnaries.Any()) return true; + var prefixUnaries = (from postfixUnaryExpression in forDescendants.OfType() + let operandSymbol = semanticModel.GetSymbolInfo(postfixUnaryExpression.Operand).Symbol + where iterableSymbols.Any(i => i.Equals(operandSymbol)) + select postfixUnaryExpression).ToList(); + if (prefixUnaries.Any()) return true; + return false; + } + private static bool IsEnumerable(ISymbol arrayId) { var type = (arrayId as ILocalSymbol)?.Type diff --git a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs index 780687f64..65b0345b9 100644 --- a/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ForInArrayTests.cs @@ -849,5 +849,70 @@ static void Goo() }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task IgnoreWhenWouldChangeTheIterationVariableWithAssignment() + { + var source = @" +var a = new[] { 1 }; +for (var i = 0; i < a.Length; i++) +{ + var item = a[i]; + item = 0; +}".WrapInCSharpMethod(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoreWhenWouldChangeTheIterationVariableWithRef() + { + var source = @" +void Foo() +{ + var a = new[] { 1 }; + for (var i = 0; i < a.Length; i++) + { + var item = a[i]; + Bar(ref item); + } +} +void Bar(ref int i) +{ + i = 1; +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoreWhenWouldChangeTheIterationVariableWithPostfixUnary() + { + var source = @" +void Foo() +{ + var a = new[] { 1 }; + for (var i = 0; i < a.Length; i++) + { + var item = a[i]; + item++; + } +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IgnoreWhenWouldChangeTheIterationVariableWithPrefixUnary() + { + var source = @" +void Foo() +{ + var a = new[] { 1 }; + for (var i = 0; i < a.Length; i++) + { + var item = a[i]; + ++item; + } +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From 4dc4707dc1d7556dbeb8684b44f7e656223cff5a Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 5 Sep 2016 13:56:11 -0300 Subject: [PATCH 193/358] Fix #774 - ignore pointer declaration --- .../MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs | 3 +++ .../MakeLocalVariablesConstWhenItIsPossibleTests.cs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs index f5c8e2b29..869a15ed4 100644 --- a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs @@ -36,6 +36,8 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; var semanticModel = context.SemanticModel; + if (localDeclaration.GetType().IsPointer) return; + if (!localDeclaration.IsConst && IsDeclarationConstFriendly(localDeclaration, semanticModel) && AreVariablesOnlyWrittenInsideDeclaration(localDeclaration, semanticModel) ) @@ -61,6 +63,7 @@ static bool IsDeclarationConstFriendly(LocalDeclarationStatementSyntax declarati // if reference type, value is null? var variableTypeName = declaration.Declaration.Type; var variableType = semanticModel.GetTypeInfo(variableTypeName).ConvertedType; + if (variableType.TypeKind == TypeKind.Pointer) return false; if (variableType.IsReferenceType && variableType.SpecialType != SpecialType.System_String && constantValue.Value != null) return false; // nullable? diff --git a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs index 1fc75b5c0..8cfa21591 100644 --- a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs @@ -52,6 +52,13 @@ public async Task IgnoresVariablesThatChangesValueOutsideDeclaration() await VerifyCSharpHasNoDiagnosticsAsync(test); } + public async Task IgnoresPointerDeclarations() + { + var test = @"void* value = null;".WrapInCSharpMethod(); + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + [Fact] public async Task CreateDiagnosticsWhenAssigningAPotentialConstant() { From 352b6b33a365466573d43d3247fda1aa360fa0ef Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 6 Sep 2016 11:41:45 -0300 Subject: [PATCH 194/358] Remove unnecessary check on MakeLocalVariableConstWhenItIsPossibleAnalyzer Also add `Fact` to missing test Related to #774 --- .../MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs | 2 -- .../Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs index 869a15ed4..60dc5f397 100644 --- a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs @@ -36,8 +36,6 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; var semanticModel = context.SemanticModel; - if (localDeclaration.GetType().IsPointer) return; - if (!localDeclaration.IsConst && IsDeclarationConstFriendly(localDeclaration, semanticModel) && AreVariablesOnlyWrittenInsideDeclaration(localDeclaration, semanticModel) ) diff --git a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs index 8cfa21591..3bbd8e378 100644 --- a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs @@ -52,6 +52,7 @@ public async Task IgnoresVariablesThatChangesValueOutsideDeclaration() await VerifyCSharpHasNoDiagnosticsAsync(test); } + [Fact] public async Task IgnoresPointerDeclarations() { var test = @"void* value = null;".WrapInCSharpMethod(); From 6f3d5aabb4ba37314732e290d88fb8a4baefe275 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 6 Sep 2016 12:40:43 -0300 Subject: [PATCH 195/358] Add v1.0.1 changelog --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7753429db..31c87d874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) From 2eadc09a850ddf93b9cebcb6cbf6c4e5fec53780 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 6 Sep 2016 13:04:45 -0300 Subject: [PATCH 196/358] Bump version to 1.0.2 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 19b4ff34c..96ab65b93 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index e08549efe..cf2da4160 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.1 + 1.0.2 CodeCracker for C# giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index e73618076..a2cbcaa12 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.0.2.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index c910e7aba..6ceea0773 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.1 + 1.0.2 CodeCracker for C# and VB giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014-2016 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index 8fd31cfbe..9bee0ce03 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.0.2.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] [assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 2292f0dec..ddd2f9d9d 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 70abb04ba..ecb28d922 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.1 + 1.0.2 CodeCracker for Visual Basic giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 9f6f2650c..1425d7339 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index 9da58a97d..8809cfb5b 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.2.0")] \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index 8c492b358..2a6956dbe 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.1.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.2.0")] \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index 2599bd9f5..f7d706ba8 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - \ No newline at end of file + \ No newline at end of file From e718be3e5dd13f5fdb7b61630ae076e6355183b6 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Tue, 6 Sep 2016 16:19:36 -0300 Subject: [PATCH 197/358] Refactor UnnecessaryToStringInStringConcatenationAnalyzer --- ...ryToStringInStringConcatenationAnalyzer.cs | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs index fb9a0974a..d2c56f355 100644 --- a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -36,39 +37,28 @@ public override void Initialize(AnalysisContext context) => private static void Analyzer(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; - var addExpression = context.Node as BinaryExpressionSyntax; + var addExpression = (BinaryExpressionSyntax)context.Node; - if (!addExpression.IsKind(SyntaxKind.AddExpression)) return; - - var hasPlusToken = addExpression.ChildNodesAndTokens().Any(x => x.IsKind(SyntaxKind.PlusToken)); var hasInvocationExpression = addExpression.ChildNodesAndTokens().Any(x => x.IsKind(SyntaxKind.InvocationExpression)); - //string concatenation must have PlusToken and an InvocationExpression - if (!hasPlusToken || !hasInvocationExpression) return; + //string concatenation must have an InvocationExpression + if (!hasInvocationExpression) return; var invocationExpressionsThatHaveToStringCall = GetInvocationExpressionsThatHaveToStringCall(addExpression); foreach (var expression in invocationExpressionsThatHaveToStringCall) - { + { var lastDot = expression.Expression.ChildNodesAndTokens().Last(x => x.IsKind(SyntaxKind.DotToken)); - var argumentList = expression.ChildNodes().Last(x => x.IsKind(SyntaxKind.ArgumentList)); - - //Only default call to ToString method must be accepted - if (expression.ArgumentList.Arguments.Count > 0) - break; - - var tree = expression.SyntaxTree; - var textspan = new TextSpan(lastDot.Span.Start, argumentList.Span.End - lastDot.Span.Start); - - var diagnostic = Diagnostic.Create(Rule, Location.Create(context.Node.SyntaxTree, textspan)); + var toStringTextSpan = new TextSpan(lastDot.Span.Start, expression.ArgumentList.Span.End - lastDot.Span.Start); + var diagnostic = Diagnostic.Create(Rule, Location.Create(context.Node.SyntaxTree, toStringTextSpan)); context.ReportDiagnostic(diagnostic); } } - private static System.Collections.Generic.List GetInvocationExpressionsThatHaveToStringCall(BinaryExpressionSyntax addExpression) + private static IEnumerable GetInvocationExpressionsThatHaveToStringCall(BinaryExpressionSyntax addExpression) { return addExpression.ChildNodes().OfType() - .Where(x => x.Expression.ToString().EndsWith(@".ToString")) - .ToList(); + //Only default call to ToString method must be accepted + .Where(x => x.Expression.ToString().EndsWith(@".ToString") && !x.ArgumentList.Arguments.Any()); } } } \ No newline at end of file From e981d303edd938f2e3da422c21035d9002688119 Mon Sep 17 00:00:00 2001 From: Nozziel Date: Wed, 19 Oct 2016 21:15:26 +0200 Subject: [PATCH 198/358] #848 - "Disposable Field Not Disposed" rule does not recognize null propagation - Fix + Unit test --- .../DisposableFieldNotDisposedAnalyzer.cs | 38 ++++++++++++++++--- .../Usage/DisposableFieldNotDisposedTests.cs | 23 +++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs index 2e625e04d..b90b12001 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs @@ -92,13 +92,41 @@ private static bool CallsDisposeOnField(IFieldSymbol fieldSymbol, MethodDeclarat var hasDisposeCall = body.DescendantNodes().OfKind(SyntaxKind.InvocationExpression) .Any(invocation => { - if (!invocation?.Expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) ?? true) return false; - var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; - if (memberAccess?.Name == null) return false; - if (memberAccess.Name.Identifier.ToString() != "Dispose" || memberAccess.Name.Arity != 0) return false; - return fieldSymbol.Equals(semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol); + if (invocation?.Expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) ?? false) + { + return IsDisposeCallOnField(invocation, fieldSymbol, semanticModel); + + } + + if (invocation?.Expression?.IsKind(SyntaxKind.MemberBindingExpression) ?? false) + { + return IsDisposeWithNullPropagationCallOnField(invocation, fieldSymbol, semanticModel); + } + + return false; }); return hasDisposeCall; } + + private static bool IsDisposeCallOnField(InvocationExpressionSyntax expression, IFieldSymbol fieldSymbol, SemanticModel semanticModel) + { + var memberAccess = (MemberAccessExpressionSyntax)expression.Expression; + if (memberAccess?.Name == null) return false; + if (memberAccess.Name.Identifier.ToString() != "Dispose" || memberAccess.Name.Arity != 0) return false; + var result = fieldSymbol.Equals(semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol); + return result; + } + + private static bool IsDisposeWithNullPropagationCallOnField(InvocationExpressionSyntax expression, IFieldSymbol fieldSymbol, SemanticModel semanticModel) + { + var memberBinding = (MemberBindingExpressionSyntax)expression.Expression; + if (memberBinding?.Name == null) return false; + if (memberBinding.Name.Identifier.ToString() != "Dispose" || memberBinding.Name.Arity != 0) return false; + + var conditionalAccessExpression = memberBinding.Parent.Parent as ConditionalAccessExpressionSyntax; + if (conditionalAccessExpression == null) return false; + var result = fieldSymbol.Equals(semanticModel.GetSymbolInfo(conditionalAccessExpression.Expression).Symbol); + return result; + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs index ba84e4bc6..1c46e93f2 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs @@ -45,6 +45,29 @@ private void Dispose(bool disposing) await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task WhenUsingTheDisposablePatternWithNullPropagationItDoesNotCreateDiagnostic() + { + const string source = @" +using System; +using System.IO; +public class A : IDisposable +{ + private MemoryStream disposableField = new MemoryStream(); + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + private void Dispose(bool disposing) + { + if (disposing) + disposableField?.Dispose(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WhenAFieldThatImplementsIDisposableIsAssignedThroughAMethodCallCreatesDiagnostic() { From dce78e2a591fcd6f58320d5a53912942d8accf96 Mon Sep 17 00:00:00 2001 From: cezar teste Date: Thu, 27 Oct 2016 11:22:35 -0200 Subject: [PATCH 199/358] - Adding test for: bool method param, int var situations,CS0151Exception and common situations with boolean variables. --- src/CSharp/CodeCracker/CodeCracker.csproj | 2 + .../Design/SwitchWithoutDefaultAnalyzer.cs | 66 ++++ .../SwitchWithoutDefaultCodeFixProvider.cs | 121 ++++++ src/Common/CodeCracker.Common/DiagnosticId.cs | 1 + .../CodeCracker.Test/CodeCracker.Test.csproj | 1 + .../Design/SwicthWithoutDefaultTests.cs | 353 ++++++++++++++++++ 6 files changed, 544 insertions(+) create mode 100644 src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs create mode 100644 src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs create mode 100644 test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 965fba6b7..8b9e64a32 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -46,6 +46,8 @@ + + diff --git a/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs new file mode 100644 index 000000000..b4531315f --- /dev/null +++ b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs @@ -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 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); + } + } + } + } +} diff --git a/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs new file mode 100644 index 000000000..192d1ac5e --- /dev/null +++ b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs @@ -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 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 SwitchWithoutDefaultAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var switchCaseLabel = new SyntaxList(); + var kindOfVariable = string.Empty; + var idForVariable = string.Empty; + var breakStatement = new SyntaxList(); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var newSections = new List(); + var switchCaseStatement = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().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().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(); + labels = labels.Add(label); + return SyntaxFactory.SwitchSection(labels, CreateSectionStatements(statement)); + } + + static SyntaxList CreateSectionStatements(StatementSyntax source) + { + var result = new SyntaxList(); + if (source is BlockSyntax) + { + var block = source as BlockSyntax; + result = result.AddRange(block.Statements); + } + else + { + result = result.Add(source); + } + return result; + } + } +} diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index 7d48257fd..1ac3b7f5e 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -81,5 +81,6 @@ public enum DiagnosticId StringFormatArgs_ExtraArgs = 111, AlwaysUseVarOnPrimitives = 105, UnnecessaryToStringInStringConcatenation = 118, + SwitchCaseWithoutDefault = 120, } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 7168f11df..915d2199d 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -129,6 +129,7 @@ + diff --git a/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs b/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs new file mode 100644 index 000000000..c9fa24b44 --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs @@ -0,0 +1,353 @@ +using CodeCracker.CSharp.Design; +using System.Threading.Tasks; +using Xunit; + +namespace CodeCracker.Test.CSharp.Design +{ + public class SwicthWithoutDefaultTests : CodeFixVerifier + { + [Fact] + public async Task SwithWithoutDefaultAnalyserString() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { +var a = """"; + switch (a) + { + case """": + break; + } + } + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { +var a = """"; + switch (a) + { + case """": + break; + default: + throw new Exception(""Unexpected Case""); + } + } + } + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + } + + [Fact] + public async Task SwithWithoutDefaultAnalyserBool() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { + var s = true; + switch (s) + { + case false: + break; + } + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { + var s = true; + switch (s) + { + case false: + break; + case true: + break; + } + } + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + } + + [Fact] + public async Task SwithWithoutDefaultAnalyserInt() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { +var s = 10; + switch (s) + { + case 10: + break; + } + +} + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { +var s = 10; + switch (s) + { + case 10: + break; + default: + throw new Exception(""Unexpected Case""); + } + } +} + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + + } + + public async Task SwithWithoutDefaultAnalyserBoolMethod() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + void Bar(bool myBool) + { + switch (myBool) + { + case false: + break; + } + } + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + void Bar(bool myBool) + { + switch (myBool) + { + case false: + break; + case true: + break; + } + } + + } + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + } + + public async Task SwithWithoutDefaultAnalyserIntMethod() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + void Bar3(int a) + { + switch (a) + { + case 10: + break; + } + } + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + void Bar3(int a) + { + switch (a) + { + case 10: + break; + default: + throw new Exception(""Unexpected Case""); + } + } +} + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + } + + public async Task SwithWithoutDefaultAnalyserIntMethodTwoParams() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { +void Bar4(int a, int b) + { + switch (a) + { + case 10: + break; + } + } + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { +void Bar4(int a, int b) + { + switch (a) + { + case 10: + break; + default: + throw new Exception(""Unexpected Case""); + } + } +} + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + } + + [Fact] + public async Task SwithWithoutDefaultAnalyserIntMethodStatic() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { +static void Bar5(int a) + { + switch (a) + { + case 10: + break; + } + } + + } + }"; + + const string fixtest = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { +static void Bar5(int a) + { + switch (a) + { + case 10: + break; + default: + throw new Exception(""Unexpected Case""); + } + } + +} + }"; + await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + } + + [Fact] + public async Task SwithWithoutDefaultAnalyseCS0151Exception() + { + const string source = @"static void M() { } + static void Main() + { + + switch (M()) // CS0151 + { + default: + break; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + + [Fact] + public async Task SwithWithoutDefaultAnalyserNoDiagnostic() + { + const string source = @"using System;namespace + ConsoleApplication1 + { + class TypeName + { + static void Main() + { + var s = ""; + switch (s) + { + case "":{break;} + default:{break;} + } + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task SwitchWithoutDefaultAnalyzerNoDiagnosticWithCompileError() + { + const string source = @"using System; + namespace ConsoleApplication1 + { + ConsoleApplication1 + { + class Teste { } + class Program + { + static void Main(string[] args) + { + Teste vo_teste = new Teste(); + switch (vo_teste) + { + case "":break; + default:break; + } + } + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + } +} From 5729fe362e47fab5492bdb6fb0ec2e7449c7d7a8 Mon Sep 17 00:00:00 2001 From: cezar teste Date: Tue, 22 Nov 2016 10:08:18 -0200 Subject: [PATCH 200/358] Fix #808 Added the suggested changes in Title and Description on ReadOnlyComplexTypesAnalyzer --- src/CSharp/CodeCracker/CodeCracker.csproj | 1 + .../Usage/ReadOnlyComplexTypesAnalyzer.cs | 69 +++ .../Usage/ReadonlyFieldCodeFixProvider.cs | 3 +- src/Common/CodeCracker.Common/DiagnosticId.cs | 1 + .../CodeCracker.Test/CodeCracker.Test.csproj | 1 + .../Usage/ReadOnlyComplexTypesTests.cs | 441 ++++++++++++++++++ 6 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 src/CSharp/CodeCracker/Usage/ReadOnlyComplexTypesAnalyzer.cs create mode 100644 test/CSharp/CodeCracker.Test/Usage/ReadOnlyComplexTypesTests.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 8b9e64a32..da195cbf0 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -139,6 +139,7 @@ + diff --git a/src/CSharp/CodeCracker/Usage/ReadOnlyComplexTypesAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadOnlyComplexTypesAnalyzer.cs new file mode 100644 index 000000000..089013936 --- /dev/null +++ b/src/CSharp/CodeCracker/Usage/ReadOnlyComplexTypesAnalyzer.cs @@ -0,0 +1,69 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; +using System.Collections.Generic; +using System; + +namespace CodeCracker.CSharp.Usage +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ReadOnlyComplexTypesAnalyzer : DiagnosticAnalyzer + { + internal const string Title = "Complex fields must be readonly"; + internal const string Message = "Make '{0}' readonly"; + internal const string Category = SupportedCategories.Usage; + const string Description = "Complex fields must be readonly"; + + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + DiagnosticId.ReadOnlyComplexTypes.ToDiagnosticId(), + Title, + Message, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: false, + description: Description, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.ReadOnlyComplexTypes)); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, + new[] { SyntaxKind.FieldDeclaration }); + + private static void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + if (context.IsGenerated()) return; + var fieldDeclaration = context.Node as FieldDeclarationSyntax; + var variable = fieldDeclaration?.Declaration.Variables.LastOrDefault(); + if (variable?.Initializer == null) return; + var semanticModel = context.SemanticModel; + var fieldSymbol = semanticModel.GetDeclaredSymbol(variable) as IFieldSymbol; + if (!IsComplexValueType(semanticModel, fieldDeclaration)) return; + if (!CanBeMadeReadonly(fieldSymbol)) return; + ReportDiagnostic(context, variable, variable.Initializer.Value); + } + private static bool IsComplexValueType(SemanticModel semanticModel, FieldDeclarationSyntax fieldDeclaration) + { + var fieldTypeName = fieldDeclaration.Declaration.Type; + var fieldType = semanticModel.GetTypeInfo(fieldTypeName).ConvertedType; + return fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + } + + private static bool CanBeMadeReadonly(IFieldSymbol fieldSymbol) + { + return (fieldSymbol.DeclaredAccessibility == Accessibility.NotApplicable + || fieldSymbol.DeclaredAccessibility == Accessibility.Private) + && !fieldSymbol.IsReadOnly + && !fieldSymbol.IsConst; + } + + private static void ReportDiagnostic(SyntaxNodeAnalysisContext context, VariableDeclaratorSyntax variable, ExpressionSyntax initializerValue) + { + var props = new Dictionary { { "identifier", variable.Identifier.Text } }.ToImmutableDictionary(); + var diag = Diagnostic.Create(Rule, variable.GetLocation(), props, initializerValue.ToString()); + context.ReportDiagnostic(diag); + } + } +} diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldCodeFixProvider.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldCodeFixProvider.cs index 9b0d0be1a..1b9e85a58 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldCodeFixProvider.cs @@ -16,7 +16,8 @@ namespace CodeCracker.CSharp.Usage public class ReadonlyFieldCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticId.ReadonlyField.ToDiagnosticId()); + ImmutableArray.Create(DiagnosticId.ReadonlyField.ToDiagnosticId(), + DiagnosticId.ReadOnlyComplexTypes.ToDiagnosticId()); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index 1ac3b7f5e..e60eb36f8 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -82,5 +82,6 @@ public enum DiagnosticId AlwaysUseVarOnPrimitives = 105, UnnecessaryToStringInStringConcatenation = 118, SwitchCaseWithoutDefault = 120, + ReadOnlyComplexTypes = 121, } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 915d2199d..aa793b0cd 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -172,6 +172,7 @@ + diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadOnlyComplexTypesTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadOnlyComplexTypesTests.cs new file mode 100644 index 000000000..d6fe05fb9 --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Usage/ReadOnlyComplexTypesTests.cs @@ -0,0 +1,441 @@ +using CodeCracker.CSharp.Usage; +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace CodeCracker.Test.CSharp.Usage +{ + public class ReadOnlyComplexTypesTests : CodeFixVerifier + { + [Fact] + public async Task FieldWithAssignmentOnDeclarationAlreadyReadonlyDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + private readonly int i = 1; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task ConstantFieldDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + private const int i = 1; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task dateTimeDoesNotCreateDiagnostics() + { + const string source1 = @" +namespace codeCrackerConsole +{ + public class MyClass + { + private readonly DateTime dt = new DateTime(1, 1, 2015); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source1); + } + [Fact] + public async Task protectedFieldDoesNotCreateDiagnostics() + { + const string source = @" + namespace ConsoleApplication1 + { +public class MyClass + { + protected MyStruct myStruct = default(MyStruct); + private struct MyStruct + { + public int Value; + } + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task publicFieldDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + public MyStruct myStruct = default(MyStruct); + private struct MyStruct + { + public int Value; + } + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task publicFieldWithClassDoesNotCreateDiagnostics() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + public MyStruct myStruct = new MyStruct(); + private struct MyStruct + { + public int Value; + } + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task readOnlyVarDoesNotCreateDiagnostics() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + readonly var s = ""; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task readOnlyFieldDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + readonly string s; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task primitiveTypesDoesNotCreateDiagnostics() + { + const string source = @" + namespace ConsoleApplication1 + { + class test + { + private byte b = new byte(); + private sbyte s = new sbyte(); + private int i = new int(); + private uint u = new uint(); + private short ss = new short(); + public ushort us = new ushort(); + public long l = new long(); + public ulong ul = new ulong(); + public float fl = new float(); + public double d = new double(); + public char c = new char(); + public bool bo = new bool(); + public object o = new object(); + public string st = ""; + public decimal dc = new decimal(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task enumDoesNotCreateDiagnostics() + { + const string source = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private test testEnum; + public enum test + { + test1 = 1, + test2 = 2 + } + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + [Fact] + public async Task IgnoreOut() + { + const string source = @" +public class C +{ + private string field = ""; + private static void Foo(out string bar) => bar = ""; + public void Baz() => Foo(out field); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task IgnoreRef() + { + const string source = @" +public class C +{ + private string field = ""; + private static void Foo(ref string bar) => bar = ""; + public void Baz() => Foo(ref field); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task IgnoreAssignmentToFieldsInOtherTypes() + { + const string source1 = @" +class TypeName1 +{ + public int i; +}"; + const string source2 = @" +class TypeName2 +{ + public TypeName2() + { + var t = new TypeName1(); + t.i = 1; + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source1, source2 }); + } + + [Fact] + public async Task FieldWithoutAssignmentDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + private int i; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task FieldWithoutAssignmentInAStructDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + struct TypeName + { + private int i; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task PublicFieldWithAssignmentOnDeclarationDoesNotCreateDiagnostic() + { + const string source = @" + namespace ConsoleApplication1 + { + class TypeName + { + public int i = 1; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + + [Fact] + public async Task structNoDiagnostic() + { + const string source1 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct; + private struct MyStruct + { + public int Value; + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source1 }); + } + + [Fact] + public async Task structWithNullValue() + { + const string source1 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct = null; + private struct MyStruct + { + public int Value; + } + } + }"; + const string source2 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private readonly MyStruct myStruct = null; + private struct MyStruct + { + public int Value; + } + } + }"; + await VerifyCSharpFixAsync(source1, source2, 0); + } + [Fact] + public async Task structDefaultCreateWithoutReadOnlyDeclarationSameClass() + { + const string source1 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct = default(MyStruct); + private struct MyStruct + { + public int Value; + } + } + }"; + const string source2 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private readonly MyStruct myStruct = default(MyStruct); + private struct MyStruct + { + public int Value; + } + } + }"; + await VerifyCSharpFixAsync(source1, source2, 0); + } + + [Fact] + public async Task structCreateWithoutReadonlyDeclaration() + { + const string source1 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct = new MyStruct(); + } + private struct MyStruct + { + public int Value; + } + }"; + const string source2 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private readonly MyStruct myStruct = new MyStruct(); + } + private struct MyStruct + { + public int Value; + } + }"; + await VerifyCSharpFixAsync(source1, source2, 0); + } + + [Fact] + public async Task structDefaultCreateWithoutReadonlyDeclaration() + { + const string source1 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private MyStruct myStruct = default(MyStruct); + } + private struct MyStruct + { + public int Value; + } + }"; + const string source2 = @" + namespace ConsoleApplication1 + { + public class MyClass + { + private readonly MyStruct myStruct = default(MyStruct); + } + private struct MyStruct + { + public int Value; + } + }"; + await VerifyCSharpFixAsync(source1, source2, 0); + } + [Fact] + public async Task enumerationsDoesNotCreateDiagnostic() + { + const string source = @" + public class EnumTest + { + enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat }; + + static void Main() + { + int x = (int)Days.Sun; + int y = (int)Days.Fri; + int z = x + y; + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + + [Fact] + public async Task privateEnumerationsDoesNotCreateDiagnostic() + { + const string source = @" + public class EnumTest + { + enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat }; + private Days enumDays; + static void Main() + { + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(new[] { source }); + } + } +} From cfa4fa358c3b0622fb2f06741461f041802bc55f Mon Sep 17 00:00:00 2001 From: Nozziel Date: Wed, 19 Oct 2016 21:15:26 +0200 Subject: [PATCH 201/358] #848 - "Disposable Field Not Disposed" rule does not recognize null propagation - Fix + Unit test --- .../DisposableFieldNotDisposedAnalyzer.cs | 38 ++++++++++++++++--- .../Usage/DisposableFieldNotDisposedTests.cs | 23 +++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs index 2e625e04d..b90b12001 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableFieldNotDisposedAnalyzer.cs @@ -92,13 +92,41 @@ private static bool CallsDisposeOnField(IFieldSymbol fieldSymbol, MethodDeclarat var hasDisposeCall = body.DescendantNodes().OfKind(SyntaxKind.InvocationExpression) .Any(invocation => { - if (!invocation?.Expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) ?? true) return false; - var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; - if (memberAccess?.Name == null) return false; - if (memberAccess.Name.Identifier.ToString() != "Dispose" || memberAccess.Name.Arity != 0) return false; - return fieldSymbol.Equals(semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol); + if (invocation?.Expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) ?? false) + { + return IsDisposeCallOnField(invocation, fieldSymbol, semanticModel); + + } + + if (invocation?.Expression?.IsKind(SyntaxKind.MemberBindingExpression) ?? false) + { + return IsDisposeWithNullPropagationCallOnField(invocation, fieldSymbol, semanticModel); + } + + return false; }); return hasDisposeCall; } + + private static bool IsDisposeCallOnField(InvocationExpressionSyntax expression, IFieldSymbol fieldSymbol, SemanticModel semanticModel) + { + var memberAccess = (MemberAccessExpressionSyntax)expression.Expression; + if (memberAccess?.Name == null) return false; + if (memberAccess.Name.Identifier.ToString() != "Dispose" || memberAccess.Name.Arity != 0) return false; + var result = fieldSymbol.Equals(semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol); + return result; + } + + private static bool IsDisposeWithNullPropagationCallOnField(InvocationExpressionSyntax expression, IFieldSymbol fieldSymbol, SemanticModel semanticModel) + { + var memberBinding = (MemberBindingExpressionSyntax)expression.Expression; + if (memberBinding?.Name == null) return false; + if (memberBinding.Name.Identifier.ToString() != "Dispose" || memberBinding.Name.Arity != 0) return false; + + var conditionalAccessExpression = memberBinding.Parent.Parent as ConditionalAccessExpressionSyntax; + if (conditionalAccessExpression == null) return false; + var result = fieldSymbol.Equals(semanticModel.GetSymbolInfo(conditionalAccessExpression.Expression).Symbol); + return result; + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs index ba84e4bc6..1c46e93f2 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs @@ -45,6 +45,29 @@ private void Dispose(bool disposing) await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task WhenUsingTheDisposablePatternWithNullPropagationItDoesNotCreateDiagnostic() + { + const string source = @" +using System; +using System.IO; +public class A : IDisposable +{ + private MemoryStream disposableField = new MemoryStream(); + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + private void Dispose(bool disposing) + { + if (disposing) + disposableField?.Dispose(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task WhenAFieldThatImplementsIDisposableIsAssignedThroughAMethodCallCreatesDiagnostic() { From e1c18b6be36ce56e3f84e6f3c6f0b2cfdda7a68f Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 7 Jan 2017 16:40:28 -0200 Subject: [PATCH 202/358] Fix bug on CC0120 when there was a conversion Also major refactors Fixes #859 --- .../Design/SwitchWithoutDefaultAnalyzer.cs | 10 +- .../SwitchWithoutDefaultCodeFixProvider.cs | 71 ++---- .../Design/SwicthWithoutDefaultTests.cs | 208 ++++++++++-------- 3 files changed, 142 insertions(+), 147 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs index b4531315f..82a31165c 100644 --- a/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultAnalyzer.cs @@ -47,16 +47,14 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var hasInitializer = from nodes in switchStatementToAnalyse.DescendantNodes() where nodes.Kind() == SyntaxKind.IdentifierName select nodes; - if (!hasInitializer.Any()) - return; + if (!hasInitializer.Any()) return; var hasTrueExpression = from nodes in switchStatementToAnalyse.DescendantNodes() - where nodes.Kind() == SyntaxKind.FalseLiteralExpression + where nodes.IsKind(SyntaxKind.FalseLiteralExpression) select nodes; var hasfalseExpression = from nodes in switchStatementToAnalyse.DescendantNodes() - where nodes.Kind() == SyntaxKind.TrueLiteralExpression + where nodes.IsKind(SyntaxKind.TrueLiteralExpression) select nodes; - if ((hasfalseExpression.Any()) && (hasTrueExpression.Any())) - return; + if (hasfalseExpression.Any() && hasTrueExpression.Any()) return; var diagnostic = Diagnostic.Create(Rule, switchStatementToAnalyse.GetLocation(), "Consider put an default clause in Switch."); context.ReportDiagnostic(diagnostic); } diff --git a/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs index 192d1ac5e..086dd9055 100644 --- a/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/SwitchWithoutDefaultCodeFixProvider.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; @@ -15,9 +16,6 @@ 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 FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.SwitchCaseWithoutDefault.ToDiagnosticId()); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; @@ -33,69 +31,32 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) private async static Task SwitchWithoutDefaultAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var switchCaseLabel = new SyntaxList(); - var kindOfVariable = string.Empty; - var idForVariable = string.Empty; - var breakStatement = new SyntaxList(); - var diagnosticSpan = diagnostic.Location.SourceSpan; var newSections = new List(); - var switchCaseStatement = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().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 switchCaseStatement = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var expressionSymbol = semanticModel.GetSymbolInfo(switchCaseStatement.Expression).Symbol; + if (semanticModel.GetTypeInfo(switchCaseStatement.Expression).Type.SpecialType == SpecialType.System_Boolean) { - 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"; - + var type = ((CaseSwitchLabelSyntax)switchCaseStatement.Sections.Last().ChildNodes().First()).Value.GetFirstToken().Text; + var againstType = type == "true" ? "false" : "true"; newSections.Add(SyntaxFactory.SwitchSection().WithLabels( - switchCaseLabel.Add(SyntaxFactory.CaseSwitchLabel(SyntaxFactory.ParseExpression(againstType)))). - WithStatements(breakStatement.Add(SyntaxFactory.ParseStatement(BreakString)))); + new SyntaxList().Add(SyntaxFactory.CaseSwitchLabel(SyntaxFactory.ParseExpression(againstType)))) + .WithStatements(new SyntaxList().Add(SyntaxFactory.ParseStatement("break;")))); } 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))); + newSections.Add(CreateSection(SyntaxFactory.DefaultSwitchLabel(), + SyntaxFactory.ThrowStatement(SyntaxFactory.ObjectCreationExpression(SyntaxFactory.ParseTypeName("System.Exception").WithAdditionalAnnotations(Simplifier.Annotation), + SyntaxFactory.ArgumentList(new SeparatedSyntaxList().Add(SyntaxFactory.Argument(SyntaxFactory.ParseExpression("\"Unexpected Case\"")))), null)))); } - var switchExpression = SyntaxFactory.ParseExpression(idForVariable); - var newsSwitchCaseStatement = SyntaxFactory.SwitchStatement(switchExpression). - WithSections(new SyntaxList().AddRange(newSections)); + var newsSwitchCaseStatement = switchCaseStatement + .AddSections(newSections.ToArray()) + .WithAdditionalAnnotations(Formatter.Annotation); var newRoot = root.ReplaceNode(switchCaseStatement, newsSwitchCaseStatement); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; } + static SwitchSectionSyntax CreateSection(SwitchLabelSyntax label, StatementSyntax statement) { var labels = new SyntaxList(); diff --git a/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs b/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs index c9fa24b44..88d7a4cc8 100644 --- a/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/SwicthWithoutDefaultTests.cs @@ -9,49 +9,49 @@ public class SwicthWithoutDefaultTests : CodeFixVerifier 1; +}"; + + const string fixtest = @" +using System; +class TypeName +{ + void Bar() + { + var t = new TypeName(); + switch ((int)t) + { + case 1: break; + default: + throw new Exception(""Unexpected Case""); + } + } + public static explicit operator int(TypeName v) => 1; +}"; + await VerifyCSharpFixAsync(source, fixtest); } + [Fact] public async Task SwithWithoutDefaultAnalyserIntMethodTwoParams() { - const string source = @"using System;namespace - ConsoleApplication1 + const string source = @"using System;namespace + ConsoleApplication1 { class TypeName { @@ -218,17 +255,17 @@ void Bar4(int a, int b) switch (a) { case 10: - break; + break; } } } }"; - const string fixtest = @"using System;namespace - ConsoleApplication1 + const string fixtest = @"using System;namespace + ConsoleApplication1 { class TypeName - { + { void Bar4(int a, int b) { switch (a) @@ -241,14 +278,14 @@ void Bar4(int a, int b) } } }"; - await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] public async Task SwithWithoutDefaultAnalyserIntMethodStatic() { - const string source = @"using System;namespace - ConsoleApplication1 + const string source = @"using System;namespace + ConsoleApplication1 { class TypeName { @@ -257,18 +294,18 @@ static void Bar5(int a) switch (a) { case 10: - break; + break; } } } }"; - const string fixtest = @"using System;namespace - ConsoleApplication1 + const string fixtest = @"using System;namespace + ConsoleApplication1 { class TypeName - { + { static void Bar5(int a) { switch (a) @@ -282,7 +319,7 @@ static void Bar5(int a) } }"; - await VerifyCSharpFixAsync(source, fixtest, 0, allowNewCompilerDiagnostics: true); + await VerifyCSharpFixAsync(source, fixtest); } [Fact] @@ -291,7 +328,6 @@ public async Task SwithWithoutDefaultAnalyseCS0151Exception() const string source = @"static void M() { } static void Main() { - switch (M()) // CS0151 { default: @@ -305,8 +341,8 @@ static void Main() [Fact] public async Task SwithWithoutDefaultAnalyserNoDiagnostic() { - const string source = @"using System;namespace - ConsoleApplication1 + const string source = @"using System;namespace + ConsoleApplication1 { class TypeName { @@ -329,25 +365,25 @@ public async Task SwitchWithoutDefaultAnalyzerNoDiagnosticWithCompileError() { const string source = @"using System; namespace ConsoleApplication1 - { - ConsoleApplication1 + { + ConsoleApplication1 { class Teste { } class Program { static void Main(string[] args) { - Teste vo_teste = new Teste(); + Teste vo_teste = new Teste(); switch (vo_teste) { - case "":break; + case "":break; default:break; } } - } - } + } + } }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } } -} +} \ No newline at end of file From af13035fbed3fb7bf7c60044773cf6cd78571c92 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 8 Jan 2017 03:06:34 -0200 Subject: [PATCH 203/358] Do not offer initializer for dynamic objects (CC0008) Fixes #837 Signed-off-by: Giovanni Bassi --- .../CodeCracker/Style/ObjectInitializerAnalyzer.cs | 1 + .../CodeCracker.Test/Style/ObjectInitializerTests.cs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs index 5dc26127d..4e67acf8b 100644 --- a/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ObjectInitializerAnalyzer.cs @@ -76,6 +76,7 @@ private static void AnalyzeLocalDeclaration(SyntaxNodeAnalysisContext context) if (equalsValueClauseSyntax?.Value.IsNotKind(SyntaxKind.ObjectCreationExpression) ?? true) return; if (((ObjectCreationExpressionSyntax)equalsValueClauseSyntax.Value).Initializer?.IsKind(SyntaxKind.CollectionInitializerExpression) ?? false) return; var variableSymbol = semanticModel.GetDeclaredSymbol(variable); + if (((ILocalSymbol)variableSymbol).Type.TypeKind == TypeKind.Dynamic) return; var assignmentExpressionStatements = FindAssignmentExpressions(semanticModel, localDeclarationStatement, variableSymbol); if (!assignmentExpressionStatements.Any()) return; if (HasAssignmentUsingDeclaredVariable(semanticModel, variableSymbol, assignmentExpressionStatements)) return; diff --git a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs index b4e1b5ddb..eacb34d86 100644 --- a/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ObjectInitializerTests.cs @@ -7,6 +7,17 @@ namespace CodeCracker.Test.CSharp.Style { public class ObjectInitializerWithLocalDeclarationTests : CodeFixVerifier { + [Fact] + public async Task WhenDeclaringADynamicVariableDoesNotCreateDiagnostic() + { + var source = @" +dynamic p = new Person(); +p.Name = ""Giovanni""; +p.Age = 25; +"; + await VerifyCSharpHasNoDiagnosticsAsync(source.WrapInCSharpMethod()); + } + [Fact] public async Task WhenAssigningButNotCreatingAnalyzerDoesNotCreateDiagnostic() { From 0055881018d2275e54ad395afe53da1f462a733e Mon Sep 17 00:00:00 2001 From: bergarces Date: Wed, 14 Dec 2016 20:57:20 +0000 Subject: [PATCH 204/358] Fixed bug that prevented a non-simple assignment to appear on the If whilst a simple assignment was on the Else. Also allows different non-simple assignments on both if and else. --- .../Style/TernaryOperatorCodeFixProviders.vb | 8 +- .../Style/TernaryOperatorTests.vb | 104 ++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb index 4b60a321e..9ef918ddf 100644 --- a/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb +++ b/src/VisualBasic/CodeCracker/Style/TernaryOperatorCodeFixProviders.vb @@ -112,7 +112,7 @@ Namespace Style EnsureNothingAsType(semanticModel, type, typeSyntax). ConvertToBaseType(elseType, type) - If ifAssign.OperatorToken.Text <> "=" Then + If ifAssign.OperatorToken.Text <> "=" AndAlso ifAssign.OperatorToken.Text = elseAssign.OperatorToken.Text Then trueExpression = ifAssign.Right. EnsureNothingAsType(semanticModel, type, typeSyntax). ConvertToBaseType(ifType, type) @@ -136,7 +136,11 @@ Namespace Style trueExpression.WithoutTrailingTrivia(), falseExpression.WithoutTrailingTrivia()) - Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left.WithLeadingTrivia(leadingTrivia), ifAssign.OperatorToken, ternary). + Dim ternaryOperatorToken As SyntaxToken = If((ifAssign.OperatorToken.Text <> "=" OrElse elseAssign.OperatorToken.Text <> "=") AndAlso ifAssign.OperatorToken.Text <> elseAssign.OperatorToken.Text, + SyntaxFactory.Token(SyntaxKind.EqualsToken), + ifAssign.OperatorToken) + + Dim assignment = SyntaxFactory.SimpleAssignmentStatement(ifAssign.Left.WithLeadingTrivia(leadingTrivia), ternaryOperatorToken, ternary). WithTrailingTrivia(trailingTrivia). WithAdditionalAnnotations(Formatter.Annotation) diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index d5357ee71..e773cb2a7 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -438,6 +438,84 @@ End Class" Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) End Function + + Public Async Function WhenUsingConcatenationAssignmentOnIfAssignExpandsToConcatenateAtEndOfTernary() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + If True Then + x &= ""1"" + Else + x = ""2"" + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + x = If(True, x & ""1"", ""2"") + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + Public Async Function WhenUsingAddAssiginmentOnIfAssignExpandsOperationProperly() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + If True Then + x += 1 + Else + x = 1 + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + x = If(True, x + 1, 1) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + + + Public Async Function WhenUsingSubtractAssiginmentOnIfAssignExpandsOperationProperly() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + If True Then + x -= 1 + Else + x = 1 + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + x = If(True, x - 1, 1) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function + Public Async Function WhenUsingAssignmentOperatorReturnSameAssignment() As Task Const source = " @@ -466,6 +544,32 @@ End Class" Await VerifyBasicFixAsync(source, fix, formatBeforeCompare:=True) End Function + + + Public Async Function WhenUsingDifferentAssiginmentsExpandsOperationProperly() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + If True Then + x += 1 + Else + x -= 1 + End If + End Sub +End Class" + + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = 0 + x = If(True, x + 1, x - 1) + End Sub +End Class" + + ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. + Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + End Function End Class Public Class TernaryOperatorWithReturnTests From 50208726bcabf414109ee25540ffcbd4c47d154d Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 8 Jan 2017 14:23:07 -0200 Subject: [PATCH 205/358] Update TernaryOperatorTests to remove unnecessary allowNewCompilerDiagnostics Also added 2 new tests Fixes #798 --- .../Style/TernaryOperatorTests.vb | 83 ++++++++++++------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index e773cb2a7..4e1c8a3a2 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -372,7 +372,6 @@ Public Class MyType End If End Sub End Class" - Const fix = " Public Class MyType Public Sub Foo() @@ -380,12 +379,9 @@ Public Class MyType x = If(True, ""1"", x & ""2"") End Sub End Class" - - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + Await VerifyBasicFixAsync(source, fix) End Function - Public Async Function WhenUsingAddAssiginmentExpandsOperationProperly() As Task Const source = " @@ -399,7 +395,6 @@ Public Class MyType End If End Sub End Class" - Const fix = " Public Class MyType Public Sub Foo() @@ -407,9 +402,7 @@ Public Class MyType x = If(True, 1, x + 1) End Sub End Class" - - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + Await VerifyBasicFixAsync(source, fix) End Function @@ -425,7 +418,6 @@ Public Class MyType End If End Sub End Class" - Const fix = " Public Class MyType Public Sub Foo() @@ -433,25 +425,68 @@ Public Class MyType x = If(True, 1, x - 1) End Sub End Class" + Await VerifyBasicFixAsync(source, fix) + End Function - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + + Public Async Function WhenUsingConcatenationAssignmentOnElseAssignWithPlusExpandsToConcatenateAtEndOfTernary() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + If True Then + x = ""1"" + Else + x += ""2"" + End If + End Sub +End Class" + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + x = If(True, ""1"", x + ""2"") + End Sub +End Class" + Await VerifyBasicFixAsync(source, fix) End Function - Public Async Function WhenUsingConcatenationAssignmentOnIfAssignExpandsToConcatenateAtEndOfTernary() As Task + Public Async Function WhenUsingConcatenationAssignmentOnIfAssignWithPlusExpandsToConcatenateAtEndOfTernary() As Task Const source = " Public Class MyType Public Sub Foo() Dim x = ""test"" If True Then - x &= ""1"" + x += ""1"" Else x = ""2"" End If End Sub End Class" + Const fix = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + x = If(True, x + ""1"", ""2"") + End Sub +End Class" + Await VerifyBasicFixAsync(source, fix) + End Function + + Public Async Function WhenUsingConcatenationAssignmentOnIfAssignWithAmpersandExpandsToConcatenateAtEndOfTernary() As Task + Const source = " +Public Class MyType + Public Sub Foo() + Dim x = ""test"" + If True Then + x &= ""1"" + Else + x = ""2"" + End If + End Sub +End Class" Const fix = " Public Class MyType Public Sub Foo() @@ -459,9 +494,7 @@ Public Class MyType x = If(True, x & ""1"", ""2"") End Sub End Class" - - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + Await VerifyBasicFixAsync(source, fix) End Function @@ -477,7 +510,6 @@ Public Class MyType End If End Sub End Class" - Const fix = " Public Class MyType Public Sub Foo() @@ -485,13 +517,11 @@ Public Class MyType x = If(True, x + 1, 1) End Sub End Class" - - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + Await VerifyBasicFixAsync(source, fix) End Function - Public Async Function WhenUsingSubtractAssiginmentOnIfAssignExpandsOperationProperly() As Task + Public Async Function WhenUsingSubtractAssignmentOnIfAssignExpandsOperationProperly() As Task Const source = " Public Class MyType Public Sub Foo() @@ -503,7 +533,6 @@ Public Class MyType End If End Sub End Class" - Const fix = " Public Class MyType Public Sub Foo() @@ -511,9 +540,7 @@ Public Class MyType x = If(True, x - 1, 1) End Sub End Class" - - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + Await VerifyBasicFixAsync(source, fix) End Function @@ -566,9 +593,7 @@ Public Class MyType x = If(True, x + 1, x - 1) End Sub End Class" - - ' Allowing new diagnostics because without it the test fails because the compiler says Integer? is not defined. - Await VerifyBasicFixAsync(source, fix, allowNewCompilerDiagnostics:=True) + Await VerifyBasicFixAsync(source, fix) End Function End Class From 25b0270b2a54edaed4060365b67e37f8ecfb9c2c Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 26 Sep 2016 19:05:39 -0300 Subject: [PATCH 206/358] Fix #841 --- .../Refactoring/ComputeExpressionCodeFixProvider.cs | 8 ++++++-- .../Refactoring/ComputeExpressionTests.cs | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Refactoring/ComputeExpressionCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ComputeExpressionCodeFixProvider.cs index bf7e40551..cdfd8a563 100644 --- a/src/CSharp/CodeCracker/Refactoring/ComputeExpressionCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ComputeExpressionCodeFixProvider.cs @@ -36,7 +36,7 @@ private async static Task ComputeExpressionAsync(Document document, Lo var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var node = root.FindNode(diagnosticLocation.SourceSpan); var parenthesized = node as ParenthesizedExpressionSyntax; - var expression = (BinaryExpressionSyntax)(parenthesized != null ? parenthesized.Expression : node); + var expression = (BinaryExpressionSyntax)(parenthesized != null ? parenthesized.Expression : node is ArgumentSyntax ? ((ArgumentSyntax)node).Expression : node); var newRoot = ComputeExpression(node, expression, root, semanticModel); if (newRoot == null) return null; var newDocument = document.WithSyntaxRoot(newRoot); @@ -47,7 +47,11 @@ internal static SyntaxNode ComputeExpression(SyntaxNode nodeToReplace, BinaryExp { var result = semanticModel.GetConstantValue(expression); if (!result.HasValue) return null; - var newExpression = SyntaxFactory.ParseExpression(System.Convert.ToString(result.Value, System.Globalization.CultureInfo.InvariantCulture)); + SyntaxNode newExpression = SyntaxFactory.ParseExpression(System.Convert.ToString(result.Value, System.Globalization.CultureInfo.InvariantCulture)); + if(nodeToReplace is ArgumentSyntax) + { + newExpression = SyntaxFactory.Argument((ExpressionSyntax)newExpression); + } var newRoot = root.ReplaceNode(nodeToReplace, newExpression); return newRoot; } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs index 4b92b70be..e7a40762e 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs @@ -80,5 +80,13 @@ public async Task CompilerErrorDoesNotRegisterAFix() => [Fact] public async Task ExpressionThatThrowsDoesNotRegisterAFix() => await VerifyCSharpHasNoFixAsync("var a = int.MaxValue + int.MaxValue;".WrapInCSharpMethod()); + + [Fact] + public async Task ExpressionOnArgumentsFix() + { + var source = "string.Format(\"2 Hours in minutes: {0}\", 60 * 2)".WrapInCSharpMethod(); + var fix = "string.Format(\"2 Hours in minutes: {0}\", 120)".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(source, fix); + } } } \ No newline at end of file From 37bfbfac79a118c8c005090cc730bece941d16dc Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 8 Jan 2017 21:31:44 -0200 Subject: [PATCH 207/358] Fix MakeReadonly with lambdas when field has initializer Fixes #853 Related to #544 but in that issue the variable was not initialized --- .../Usage/ReadonlyFieldAnalyzer.cs | 15 ++++++----- .../Usage/ReadonlyFieldTests.cs | 25 ++++++++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index d9db192ba..4ba9688b5 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -118,25 +118,28 @@ private static void VerifyVariable(Dictionary variablesToMakeReadonly, IFieldSymbol fieldSymbol, SyntaxNode assignment, SemanticModel semanticModel) + private static bool HasAssignmentInLambda(SyntaxNode assignment) { var parent = assignment.Parent; while (parent != null) { if (parent is AnonymousFunctionExpressionSyntax) - return; - if (parent is ConstructorDeclarationSyntax) - break; + return true; parent = parent.Parent; } + return false; + } + private static void AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(Dictionary variablesToMakeReadonly, IFieldSymbol fieldSymbol, SyntaxNode assignment, SemanticModel semanticModel) + { if (!fieldSymbol.IsReadOnly && !variablesToMakeReadonly.Keys.Contains(fieldSymbol)) { var containingType = assignment.FirstAncestorOfKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration); diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index e4181d876..25442201e 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -849,6 +849,29 @@ public Test() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task FieldsAssignedOnLambdaWithInitializerDoesNotCreateDiagnostic() + { + const string source = @" +using System; +class C +{ + private readonly Action set; + private int i = 0; + + public C() + { + set = () => i = 1; + } + + public void Modify() + { + set(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task VariableInitializerDoesNotCreateDiagnostic() { @@ -992,4 +1015,4 @@ public Test() await VerifyCSharpHasNoDiagnosticsAsync(source); } } -} +} \ No newline at end of file From af791db541fd98e7a0bbb7121967789d9e57cd4c Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Mon, 9 Jan 2017 00:18:01 -0200 Subject: [PATCH 208/358] Remove async from DisposablesShouldCallSuppressFinalizeAnalyzer Fixes #821 --- .../Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.vb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.vb index c7ee0b6e2..2b80fa72d 100644 --- a/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/DisposablesShouldCallSuppressFinalizeAnalyzer.vb @@ -35,7 +35,7 @@ This rule should be followed even if the class doesn't have a finalizer in a der context.RegisterSymbolAction(AddressOf AnalyzeAsync, SymbolKind.NamedType) End Sub - Public Async Sub AnalyzeAsync(context As SymbolAnalysisContext) + Public Sub AnalyzeAsync(context As SymbolAnalysisContext) If (context.IsGenerated()) Then Return Dim symbol = DirectCast(context.Symbol, INamedTypeSymbol) If symbol.TypeKind <> TypeKind.Class Then Exit Sub @@ -48,7 +48,7 @@ This rule should be followed even if the class doesn't have a finalizer in a der Dim disposeMethod = FindDisposeMethod(symbol) If disposeMethod Is Nothing Then Exit Sub - Dim syntaxTree = Await disposeMethod.DeclaringSyntaxReferences(0)?.GetSyntaxAsync(context.CancellationToken) + Dim syntaxTree = disposeMethod.DeclaringSyntaxReferences(0)?.GetSyntax(context.CancellationToken) Dim methodBlock = TryCast(TryCast(syntaxTree, MethodStatementSyntax)?.Parent, MethodBlockSyntax) Dim statements = methodBlock?.Statements.OfType(Of ExpressionStatementSyntax) From e0492cf1f941c552ed04b93c10875745fc567968 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Mon, 9 Jan 2017 00:25:21 -0200 Subject: [PATCH 209/358] Fix grammar in MakeLocalVariableConstWhenItIsPossibleAnalyzer And on the test Fixes #838 Related to #839 --- .../MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs | 2 +- .../MakeLocalVariablesConstWhenItIsPossibleTests.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs index 60dc5f397..f49aba20a 100644 --- a/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/MakeLocalVariableConstWhenItIsPossibleAnalyzer.cs @@ -12,7 +12,7 @@ public class MakeLocalVariableConstWhenItIsPossibleAnalyzer : DiagnosticAnalyzer { internal const string Title = "Make Local Variable Constant."; - internal const string MessageFormat = "This variables can be made const."; + internal const string MessageFormat = "This variable can be made const."; internal const string Category = SupportedCategories.Performance; const string Description = "This variable is assigned a constant value and never changed it can be made 'const'"; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( diff --git a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs index 3bbd8e378..e37f52a46 100644 --- a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs @@ -67,7 +67,7 @@ public async Task CreateDiagnosticsWhenAssigningAPotentialConstant() var expected = new DiagnosticResult { Id = DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), - Message = "This variables can be made const.", + Message = "This variable can be made const.", Severity = DiagnosticSeverity.Info, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } }; @@ -82,7 +82,7 @@ public async Task CreateDiagnosticsWhenAssigningAPotentialConstantInAVarDeclarat var expected = new DiagnosticResult { Id = DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), - Message = "This variables can be made const.", + Message = "This variable can be made const.", Severity = DiagnosticSeverity.Info, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } }; @@ -97,7 +97,7 @@ public async Task CreateDiagnosticsWhenAssigningNullToAReferenceType() var expected = new DiagnosticResult { Id = DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), - Message = "This variables can be made const.", + Message = "This variable can be made const.", Severity = DiagnosticSeverity.Info, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } }; From e071c8ad8392d6c007d7fbaf1056b89cb6343a33 Mon Sep 17 00:00:00 2001 From: Hubert Kindermann Date: Fri, 13 Jan 2017 11:36:57 +0100 Subject: [PATCH 210/358] Fixes #854. --- .../Usage/ReadonlyFieldAnalyzer.cs | 8 +++--- .../Usage/ReadonlyFieldTests.cs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index d9db192ba..6ee2c84e1 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -2,9 +2,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Collections.Generic; namespace CodeCracker.CSharp.Usage { @@ -137,7 +137,7 @@ private static void AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(D parent = parent.Parent; } - if (!fieldSymbol.IsReadOnly && !variablesToMakeReadonly.Keys.Contains(fieldSymbol)) + if (!fieldSymbol.IsReadOnly && !variablesToMakeReadonly.Keys.Contains(fieldSymbol) && !IsComplexValueType(fieldSymbol.Type)) { var containingType = assignment.FirstAncestorOfKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration); if (containingType == null) return; @@ -196,9 +196,11 @@ private static bool IsComplexValueType(SemanticModel semanticModel, FieldDeclara { var fieldTypeName = fieldDeclaration.Declaration.Type; var fieldType = semanticModel.GetTypeInfo(fieldTypeName).ConvertedType; - return fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + return IsComplexValueType(fieldType); } + private static bool IsComplexValueType(ITypeSymbol fieldType) => fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + private static bool CanBeMadeReadonly(IFieldSymbol fieldSymbol) { return (fieldSymbol.DeclaredAccessibility == Accessibility.NotApplicable diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index e4181d876..fb208a531 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -988,6 +988,32 @@ public Test() { value = 8; } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task ComplexTypeDoesNotCreateDiagnosticAsync() + { + const string source = @" +class C +{ + private S s; + + public C() + { + s = default(S); + } + + public void M1() + { + s.Value = 1; + } + + public struct S + { + public int Value; + } }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } From 50ea8e08577c4df93702814cb9722484bf0d010a Mon Sep 17 00:00:00 2001 From: Hubert Kindermann Date: Mon, 16 Jan 2017 13:07:18 +0100 Subject: [PATCH 211/358] Fix #CC0060. --- ...ctClassShouldNotHavePublicCtorsAnalyzer.cs | 8 +++---- ...stractClassShouldNotHavePublicCtorTests.cs | 24 +++++++++++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs index 4e70142cd..f753cbebe 100644 --- a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs @@ -1,9 +1,9 @@ -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; namespace CodeCracker.CSharp.Usage { @@ -33,7 +33,7 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) var ctor = (ConstructorDeclarationSyntax)context.Node; if (!ctor.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))) return; - var @class = ctor.Ancestors().OfType().FirstOrDefault(); + var @class = ctor.Ancestors().FirstOrDefault() as ClassDeclarationSyntax; if (@class == null) return; if (!@class.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword))) return; diff --git a/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs b/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs index 6d804ca61..4fd659794 100644 --- a/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; -using CodeCracker.CSharp.Usage; +using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using System.Threading.Tasks; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -66,6 +66,26 @@ private Foo() { /* .. */ } await VerifyCSharpHasNoDiagnosticsAsync(test); } + [Fact] + public async Task IgnoresCtorOfStructNestedInAbstractClasses() + { + const string test = @" + public abstract class C + { + public struct S + { + private int x; + + public S(int x) + { + this.x = x; + } + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + [Fact] public async Task FixReplacesPublicWithProtectedModifierInAbstractClasses() { From 8a8dc0ee8221f76aca22b871411a97560442ca7a Mon Sep 17 00:00:00 2001 From: Hubert Kindermann Date: Mon, 16 Jan 2017 13:16:27 +0100 Subject: [PATCH 212/358] Revert "Fix #CC0060." This reverts commit 50ea8e08577c4df93702814cb9722484bf0d010a. --- ...ctClassShouldNotHavePublicCtorsAnalyzer.cs | 8 +++---- ...stractClassShouldNotHavePublicCtorTests.cs | 24 ++----------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs index f753cbebe..4e70142cd 100644 --- a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs @@ -1,9 +1,9 @@ -using Microsoft.CodeAnalysis; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using System.Collections.Immutable; -using System.Linq; namespace CodeCracker.CSharp.Usage { @@ -33,7 +33,7 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) var ctor = (ConstructorDeclarationSyntax)context.Node; if (!ctor.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))) return; - var @class = ctor.Ancestors().FirstOrDefault() as ClassDeclarationSyntax; + var @class = ctor.Ancestors().OfType().FirstOrDefault(); if (@class == null) return; if (!@class.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword))) return; diff --git a/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs b/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs index 4fd659794..6d804ca61 100644 --- a/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs @@ -1,6 +1,6 @@ -using CodeCracker.CSharp.Usage; +using System.Threading.Tasks; +using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; -using System.Threading.Tasks; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -66,26 +66,6 @@ private Foo() { /* .. */ } await VerifyCSharpHasNoDiagnosticsAsync(test); } - [Fact] - public async Task IgnoresCtorOfStructNestedInAbstractClasses() - { - const string test = @" - public abstract class C - { - public struct S - { - private int x; - - public S(int x) - { - this.x = x; - } - } - }"; - - await VerifyCSharpHasNoDiagnosticsAsync(test); - } - [Fact] public async Task FixReplacesPublicWithProtectedModifierInAbstractClasses() { From 20bd8a042b47e8b7523d47c3e04673b086c9c7a6 Mon Sep 17 00:00:00 2001 From: Stefan Theiner Date: Mon, 6 Feb 2017 09:25:34 +0100 Subject: [PATCH 213/358] Fix #872: UnusedParametersAnalyzer Analyzer should not be triggered on virtual methods Includes test case and fix. --- .../Usage/UnusedParametersAnalyzer.cs | 6 ++++++ .../Usage/UnusedParametersTests.cs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs index cec3e43ea..cae19517e 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs @@ -59,6 +59,12 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) } var method = methodOrConstructor as MethodDeclarationSyntax; + + // It is legit for virtual methods to have parameters that aren't used in the default + // base class implementation, but are only provided for sub classes instead. + // See https://github.com/code-cracker/code-cracker/issues/872 + if (method?.Modifiers.Any(SyntaxKind.VirtualKeyword) == true) return; + IEnumerable methodChildren = methodOrConstructor.Body?.Statements; var expressionBody = (methodOrConstructor as MethodDeclarationSyntax)?.ExpressionBody; if (methodChildren == null && expressionBody != null) diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 44cf5f2b9..2b08add48 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -893,5 +893,24 @@ public class TypeName }"; await VerifyCSharpFixAsync(source, fixtest); } + + /// + /// Virtual methods should be ignored by the analyzer, because variables don't need + /// to be actually used by the base class and still serve a legit purpose. + /// + [Fact] + public async Task VirtualMethodsShouldBeIgnored() + { + + const string source = @" +public class BaseClass +{ + protected virtual void PreProcess(string data) + { + // no real action in base class + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From a9df7f4496941157c90aeafd57fd16a2becb5487 Mon Sep 17 00:00:00 2001 From: sdygert Date: Mon, 20 Feb 2017 20:31:51 -0800 Subject: [PATCH 214/358] Fixed grammer in CatchEmptyAnalyzer --- src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs | 6 +++--- src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs b/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs index ca0c5506a..82e455d7f 100644 --- a/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs @@ -10,7 +10,7 @@ namespace CodeCracker.CSharp.Design [DiagnosticAnalyzer(LanguageNames.CSharp)] public class CatchEmptyAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Your catch maybe include some Exception"; + internal const string Title = "Your catch should include an Exception"; internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Design; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( @@ -33,7 +33,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var catchStatement = (CatchClauseSyntax)context.Node; if (catchStatement == null || catchStatement.Declaration != null) return; - if (catchStatement.Block?.Statements.Count == 0) return; // there is another analizer for this: EmptyCatchBlock + if (catchStatement.Block?.Statements.Count == 0) return; // there is another analyzer for this: EmptyCatchBlock if (catchStatement.Block != null) { @@ -42,7 +42,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (!controlFlow.EndPointIsReachable && controlFlow.ExitPoints.All(i => i.IsKind(SyntaxKind.ThrowStatement))) return; } - var diagnostic = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider put an Exception Class in catch."); + var diagnostic = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider adding an Exception to the catch."); context.ReportDiagnostic(diagnostic); } } diff --git a/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb b/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb index 132345083..e4f1b7c9c 100644 --- a/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb @@ -9,7 +9,7 @@ Namespace Design Inherits DiagnosticAnalyzer Public Shared ReadOnly Id As String = DiagnosticId.CatchEmpty.ToDiagnosticId() - Public Const Title As String = "Your catch may includes some Exception" + Public Const Title As String = "Your catch should include an Exception" Public Const MessageFormat As String = "{0}" Public Const Category As String = SupportedCategories.Design Protected Shared Rule As DiagnosticDescriptor = New DiagnosticDescriptor( @@ -33,7 +33,7 @@ Namespace Design If catchStatement Is Nothing Then Exit Sub If catchStatement.IdentifierName Is Nothing Then - Dim diag = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider including an Exception Class in catch.") + Dim diag = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider adding an Exception to the catch.") context.ReportDiagnostic(diag) End If End Sub From e4d2a3152a8fb20ca0ccac48a58e3f388ca89a16 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Mon, 27 Feb 2017 19:17:58 +0100 Subject: [PATCH 215/358] #522 first prototype --- .../Style/TernaryOperatorCodeFixProvider.cs | 69 +++++++++- .../Style/TernaryOperatorTests.cs | 123 ++++++++++++++++++ 2 files changed, 185 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 97ebd2e3f..0e6a22ed6 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using System; namespace CodeCracker.CSharp.Style { @@ -37,11 +38,10 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var elseStatement = ifStatement.Else; var returnStatementInsideElse = (ReturnStatementSyntax)(elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement); var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - ExpressionSyntax trueExpression, falseExpression; - TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, semanticModel, out trueExpression, out falseExpression); + var conditionalExpression = TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, ifStatement.Condition, semanticModel); var ternary = SyntaxFactory.ReturnStatement( - SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression)) + conditionalExpression) .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(ifStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); @@ -76,14 +76,13 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var assignmentExpressionInsideIf = (AssignmentExpressionSyntax)expressionInsideIf.Expression; var assignmentExpressionInsideElse = (AssignmentExpressionSyntax)expressionInsideElse.Expression; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - ExpressionSyntax trueExpression, falseExpression; - TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, semanticModel, out trueExpression, out falseExpression); + var conditionalExpression = TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, ifStatement.Condition, semanticModel); var ternary = SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( assignmentExpressionInsideIf.Kind(), assignmentExpressionInsideIf.Left, - SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression))) + conditionalExpression)) .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(ifStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); @@ -95,13 +94,69 @@ private static async Task MakeTernaryAsync(Document document, Diagnost internal static class TernaryOperatorCodeFixHelper { - public static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel, out ExpressionSyntax trueExpression, out ExpressionSyntax falseExpression) + public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, ExpressionSyntax ifStatementCondition, SemanticModel semanticModel) + { + + var methodCallSimplification = TrySimplifyMethodCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (methodCallSimplification != null) return methodCallSimplification; + var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); + var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); + var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + ExpressionSyntax trueExpression; ExpressionSyntax falseExpression; + CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, + ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); + } + + private static ExpressionSyntax TrySimplifyMethodCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + { + if (ifExpression is InvocationExpressionSyntax && elseExpression is InvocationExpressionSyntax) + { + var ifInvocation = ifExpression as InvocationExpressionSyntax; + var elseInvocation = elseExpression as InvocationExpressionSyntax; + var ifMethodinfo = semanticModel.GetSymbolInfo(ifInvocation.Expression); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation.Expression); + if (object.Equals(ifMethodinfo, elseMethodinfo)) //same method and overload + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.InvocationExpression(ifInvocation.Expression, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel)); + } + } + return null; + } + + private static ArgumentListSyntax CreateMethodArgumentList(ExpressionSyntax ifStatementCondition, ArgumentListSyntax argList1, ArgumentListSyntax argList2, int argumentIndexThatDiffers, SemanticModel semanticModel) + { + var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); + var argSelector = zipped.Select((args, i) => + (i == argumentIndexThatDiffers) ? + SyntaxFactory.Argument(GetConditionalExpressionForArgument(ifStatementCondition, args.a1.Expression, args.a2.Expression, semanticModel)) + : args.a1); + return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argSelector)); + } + + private static ConditionalExpressionSyntax GetConditionalExpressionForArgument(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) { var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + ExpressionSyntax trueExpression; ExpressionSyntax falseExpression; CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); + } + + private static int FindSingleArgumentIndexThatDiffers(ArgumentListSyntax argList1, ArgumentListSyntax argList2, SemanticModel semanticModel) + { + var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); + var singleMissmatch = zipped.Where(args => + { + var a1Text = args.a1.GetText(); + var a2Text = args.a2.GetText(); + return !a1Text.ContentEquals(a2Text); + }).Take(2).ToList(); + return (singleMissmatch.Count == 0 || singleMissmatch.Count > 1) ? -1 : singleMissmatch[0].i; } private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 68d90f96d..fcd61b6a1 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -723,5 +723,128 @@ public static Base Foo() "; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenReturnStatementContainsMethodCallAnalyzerCreatesDiagnostic() + { + var source = @" + private int Method(int i) => i; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), + Message = "You can use a ternary operator.", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithSingleDifferentArgumentGetsSimplified() + { + var source = @" + private int Method(int i) => i; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i) => i; + + public int Foo() + { + return Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereSingleDifferentGetsSimplified() + { + var source = @" + private int Method(int i, string t) => i; + + public int Foo() + { + if (true) + return Method(1, ""hello""); + else + return Method(2, ""hello""); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i, string t) => i; + + public int Foo() + { + return Method(true?1:2, ""hello""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereMultipleDifferentGetsNotSimplified() + { + var source = @" + private int Method(int i, string t) => i; + + public int Foo() + { + if (true) + return Method(1, ""hello1""); + else + return Method(2, ""hello2""); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i, string t) => i; + + public int Foo() + { + return true?Method(1,""hello1""):Method(2, ""hello2""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodArgumentsGetCastedWhenSimplified() + { + var source = @" + class Base { } + class A : Base { } + class B : Base { } + + private string Method(Base b, string t) => t; + + public int Foo() + { + if (true) + return Method(new A(), ""hello""); + else + return Method(new B(), ""hello""); + }".WrapInCSharpClass(); + var fixtest = @" + class Base { } + class A : Base { } + class B : Base { } + + private string Method(Base b, string t) => t; + + public int Foo() + { + return Method(true?(Base)new A():new B(),""hello""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From 0b218c0ffa0107b21c7a24b3e32805de112e82f6 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 28 Feb 2017 18:55:27 +0100 Subject: [PATCH 216/358] Small improvement and many more tests --- .../Style/TernaryOperatorCodeFixProvider.cs | 11 +- .../Style/TernaryOperatorTests.cs | 230 +++++++++++++++++- 2 files changed, 235 insertions(+), 6 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 0e6a22ed6..33a44e884 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -118,9 +118,12 @@ private static ExpressionSyntax TrySimplifyMethodCalls(ExpressionSyntax ifStatem var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation.Expression); if (object.Equals(ifMethodinfo, elseMethodinfo)) //same method and overload { - var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); - if (findSingleArgumentIndexThatDiffers >= 0) - return SyntaxFactory.InvocationExpression(ifInvocation.Expression, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel)); + if (ifInvocation.Expression.GetText().ContentEquals(elseInvocation.Expression.GetText())) //same 'path' to the invocation + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.InvocationExpression(ifInvocation.Expression, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel)); + } } } return null; @@ -156,7 +159,7 @@ private static int FindSingleArgumentIndexThatDiffers(ArgumentListSyntax argList var a2Text = args.a2.GetText(); return !a1Text.ContentEquals(a2Text); }).Take(2).ToList(); - return (singleMissmatch.Count == 0 || singleMissmatch.Count > 1) ? -1 : singleMissmatch[0].i; + return (singleMissmatch.Count == 1) ? singleMissmatch[0].i : -1; } private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index fcd61b6a1..0300d66b0 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -334,6 +334,68 @@ public static void Foo() "; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultChangeToTernaryFixGetsSimplified() + { + var source = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + if (something) + { + a = Method(1); + } + else + { + a = Method(2); + } + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + a = Method(something?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultWithComplexArgumentEvaluationChangeToTernaryFixGetsSimplified() + { + var source = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + if (something) + { + a = Method(1); + } + else + { + a = Method(2 + 2); + } + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + a = Method(something?1:2 + 2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } public class TernaryOperatorWithReturnTests : CodeFixVerifier @@ -824,7 +886,7 @@ class Base { } class A : Base { } class B : Base { } - private string Method(Base b, string t) => t; + private int Method(Base b, string t) => 1; public int Foo() { @@ -838,7 +900,7 @@ class Base { } class A : Base { } class B : Base { } - private string Method(Base b, string t) => t; + private int Method(Base b, string t) => 1; public int Foo() { @@ -846,5 +908,169 @@ public int Foo() }".WrapInCSharpClass(); await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task FixWhenReturningWithPrefixedMethodGetsSimplified() + { + var source = @" + private int Method(int a) => a; + + public int Foo() + { + if (true) + return this.Method(1); + else + return this.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int a) => a; + + public int Foo() + { + return this.Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfPropertyGetsSimplified() + { + var source = @" + class A { + private int Method(int a) => a; + } + + public int Foo() + { + var a=new A(); + if (true) + return a.Method(1); + else + return a.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + class A { + private int Method(int a) => a; + } + + public int Foo() + { + var a=new A(); + return a.Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentPropertyGetsNotSimplified() + { + var source = @" + class A { + public int Method(int a) => a; + } + A Prop1 { get { return new A(); } } + A Prop2 { get { return new A(); } } + + public int Foo() + { + if (true) + return this.Prop1.Method(1); + else + return this.Prop2.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + class A { + public int Method(int a) => a; + } + A Prop1 { get { return new A(); } } + A Prop2 { get { return new A(); } } + + public int Foo() + { + return true?this.Prop1.Method(1):this.Prop2.Method(2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfSameOverloadGetsSimplified() + { + var source = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + return Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentOverloadGetsNotSimplified() + { + var source = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(""2""); + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + return true?Method(1):Method(""2""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodNestedInMemberAccessGetsNotSimplified() + { + var source = @" + class A { + public int Prop { get; } + } + + A GetA(int i) => new A(); + + public int Foo() + { + if (true) + return GetA(1).Prop; + else + return GetA(2).Prop; + }".WrapInCSharpClass(); + var fixtest = @" + class A { + public int Prop { get; } + } + + A GetA(int i) => new A(); + + public int Foo() + { + return true?GetA(1).Prop:GetA(2).Prop; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From e3b934f0cf68c7f433cdfcc32893a5953c6a074a Mon Sep 17 00:00:00 2001 From: Stefan Theiner Date: Mon, 6 Feb 2017 09:25:34 +0100 Subject: [PATCH 217/358] Fix #872: UnusedParametersAnalyzer Analyzer should not be triggered on virtual methods Includes test case and fix. --- .../Usage/UnusedParametersAnalyzer.cs | 6 ++++++ .../Usage/UnusedParametersTests.cs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs index cec3e43ea..cae19517e 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersAnalyzer.cs @@ -59,6 +59,12 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) } var method = methodOrConstructor as MethodDeclarationSyntax; + + // It is legit for virtual methods to have parameters that aren't used in the default + // base class implementation, but are only provided for sub classes instead. + // See https://github.com/code-cracker/code-cracker/issues/872 + if (method?.Modifiers.Any(SyntaxKind.VirtualKeyword) == true) return; + IEnumerable methodChildren = methodOrConstructor.Body?.Statements; var expressionBody = (methodOrConstructor as MethodDeclarationSyntax)?.ExpressionBody; if (methodChildren == null && expressionBody != null) diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 44cf5f2b9..2b08add48 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -893,5 +893,24 @@ public class TypeName }"; await VerifyCSharpFixAsync(source, fixtest); } + + /// + /// Virtual methods should be ignored by the analyzer, because variables don't need + /// to be actually used by the base class and still serve a legit purpose. + /// + [Fact] + public async Task VirtualMethodsShouldBeIgnored() + { + + const string source = @" +public class BaseClass +{ + protected virtual void PreProcess(string data) + { + // no real action in base class + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } } \ No newline at end of file From b5fe3e6542764e8be365920726b4e5130b62d99b Mon Sep 17 00:00:00 2001 From: sdygert Date: Mon, 20 Feb 2017 20:31:51 -0800 Subject: [PATCH 218/358] Fixed grammer in CatchEmptyAnalyzer --- src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs | 6 +++--- src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs b/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs index ca0c5506a..82e455d7f 100644 --- a/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/CatchEmptyAnalyzer.cs @@ -10,7 +10,7 @@ namespace CodeCracker.CSharp.Design [DiagnosticAnalyzer(LanguageNames.CSharp)] public class CatchEmptyAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Your catch maybe include some Exception"; + internal const string Title = "Your catch should include an Exception"; internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Design; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( @@ -33,7 +33,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) var catchStatement = (CatchClauseSyntax)context.Node; if (catchStatement == null || catchStatement.Declaration != null) return; - if (catchStatement.Block?.Statements.Count == 0) return; // there is another analizer for this: EmptyCatchBlock + if (catchStatement.Block?.Statements.Count == 0) return; // there is another analyzer for this: EmptyCatchBlock if (catchStatement.Block != null) { @@ -42,7 +42,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (!controlFlow.EndPointIsReachable && controlFlow.ExitPoints.All(i => i.IsKind(SyntaxKind.ThrowStatement))) return; } - var diagnostic = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider put an Exception Class in catch."); + var diagnostic = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider adding an Exception to the catch."); context.ReportDiagnostic(diagnostic); } } diff --git a/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb b/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb index 132345083..e4f1b7c9c 100644 --- a/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Design/CatchEmptyAnalyzer.vb @@ -9,7 +9,7 @@ Namespace Design Inherits DiagnosticAnalyzer Public Shared ReadOnly Id As String = DiagnosticId.CatchEmpty.ToDiagnosticId() - Public Const Title As String = "Your catch may includes some Exception" + Public Const Title As String = "Your catch should include an Exception" Public Const MessageFormat As String = "{0}" Public Const Category As String = SupportedCategories.Design Protected Shared Rule As DiagnosticDescriptor = New DiagnosticDescriptor( @@ -33,7 +33,7 @@ Namespace Design If catchStatement Is Nothing Then Exit Sub If catchStatement.IdentifierName Is Nothing Then - Dim diag = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider including an Exception Class in catch.") + Dim diag = Diagnostic.Create(Rule, catchStatement.GetLocation(), "Consider adding an Exception to the catch.") context.ReportDiagnostic(diag) End If End Sub From 233cdf7474110d48144c0fe9083e37eca292386b Mon Sep 17 00:00:00 2001 From: hkindermann Date: Mon, 16 Jan 2017 14:23:06 +0100 Subject: [PATCH 219/358] Fixes #867. --- ...ctClassShouldNotHavePublicCtorsAnalyzer.cs | 8 +++---- ...stractClassShouldNotHavePublicCtorTests.cs | 24 +++++++++++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs index 4e70142cd..f753cbebe 100644 --- a/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/AbstractClassShouldNotHavePublicCtorsAnalyzer.cs @@ -1,9 +1,9 @@ -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; namespace CodeCracker.CSharp.Usage { @@ -33,7 +33,7 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) var ctor = (ConstructorDeclarationSyntax)context.Node; if (!ctor.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))) return; - var @class = ctor.Ancestors().OfType().FirstOrDefault(); + var @class = ctor.Ancestors().FirstOrDefault() as ClassDeclarationSyntax; if (@class == null) return; if (!@class.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword))) return; diff --git a/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs b/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs index 6d804ca61..4fd659794 100644 --- a/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/AbstractClassShouldNotHavePublicCtorTests.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; -using CodeCracker.CSharp.Usage; +using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using System.Threading.Tasks; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -66,6 +66,26 @@ private Foo() { /* .. */ } await VerifyCSharpHasNoDiagnosticsAsync(test); } + [Fact] + public async Task IgnoresCtorOfStructNestedInAbstractClasses() + { + const string test = @" + public abstract class C + { + public struct S + { + private int x; + + public S(int x) + { + this.x = x; + } + } + }"; + + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + [Fact] public async Task FixReplacesPublicWithProtectedModifierInAbstractClasses() { From e86f1ffca13e8e561433f71b06ea945be3705d25 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 8 Mar 2017 14:32:30 +0100 Subject: [PATCH 220/358] Supoport for constructor calls added. --- .../Style/TernaryOperatorCodeFixProvider.cs | 20 +++++++++++++++++++ .../Style/TernaryOperatorTests.cs | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 33a44e884..2f3b6a0c0 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -99,6 +99,8 @@ public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, var methodCallSimplification = TrySimplifyMethodCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); if (methodCallSimplification != null) return methodCallSimplification; + var constructorSimplification = TrySimplifyConstructorCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (constructorSimplification != null) return constructorSimplification; var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); @@ -108,6 +110,24 @@ public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); } + private static ExpressionSyntax TrySimplifyConstructorCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + { + if (ifExpression is ObjectCreationExpressionSyntax && elseExpression is ObjectCreationExpressionSyntax) + { + var ifInvocation = ifExpression as ObjectCreationExpressionSyntax; + var elseInvocation = elseExpression as ObjectCreationExpressionSyntax; + var ifMethodinfo = semanticModel.GetSymbolInfo(ifInvocation); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation); + if (object.Equals(ifMethodinfo, elseMethodinfo)) //same method and overload + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.ObjectCreationExpression(ifInvocation.Type, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel), null); + } + } + return null; + } + private static ExpressionSyntax TrySimplifyMethodCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) { if (ifExpression is InvocationExpressionSyntax && elseExpression is InvocationExpressionSyntax) diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 0300d66b0..714041c00 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -1072,5 +1072,24 @@ public int Foo() }".WrapInCSharpClass(); await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task FixWhenReturningWithConstructorGetsSimplified() + { + var source = @" + public int Foo() + { + if (true) + return new System.Collections.Generic.List(1); + else + return new System.Collections.Generic.List(2); + }".WrapInCSharpClass(); + var fixtest = @" + public int Foo() + { + return new System.Collections.Generic.List(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From 36eaae34115e5b0b63089e77935a1ea2833a7b8a Mon Sep 17 00:00:00 2001 From: Hubert Kindermann Date: Fri, 13 Jan 2017 11:36:57 +0100 Subject: [PATCH 221/358] Fixes #854. --- .../Usage/ReadonlyFieldAnalyzer.cs | 8 +++--- .../Usage/ReadonlyFieldTests.cs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs index 4ba9688b5..1fa957957 100644 --- a/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/ReadonlyFieldAnalyzer.cs @@ -2,9 +2,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Collections.Generic; namespace CodeCracker.CSharp.Usage { @@ -140,7 +140,7 @@ private static bool HasAssignmentInLambda(SyntaxNode assignment) private static void AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(Dictionary variablesToMakeReadonly, IFieldSymbol fieldSymbol, SyntaxNode assignment, SemanticModel semanticModel) { - if (!fieldSymbol.IsReadOnly && !variablesToMakeReadonly.Keys.Contains(fieldSymbol)) + if (!fieldSymbol.IsReadOnly && !variablesToMakeReadonly.Keys.Contains(fieldSymbol) && !IsComplexValueType(fieldSymbol.Type)) { var containingType = assignment.FirstAncestorOfKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration); if (containingType == null) return; @@ -199,9 +199,11 @@ private static bool IsComplexValueType(SemanticModel semanticModel, FieldDeclara { var fieldTypeName = fieldDeclaration.Declaration.Type; var fieldType = semanticModel.GetTypeInfo(fieldTypeName).ConvertedType; - return fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + return IsComplexValueType(fieldType); } + private static bool IsComplexValueType(ITypeSymbol fieldType) => fieldType.IsValueType && !(fieldType.TypeKind == TypeKind.Enum || fieldType.IsPrimitive()); + private static bool CanBeMadeReadonly(IFieldSymbol fieldSymbol) { return (fieldSymbol.DeclaredAccessibility == Accessibility.NotApplicable diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index 25442201e..e49637973 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -1011,6 +1011,32 @@ public Test() { value = 8; } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task ComplexTypeDoesNotCreateDiagnosticAsync() + { + const string source = @" +class C +{ + private S s; + + public C() + { + s = default(S); + } + + public void M1() + { + s.Value = 1; + } + + public struct S + { + public int Value; + } }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } From 7b21fbdd55ba90e2ccde1d3835ca698ef84660aa Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 11 Mar 2017 18:47:14 -0300 Subject: [PATCH 222/358] Migrate projects to VS2017 format and create new ones for VS2015 Anyone wanting to code on CodeCracker now should use VS2017, or use the new .2015.sln files --- CodeCracker.2015.sln | 141 ++++++++++++++++++ CodeCracker.CSharp.2015.sln | 101 +++++++++++++ CodeCracker.VisualBasic.2015.sln | 97 ++++++++++++ README.md | 5 + .../CodeCracker.Vsix.2015.csproj | 84 +++++++++++ .../CodeCracker.Vsix/CodeCracker.Vsix.csproj | 9 +- .../source.extension.vsixmanifest | 4 + .../CodeCracker.Vsix.2015.csproj | 84 +++++++++++ .../CodeCracker.Vsix/CodeCracker.Vsix.csproj | 7 +- 9 files changed, 529 insertions(+), 3 deletions(-) create mode 100644 CodeCracker.2015.sln create mode 100644 CodeCracker.CSharp.2015.sln create mode 100644 CodeCracker.VisualBasic.2015.sln create mode 100644 src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj create mode 100644 src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj diff --git a/CodeCracker.2015.sln b/CodeCracker.2015.sln new file mode 100644 index 000000000..729d7ca60 --- /dev/null +++ b/CodeCracker.2015.sln @@ -0,0 +1,141 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker", "src\CSharp\CodeCracker\CodeCracker.csproj", "{FF1097FB-A890-461B-979E-064697891B96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{6BAC4057-7239-485E-A04B-02E687A83BAA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test", "test\CSharp\CodeCracker.Test\CodeCracker.Test.csproj", "{F7843158-046E-4B22-95D7-CAC7BB01283D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vb", "vb", "{11473308-7FD9-43CE-84CE-5912EEFDD1DC}" +EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cs", "cs", "{90D62FF0-A374-4C14-B827-1FFA8E384E18}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{B7B513B4-0317-4F32-B560-4BFC4FAEC239}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" +EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker.Test", "test\VisualBasic\CodeCracker.Test\CodeCracker.Test.vbproj", "{5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{A26BEB5D-9C92-4F60-9789-563A327605C3}" + ProjectSection(SolutionItems) = preProject + src\CodeCracker.nuspec = src\CodeCracker.nuspec + nuget.config = nuget.config + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solution Items", ".Solution Items", "{E1B8ADBF-3442-4EF3-8C6B-146B576340E9}" + ProjectSection(SolutionItems) = preProject + .gitattributes = .gitattributes + .gitignore = .gitignore + CHANGELOG.md = CHANGELOG.md + README.md = README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{234973E7-794D-4BC5-8D5F-FB98D8BFA967}" + ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml + build.ps1 = build.ps1 + build.targets.ps1 = build.targets.ps1 + psake.ps1 = psake.ps1 + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6E93-4D2D-B6F0-141B977AFC9F}" + ProjectSection(SolutionItems) = preProject + test\CSharp\AnalyzeCecil.ps1 = test\CSharp\AnalyzeCecil.ps1 + test\CSharp\AnalyzeCoreFx.ps1 = test\CSharp\AnalyzeCoreFx.ps1 + test\CSharp\AnalyzeRoslyn.ps1 = test\CSharp\AnalyzeRoslyn.ps1 + runTestsCS.ps1 = runTestsCS.ps1 + runTestsVB.ps1 = runTestsVB.ps1 + test.ps1 = test.ps1 + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + DebugNoVsix|Any CPU = DebugNoVsix|Any CPU + Release|Any CPU = Release|Any CPU + ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.Build.0 = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {FF1097FB-A890-461B-979E-064697891B96} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} + {6BAC4057-7239-485E-A04B-02E687A83BAA} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} + {F7843158-046E-4B22-95D7-CAC7BB01283D} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} + {41FA4971-D354-4647-A269-4A886DA2EF4C} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} + {B7B513B4-0317-4F32-B560-4BFC4FAEC239} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} + {234973E7-794D-4BC5-8D5F-FB98D8BFA967} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} + {C5584F20-6E93-4D2D-B6F0-141B977AFC9F} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} + EndGlobalSection +EndGlobal diff --git a/CodeCracker.CSharp.2015.sln b/CodeCracker.CSharp.2015.sln new file mode 100644 index 000000000..0600d9a27 --- /dev/null +++ b/CodeCracker.CSharp.2015.sln @@ -0,0 +1,101 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F5240AD-2B4E-48A4-B9FC-7D19DACEF2CD}" + ProjectSection(SolutionItems) = preProject + nuget.config = nuget.config + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker", "src\CSharp\CodeCracker\CodeCracker.csproj", "{FF1097FB-A890-461B-979E-064697891B96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.2015.Vsix", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{6BAC4057-7239-485E-A04B-02E687A83BAA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test", "test\CSharp\CodeCracker.Test\CodeCracker.Test.csproj", "{F7843158-046E-4B22-95D7-CAC7BB01283D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7B4F0131-D598-4692-9E2C-111E6C42C6AD}" + ProjectSection(SolutionItems) = preProject + .gitattributes = .gitattributes + .gitignore = .gitignore + CHANGELOG.md = CHANGELOG.md + README.md = README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{051F1BE2-9A44-4B84-9DF8-6537852B7BBC}" + ProjectSection(SolutionItems) = preProject + test\CSharp\AnalyzeCecil.ps1 = test\CSharp\AnalyzeCecil.ps1 + test\CSharp\AnalyzeCoreFx.ps1 = test\CSharp\AnalyzeCoreFx.ps1 + test\CSharp\AnalyzeRoslyn.ps1 = test\CSharp\AnalyzeRoslyn.ps1 + runTestsCS.ps1 = runTestsCS.ps1 + test.ps1 = test.ps1 + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{40545653-8444-49E0-8DAD-BBB381F8A3B2}" + ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml + build.ps1 = build.ps1 + build.targets.ps1 = build.targets.ps1 + psake.ps1 = psake.ps1 + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + DebugNoVsix|Any CPU = DebugNoVsix|Any CPU + Release|Any CPU = Release|Any CPU + ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU + {6BAC4057-7239-485E-A04B-02E687A83BAA}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.Build.0 = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {051F1BE2-9A44-4B84-9DF8-6537852B7BBC} = {7B4F0131-D598-4692-9E2C-111E6C42C6AD} + {40545653-8444-49E0-8DAD-BBB381F8A3B2} = {7B4F0131-D598-4692-9E2C-111E6C42C6AD} + EndGlobalSection +EndGlobal diff --git a/CodeCracker.VisualBasic.2015.sln b/CodeCracker.VisualBasic.2015.sln new file mode 100644 index 000000000..9d3b4ba56 --- /dev/null +++ b/CodeCracker.VisualBasic.2015.sln @@ -0,0 +1,97 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" +EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker.Test", "test\VisualBasic\CodeCracker.Test\CodeCracker.Test.vbproj", "{5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6}" + ProjectSection(SolutionItems) = preProject + .gitattributes = .gitattributes + .gitignore = .gitignore + README.md = README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{5413BEBC-2F00-4B54-98E9-B1A7618C3C2A}" + ProjectSection(SolutionItems) = preProject + nuget.config = nuget.config + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{D1591C8E-982D-402F-B3CB-1D1662104425}" + ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml + build.ps1 = build.ps1 + build.targets.ps1 = build.targets.ps1 + psake.ps1 = psake.ps1 + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{22D6C608-E7F1-4236-BB07-BE5F97A4C810}" + ProjectSection(SolutionItems) = preProject + runTestsVB.ps1 = runTestsVB.ps1 + test.ps1 = test.ps1 + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{B7B513B4-0317-4F32-B560-4BFC4FAEC239}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + DebugNoVsix|Any CPU = DebugNoVsix|Any CPU + Release|Any CPU = Release|Any CPU + ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU + {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D1591C8E-982D-402F-B3CB-1D1662104425} = {3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6} + {22D6C608-E7F1-4236-BB07-BE5F97A4C810} = {3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md index f3ae91e29..6cfef52f6 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,11 @@ Then add a reference to CodeCracker.dll from within the Analyzers node inside Re ## Contributing +The main supported IDE for development is Visual Studio 2015. +If you want to use VS 2015 to contribute to Code Cracker use +the *.2015.sln files. We recommend migrating to VS 2017 ASAP, as +we might make VS 2015 obsolete at any time. + Questions, comments, bug reports, and pull requests are all welcome. Bug reports that include steps-to-reproduce (including code) are preferred. Even better, make them in the form of pull requests. diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj new file mode 100644 index 000000000..05f70110b --- /dev/null +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj @@ -0,0 +1,84 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {6BAC4057-7239-485E-A04B-02E687A83BAA} + Library + Properties + CodeCracker + CodeCracker.CSharp + v4.5.2 + false + false + false + false + false + false + Roslyn + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Program + $(DevEnvDir)devenv.exe + /rootsuffix Roslyn + + + + Designer + + + + + {FF1097FB-A890-461B-979E-064697891B96} + CodeCracker + + + + + Always + true + + + Always + true + + + Always + true + + + + + + \ No newline at end of file diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj index 05f70110b..12f744c47 100644 --- a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj @@ -1,9 +1,14 @@  - + - 14.0 + 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 15.0 diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 96ab65b93..d2b7702fd 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -25,4 +25,8 @@ This is a community project, free and open source. Everyone is invited to contri + + + + diff --git a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj new file mode 100644 index 000000000..dcdad50cf --- /dev/null +++ b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj @@ -0,0 +1,84 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {B7B513B4-0317-4F32-B560-4BFC4FAEC239} + Library + Properties + CodeCracker + CodeCracker.VisualBasic + v4.5.2 + false + false + false + false + false + false + Roslyn + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Program + $(DevEnvDir)devenv.exe + /rootsuffix Roslyn + + + + Designer + + + + + Always + true + + + Always + true + + + Always + true + + + + + {41fa4971-d354-4647-a269-4a886da2ef4c} + CodeCracker + + + + + + \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.csproj b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.csproj index dcdad50cf..b2f8a0250 100644 --- a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.csproj +++ b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.csproj @@ -1,9 +1,14 @@  - 14.0 + 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 14.0 From f941c7b27342f856541398b056b27db4b37a516a Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 11 Mar 2017 18:58:29 -0300 Subject: [PATCH 223/358] Use VS 2017 on appveyor --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 58c443b5b..ac50d45ed 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,7 @@ version: 1.0.0.{build} +image: Visual Studio 2017 + configuration: ReleaseNoVsix init: @@ -17,8 +19,6 @@ environment: before_build: - ps: >- - $env:path="C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\;C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.1;C:\Program Files (x86)\MSBuild\14.0\bin;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools;C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\VCPackages;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Performance Tools;C:\Program Files (x86)\Windows Kits\8.1\bin\x86;C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.1\;$env:path" - . .\build.ps1 Prepare-Build From e42fce03c7669526314dc02b42fba5a9ca966b37 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 11 Mar 2017 19:38:06 -0300 Subject: [PATCH 224/358] Fix build.ps1 --- build.ps1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/build.ps1 b/build.ps1 index c51dd0bf9..691e90be6 100644 --- a/build.ps1 +++ b/build.ps1 @@ -16,21 +16,21 @@ function IsNugetVersion3($theNugetExe) { function Get-Nuget { if (gcm nuget -ErrorAction SilentlyContinue) { if (IsNugetVersion3 'nuget') { - return 'nuget' + $nugetExe = 'nuget' } else { Download-Nuget - return $localNuget + $nugetExe = $localNuget } } else { Download-Nuget - return $localNuget + $nugetExe = $localNuget } } function Download-Nuget { $tempNuget = "$env:TEMP\codecracker\nuget.exe" if (!(Test-Path "$env:TEMP\codecracker\")) { - md "$env:TEMP\codecracker\" + md "$env:TEMP\codecracker\" | Out-Null } if (Test-Path $localNuget) { if (IsNugetVersion3($localNuget)) { return } @@ -48,7 +48,7 @@ function Download-Nuget { function Import-Psake { $psakeModule = "$PSScriptRoot\packages\psake.4.5.0\tools\psake.psm1" if ((Test-Path $psakeModule) -ne $true) { - . $nugetExe restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot + . "$nugetExe" restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot } Import-Module $psakeModule -force } @@ -56,7 +56,8 @@ function Import-Psake { # statements: $localNuget = "$PSScriptRoot\.nuget\nuget.exe" -$nugetExe = Get-Nuget +$nugetExe = "" +Get-Nuget Import-Psake if ($MyInvocation.UnboundArguments.Count -ne 0) { . $PSScriptRoot\psake.ps1 -taskList ($MyInvocation.UnboundArguments -join " ") From 75a2904613a3cbfb912bbd2b3ef22ef8159be907 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Sun, 12 Mar 2017 17:27:22 +0100 Subject: [PATCH 225/358] Support and tests for dynamic and params added. --- .../Style/TernaryOperatorCodeFixProvider.cs | 36 +-- .../Style/TernaryOperatorTests.cs | 239 ++++++++++++++++-- 2 files changed, 244 insertions(+), 31 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 2f3b6a0c0..8444c0705 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -97,10 +97,10 @@ internal static class TernaryOperatorCodeFixHelper public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, ExpressionSyntax ifStatementCondition, SemanticModel semanticModel) { - var methodCallSimplification = TrySimplifyMethodCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); - if (methodCallSimplification != null) return methodCallSimplification; - var constructorSimplification = TrySimplifyConstructorCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); - if (constructorSimplification != null) return constructorSimplification; + var methodCallArgApplied = TryApplyArgsOnMethodCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (methodCallArgApplied != null) return methodCallArgApplied; + var constructorArgsApplied = TryApplyArgsOnConstructorCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (constructorArgsApplied != null) return constructorArgsApplied; var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); @@ -110,25 +110,30 @@ public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); } - private static ExpressionSyntax TrySimplifyConstructorCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + private static ExpressionSyntax TryApplyArgsOnConstructorCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) { if (ifExpression is ObjectCreationExpressionSyntax && elseExpression is ObjectCreationExpressionSyntax) { - var ifInvocation = ifExpression as ObjectCreationExpressionSyntax; - var elseInvocation = elseExpression as ObjectCreationExpressionSyntax; - var ifMethodinfo = semanticModel.GetSymbolInfo(ifInvocation); - var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation); - if (object.Equals(ifMethodinfo, elseMethodinfo)) //same method and overload + var ifObjCreation = ifExpression as ObjectCreationExpressionSyntax; + var elseObjCreation = elseExpression as ObjectCreationExpressionSyntax; + if ((ifObjCreation.Initializer == null && elseObjCreation.Initializer == null) || + ifObjCreation.Initializer != null && elseObjCreation.Initializer != null && + ifObjCreation.Initializer.GetText().ContentEquals(elseObjCreation.Initializer.GetText())) // Initializer are either absent or text equals { - var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); - if (findSingleArgumentIndexThatDiffers >= 0) - return SyntaxFactory.ObjectCreationExpression(ifInvocation.Type, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel), null); + var ifMethodinfo = semanticModel.GetSymbolInfo(ifObjCreation); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseObjCreation); + if (object.Equals(ifMethodinfo, elseMethodinfo)) //same constructor and overload + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifObjCreation.ArgumentList, elseObjCreation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.ObjectCreationExpression(ifObjCreation.Type, CreateMethodArgumentList(ifStatementCondition, ifObjCreation.ArgumentList, elseObjCreation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel), ifObjCreation.Initializer); + } } } return null; } - private static ExpressionSyntax TrySimplifyMethodCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + private static ExpressionSyntax TryApplyArgsOnMethodCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) { if (ifExpression is InvocationExpressionSyntax && elseExpression is InvocationExpressionSyntax) { @@ -136,7 +141,7 @@ private static ExpressionSyntax TrySimplifyMethodCalls(ExpressionSyntax ifStatem var elseInvocation = elseExpression as InvocationExpressionSyntax; var ifMethodinfo = semanticModel.GetSymbolInfo(ifInvocation.Expression); var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation.Expression); - if (object.Equals(ifMethodinfo, elseMethodinfo)) //same method and overload + if (object.Equals(ifMethodinfo, elseMethodinfo) && ifMethodinfo.CandidateReason != CandidateReason.LateBound) //same method and overload, but not dynamic { if (ifInvocation.Expression.GetText().ContentEquals(elseInvocation.Expression.GetText())) //same 'path' to the invocation { @@ -172,6 +177,7 @@ private static ConditionalExpressionSyntax GetConditionalExpressionForArgument(E private static int FindSingleArgumentIndexThatDiffers(ArgumentListSyntax argList1, ArgumentListSyntax argList2, SemanticModel semanticModel) { + if (argList1.Arguments.Count != argList2.Arguments.Count) return -1; // in case of 'params' var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); var singleMissmatch = zipped.Where(args => { diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 714041c00..c9f42e24f 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -336,8 +336,8 @@ public static void Foo() } [Fact] - public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultChangeToTernaryFixGetsSimplified() - { + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultChangeToTernaryFixGetsArgsApplied() + { var source = @" int Method(int a) => a; @@ -353,7 +353,7 @@ public void Foo() { a = Method(2); } - }".WrapInCSharpClass(); + }".WrapInCSharpClass(); var fixtest = @" int Method(int a) => a; @@ -367,7 +367,7 @@ public void Foo() } [Fact] - public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultWithComplexArgumentEvaluationChangeToTernaryFixGetsSimplified() + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultWithComplexArgumentEvaluationChangeToTernaryFixGetsArgsApplied() { var source = @" int Method(int a) => a; @@ -810,7 +810,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodWithSingleDifferentArgumentGetsSimplified() + public async Task FixWhenReturningWithMethodWithSingleDifferentArgumentGetsArgsApplied() { var source = @" private int Method(int i) => i; @@ -833,7 +833,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereSingleDifferentGetsSimplified() + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereSingleDifferentGetsArgsApplied() { var source = @" private int Method(int i, string t) => i; @@ -856,7 +856,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereMultipleDifferentGetsNotSimplified() + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereMultipleDifferentGetsArgsNotApplied() { var source = @" private int Method(int i, string t) => i; @@ -879,7 +879,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodArgumentsGetCastedWhenSimplified() + public async Task FixWhenReturningWithMethodArgumentsGetCastedWhenGetsArgsApplied() { var source = @" class Base { } @@ -910,7 +910,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithPrefixedMethodGetsSimplified() + public async Task FixWhenReturningWithPrefixedMethodGetsArgsApplied() { var source = @" private int Method(int a) => a; @@ -933,7 +933,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodOfPropertyGetsSimplified() + public async Task FixWhenReturningWithMethodOfPropertyGetsArgsApplied() { var source = @" class A { @@ -962,7 +962,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodOfDifferentPropertyGetsNotSimplified() + public async Task FixWhenReturningWithMethodOfDifferentPropertyGetsArgsNotApplied() { var source = @" class A { @@ -993,7 +993,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodOfSameOverloadGetsSimplified() + public async Task FixWhenReturningWithMethodOfSameOverloadGetsArgsApplied() { var source = @" int Method(int a)=>a; @@ -1018,7 +1018,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodOfDifferentOverloadGetsNotSimplified() + public async Task FixWhenReturningWithMethodOfDifferentOverloadGetsArgsNotApplied() { var source = @" int Method(int a)=>a; @@ -1043,7 +1043,7 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithMethodNestedInMemberAccessGetsNotSimplified() + public async Task FixWhenReturningWithMethodNestedInMemberAccessGetsArgsNotApplied() { var source = @" class A { @@ -1074,10 +1074,113 @@ public int Foo() } [Fact] - public async Task FixWhenReturningWithConstructorGetsSimplified() + public async Task FixWhenReturningWithMethodParamOverloadAndNumerOfArgsAreEqualGetsApplied() + { + var source = @" + private int M(params int[] args) { } + + public int Foo() + { + if (true) + return M(1,1); + else + return M(1,2); + }".WrapInCSharpClass(); + var fixtest = @" + private int M(params int[] args) { } + + public int Foo() + { + return M(1,true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodParamOverloadAndNumerOfArgsAreDifferentGetsNotApplied() { var source = @" + private int M(params int[] args) { } + public int Foo() + { + if (true) + return M(1,1); + else + return M(1,2,3); + }".WrapInCSharpClass(); + var fixtest = @" + private int M(params int[] args) { } + + public int Foo() + { + return true?M(1,1):M(1,2,3); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDynamicObjGetsArgsNotApplied() + { + // Calls on dynamic objects get dispatched during runtime. + // Therefore the semantic would be changed if we apply to arguments + // and casting is involved: + // d.M(new A()) else d.M(new B()) -> d.M(cond?(Base)new A():new B()); + // is not the same as cond?d.M(new A()): d.M(new B()) on dynamic objects. + var source = @" + public class Base {} + public class A: Base {} + public class B: Base {} + + public int Foo() + { + dynamic d = new object(); + if (true) + return d.M(new A()); + else + return d.M(new B()); + }".WrapInCSharpClass(); + var fixtest = @" + public class Base {} + public class A: Base {} + public class B: Base {} + + public int Foo() + { + dynamic d = new object(); + return true?d.M(new A()):d.M(new B()); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDynamicObjGetsArgsNeverApplied() + { + // arguments on dynamic method calls are never applied even if it would be save. + // see comments above for why dynamic is dangerous. + var source = @" + public int Foo() + { + dynamic d = new object(); + if (true) + return d.M(1,1); + else + return d.M(1,2); + }".WrapInCSharpClass(); + var fixtest = @" + public int Foo() + { + dynamic d = new object(); + return true?d.M(1,1):d.M(1,2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorGetsArgsApplied() + { + var source = @" + public System.Collections.Generic.List Foo() { if (true) return new System.Collections.Generic.List(1); @@ -1085,11 +1188,115 @@ public int Foo() return new System.Collections.Generic.List(2); }".WrapInCSharpClass(); var fixtest = @" - public int Foo() + public System.Collections.Generic.List Foo() { return new System.Collections.Generic.List(true?1:2); }".WrapInCSharpClass(); await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task FixWhenReturningWithConstructorWithIdenticalInitializerGetsArgsApplied() + { + var source = @" + public new System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1) { 1 }; + else + return new System.Collections.Generic.List(2) { 1 }; + }".WrapInCSharpClass(); + var fixtest = @" + public new System.Collections.Generic.List Foo() + { + return new System.Collections.Generic.List(true?1:2) { 1 }; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithDifferentInitializerGetsArgsNotApplied() + { + var source = @" + public System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1) { 1 }; + else + return new System.Collections.Generic.List(2) { 1, 2 }; + }".WrapInCSharpClass(); + var fixtest = @" + public System.Collections.Generic.List Foo() + { + return true?new System.Collections.Generic.List(1) { 1 } : new System.Collections.Generic.List(2) { 1, 2 }; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithDifferentOverloadsGetArgsNotApplied() + { + var source = @" + public class A + { + public A(int i) { } + public A(string s) { } + } + public A Foo() + { + if (true) + return new A(1); + else + return new A(""1""); + }".WrapInCSharpClass(); + var fixtest = @" + public class A + { + public A(int i) { } + public A(string s) { } + } + public A Foo() + { + return true?new A(1):new A(""1""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorOfDifferentObjectsGetArgsNotApplied() + { + var source = @" + public class A + { + public A(int i) { } + } + public class B + { + public B(int i) { } + } + + public Object Foo() + { + if (true) + return new A(1); + else + return new B(2); + }".WrapInCSharpClass(); + var fixtest = @" + public class A + { + public A(int i) { } + } + public class B + { + public B(int i) { } + } + + public Object Foo() + { + return true?(object)new A(1):new B(2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From 61dae0431931613fb86479aec29648a409fefb45 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Sun, 12 Mar 2017 17:39:11 +0100 Subject: [PATCH 226/358] Added additional test for overload resolution. --- .../Style/TernaryOperatorTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index c9f42e24f..c9c86f91c 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -1042,6 +1042,35 @@ public int Foo() await VerifyCSharpFixAsync(source, fixtest); } + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentOverloadButCastingPossibleGetsArgsNotApplied() + { + var source = @" + public class A { } + public class B:A { } + void Method(A a) { }; + void Method(B b) { }; + + public int Foo() + { + if (true) + return Method(new A()); + else + return Method(new B()); + }".WrapInCSharpClass(); + var fixtest = @" + public class A { } + public class B:A { } + void Method(A a) { }; + void Method(B b) { }; + + public int Foo() + { + return true?Method(new A()):Method(new B()); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + [Fact] public async Task FixWhenReturningWithMethodNestedInMemberAccessGetsArgsNotApplied() { From 174493e21c5861977c89dfafb9a38fb8de18558c Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 11 Mar 2017 19:44:11 -0300 Subject: [PATCH 227/358] Evolve build.ps1 to work with Nuget 3 or greater --- build.ps1 | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/build.ps1 b/build.ps1 index 691e90be6..d1a072785 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,29 +1,30 @@ $ErrorActionPreference = "Stop" # functions: -function IsNugetVersion3($theNugetExe) { +function IsNugetVersion3OrAbove($theNugetExe) { try { $nugetText = . $theNugetExe | Out-String } catch { return false } - [regex]$regex = '^NuGet Version: (.*)\n' + [regex]$regex = '^NuGet Version: (\d)\.(\d).*\n' $match = $regex.Match($nugetText) $version = $match.Groups[1].Value - return $version.StartsWith(3) + Write-Host "Nuget major version is $version" + return [System.Convert]::ToInt32($version) -ge 3 } function Get-Nuget { if (gcm nuget -ErrorAction SilentlyContinue) { - if (IsNugetVersion3 'nuget') { - $nugetExe = 'nuget' + if (IsNugetVersion3OrAbove 'nuget') { + $script:nugetExe = 'nuget' } else { Download-Nuget - $nugetExe = $localNuget + $script:nugetExe = $localNuget } } else { Download-Nuget - $nugetExe = $localNuget + $script:nugetExe = $localNuget } } @@ -33,10 +34,10 @@ function Download-Nuget { md "$env:TEMP\codecracker\" | Out-Null } if (Test-Path $localNuget) { - if (IsNugetVersion3($localNuget)) { return } + if (IsNugetVersion3OrAbove($localNuget)) { return } } if (Test-Path $tempNuget) { - if (IsNugetVersion3($tempNuget)) { + if (IsNugetVersion3OrAbove($tempNuget)) { cp $tempNuget $localNuget return } @@ -48,7 +49,8 @@ function Download-Nuget { function Import-Psake { $psakeModule = "$PSScriptRoot\packages\psake.4.5.0\tools\psake.psm1" if ((Test-Path $psakeModule) -ne $true) { - . "$nugetExe" restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot + Write-Host "Restoring $PSScriptRoot\.nuget with $script:nugetExe" + . "$script:nugetExe" restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot } Import-Module $psakeModule -force } From bf783486f04425fba8047e2dbdfc2acd235bae03 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 12 Mar 2017 21:24:08 -0300 Subject: [PATCH 228/358] Add changelog --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c87d874..8af91802e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Change Log +## [Unreleased](https://github.com/code-cracker/code-cracker/tree/HEAD) + +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.2...HEAD) + +**Closed issues:** + + +## [v1.0.2](https://github.com/code-cracker/code-cracker/tree/v1.0.2) (2017-03-12) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.1...v1.0.2) + +**Implemented enhancements:** + +- VS 2017RC Support [\#856](https://github.com/code-cracker/code-cracker/issues/856) + +**Fixed bugs:** + +- CC0057 UnusedParametersAnalyzer should not be triggered on virtual methods [\#872](https://github.com/code-cracker/code-cracker/issues/872) +- BUG: CC0060 - detected for nested struct in abstract class [\#867](https://github.com/code-cracker/code-cracker/issues/867) +- Bug on CC0120 for the fix when there is a conversion [\#859](https://github.com/code-cracker/code-cracker/issues/859) +- BUG: CC0052 \(Make readonly\) sometimes detects complex value types [\#854](https://github.com/code-cracker/code-cracker/issues/854) +- BUG: CC0052 \(Make readonly\) does not work with lambda expressions and initialized variables [\#853](https://github.com/code-cracker/code-cracker/issues/853) +- "Disposable Field Not Disposed" rule does not recognize null propagation [\#848](https://github.com/code-cracker/code-cracker/issues/848) +- CC0082: ComputeExpressionCodeFixProvider crashs [\#841](https://github.com/code-cracker/code-cracker/issues/841) +- CC0030: Bad grammar in message [\#838](https://github.com/code-cracker/code-cracker/issues/838) +- CC0008: Don't suggest for dynamic objects [\#837](https://github.com/code-cracker/code-cracker/issues/837) +- Bug: Should not use Async methods in analyzers \(CC0029\) [\#821](https://github.com/code-cracker/code-cracker/issues/821) +- BUG: CC0014 converts if y then x += 1 else x =1 to x +=\(if\(y, 1, 1\) [\#798](https://github.com/code-cracker/code-cracker/issues/798) + ## [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) From c92c0001514ba8e777858714b6417e8b75ab4a92 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 12 Mar 2017 21:36:43 -0300 Subject: [PATCH 229/358] Update vsix --- .../CodeCracker.Vsix/source.extension.vsixmanifest | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index ddd2f9d9d..49925d371 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -25,4 +25,8 @@ This is a community project, free and open source. Everyone is invited to contri + + + + From 9e87cfe904e564da4865bb81719981ba6dedebab Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 12 Mar 2017 21:51:07 -0300 Subject: [PATCH 230/358] Bump version to 1.0.2 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/CodeCracker.nuspec | 6 +++--- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- src/VisualBasic/CodeCracker/CodeCracker.nuspec | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- .../CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- .../VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index d2b7702fd..940a535fc 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index cf2da4160..31a6c4a08 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.CSharp - 1.0.2 + 1.0.3 CodeCracker for C# giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index a2cbcaa12..3d1250f56 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -14,5 +14,5 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.2.0")] +[assembly: AssemblyFileVersion("1.0.3.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec index 6ceea0773..61ef261bc 100644 --- a/src/CodeCracker.nuspec +++ b/src/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker - 1.0.2 + 1.0.3 CodeCracker for C# and VB giggio,elemarjr,carloscds giggio,elemarjr,carloscds @@ -19,8 +19,8 @@ This is a community project, free and open source. Everyone is invited to contri Copyright CodeCracker 2014-2016 roslyn, analyzers - - + + diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index 9bee0ce03..c63e0d98f 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -14,6 +14,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.2.0")] +[assembly: AssemblyFileVersion("1.0.3.0")] [assembly: InternalsVisibleTo("CodeCracker.Test.CSharp")] [assembly: InternalsVisibleTo("CodeCracker.Test.VisualBasic")] \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 49925d371..4f7911589 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for Visual Basic An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index ecb28d922..0b6a31ec4 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -2,7 +2,7 @@ codecracker.VisualBasic - 1.0.2 + 1.0.3 CodeCracker for Visual Basic giggio,elemarjr,carloscds giggio,elemarjr,carloscds diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 1425d7339..a3478becf 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -14,5 +14,5 @@ Imports System.Runtime.InteropServices - + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index 8809cfb5b..92983d5f5 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.2.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.3.0")] \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index 2a6956dbe..e7a08f024 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -14,4 +14,4 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.2.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.3.0")] \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index f7d706ba8..2b5faf79b 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -14,4 +14,4 @@ Imports System.Runtime.InteropServices - \ No newline at end of file + \ No newline at end of file From b63870c10e19a71b80cf78a46085cf316a81364d Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Mon, 27 Feb 2017 19:17:58 +0100 Subject: [PATCH 231/358] Tenary operator: apply to arguments. Fix: #522 --- .../Style/TernaryOperatorCodeFixProvider.cs | 98 ++- .../Style/TernaryOperatorTests.cs | 604 ++++++++++++++++++ 2 files changed, 695 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 97ebd2e3f..8444c0705 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using System; namespace CodeCracker.CSharp.Style { @@ -37,11 +38,10 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var elseStatement = ifStatement.Else; var returnStatementInsideElse = (ReturnStatementSyntax)(elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement); var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - ExpressionSyntax trueExpression, falseExpression; - TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, semanticModel, out trueExpression, out falseExpression); + var conditionalExpression = TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, ifStatement.Condition, semanticModel); var ternary = SyntaxFactory.ReturnStatement( - SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression)) + conditionalExpression) .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(ifStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); @@ -76,14 +76,13 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var assignmentExpressionInsideIf = (AssignmentExpressionSyntax)expressionInsideIf.Expression; var assignmentExpressionInsideElse = (AssignmentExpressionSyntax)expressionInsideElse.Expression; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - ExpressionSyntax trueExpression, falseExpression; - TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, semanticModel, out trueExpression, out falseExpression); + var conditionalExpression = TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, ifStatement.Condition, semanticModel); var ternary = SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( assignmentExpressionInsideIf.Kind(), assignmentExpressionInsideIf.Left, - SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression))) + conditionalExpression)) .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(ifStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); @@ -95,13 +94,98 @@ private static async Task MakeTernaryAsync(Document document, Diagnost internal static class TernaryOperatorCodeFixHelper { - public static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel, out ExpressionSyntax trueExpression, out ExpressionSyntax falseExpression) + public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, ExpressionSyntax ifStatementCondition, SemanticModel semanticModel) + { + + var methodCallArgApplied = TryApplyArgsOnMethodCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (methodCallArgApplied != null) return methodCallArgApplied; + var constructorArgsApplied = TryApplyArgsOnConstructorCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (constructorArgsApplied != null) return constructorArgsApplied; + var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); + var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); + var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + ExpressionSyntax trueExpression; ExpressionSyntax falseExpression; + CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, + ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); + } + + private static ExpressionSyntax TryApplyArgsOnConstructorCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + { + if (ifExpression is ObjectCreationExpressionSyntax && elseExpression is ObjectCreationExpressionSyntax) + { + var ifObjCreation = ifExpression as ObjectCreationExpressionSyntax; + var elseObjCreation = elseExpression as ObjectCreationExpressionSyntax; + if ((ifObjCreation.Initializer == null && elseObjCreation.Initializer == null) || + ifObjCreation.Initializer != null && elseObjCreation.Initializer != null && + ifObjCreation.Initializer.GetText().ContentEquals(elseObjCreation.Initializer.GetText())) // Initializer are either absent or text equals + { + var ifMethodinfo = semanticModel.GetSymbolInfo(ifObjCreation); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseObjCreation); + if (object.Equals(ifMethodinfo, elseMethodinfo)) //same constructor and overload + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifObjCreation.ArgumentList, elseObjCreation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.ObjectCreationExpression(ifObjCreation.Type, CreateMethodArgumentList(ifStatementCondition, ifObjCreation.ArgumentList, elseObjCreation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel), ifObjCreation.Initializer); + } + } + } + return null; + } + + private static ExpressionSyntax TryApplyArgsOnMethodCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + { + if (ifExpression is InvocationExpressionSyntax && elseExpression is InvocationExpressionSyntax) + { + var ifInvocation = ifExpression as InvocationExpressionSyntax; + var elseInvocation = elseExpression as InvocationExpressionSyntax; + var ifMethodinfo = semanticModel.GetSymbolInfo(ifInvocation.Expression); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation.Expression); + if (object.Equals(ifMethodinfo, elseMethodinfo) && ifMethodinfo.CandidateReason != CandidateReason.LateBound) //same method and overload, but not dynamic + { + if (ifInvocation.Expression.GetText().ContentEquals(elseInvocation.Expression.GetText())) //same 'path' to the invocation + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.InvocationExpression(ifInvocation.Expression, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel)); + } + } + } + return null; + } + + private static ArgumentListSyntax CreateMethodArgumentList(ExpressionSyntax ifStatementCondition, ArgumentListSyntax argList1, ArgumentListSyntax argList2, int argumentIndexThatDiffers, SemanticModel semanticModel) + { + var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); + var argSelector = zipped.Select((args, i) => + (i == argumentIndexThatDiffers) ? + SyntaxFactory.Argument(GetConditionalExpressionForArgument(ifStatementCondition, args.a1.Expression, args.a2.Expression, semanticModel)) + : args.a1); + return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argSelector)); + } + + private static ConditionalExpressionSyntax GetConditionalExpressionForArgument(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) { var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + ExpressionSyntax trueExpression; ExpressionSyntax falseExpression; CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); + } + + private static int FindSingleArgumentIndexThatDiffers(ArgumentListSyntax argList1, ArgumentListSyntax argList2, SemanticModel semanticModel) + { + if (argList1.Arguments.Count != argList2.Arguments.Count) return -1; // in case of 'params' + var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); + var singleMissmatch = zipped.Where(args => + { + var a1Text = args.a1.GetText(); + var a2Text = args.a2.GetText(); + return !a1Text.ContentEquals(a2Text); + }).Take(2).ToList(); + return (singleMissmatch.Count == 1) ? singleMissmatch[0].i : -1; } private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 68d90f96d..c9c86f91c 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -334,6 +334,68 @@ public static void Foo() "; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultChangeToTernaryFixGetsArgsApplied() + { + var source = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + if (something) + { + a = Method(1); + } + else + { + a = Method(2); + } + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + a = Method(something?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultWithComplexArgumentEvaluationChangeToTernaryFixGetsArgsApplied() + { + var source = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + if (something) + { + a = Method(1); + } + else + { + a = Method(2 + 2); + } + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + a = Method(something?1:2 + 2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } public class TernaryOperatorWithReturnTests : CodeFixVerifier @@ -723,5 +785,547 @@ public static Base Foo() "; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenReturnStatementContainsMethodCallAnalyzerCreatesDiagnostic() + { + var source = @" + private int Method(int i) => i; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), + Message = "You can use a ternary operator.", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithSingleDifferentArgumentGetsArgsApplied() + { + var source = @" + private int Method(int i) => i; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i) => i; + + public int Foo() + { + return Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereSingleDifferentGetsArgsApplied() + { + var source = @" + private int Method(int i, string t) => i; + + public int Foo() + { + if (true) + return Method(1, ""hello""); + else + return Method(2, ""hello""); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i, string t) => i; + + public int Foo() + { + return Method(true?1:2, ""hello""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereMultipleDifferentGetsArgsNotApplied() + { + var source = @" + private int Method(int i, string t) => i; + + public int Foo() + { + if (true) + return Method(1, ""hello1""); + else + return Method(2, ""hello2""); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i, string t) => i; + + public int Foo() + { + return true?Method(1,""hello1""):Method(2, ""hello2""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodArgumentsGetCastedWhenGetsArgsApplied() + { + var source = @" + class Base { } + class A : Base { } + class B : Base { } + + private int Method(Base b, string t) => 1; + + public int Foo() + { + if (true) + return Method(new A(), ""hello""); + else + return Method(new B(), ""hello""); + }".WrapInCSharpClass(); + var fixtest = @" + class Base { } + class A : Base { } + class B : Base { } + + private int Method(Base b, string t) => 1; + + public int Foo() + { + return Method(true?(Base)new A():new B(),""hello""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithPrefixedMethodGetsArgsApplied() + { + var source = @" + private int Method(int a) => a; + + public int Foo() + { + if (true) + return this.Method(1); + else + return this.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int a) => a; + + public int Foo() + { + return this.Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfPropertyGetsArgsApplied() + { + var source = @" + class A { + private int Method(int a) => a; + } + + public int Foo() + { + var a=new A(); + if (true) + return a.Method(1); + else + return a.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + class A { + private int Method(int a) => a; + } + + public int Foo() + { + var a=new A(); + return a.Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentPropertyGetsArgsNotApplied() + { + var source = @" + class A { + public int Method(int a) => a; + } + A Prop1 { get { return new A(); } } + A Prop2 { get { return new A(); } } + + public int Foo() + { + if (true) + return this.Prop1.Method(1); + else + return this.Prop2.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + class A { + public int Method(int a) => a; + } + A Prop1 { get { return new A(); } } + A Prop2 { get { return new A(); } } + + public int Foo() + { + return true?this.Prop1.Method(1):this.Prop2.Method(2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfSameOverloadGetsArgsApplied() + { + var source = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + return Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentOverloadGetsArgsNotApplied() + { + var source = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(""2""); + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + return true?Method(1):Method(""2""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentOverloadButCastingPossibleGetsArgsNotApplied() + { + var source = @" + public class A { } + public class B:A { } + void Method(A a) { }; + void Method(B b) { }; + + public int Foo() + { + if (true) + return Method(new A()); + else + return Method(new B()); + }".WrapInCSharpClass(); + var fixtest = @" + public class A { } + public class B:A { } + void Method(A a) { }; + void Method(B b) { }; + + public int Foo() + { + return true?Method(new A()):Method(new B()); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodNestedInMemberAccessGetsArgsNotApplied() + { + var source = @" + class A { + public int Prop { get; } + } + + A GetA(int i) => new A(); + + public int Foo() + { + if (true) + return GetA(1).Prop; + else + return GetA(2).Prop; + }".WrapInCSharpClass(); + var fixtest = @" + class A { + public int Prop { get; } + } + + A GetA(int i) => new A(); + + public int Foo() + { + return true?GetA(1).Prop:GetA(2).Prop; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodParamOverloadAndNumerOfArgsAreEqualGetsApplied() + { + var source = @" + private int M(params int[] args) { } + + public int Foo() + { + if (true) + return M(1,1); + else + return M(1,2); + }".WrapInCSharpClass(); + var fixtest = @" + private int M(params int[] args) { } + + public int Foo() + { + return M(1,true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodParamOverloadAndNumerOfArgsAreDifferentGetsNotApplied() + { + var source = @" + private int M(params int[] args) { } + + public int Foo() + { + if (true) + return M(1,1); + else + return M(1,2,3); + }".WrapInCSharpClass(); + var fixtest = @" + private int M(params int[] args) { } + + public int Foo() + { + return true?M(1,1):M(1,2,3); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDynamicObjGetsArgsNotApplied() + { + // Calls on dynamic objects get dispatched during runtime. + // Therefore the semantic would be changed if we apply to arguments + // and casting is involved: + // d.M(new A()) else d.M(new B()) -> d.M(cond?(Base)new A():new B()); + // is not the same as cond?d.M(new A()): d.M(new B()) on dynamic objects. + var source = @" + public class Base {} + public class A: Base {} + public class B: Base {} + + public int Foo() + { + dynamic d = new object(); + if (true) + return d.M(new A()); + else + return d.M(new B()); + }".WrapInCSharpClass(); + var fixtest = @" + public class Base {} + public class A: Base {} + public class B: Base {} + + public int Foo() + { + dynamic d = new object(); + return true?d.M(new A()):d.M(new B()); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDynamicObjGetsArgsNeverApplied() + { + // arguments on dynamic method calls are never applied even if it would be save. + // see comments above for why dynamic is dangerous. + var source = @" + public int Foo() + { + dynamic d = new object(); + if (true) + return d.M(1,1); + else + return d.M(1,2); + }".WrapInCSharpClass(); + var fixtest = @" + public int Foo() + { + dynamic d = new object(); + return true?d.M(1,1):d.M(1,2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorGetsArgsApplied() + { + var source = @" + public System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1); + else + return new System.Collections.Generic.List(2); + }".WrapInCSharpClass(); + var fixtest = @" + public System.Collections.Generic.List Foo() + { + return new System.Collections.Generic.List(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithIdenticalInitializerGetsArgsApplied() + { + var source = @" + public new System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1) { 1 }; + else + return new System.Collections.Generic.List(2) { 1 }; + }".WrapInCSharpClass(); + var fixtest = @" + public new System.Collections.Generic.List Foo() + { + return new System.Collections.Generic.List(true?1:2) { 1 }; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithDifferentInitializerGetsArgsNotApplied() + { + var source = @" + public System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1) { 1 }; + else + return new System.Collections.Generic.List(2) { 1, 2 }; + }".WrapInCSharpClass(); + var fixtest = @" + public System.Collections.Generic.List Foo() + { + return true?new System.Collections.Generic.List(1) { 1 } : new System.Collections.Generic.List(2) { 1, 2 }; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithDifferentOverloadsGetArgsNotApplied() + { + var source = @" + public class A + { + public A(int i) { } + public A(string s) { } + } + public A Foo() + { + if (true) + return new A(1); + else + return new A(""1""); + }".WrapInCSharpClass(); + var fixtest = @" + public class A + { + public A(int i) { } + public A(string s) { } + } + public A Foo() + { + return true?new A(1):new A(""1""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorOfDifferentObjectsGetArgsNotApplied() + { + var source = @" + public class A + { + public A(int i) { } + } + public class B + { + public B(int i) { } + } + + public Object Foo() + { + if (true) + return new A(1); + else + return new B(2); + }".WrapInCSharpClass(); + var fixtest = @" + public class A + { + public A(int i) { } + } + public class B + { + public B(int i) { } + } + + public Object Foo() + { + return true?(object)new A(1):new B(2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From 1e6d745cac04c93f0bc303b14835df2f63f375a3 Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:04:58 -0700 Subject: [PATCH 232/358] Update grammar in StaticConstructorExceptionAnalyzer.cs #839 --- .../Design/StaticConstructorExceptionAnalyzer.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs index 946cae300..c8a9f2f23 100644 --- a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs @@ -10,13 +10,11 @@ namespace CodeCracker.CSharp.Design [DiagnosticAnalyzer(LanguageNames.CSharp)] public class StaticConstructorExceptionAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Don't throw exception inside static constructors."; - internal const string MessageFormat = "Don't throw exception inside static constructors."; + internal const string Title = "Don't throw exceptions inside static constructors."; + internal const string MessageFormat = "Don't throw exceptions inside static constructors."; internal const string Category = SupportedCategories.Design; - const string Description = "Static constructor are called before the first time a class is used but the " - + "caller doesn't control when exactly.\r\n" - + "Exception thrown in this context force callers to use 'try' block around any useage of the class " - + "and should be avoided."; + const string Description = "Static constructors are called before a class is used for the first time. Exceptions thrown " + + "in static constructors force the use of a try block and should be avoided."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StaticConstructorException.ToDiagnosticId(), @@ -49,4 +47,4 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(Diagnostic.Create(Rule, @throw.GetLocation(), ctor.Identifier.Text)); } } -} \ No newline at end of file +} From 2e74e2698ede0d57426192deed7b5a652eaa3ed8 Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:06:30 -0700 Subject: [PATCH 233/358] Update grammar in StaticConstructorExceptionAnalyzer.vb #839 --- .../Design/StaticConstructorExceptionAnalyzer.vb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb b/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb index 72799cbd9..3cfaab1f3 100644 --- a/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb @@ -9,11 +9,11 @@ Namespace Design Inherits DiagnosticAnalyzer Public Shared ReadOnly Id As String = DiagnosticId.StaticConstructorException.ToDiagnosticId() - Public Const Title As String = "Don't throw exception inside static constructors." + Public Const Title As String = "Don't throw exceptions inside static constructors." Public Const MessageFormat As String = "Don't throw exceptions inside static constructors." Public Const Category As String = SupportedCategories.Design - Public Const Description As String = "Static constructor are called before the first time a class is used but the caller doesn't control when exactly. -Exception thrown in this context forces callers to use 'try' block around any useage of the class and should be avoided." + Public Const Description As String = "Static constructors are called before a class is used for the first time. Exceptions thrown + in static constructors force the use of a try block and should be avoided." Protected Shared Rule As DiagnosticDescriptor = New DiagnosticDescriptor( Id, Title, From 05ef8216052afc705d7de3abc3f4a6c7780cbcae Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:08:11 -0700 Subject: [PATCH 234/358] Update grammar in StaticConstructorExceptionAnalyzer.cs #839 From 089f3a6cff713e81d485d0c5c534b438d9077601 Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:23:19 -0700 Subject: [PATCH 235/358] Update grammar in StaticConstructorExceptionTests.cs #839 --- .../Design/StaticConstructorExceptionTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs b/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs index 5672bd5a9..f6ba9d8a0 100644 --- a/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs @@ -22,7 +22,7 @@ static MyClass() var expected = new DiagnosticResult { Id = DiagnosticId.StaticConstructorException.ToDiagnosticId(), - Message = "Don't throw exception inside static constructors.", + Message = "Don't throw exceptions inside static constructors.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } }; @@ -149,4 +149,4 @@ static MyClass2() await VerifyCSharpFixAllAsync(new string[] { source1, source2 }, new string[] { fixtest1, fixtest2 }); } } -} \ No newline at end of file +} From 0459cc5ef6c1d86e60f4248c40184868b5c44deb Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:48:57 -0700 Subject: [PATCH 236/358] Update grammar in StringBuilderInLoopAnalyzer.cs #839 --- .../CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs index 27427a1f3..60960be01 100644 --- a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs @@ -14,8 +14,7 @@ public class StringBuilderInLoopAnalyzer : DiagnosticAnalyzer internal const string Title = "Don't concatenate strings in loops"; internal const string MessageFormat = "Don't concatenate '{0}' in a loop"; internal const string Category = SupportedCategories.Performance; - const string Description = "Do not concatenate a string on a loop. It will alocate a lot of memory." - + "Use a StringBuilder instead. It will will require less allocation, less garbage collector work, less CPU cycles, and less overall time."; + const string Description = "Don't concatenate strings in a loop. Using a StringBuilder will require less memory and time."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), @@ -84,4 +83,4 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(diagnostic); } } -} \ No newline at end of file +} From 0dc0321d89a6a27da2b02cf119f5e91dc8497bbf Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:50:00 -0700 Subject: [PATCH 237/358] Update grammar in StringBuilderInLoopAnalyzer.vb #839 --- .../CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb index e00b20f13..36c1a1ac1 100644 --- a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb @@ -13,7 +13,7 @@ Namespace Performance Public Const Title As String = "Don't concatenate strings in loops" Public Const MessageFormat As String = "Don't concatenate '{0}' in a loop." Public Const Category As String = SupportedCategories.Performance - Public Const Description As String = "Do not concatenate a string in a loop. It will allocate a lot of memory. Use a StringBuilder instead. It will require less allocation, less garbage collection work, less CPU cycles, and less overall time." + Public Const Description As String = "Don't concatenate strings in a loop. Using a StringBuilder will require less memory and time." Protected Shared Rule As DiagnosticDescriptor = New DiagnosticDescriptor( Id, Title, @@ -71,4 +71,4 @@ Namespace Performance context.ReportDiagnostic(diag) End Sub End Class -End Namespace \ No newline at end of file +End Namespace From 51fbe1cd7ce47e3fd5c1f0d93a70302fb1295e7b Mon Sep 17 00:00:00 2001 From: sdygert Date: Sat, 18 Mar 2017 07:47:05 -0700 Subject: [PATCH 238/358] Update grammar in RemovePrivateMethodNeverUsedAnalyzer.cs #839 --- .../CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs index 40b86f79d..25bd20246 100644 --- a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs @@ -16,7 +16,7 @@ public class RemovePrivateMethodNeverUsedAnalyzer : DiagnosticAnalyzer internal const string Title = "Unused Method"; internal const string Message = "Method is not used."; internal const string Category = SupportedCategories.Usage; - const string Description = "When a private method declared does not used might bring incorrect conclusions."; + const string Description = "Unused private methods can be safely removed as they are unnecessary."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemovePrivateMethodNeverUsed.ToDiagnosticId(), @@ -126,4 +126,4 @@ private static bool IsMainMethodEntryPoint(MethodDeclarationSyntax methodTarget, return true; } } -} \ No newline at end of file +} From d7fe7955f96d2e64a76c00a1982c83dd94282739 Mon Sep 17 00:00:00 2001 From: sdygert Date: Sat, 18 Mar 2017 07:47:31 -0700 Subject: [PATCH 239/358] Update grammar in RemovePrivateMethodNeverUsedAnalyzer.vb #839 --- .../CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb index e1ecd9068..652a83ca7 100644 --- a/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.vb @@ -11,7 +11,7 @@ Namespace Usage Friend Const Title = "Unused Method" Friend Const Message = "Method is not used." - Private Const Description = "When a private method is declared but not used, remove it to avoid confusion." + Private Const Description = "Unused private methods can be safely removed as they are unnecessary." Friend Shared Rule As New DiagnosticDescriptor( DiagnosticId.RemovePrivateMethodNeverUsed.ToDiagnosticId(), From b71177cbde7855104f2334e9d5c8b3cf815c377c Mon Sep 17 00:00:00 2001 From: sdygert Date: Sat, 18 Mar 2017 07:54:39 -0700 Subject: [PATCH 240/358] Update grammar in RegexAnalyzer.cs #839 --- src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs index 6ce7c1a5d..41393ac96 100644 --- a/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RegexAnalyzer.cs @@ -10,11 +10,10 @@ namespace CodeCracker.CSharp.Usage [DiagnosticAnalyzer(LanguageNames.CSharp)] public class RegexAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Your Regex expression is wrong"; + internal const string Title = "Your regex expression is incorrect"; internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Naming; - const string Description = "This diagnostic compile the Regex expression and trigger if the compilation fail " - + "by throwing an exception."; + const string Description = "There is an error in your regex expression."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.Regex.ToDiagnosticId(), @@ -63,4 +62,4 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) } } } -} \ No newline at end of file +} From 0b1a1783aa94fa2a09622117036b42677c8727cc Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:48:57 -0700 Subject: [PATCH 241/358] Update grammar in StringBuilderInLoopAnalyzer.cs #839 --- .../CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs index 27427a1f3..60960be01 100644 --- a/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/StringBuilderInLoopAnalyzer.cs @@ -14,8 +14,7 @@ public class StringBuilderInLoopAnalyzer : DiagnosticAnalyzer internal const string Title = "Don't concatenate strings in loops"; internal const string MessageFormat = "Don't concatenate '{0}' in a loop"; internal const string Category = SupportedCategories.Performance; - const string Description = "Do not concatenate a string on a loop. It will alocate a lot of memory." - + "Use a StringBuilder instead. It will will require less allocation, less garbage collector work, less CPU cycles, and less overall time."; + const string Description = "Don't concatenate strings in a loop. Using a StringBuilder will require less memory and time."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), @@ -84,4 +83,4 @@ private static void AnalyzeAssignment(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(diagnostic); } } -} \ No newline at end of file +} From 7b3122aefb4a3f1ff184d3ef0f3a85af8be2e1c0 Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:50:00 -0700 Subject: [PATCH 242/358] Update grammar in StringBuilderInLoopAnalyzer.vb #839 --- .../CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb index e00b20f13..36c1a1ac1 100644 --- a/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Performance/StringBuilderInLoopAnalyzer.vb @@ -13,7 +13,7 @@ Namespace Performance Public Const Title As String = "Don't concatenate strings in loops" Public Const MessageFormat As String = "Don't concatenate '{0}' in a loop." Public Const Category As String = SupportedCategories.Performance - Public Const Description As String = "Do not concatenate a string in a loop. It will allocate a lot of memory. Use a StringBuilder instead. It will require less allocation, less garbage collection work, less CPU cycles, and less overall time." + Public Const Description As String = "Don't concatenate strings in a loop. Using a StringBuilder will require less memory and time." Protected Shared Rule As DiagnosticDescriptor = New DiagnosticDescriptor( Id, Title, @@ -71,4 +71,4 @@ Namespace Performance context.ReportDiagnostic(diag) End Sub End Class -End Namespace \ No newline at end of file +End Namespace From 1699a3178249cee656541bd3d885a30f519dec2c Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:04:58 -0700 Subject: [PATCH 243/358] Update grammar in StaticConstructorExceptionAnalyzer.cs #839 --- .../Design/StaticConstructorExceptionAnalyzer.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs index 946cae300..c8a9f2f23 100644 --- a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionAnalyzer.cs @@ -10,13 +10,11 @@ namespace CodeCracker.CSharp.Design [DiagnosticAnalyzer(LanguageNames.CSharp)] public class StaticConstructorExceptionAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Don't throw exception inside static constructors."; - internal const string MessageFormat = "Don't throw exception inside static constructors."; + internal const string Title = "Don't throw exceptions inside static constructors."; + internal const string MessageFormat = "Don't throw exceptions inside static constructors."; internal const string Category = SupportedCategories.Design; - const string Description = "Static constructor are called before the first time a class is used but the " - + "caller doesn't control when exactly.\r\n" - + "Exception thrown in this context force callers to use 'try' block around any useage of the class " - + "and should be avoided."; + const string Description = "Static constructors are called before a class is used for the first time. Exceptions thrown " + + "in static constructors force the use of a try block and should be avoided."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.StaticConstructorException.ToDiagnosticId(), @@ -49,4 +47,4 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(Diagnostic.Create(Rule, @throw.GetLocation(), ctor.Identifier.Text)); } } -} \ No newline at end of file +} From c1d348985b116736f9ba1092ac05d1de1b47d269 Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:06:30 -0700 Subject: [PATCH 244/358] Update grammar in StaticConstructorExceptionAnalyzer.vb #839 --- .../Design/StaticConstructorExceptionAnalyzer.vb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb b/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb index 72799cbd9..3cfaab1f3 100644 --- a/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb +++ b/src/VisualBasic/CodeCracker/Design/StaticConstructorExceptionAnalyzer.vb @@ -9,11 +9,11 @@ Namespace Design Inherits DiagnosticAnalyzer Public Shared ReadOnly Id As String = DiagnosticId.StaticConstructorException.ToDiagnosticId() - Public Const Title As String = "Don't throw exception inside static constructors." + Public Const Title As String = "Don't throw exceptions inside static constructors." Public Const MessageFormat As String = "Don't throw exceptions inside static constructors." Public Const Category As String = SupportedCategories.Design - Public Const Description As String = "Static constructor are called before the first time a class is used but the caller doesn't control when exactly. -Exception thrown in this context forces callers to use 'try' block around any useage of the class and should be avoided." + Public Const Description As String = "Static constructors are called before a class is used for the first time. Exceptions thrown + in static constructors force the use of a try block and should be avoided." Protected Shared Rule As DiagnosticDescriptor = New DiagnosticDescriptor( Id, Title, From 67e4081bd90b48f57365fa28ed85879805e9e2e1 Mon Sep 17 00:00:00 2001 From: sdygert Date: Wed, 15 Mar 2017 19:23:19 -0700 Subject: [PATCH 245/358] Update grammar in StaticConstructorExceptionTests.cs #839 --- .../Design/StaticConstructorExceptionTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs b/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs index 5672bd5a9..f6ba9d8a0 100644 --- a/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs @@ -22,7 +22,7 @@ static MyClass() var expected = new DiagnosticResult { Id = DiagnosticId.StaticConstructorException.ToDiagnosticId(), - Message = "Don't throw exception inside static constructors.", + Message = "Don't throw exceptions inside static constructors.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } }; @@ -149,4 +149,4 @@ static MyClass2() await VerifyCSharpFixAllAsync(new string[] { source1, source2 }, new string[] { fixtest1, fixtest2 }); } } -} \ No newline at end of file +} From 62ecc7729f766f781a3eb07da4120a78eb57e4ca Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 19 Mar 2017 12:25:54 -0300 Subject: [PATCH 246/358] Update dependencies This will enable tests to run in VS again, including live unit testing. We had to roll back Microsoft.CodeAnalysis.Analyzers, because it conflicted with other packages, we might have to upgrade them all to 1.1.0 so that we don't get those nasty build warnings. --- build.targets.ps1 | 2 +- src/CSharp/CodeCracker/CodeCracker.csproj | 8 ++-- src/CSharp/CodeCracker/packages.config | 4 +- .../CodeCracker.Common.csproj | 8 ++-- src/Common/CodeCracker.Common/packages.config | 4 +- .../CodeCracker/CodeCracker.vbproj | 8 ++-- src/VisualBasic/CodeCracker/packages.config | 4 +- .../CodeCracker.Test/CodeCracker.Test.csproj | 45 ++++++++--------- test/CSharp/CodeCracker.Test/packages.config | 22 ++++----- .../CodeCracker.Test.Common.csproj | 48 +++++++------------ .../CodeCracker.Test.Common/packages.config | 24 +++++----- .../CodeCracker.Test/CodeCracker.Test.vbproj | 41 +++++++--------- .../CodeCracker.Test/packages.config | 22 ++++----- 13 files changed, 106 insertions(+), 134 deletions(-) diff --git a/build.targets.ps1 b/build.targets.ps1 index 42ee817bb..430e72c21 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -23,7 +23,7 @@ Properties { $testDirVB = "$testDir\VisualBasic\CodeCracker.Test\bin\Release" $logDir = "$rootDir\log" $outputXml = "$logDir\CodeCoverageResults.xml" - $reportGeneratorExe = "$packagesDir\ReportGenerator.2.4.4.0\tools\ReportGenerator.exe" + $reportGeneratorExe = "$packagesDir\ReportGenerator.2.5.6\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" $coverallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" $isRelease = $isAppVeyor -and (($env:APPVEYOR_REPO_BRANCH -eq "release") -or ($env:APPVEYOR_REPO_TAG -eq "true")) diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index e1a60a05e..762e6c620 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -221,10 +221,10 @@ - - - - + + + + diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index 26624b6d1..d1bbcab2c 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,7 +1,7 @@  - - + + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 6ecee6f01..3426e7d12 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -70,10 +70,10 @@ - - - - + + + + diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index 564e6399a..d8681f9ca 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,7 +1,7 @@  - - + + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index ba1b36a08..e2deff9b9 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -162,10 +162,10 @@ - - - - + + + + diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index 06a0521ef..20b3df7df 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,7 +1,7 @@  - - + + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index b17ba4a79..e0e64dccb 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -1,6 +1,6 @@  - + Debug AnyCPU @@ -40,13 +40,11 @@ false - - ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.dll - True + + ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.dll - - ..\..\..\packages\FluentAssertions.4.3.2\lib\net45\FluentAssertions.Core.dll - True + + ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.Core.dll ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll @@ -68,9 +66,8 @@ ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll True - - ..\..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll @@ -108,20 +105,16 @@ - ..\..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll - True + ..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - - ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll - True + + ..\..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll - - ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll - True + + ..\..\..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll - - ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll - True + + ..\..\..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll @@ -235,17 +228,17 @@ - - - - + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + - \ No newline at end of file + From 099159dfedd4c57105d26a196bde2c3c5833c902 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 19 Mar 2017 12:47:27 -0300 Subject: [PATCH 258/358] Fix xunit console location in script --- build.targets.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.targets.ps1 b/build.targets.ps1 index 430e72c21..d5c0cc057 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -15,7 +15,7 @@ Properties { $nupkgPathCS = "$rootDir\src\CSharp\CodeCracker.CSharp.{0}.nupkg" $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" $nupkgPathJoint = "$rootDir\CodeCracker.{0}.nupkg" - $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" + $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe" $openCoverExe = "$packagesDir\OpenCover.4.6.519\tools\OpenCover.Console.exe" $testDllCS = "CodeCracker.Test.CSharp.dll" $testDllVB = "CodeCracker.Test.VisualBasic.dll" @@ -223,4 +223,4 @@ function RunTestWithCoverage($fullTestDllPaths) { Write-Host -ForegroundColor DarkBlue "Uploading coverage report to Coveralls.io" Exec { . $coverallsNetExe --opencover $outputXml --full-sources } } -} \ No newline at end of file +} From ac872ca9ebdd3db4aece2c60ef9e80b4173c42f9 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 19 Mar 2017 13:09:32 -0300 Subject: [PATCH 259/358] Fix test run scripts --- runTestsCS.ps1 | 2 +- runTestsVB.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runTestsCS.ps1 b/runTestsCS.ps1 index 2131ad77c..930bdccb4 100644 --- a/runTestsCS.ps1 +++ b/runTestsCS.ps1 @@ -2,7 +2,7 @@ param([String]$testClass) $testDllDirPath = "$PSScriptRoot\test\CSharp\CodeCracker.Test\bin\Debug\" $testDllFileName = "CodeCracker.Test.CSharp.dll" $testDllFullFileName = "$testDllDirPath$testDllFileName" -$xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" +$xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe" if (!(gcm nodemon -ErrorAction Ignore)) { Write-Host -ForegroundColor DarkRed 'Nodemon not found, install it with npm: `npm i -g nodemon`' diff --git a/runTestsVB.ps1 b/runTestsVB.ps1 index 2da22c936..b2d53d619 100644 --- a/runTestsVB.ps1 +++ b/runTestsVB.ps1 @@ -2,7 +2,7 @@ param([String]$testClass) $testDllDirPath = "$PSScriptRoot\test\VisualBasic\CodeCracker.Test\bin\Debug\" $testDllFileName = "CodeCracker.Test.VisualBasic.dll" $testDllFullFileName = "$testDllDirPath$testDllFileName" -$xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.1.0\tools\xunit.console.x86.exe" +$xunitConsole = "$PSScriptRoot\packages\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe" if (!(gcm nodemon -ErrorAction Ignore)) { Write-Host -ForegroundColor DarkRed 'Nodemon not found, install it with npm: `npm i -g nodemon`' From 8247e6509729acd2513ab478bc5ac2fee7ce48f8 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 19 Mar 2017 13:09:59 -0300 Subject: [PATCH 260/358] Do not raise a diagnostic for disposables with yield return Fixes #877 --- .../Extensions/CSharpAnalyzerExtensions.cs | 7 ++++++ .../DisposableVariableNotDisposedAnalyzer.cs | 6 +++-- .../DisposableVariableNotDisposedTests.cs | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 50065c3d7..8a248fad1 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -469,6 +469,13 @@ public static IEnumerable OfKind(this IEnumerable node yield return (TNode)node; } + public static IEnumerable OfKind(this IEnumerable nodes, params SyntaxKind[] kinds) where TNode : SyntaxNode + { + foreach (var node in nodes) + if (node.IsAnyKind(kinds)) + yield return (TNode)node; + } + public static IEnumerable OfKind(this IEnumerable nodes, SyntaxKind kind) where TNode : SyntaxNode { foreach (var node in nodes) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index e53f40891..75ed943f4 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -43,7 +43,7 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) while (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CastExpression)) topSyntaxNode = topSyntaxNode.Parent; - if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ReturnStatement, SyntaxKind.UsingStatement)) + if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ReturnStatement, SyntaxKind.UsingStatement, SyntaxKind.YieldReturnStatement)) return; if (topSyntaxNode.Ancestors().Any(i => i.IsAnyKind( @@ -148,10 +148,12 @@ private static bool IsReturned(MethodDeclarationSyntax method, StatementSyntax s body = method.Body; } if (body == null) return true; - var returnExpressions = body.DescendantNodes().OfType().Select(r => r.Expression); var returnTypeSymbol = methodSymbol?.ReturnType; if (returnTypeSymbol == null) return false; if (returnTypeSymbol.SpecialType == SpecialType.System_Void) return false; + var bodyDescendantNodes = body.DescendantNodes().ToList(); + var returnExpressions = bodyDescendantNodes.OfType().Select(r => r.Expression).Union( + bodyDescendantNodes.OfKind(SyntaxKind.YieldReturnStatement).Select(yr => yr.Expression)); var isReturning = returnExpressions.Any(returnExpression => { var returnSymbol = semanticModel.GetSymbolInfo(returnExpression).Symbol; diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index a07c13405..83564c0be 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -123,6 +123,29 @@ public async Task VariableNotDisposableDoesNotCreateDiagnostic() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task IteratorWithDirectReturnDoesNotCreateDiagnostic() + { + var source = @" +public System.Collections.Generic.IEnumerable Foo() +{ + yield return new System.IO.MemoryStream(); +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task IteratorWithIndirectReturnDoesNotCreateDiagnostic() + { + var source = @" +public System.Collections.Generic.IEnumerable Foo() +{ + var disposable = new System.IO.MemoryStream(); + yield return disposable; +}".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task DisposableVariableCreatesDiagnostic() { From f93c65c84f344218e0e100074c5e314168364f1c Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 19 Mar 2017 13:40:53 -0300 Subject: [PATCH 261/358] Disregard disposables in arrow expressions Fixes #880 --- .../Usage/DisposableVariableNotDisposedAnalyzer.cs | 1 + .../Usage/DisposableVariableNotDisposedTests.cs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index 75ed943f4..2a4b4c32f 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -47,6 +47,7 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) return; if (topSyntaxNode.Ancestors().Any(i => i.IsAnyKind( + SyntaxKind.ArrowExpressionClause, SyntaxKind.ThisConstructorInitializer, SyntaxKind.BaseConstructorInitializer, SyntaxKind.ObjectCreationExpression))) diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index 83564c0be..d1ad9d3e9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -123,6 +123,13 @@ public async Task VariableNotDisposableDoesNotCreateDiagnostic() await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task ReturnOnExpressionBodiedMembersDoNotCreateDiagnostic() + { + var source = @"public static System.IO.MemoryStream Foo() => new System.IO.MemoryStream();".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task IteratorWithDirectReturnDoesNotCreateDiagnostic() { From 5c769f3431f3fbd1e867069b87fc1409d6877292 Mon Sep 17 00:00:00 2001 From: sdygert Date: Sun, 19 Mar 2017 13:39:28 -0700 Subject: [PATCH 262/358] Update grammar in TaskNameAsyncAnalyzer.cs #839 --- src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs index d90d22915..6c0f8997c 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs @@ -10,10 +10,10 @@ namespace CodeCracker.CSharp.Style [DiagnosticAnalyzer(LanguageNames.CSharp)] public class TaskNameAsyncAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Async method can be terminating with 'Async' name."; + internal const string Title = "Asynchronous method can be terminated with the 'Async' keyword."; internal const string MessageFormat = "Change method name to {0}"; internal const string Category = SupportedCategories.Style; - const string Description = "Async method can be terminating with 'Async' name."; + const string Description = "Asynchronous method can be terminated with the 'Async' keyword."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.TaskNameAsync.ToDiagnosticId(), @@ -55,4 +55,4 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(diag); } } -} \ No newline at end of file +} From c3402230b1fde51ae52837a27469fc57d4f0509b Mon Sep 17 00:00:00 2001 From: sdygert Date: Sun, 19 Mar 2017 13:50:01 -0700 Subject: [PATCH 263/358] Update grammar in EmptyObjectInitializerAnalyzer.cs #839 --- .../CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs b/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs index 7597ea48c..1ae23376f 100644 --- a/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/EmptyObjectInitializerAnalyzer.cs @@ -12,8 +12,7 @@ public class EmptyObjectInitializerAnalyzer : DiagnosticAnalyzer internal const string Title = "Empty Object Initializer"; internal const string MessageFormat = "{0}"; internal const string Category = SupportedCategories.Style; - const string Description = "An empty object initializer doesn't add any information and only clutter the code.\r\n" - + "If there is no member to initialize, prefer using the standard constructor syntax."; + const string Description = "An object initializer without any arguments can be replaced with the standard constructor syntax."; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.EmptyObjectInitializer.ToDiagnosticId(), @@ -38,9 +37,9 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (objectCreation.Initializer != null && !objectCreation.Initializer.Expressions.Any()) { - var diagnostic = Diagnostic.Create(Rule, objectCreation.Initializer.OpenBraceToken.GetLocation(), "Remove empty object initializer."); + var diagnostic = Diagnostic.Create(Rule, objectCreation.Initializer.OpenBraceToken.GetLocation(), "Remove the empty object initializer."); context.ReportDiagnostic(diagnostic); } } } -} \ No newline at end of file +} From fafd44dc44387d31936c9b8cac50ba20fb54f138 Mon Sep 17 00:00:00 2001 From: sdygert Date: Sun, 19 Mar 2017 13:50:21 -0700 Subject: [PATCH 264/358] Update grammar in EmptyObjectInitializerTests.cs #839 --- .../CodeCracker.Test/Style/EmptyObjectInitializerTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs index a32dccc61..129824e22 100644 --- a/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs @@ -14,7 +14,7 @@ public async Task EmptyObjectInitializerTriggersFix() var expected = new DiagnosticResult { Id = DiagnosticId.EmptyObjectInitializer.ToDiagnosticId(), - Message = "Remove empty object initializer.", + Message = "Remove the empty object initializer.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 1, 15) } }; @@ -54,4 +54,4 @@ public async Task AbsenceOfObjectInitializerIsIgnored() await VerifyCSharpHasNoDiagnosticsAsync(code); } } -} \ No newline at end of file +} From 6d7ad2139631d24555d23aae321b8e2be210b728 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 19 Mar 2017 22:20:13 -0300 Subject: [PATCH 265/358] Update changelog --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8af91802e..1b460cecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,15 @@ ## [Unreleased](https://github.com/code-cracker/code-cracker/tree/HEAD) -[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.2...HEAD) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.3...HEAD) -**Closed issues:** +## [v1.0.3](https://github.com/code-cracker/code-cracker/tree/v1.0.3) (2017-03-20) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.2...v1.0.3) + +**Fixed bugs:** +- BUG: CC0022 DisposableVariableNotDisposedAnalyzer: False positive for expression bodied members [\#880](https://github.com/code-cracker/code-cracker/issues/880) +- BUG: CC0022 DisposableVariableNotDisposedAnalyzer: False positive in iterator methods [\#877](https://github.com/code-cracker/code-cracker/issues/877) ## [v1.0.2](https://github.com/code-cracker/code-cracker/tree/v1.0.2) (2017-03-12) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.1...v1.0.2) From 02bbf094a2f92e93e527758b6cd2f5bec4347dc1 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Mon, 20 Mar 2017 18:05:43 +0100 Subject: [PATCH 266/358] Ported analyzer and codefixprovider from https://github.com/ifpanalytics/Ifp.Analyzers/ --- .../CodeCracker.Vsix/CodeCracker.Vsix.csproj | 5 +- src/CSharp/CodeCracker/CodeCracker.csproj | 2 + .../Extensions/CSharpAnalyzerExtensions.cs | 5 + ...placeWithGetterOnlyAutoPropertyAnalyzer.cs | 77 +++++ ...thGetterOnlyAutoPropertyCodeFixProvider.cs | 140 ++++++++ src/Common/CodeCracker.Common/DiagnosticId.cs | 1 + .../Properties/Resources.Designer.cs | 126 ++++--- .../Properties/Resources.resx | 12 + .../CodeCracker.Test/CodeCracker.Test.csproj | 1 + .../ReplaceWithGetterOnlyAutoPropertyTests.cs | 325 ++++++++++++++++++ 10 files changed, 646 insertions(+), 48 deletions(-) create mode 100644 src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs create mode 100644 src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs create mode 100644 test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj index 12f744c47..7dde1ebf3 100644 --- a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj @@ -1,14 +1,13 @@  - + - 15.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - 15.0 diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 19bb1a9e7..a6d7d52d7 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -67,6 +67,8 @@ + + diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 8a248fad1..0ccb8b5a6 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -17,12 +17,17 @@ public static void RegisterSyntaxNodeAction(this AnalysisCont public static void RegisterCompilationStartAction(this AnalysisContext context, LanguageVersion greaterOrEqualThanLanguageVersion, Action registrationAction) => context.RegisterCompilationStartAction(compilationContext => compilationContext.RunIfCSharpVersionOrGreater(greaterOrEqualThanLanguageVersion, () => registrationAction?.Invoke(compilationContext))); + + public static void RegisterSymbolAction(this AnalysisContext context, LanguageVersion greaterOrEqualThanLanguageVersion, Action registrationAction, params SymbolKind[] symbolKinds) => + context.RegisterSymbolAction(compilationContext => compilationContext.RunIfCSharpVersionOrGreater(greaterOrEqualThanLanguageVersion, () => registrationAction?.Invoke(compilationContext)), symbolKinds); #pragma warning disable RS1012 private static void RunIfCSharpVersionOrGreater(this CompilationStartAnalysisContext context, LanguageVersion greaterOrEqualThanLanguageVersion, Action action) => context.Compilation.RunIfCSharpVersionOrGreater(action, greaterOrEqualThanLanguageVersion); #pragma warning restore RS1012 private static void RunIfCSharpVersionOrGreater(this Compilation compilation, Action action, LanguageVersion greaterOrEqualThanLanguageVersion) => (compilation as CSharpCompilation)?.LanguageVersion.RunIfCSharpVersionGreater(action, greaterOrEqualThanLanguageVersion); + private static void RunIfCSharpVersionOrGreater(this SymbolAnalysisContext context, LanguageVersion greaterOrEqualThanLanguageVersion, Action action) => + context.Compilation.RunIfCSharpVersionOrGreater(action, greaterOrEqualThanLanguageVersion); private static void RunIfCSharpVersionGreater(this LanguageVersion languageVersion, Action action, LanguageVersion greaterOrEqualThanLanguageVersion) { diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs new file mode 100644 index 000000000..b9d16cc4a --- /dev/null +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs @@ -0,0 +1,77 @@ +using CodeCracker.Properties; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeCracker.CSharp.Refactoring +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ReplaceWithGetterOnlyAutoPropertyAnalyzer : DiagnosticAnalyzer + { + internal const string Category = SupportedCategories.Refactoring; + internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.ReplaceWithGetterOnlyAutoPropertyAnalyzer_Title), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.ReplaceWithGetterOnlyAutoPropertyAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.ReplaceWithGetterOnlyAutoPropertyAnalyzer_MessageFormat), Resources.ResourceManager, typeof(Resources)); + + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Title, + MessageFormat, + Category, + DiagnosticSeverity.Hidden, + isEnabledByDefault: true, + description: Description, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.ReplaceWithGetterOnlyAutoProperty)); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override void Initialize(AnalysisContext context) + { + context.RegisterSymbolAction(LanguageVersion.CSharp6, AnalyzeSymbol, SymbolKind.Property); + } + + private static void AnalyzeSymbol(SymbolAnalysisContext context) + { + if (context.IsGenerated()) return; + var namedTypeSymbol = (IPropertySymbol)context.Symbol; + var properties = GetPropsWithOnlyGettersAndReadonlyBackingField(namedTypeSymbol, context); + if (properties == null) return; + var diagnostic = Diagnostic.Create(Rule, properties.Item1.Locations[0], properties.Item1.Name); + context.ReportDiagnostic(diagnostic); + } + private static Tuple GetPropsWithOnlyGettersAndReadonlyBackingField(IPropertySymbol propertySymbol, SymbolAnalysisContext context) + { + SemanticModel model = null; + if (!propertySymbol.IsReadOnly || propertySymbol.IsStatic || !propertySymbol.CanBeReferencedByName) return null; + var getMethod = propertySymbol.GetMethod; + if (getMethod == null) return null; + var reference = getMethod.DeclaringSyntaxReferences.FirstOrDefault(); + if (reference == null) return null; + var declaration = reference.GetSyntax(context.CancellationToken) as AccessorDeclarationSyntax; + if (declaration?.Body == null) return null; + var returnNode = declaration.Body.ChildNodes().FirstOrDefault(); + if (returnNode?.Kind() != SyntaxKind.ReturnStatement) return null; + var fieldNode = returnNode.ChildNodes().FirstOrDefault(); + if (fieldNode == null) return null; + if (fieldNode.Kind() == SyntaxKind.SimpleMemberAccessExpression) + fieldNode = (fieldNode as MemberAccessExpressionSyntax).Name; + if (fieldNode.Kind() != SyntaxKind.IdentifierName) return null; + model = model ?? context.Compilation.GetSemanticModel(fieldNode.SyntaxTree); + var symbolInfo = model.GetSymbolInfo(fieldNode).Symbol as IFieldSymbol; + if (symbolInfo != null && + symbolInfo.IsReadOnly && + (symbolInfo.DeclaredAccessibility == Accessibility.Private || symbolInfo.DeclaredAccessibility == Accessibility.NotApplicable) && + symbolInfo.ContainingType == propertySymbol.ContainingType && + symbolInfo.Type.Equals(propertySymbol.Type)) + + return new Tuple(propertySymbol, symbolInfo); + return null; + } + } +} diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs new file mode 100644 index 000000000..c67c076ed --- /dev/null +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs @@ -0,0 +1,140 @@ +using CodeCracker.Properties; +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 Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeCracker.CSharp.Refactoring +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ReplaceWithGetterOnlyAutoPropertyCodeFixProvider)), Shared] + public class ReplaceWithGetterOnlyAutoPropertyCodeFixProvider : CodeFixProvider + { + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId()); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = context.Diagnostics.First(); + var diagnosticSpan = diagnostic.Location.SourceSpan; + + context.RegisterCodeFix( + CodeAction.Create( + title: Resources.ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title, + createChangedDocument: c => ReplaceByGetterOnlyAutoPropertyAsync(context.Document, diagnosticSpan, c), + equivalenceKey: nameof(ReplaceWithGetterOnlyAutoPropertyCodeFixProvider)), + diagnostic); + return Task.FromResult(0); + } + private async static Task ReplaceByGetterOnlyAutoPropertyAsync(Document document, TextSpan propertyDeclarationSpan, CancellationToken cancellationToken) + { + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); + var root = await document.GetSyntaxRootAsync(cancellationToken); + var token = root.FindToken(propertyDeclarationSpan.Start); + var property = token.Parent.AncestorsAndSelf().OfType().First(); + var fieldVariableDeclaratorSyntax = await GetFieldDeclarationSyntaxNodeAsync(property, cancellationToken, semanticModel); + if (fieldVariableDeclaratorSyntax == null) return document; + var fieldReferences = await GetFieldReferencesAsync(fieldVariableDeclaratorSyntax, cancellationToken, semanticModel); + var nodesToUpdate = fieldReferences.Cast().Union(Enumerable.Repeat(property, 1)).Union(Enumerable.Repeat(fieldVariableDeclaratorSyntax, 1)); + var newRoot = FixWithTrackNode(root, property, fieldVariableDeclaratorSyntax, nodesToUpdate); + var resultDocument = document.WithSyntaxRoot(newRoot); + return resultDocument; + } + + private static SyntaxNode FixWithTrackNode(SyntaxNode root, PropertyDeclarationSyntax property, VariableDeclaratorSyntax fieldVariableDeclaratorSyntax, IEnumerable nodesToUpdate) + { + var newRoot = root.TrackNodes(nodesToUpdate); + var fieldReferences = newRoot.GetCurrentNodes(nodesToUpdate.OfType()); + foreach (var identifier in fieldReferences) + { + var newIdentifier = SyntaxFactory.IdentifierName(property.Identifier.Text); + newIdentifier = newIdentifier.WithLeadingTrivia(identifier.GetLeadingTrivia()).WithTrailingTrivia(identifier.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation); + newRoot = newRoot.ReplaceNode(identifier, newIdentifier); + } + var prop = newRoot.GetCurrentNode(nodesToUpdate.OfType().Single()); + var fieldInitilization = GetFieldInitialization(fieldVariableDeclaratorSyntax); + var getter = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + var accessorList = SyntaxFactory.AccessorList( + SyntaxFactory.List(new[] { + getter + })); + var newProp = prop.WithAccessorList(accessorList); + if (fieldInitilization != null) + newProp = newProp.WithInitializer(fieldInitilization).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + newProp = newProp.WithLeadingTrivia(prop.GetLeadingTrivia()).WithTrailingTrivia(prop.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation); + newRoot = newRoot.ReplaceNode(prop, newProp); + var variableDeclarator = newRoot.GetCurrentNode(nodesToUpdate.OfType().Single()); + var declaration = variableDeclarator.AncestorsAndSelf().OfType().First(); + if (declaration.Variables.Count == 1) + { + var fieldDeclaration = declaration.AncestorsAndSelf().OfType().First(); + newRoot = newRoot.RemoveNode(fieldDeclaration, SyntaxRemoveOptions.KeepUnbalancedDirectives); + } + else + newRoot = newRoot.RemoveNode(variableDeclarator, SyntaxRemoveOptions.KeepUnbalancedDirectives); + return newRoot; + } + + private static EqualsValueClauseSyntax GetFieldInitialization(VariableDeclaratorSyntax fieldVariableDeclaratorSyntax) + { + var declaration = fieldVariableDeclaratorSyntax.AncestorsAndSelf().OfType().First(); + if (declaration == null) + return null; + var variableWithPotentialInitializer = declaration.Variables.SkipWhile(v => v != fieldVariableDeclaratorSyntax).FirstOrDefault(v => v.Initializer != null); + if (variableWithPotentialInitializer == null) + return null; + var initializer = variableWithPotentialInitializer.Initializer; + return initializer; + } + + private static async Task> GetFieldReferencesAsync(VariableDeclaratorSyntax fieldDeclarationSyntax, CancellationToken cancellationToken, SemanticModel semanticModel) + { + HashSet fieldReferences = null; + var fieldSymbol = semanticModel.GetDeclaredSymbol(fieldDeclarationSyntax); + var declaredInType = fieldSymbol.ContainingType; + foreach (var reference in declaredInType.DeclaringSyntaxReferences) + { + var allNodesOfType = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); + var allFieldReferenceNodes = from n in allNodesOfType.OfType() + where n.Identifier.ValueText == fieldDeclarationSyntax.Identifier.ValueText + select n; + foreach (var fieldReference in allFieldReferenceNodes) + { + var parentExpression = fieldReference.Parent; + if (parentExpression is MemberAccessExpressionSyntax) + parentExpression = parentExpression.Parent; + if (parentExpression is AssignmentExpressionSyntax) + { + var assignmentEx = (AssignmentExpressionSyntax)parentExpression; + if (assignmentEx.Left == fieldReference || assignmentEx.Left == fieldReference.Parent) + (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); + } + } + } + return fieldReferences ?? Enumerable.Empty(); + } + + private static async Task GetFieldDeclarationSyntaxNodeAsync(PropertyDeclarationSyntax propertyDeclaration, CancellationToken cancellationToken, SemanticModel semanticModel) + { + var propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); + var declaredProperty = propertySymbol.GetMethod.DeclaringSyntaxReferences.FirstOrDefault(); + var declaredPropertySyntax = await declaredProperty.GetSyntaxAsync(cancellationToken); + var fieldIdentifier = declaredPropertySyntax.DescendantNodesAndTokens().FirstOrDefault(n => n.IsNode && n.Kind() == SyntaxKind.IdentifierName); + var fieldInfo = semanticModel.GetSymbolInfo(fieldIdentifier.AsNode()); + var fieldDeclaration = fieldInfo.Symbol.DeclaringSyntaxReferences.FirstOrDefault(); + var fieldDeclarationSyntax = await fieldDeclaration.GetSyntaxAsync(); + return fieldDeclarationSyntax as VariableDeclaratorSyntax; + } + } +} diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index e60eb36f8..a0d12446a 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -83,5 +83,6 @@ public enum DiagnosticId UnnecessaryToStringInStringConcatenation = 118, SwitchCaseWithoutDefault = 120, ReadOnlyComplexTypes = 121, + ReplaceWithGetterOnlyAutoProperty=125, } } \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs index a9cc2ac5f..318839da0 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs +++ b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. // //------------------------------------------------------------------------------ @@ -14,12 +14,12 @@ namespace CodeCracker.Properties { /// - /// A strongly-typed resource class, for looking up localized strings, etc. + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -34,7 +34,7 @@ internal Resources() { } /// - /// Returns the cached ResourceManager instance used by this class. + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { @@ -48,8 +48,8 @@ internal Resources() { } /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { @@ -62,7 +62,7 @@ internal Resources() { } /// - /// Looks up a localized string similar to String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string.. + /// Sucht eine lokalisierte Zeichenfolge, die String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string. ähnelt. /// public static string ConsoleWriteLineAnalyzer_Description { get { @@ -71,7 +71,7 @@ public static string ConsoleWriteLineAnalyzer_Description { } /// - /// Looks up a localized string similar to Use string interpolation. + /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation ähnelt. /// public static string ConsoleWriteLineAnalyzer_MessageFormat { get { @@ -80,7 +80,7 @@ public static string ConsoleWriteLineAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use string interpolation instead of arguments on Console.WriteLine. + /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation instead of arguments on Console.WriteLine ähnelt. /// public static string ConsoleWriteLineAnalyzer_Title { get { @@ -89,7 +89,7 @@ public static string ConsoleWriteLineAnalyzer_Title { } /// - /// Looks up a localized string similar to Change to string interpolation. + /// Sucht eine lokalisierte Zeichenfolge, die Change to string interpolation ähnelt. /// public static string ConsoleWriteLineCodeFixProvider_Title { get { @@ -98,7 +98,7 @@ public static string ConsoleWriteLineCodeFixProvider_Title { } /// - /// Looks up a localized string similar to An empty catch block suppress all errors and shouldn't be used.\r\nIf the error is expected consider logging it or changing the control flow such that it is explicit.. + /// Sucht eine lokalisierte Zeichenfolge, die An empty catch block suppress all errors and shouldn't be used.\r\nIf the error is expected consider logging it or changing the control flow such that it is explicit. ähnelt. /// public static string EmptyCatchBlockAnalyzer_Description { get { @@ -107,7 +107,7 @@ public static string EmptyCatchBlockAnalyzer_Description { } /// - /// Looks up a localized string similar to Empty Catch Block.. + /// Sucht eine lokalisierte Zeichenfolge, die Empty Catch Block. ähnelt. /// public static string EmptyCatchBlockAnalyzer_Message { get { @@ -116,7 +116,7 @@ public static string EmptyCatchBlockAnalyzer_Message { } /// - /// Looks up a localized string similar to Catch block cannot be empty. + /// Sucht eine lokalisierte Zeichenfolge, die Catch block cannot be empty ähnelt. /// public static string EmptyCatchBlockAnalyzer_Title { get { @@ -125,7 +125,7 @@ public static string EmptyCatchBlockAnalyzer_Title { } /// - /// Looks up a localized string similar to Insert Exception class to Catch. + /// Sucht eine lokalisierte Zeichenfolge, die Insert Exception class to Catch ähnelt. /// public static string EmptyCatchBlockCodeFixProvider_InsertException { get { @@ -134,7 +134,7 @@ public static string EmptyCatchBlockCodeFixProvider_InsertException { } /// - /// Looks up a localized string similar to Remove Empty Catch Block. + /// Sucht eine lokalisierte Zeichenfolge, die Remove Empty Catch Block ähnelt. /// public static string EmptyCatchBlockCodeFixProvider_Remove { get { @@ -143,7 +143,7 @@ public static string EmptyCatchBlockCodeFixProvider_Remove { } /// - /// Looks up a localized string similar to Remove Empty Catch Block and Put a Documentation Link about Try...Catch use. + /// Sucht eine lokalisierte Zeichenfolge, die Remove Empty Catch Block and Put a Documentation Link about Try...Catch use ähnelt. /// public static string EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation { get { @@ -152,7 +152,7 @@ public static string EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation { } /// - /// Looks up a localized string similar to Remove wrapping Try Block. + /// Sucht eine lokalisierte Zeichenfolge, die Remove wrapping Try Block ähnelt. /// public static string EmptyCatchBlockCodeFixProvider_RemoveTry { get { @@ -161,7 +161,7 @@ public static string EmptyCatchBlockCodeFixProvider_RemoveTry { } /// - /// Looks up a localized string similar to Change field type '{0}' accessibility to be as accessible as field '{1}'. + /// Sucht eine lokalisierte Zeichenfolge, die Change field type '{0}' accessibility to be as accessible as field '{1}' ähnelt. /// public static string InconsistentAccessibilityInFieldType_Title { get { @@ -170,7 +170,7 @@ public static string InconsistentAccessibilityInFieldType_Title { } /// - /// Looks up a localized string similar to Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. + /// Sucht eine lokalisierte Zeichenfolge, die Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]' ähnelt. /// public static string InconsistentAccessibilityInIndexerParameter_Title { get { @@ -179,7 +179,7 @@ public static string InconsistentAccessibilityInIndexerParameter_Title { } /// - /// Looks up a localized string similar to Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. + /// Sucht eine lokalisierte Zeichenfolge, die Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]' ähnelt. /// public static string InconsistentAccessibilityInIndexerReturnType_Title { get { @@ -188,7 +188,7 @@ public static string InconsistentAccessibilityInIndexerReturnType_Title { } /// - /// Looks up a localized string similar to Change parameter type '{0}' accessibility to be as accessible as method '{1}'. + /// Sucht eine lokalisierte Zeichenfolge, die Change parameter type '{0}' accessibility to be as accessible as method '{1}' ähnelt. /// public static string InconsistentAccessibilityInMethodParameter_Title { get { @@ -197,7 +197,7 @@ public static string InconsistentAccessibilityInMethodParameter_Title { } /// - /// Looks up a localized string similar to Change return type '{0}' accessibility to be as accessible as method '{1}'. + /// Sucht eine lokalisierte Zeichenfolge, die Change return type '{0}' accessibility to be as accessible as method '{1}' ähnelt. /// public static string InconsistentAccessibilityInMethodReturnType_Title { get { @@ -206,7 +206,7 @@ public static string InconsistentAccessibilityInMethodReturnType_Title { } /// - /// Looks up a localized string similar to Change property type '{0}' accessibility to be as accessible as property '{1}'. + /// Sucht eine lokalisierte Zeichenfolge, die Change property type '{0}' accessibility to be as accessible as property '{1}' ähnelt. /// public static string InconsistentAccessibilityInPropertyType_Title { get { @@ -215,7 +215,7 @@ public static string InconsistentAccessibilityInPropertyType_Title { } /// - /// Looks up a localized string similar to Make method non async. + /// Sucht eine lokalisierte Zeichenfolge, die Make method non async ähnelt. /// public static string MakeMethodNonAsyncCodeFixProvider_Title { get { @@ -224,7 +224,7 @@ public static string MakeMethodNonAsyncCodeFixProvider_Title { } /// - /// Looks up a localized string similar to In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor.. + /// Sucht eine lokalisierte Zeichenfolge, die In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor. ähnelt. /// public static string NameOfAnalyzer_Description { get { @@ -233,7 +233,7 @@ public static string NameOfAnalyzer_Description { } /// - /// Looks up a localized string similar to Use 'nameof({0})' instead of specifying the program element name.. + /// Sucht eine lokalisierte Zeichenfolge, die Use 'nameof({0})' instead of specifying the program element name. ähnelt. /// public static string NameOfAnalyzer_MessageFormat { get { @@ -242,7 +242,7 @@ public static string NameOfAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use nameof. + /// Sucht eine lokalisierte Zeichenfolge, die Use nameof ähnelt. /// public static string NameOfAnalyzer_Title { get { @@ -251,7 +251,7 @@ public static string NameOfAnalyzer_Title { } /// - /// Looks up a localized string similar to Use nameof(). + /// Sucht eine lokalisierte Zeichenfolge, die Use nameof() ähnelt. /// public static string NameOfCodeFixProvider_Title { get { @@ -260,7 +260,43 @@ public static string NameOfCodeFixProvider_Title { } /// - /// Looks up a localized string similar to String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string.. + /// Sucht eine lokalisierte Zeichenfolge, die Getter only properties with backing read-only field can be converted to getter-only auto-properties. ähnelt. + /// + public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_Description { + get { + return ResourceManager.GetString("ReplaceWithGetterOnlyAutoPropertyAnalyzer_Description", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Property {0} can be converted to an getter-only auto-property. ähnelt. + /// + public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_MessageFormat { + get { + return ResourceManager.GetString("ReplaceWithGetterOnlyAutoPropertyAnalyzer_MessageFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Property can be simplified by using an getter-only auto-property. ähnelt. + /// + public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_Title { + get { + return ResourceManager.GetString("ReplaceWithGetterOnlyAutoPropertyAnalyzer_Title", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Simplify by using an getter-only auto-property ähnelt. + /// + public static string ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title { + get { + return ResourceManager.GetString("ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string. ähnelt. /// public static string StringFormatAnalyzer_Description { get { @@ -269,7 +305,7 @@ public static string StringFormatAnalyzer_Description { } /// - /// Looks up a localized string similar to Use string interpolation. + /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation ähnelt. /// public static string StringFormatAnalyzer_MessageFormat { get { @@ -278,7 +314,7 @@ public static string StringFormatAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use string interpolation instead of String.Format. + /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation instead of String.Format ähnelt. /// public static string StringFormatAnalyzer_Title { get { @@ -287,7 +323,7 @@ public static string StringFormatAnalyzer_Title { } /// - /// Looks up a localized string similar to Change to string interpolation. + /// Sucht eine lokalisierte Zeichenfolge, die Change to string interpolation ähnelt. /// public static string StringFormatCodeFixProvider_Title { get { @@ -296,7 +332,7 @@ public static string StringFormatCodeFixProvider_Title { } /// - /// Looks up a localized string similar to Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties.. + /// Sucht eine lokalisierte Zeichenfolge, die Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties. ähnelt. /// public static string SwitchToAutoPropAnalyzer_Description { get { @@ -305,7 +341,7 @@ public static string SwitchToAutoPropAnalyzer_Description { } /// - /// Looks up a localized string similar to Change {0} to an auto property. + /// Sucht eine lokalisierte Zeichenfolge, die Change {0} to an auto property ähnelt. /// public static string SwitchToAutoPropAnalyzer_MessageFormat { get { @@ -314,7 +350,7 @@ public static string SwitchToAutoPropAnalyzer_MessageFormat { } /// - /// Looks up a localized string similar to Use auto property. + /// Sucht eine lokalisierte Zeichenfolge, die Use auto property ähnelt. /// public static string SwitchToAutoPropAnalyzer_Title { get { @@ -323,7 +359,7 @@ public static string SwitchToAutoPropAnalyzer_Title { } /// - /// Looks up a localized string similar to Change to auto property. + /// Sucht eine lokalisierte Zeichenfolge, die Change to auto property ähnelt. /// public static string SwitchToAutoPropCodeFixProvider_Title { get { @@ -332,7 +368,7 @@ public static string SwitchToAutoPropCodeFixProvider_Title { } /// - /// Looks up a localized string similar to You have missing/unexistent parameters in Xml Docs. + /// Sucht eine lokalisierte Zeichenfolge, die You have missing/unexistent parameters in Xml Docs ähnelt. /// public static string XmlDocumentationAnalyzer_Title { get { @@ -341,7 +377,7 @@ public static string XmlDocumentationAnalyzer_Title { } /// - /// Looks up a localized string similar to Create missing parameters in xml docs. + /// Sucht eine lokalisierte Zeichenfolge, die Create missing parameters in xml docs ähnelt. /// public static string XmlDocumentationCreateMissingParametersCodeFixProvider_Title { get { @@ -350,7 +386,7 @@ public static string XmlDocumentationCreateMissingParametersCodeFixProvider_Titl } /// - /// Looks up a localized string similar to Remove unexistent parameters in xml docs. + /// Sucht eine lokalisierte Zeichenfolge, die Remove unexistent parameters in xml docs ähnelt. /// public static string XmlDocumentationRemoveNonExistentParametersCodeFixProvider_Title { get { diff --git a/src/Common/CodeCracker.Common/Properties/Resources.resx b/src/Common/CodeCracker.Common/Properties/Resources.resx index 1b6e5d917..accb497bd 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.resx +++ b/src/Common/CodeCracker.Common/Properties/Resources.resx @@ -216,4 +216,16 @@ Remove wrapping Try Block + + Getter only properties with backing read-only field can be converted to getter-only auto-properties. + + + Property {0} can be converted to an getter-only auto-property. + + + Property can be simplified by using an getter-only auto-property. + + + Simplify by using an getter-only auto-property + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 1b62b386c..4198a1676 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -135,6 +135,7 @@ + diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs new file mode 100644 index 000000000..ec2ad725b --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs @@ -0,0 +1,325 @@ +using CodeCracker.CSharp.Refactoring; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace CodeCracker.Test.CSharp.Refactoring +{ + public class ReplaceWithGetterOnlyAutoPropertyTests : CodeFixVerifier + { + private static string GetDiagnosticMessage(string propertyName) => $"Property {propertyName} can be converted to an getter-only auto-property."; + + [Fact] + public async Task EmptyCodeBlockPassesWithoutErrors() + { + const string test = @""; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async Task SimplePropertyGetsTransformed() + { + var test = @" + readonly string _value; + + TypeName(string value) + { + _value=value; + } + + public string Value { get { return _value; } } + ".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = "CC0125", + Message = GetDiagnosticMessage("Value"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 16, 27) + } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + + var fixtest = @" + TypeName(string value) + { + Value = value; + } + + public string Value { get; } + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task SimplePropertyGetsNotTransformedIfLessThanCSharp6() + { + var test = @" + readonly string _value; + + TypeName(string value) + { + _value=value; + } + + public string Value { get { return _value; } } + ".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(test, LanguageVersion.CSharp5); + } + + [Fact] + public async Task FieldInitializerIsPreserved() + { + var test = @" + readonly string value, value2 = ""InitValue""; + + TypeName(string value) + { + this.value=value; + } + + public string Value { get { return this.value; } } + ".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("Value"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 16, 27) + } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + + var fixtest = @" + readonly string value2 = ""InitValue""; + + TypeName(string value) + { + this.Value = value; + } + + public string Value { get; } = ""InitValue""; + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task MultiplePropertiesPerClassGetTranformed() + { + var test = @" + readonly string value, value2=""InitValue""; + + TypeName(string value) + { + this.value=value; + this.value2=value; + } + + public string Value { get { return this.value; } } + public string Value2 { get { return this.value2; } } + ".WrapInCSharpClass(); + + var expected1 = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("Value"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 17, 27) + } + }; + var expected2 = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("Value2"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 18, 27) + } + }; + + await VerifyCSharpDiagnosticAsync(test, new DiagnosticResult[] { expected1, expected2 }); + + var fixtest = @" + TypeName(string value) + { + this.Value = value; + this.Value2 = value; + } + + public string Value { get; } = ""InitValue""; + public string Value2 { get; } = ""InitValue""; + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task MultiplePropertiesPerClassWithFieldInitilizerAndUnusedFieldsGetTranformed() + { + var test = @" + readonly string value, value2, value3=""InitValue""; + + TypeName(string value) + { + this.value=value; + this.value2=value; + } + + public string Value { get { return this.value; } } + public string Value2 { get { return this.value2; } } + ".WrapInCSharpClass(); + var expected1 = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("Value"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 17, 27) + } + }; + var expected2 = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("Value2"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 18, 27) + } + }; + + await VerifyCSharpDiagnosticAsync(test, new DiagnosticResult[] { expected1, expected2 }); + + var fixtest = @" + readonly string value3=""InitValue""; + + TypeName(string value) + { + this.Value = value; + this.Value2 = value; + } + + public string Value { get; } = ""InitValue""; + public string Value2 { get; } = ""InitValue""; + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task TypeOfPropertyMustFitTypeOfBackingField() + { + var test = @" + readonly IList value, value2; + + TypeName(IEnumerable value) + { + this.value=value.ToList(); + this.value2=value.ToList(); + } + + public IEnumerable Value { get { return this.value; } } + public IList Value2 { get { return this.value2; } } + ".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("Value2"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 18, 34) + } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + + var fixtest = @" + readonly IList value; + + TypeName(IEnumerable value) + { + this.value=value.ToList(); + this.Value2 = value.ToList(); + } + + public IEnumerable Value { get { return this.value; } } + public IList Value2 { get; } + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task ExplicitPropertyImplementationsAreIgnored() + { + const string test = @" + namespace ConsoleApplication1 + { + interface ITestInterface + { + string Property { get; } + } + class TestClass2: ITestInterface + { + readonly string _Property; + + string ITestInterface.Property + { + get + { + return _Property; + } + } + } + }"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async Task SeveralInitializerAreAssignedProperly() + { + var test = @" + readonly int a = 0, x, y = 1, z = 2; + + public int X + { + get + { + return x; + } + } + ".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), + Message = GetDiagnosticMessage("X"), + Severity = DiagnosticSeverity.Hidden, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 11, 24) + } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + + var fixtest = @" + readonly int a = 0, y = 1, z = 2; + + public int X { get; } = 1; + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + } +} From 07c9a00e0810a522d9d1ff43f4ea92fc7fbb8a1a Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 22 Mar 2017 10:13:13 +0100 Subject: [PATCH 267/358] Changed Renaming logic and added some renaming tests. --- ...thGetterOnlyAutoPropertyCodeFixProvider.cs | 30 +-- .../ReplaceWithGetterOnlyAutoPropertyTests.cs | 219 ++++++++++++++++-- 2 files changed, 215 insertions(+), 34 deletions(-) diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs index c67c076ed..5503dbe8f 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs @@ -34,7 +34,7 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) title: Resources.ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title, createChangedDocument: c => ReplaceByGetterOnlyAutoPropertyAsync(context.Document, diagnosticSpan, c), equivalenceKey: nameof(ReplaceWithGetterOnlyAutoPropertyCodeFixProvider)), - diagnostic); + diagnostic); return Task.FromResult(0); } private async static Task ReplaceByGetterOnlyAutoPropertyAsync(Document document, TextSpan propertyDeclarationSpan, CancellationToken cancellationToken) @@ -55,12 +55,13 @@ private async static Task ReplaceByGetterOnlyAutoPropertyAsync(Documen private static SyntaxNode FixWithTrackNode(SyntaxNode root, PropertyDeclarationSyntax property, VariableDeclaratorSyntax fieldVariableDeclaratorSyntax, IEnumerable nodesToUpdate) { var newRoot = root.TrackNodes(nodesToUpdate); - var fieldReferences = newRoot.GetCurrentNodes(nodesToUpdate.OfType()); + var fieldReferences = nodesToUpdate.OfType(); foreach (var identifier in fieldReferences) { - var newIdentifier = SyntaxFactory.IdentifierName(property.Identifier.Text); - newIdentifier = newIdentifier.WithLeadingTrivia(identifier.GetLeadingTrivia()).WithTrailingTrivia(identifier.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation); - newRoot = newRoot.ReplaceNode(identifier, newIdentifier); + var trackedIdentifierNode = newRoot.GetCurrentNode(identifier); + var newIdentifierExpression = SyntaxFactory.IdentifierName(property.Identifier.Text); + newIdentifierExpression = newIdentifierExpression.WithLeadingTrivia(trackedIdentifierNode.GetLeadingTrivia()).WithTrailingTrivia(trackedIdentifierNode.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation); + newRoot = newRoot.ReplaceNode(trackedIdentifierNode, newIdentifierExpression); } var prop = newRoot.GetCurrentNode(nodesToUpdate.OfType().Single()); var fieldInitilization = GetFieldInitialization(fieldVariableDeclaratorSyntax); @@ -101,25 +102,18 @@ private static EqualsValueClauseSyntax GetFieldInitialization(VariableDeclarator private static async Task> GetFieldReferencesAsync(VariableDeclaratorSyntax fieldDeclarationSyntax, CancellationToken cancellationToken, SemanticModel semanticModel) { HashSet fieldReferences = null; - var fieldSymbol = semanticModel.GetDeclaredSymbol(fieldDeclarationSyntax); + var fieldSymbol = semanticModel.GetDeclaredSymbol(fieldDeclarationSyntax, cancellationToken); var declaredInType = fieldSymbol.ContainingType; foreach (var reference in declaredInType.DeclaringSyntaxReferences) { - var allNodesOfType = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); - var allFieldReferenceNodes = from n in allNodesOfType.OfType() - where n.Identifier.ValueText == fieldDeclarationSyntax.Identifier.ValueText + var allNodes = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); + var allFieldReferenceNodes = from n in allNodes.OfType() + let nodeSymbolInfo = semanticModel.GetSymbolInfo(n, cancellationToken) + where object.Equals(nodeSymbolInfo.Symbol, fieldSymbol) select n; foreach (var fieldReference in allFieldReferenceNodes) { - var parentExpression = fieldReference.Parent; - if (parentExpression is MemberAccessExpressionSyntax) - parentExpression = parentExpression.Parent; - if (parentExpression is AssignmentExpressionSyntax) - { - var assignmentEx = (AssignmentExpressionSyntax)parentExpression; - if (assignmentEx.Left == fieldReference || assignmentEx.Left == fieldReference.Parent) - (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); - } + (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); } } return fieldReferences ?? Enumerable.Empty(); diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs index ec2ad725b..825a083e0 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs @@ -1,10 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using Xunit; @@ -301,25 +297,216 @@ public int X } } ".WrapInCSharpClass(); - var expected = new DiagnosticResult + var fixtest = @" + readonly int a = 0, y = 1, z = 2; + + public int X { get; } = 1; + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task FieldNameIsRenamedInClass() + { + var test = @" + readonly int _X; + + public TypeName(int x) { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("X"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 11, 24) - } - }; + _X=x; + _X=_X*2; + Console.Write(_X); + } - await VerifyCSharpDiagnosticAsync(test, expected); + protected void M() => Console.Write(_X); + public int X + { + get + { + return _X; + } + } + ".WrapInCSharpClass(); var fixtest = @" - readonly int a = 0, y = 1, z = 2; + public TypeName(int x) + { + X=x; + X=X*2; + Console.Write(X); + } - public int X { get; } = 1; + protected void M() => Console.Write(X); + + public int X { get; } + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task ShadowedFieldNameIsNotRenamedInClass() + { + var test = @" + readonly int _X; + + public TypeName(int x) + { + _X=x; + } + + protected void M() + { + string _X=""; + Console.Write(_X); + } + + public int X + { + get + { + return _X; + } + } + ".WrapInCSharpClass(); + var fixtest = @" + public TypeName(int x) + { + X=x; + } + + protected void M() + { + string _X=""; + Console.Write(_X); + } + + public int X { get; } + ".WrapInCSharpClass(); + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task FieldAccessInInnerClassIsRenamed() + { + var test = @" + readonly int _A; + + public TypeName(int a) + { + _A=a; + } + + class InnerClass { + InnerClass(TypeName outterObject) + { + Console.Write(outterObject._A); + } + } + public int A + { + get + { + return _A; + } + } + ".WrapInCSharpClass(); + var fixtest = @" + public TypeName(int a) + { + A=a; + } + + class InnerClass { + InnerClass(TypeName outterObject) + { + Console.Write(outterObject.A); + } + } + public int A { get; } ".WrapInCSharpClass(); await VerifyCSharpFixAsync(test, fixtest); } + + [Fact] + public async Task FieldWithSameNameInOtherClassIsNotRenamed() + { + var test = @" + using System; + namespace App { + public class C1 + { + readonly int _A; + + public C1(int a) + { + _A=a; + } + + public int A + { + get + { + return _A; + } + } + } + public class C2 + { + readonly int _A; + } + }"; + var fixtest = @" + using System; + namespace App { + public class C1 + { + + public C1(int a) + { + A=a; + } + + public int A { get; } + } + public class C2 + { + readonly int _A; + } + }"; + await VerifyCSharpFixAsync(test, fixtest); + } + + [Fact] + public async Task RenamingOfFieldAccessCanIntroduceNameClashesCaughtByCompilerWarningCS1717() + { + var test = @" + readonly int _A; + + public TypeName(int A) + { + _A=A; + } + + public int A + { + get + { + return _A; + } + } + ".WrapInCSharpClass(); + var fixtest = @" + public TypeName(int A) + { + A=A; + } + + public int A { get; } + ".WrapInCSharpClass(); + // "A=A;" causes new compiler warning CS1717: Assignment made to same variable; did you mean to assign something else? + // The fix would be to transform the expression to this.A=A; + // Maybe using Microsoft.CodeAnalysis.Rename.Renamer.RenameSymbolAsync() for the renaming is the able to fix this. + await VerifyCSharpFixAsync(oldSource: test, newSource: fixtest, allowNewCompilerDiagnostics: true); + } } } From c1bdfbda9fd4578b4b2613a4fd5269a7e74d4eb0 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 22 Mar 2017 10:57:30 +0100 Subject: [PATCH 268/358] Prepare Pull Request: Reverted some VS2015 compatibility changes. --- src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj index 7dde1ebf3..12f744c47 100644 --- a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj @@ -1,13 +1,14 @@  - + - 14.0 + 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + 15.0 From 5c4007b3ce70e48cd3df2f1d7b219624d58de410 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 22 Mar 2017 11:00:01 +0100 Subject: [PATCH 269/358] Cleanup before PullRequest --- .../Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs | 3 --- .../ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs | 2 -- src/Common/CodeCracker.Common/DiagnosticId.cs | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs index b9d16cc4a..59291bf23 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs @@ -4,11 +4,8 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace CodeCracker.CSharp.Refactoring { diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs index 5503dbe8f..e467153ed 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs @@ -6,12 +6,10 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index a0d12446a..28feee0f8 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -83,6 +83,6 @@ public enum DiagnosticId UnnecessaryToStringInStringConcatenation = 118, SwitchCaseWithoutDefault = 120, ReadOnlyComplexTypes = 121, - ReplaceWithGetterOnlyAutoProperty=125, + ReplaceWithGetterOnlyAutoProperty = 125, } } \ No newline at end of file From b4d2856fc88dd38366f1ad41311f11890d08f7ed Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 22 Mar 2017 11:07:20 +0100 Subject: [PATCH 270/358] Clean up of analyzer. --- .../ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs index 59291bf23..cc8b4ef13 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyAnalyzer.cs @@ -28,6 +28,7 @@ public class ReplaceWithGetterOnlyAutoPropertyAnalyzer : DiagnosticAnalyzer helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.ReplaceWithGetterOnlyAutoProperty)); public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override void Initialize(AnalysisContext context) { context.RegisterSymbolAction(LanguageVersion.CSharp6, AnalyzeSymbol, SymbolKind.Property); @@ -39,12 +40,11 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) var namedTypeSymbol = (IPropertySymbol)context.Symbol; var properties = GetPropsWithOnlyGettersAndReadonlyBackingField(namedTypeSymbol, context); if (properties == null) return; - var diagnostic = Diagnostic.Create(Rule, properties.Item1.Locations[0], properties.Item1.Name); + var diagnostic = Diagnostic.Create(Rule, properties.Locations[0], properties.Name); context.ReportDiagnostic(diagnostic); } - private static Tuple GetPropsWithOnlyGettersAndReadonlyBackingField(IPropertySymbol propertySymbol, SymbolAnalysisContext context) + private static ISymbol GetPropsWithOnlyGettersAndReadonlyBackingField(IPropertySymbol propertySymbol, SymbolAnalysisContext context) { - SemanticModel model = null; if (!propertySymbol.IsReadOnly || propertySymbol.IsStatic || !propertySymbol.CanBeReferencedByName) return null; var getMethod = propertySymbol.GetMethod; if (getMethod == null) return null; @@ -59,7 +59,7 @@ private static Tuple GetPropsWithOnlyGettersAndReadonlyBa if (fieldNode.Kind() == SyntaxKind.SimpleMemberAccessExpression) fieldNode = (fieldNode as MemberAccessExpressionSyntax).Name; if (fieldNode.Kind() != SyntaxKind.IdentifierName) return null; - model = model ?? context.Compilation.GetSemanticModel(fieldNode.SyntaxTree); + var model = context.Compilation.GetSemanticModel(fieldNode.SyntaxTree); var symbolInfo = model.GetSymbolInfo(fieldNode).Symbol as IFieldSymbol; if (symbolInfo != null && symbolInfo.IsReadOnly && @@ -67,7 +67,7 @@ private static Tuple GetPropsWithOnlyGettersAndReadonlyBa symbolInfo.ContainingType == propertySymbol.ContainingType && symbolInfo.Type.Equals(propertySymbol.Type)) - return new Tuple(propertySymbol, symbolInfo); + return propertySymbol; return null; } } From fa20c951cf11e561a64c1d141a8a95614f53f7ca Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Mon, 27 Mar 2017 13:58:44 +0200 Subject: [PATCH 271/358] Bugfix: semanticModel.GetSymbolInfo might raise ArgumentException (Node not found in tree) for certain symbols. --- .../ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs index e467153ed..80db718c6 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs @@ -106,6 +106,7 @@ private static async Task> GetFieldReferencesA { var allNodes = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); var allFieldReferenceNodes = from n in allNodes.OfType() + where n.Identifier.Text == fieldSymbol.Name let nodeSymbolInfo = semanticModel.GetSymbolInfo(n, cancellationToken) where object.Equals(nodeSymbolInfo.Symbol, fieldSymbol) select n; From 308f450277867ad479105b1b7b2c8bb4f2589c90 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 29 Mar 2017 13:52:12 +0200 Subject: [PATCH 272/358] Bugfix: Partial classes in different documents cause ArgumentException. --- ...thGetterOnlyAutoPropertyCodeFixProvider.cs | 20 ++-- .../ReplaceWithGetterOnlyAutoPropertyTests.cs | 94 ++++++++++++++++++- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs index 80db718c6..d22626bae 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs @@ -102,18 +102,16 @@ private static async Task> GetFieldReferencesA HashSet fieldReferences = null; var fieldSymbol = semanticModel.GetDeclaredSymbol(fieldDeclarationSyntax, cancellationToken); var declaredInType = fieldSymbol.ContainingType; - foreach (var reference in declaredInType.DeclaringSyntaxReferences) + var reference = declaredInType.DeclaringSyntaxReferences[0]; + var allNodes = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); + var allFieldReferenceNodes = from n in allNodes.OfType() + where n.Identifier.Text == fieldSymbol.Name + let nodeSymbolInfo = semanticModel.GetSymbolInfo(n, cancellationToken) + where object.Equals(nodeSymbolInfo.Symbol, fieldSymbol) + select n; + foreach (var fieldReference in allFieldReferenceNodes) { - var allNodes = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); - var allFieldReferenceNodes = from n in allNodes.OfType() - where n.Identifier.Text == fieldSymbol.Name - let nodeSymbolInfo = semanticModel.GetSymbolInfo(n, cancellationToken) - where object.Equals(nodeSymbolInfo.Symbol, fieldSymbol) - select n; - foreach (var fieldReference in allFieldReferenceNodes) - { - (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); - } + (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); } return fieldReferences ?? Enumerable.Empty(); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs index 825a083e0..d7ffc711d 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs @@ -508,5 +508,97 @@ public TypeName(int A) // Maybe using Microsoft.CodeAnalysis.Rename.Renamer.RenameSymbolAsync() for the renaming is the able to fix this. await VerifyCSharpFixAsync(oldSource: test, newSource: fixtest, allowNewCompilerDiagnostics: true); } + + [Fact] + public async Task FieldReferencesInPartialClassesGetNotRenamedAndCasueCompilerErrorCS0103() + { + const string test = @" + namespace A + { + using System; + public partial class A1 + { + readonly int _I; + public A1(int i) + { + _I = i; + } + public int I { get { return _I; } } + } + public partial class A1 + { + public void Print() => Console.Write(_I); + } + }"; + const string fixtest = @" + namespace A + { + using System; + public partial class A1 + { + public A1(int i) + { + I = i; + } + public int I { get; } + } + public partial class A1 + { + public void Print() => Console.Write(_I); + } + }"; + //Console.Write(_I); causes CS0103 The name '_I' does not exist in the current context + await VerifyCSharpFixAsync(oldSource: test, newSource: fixtest, allowNewCompilerDiagnostics: true); + } + + [Fact] + public async Task FieldReferencesInPartialClassesInDifferentDocumentsGetNotRenamedAndCauseCompilerErrorCS0103() + { + const string testPart1 = @" + namespace A + { + public partial class A1 + { + readonly int _I; + public A1(int i) + { + _I = i; + } + public int I { get { return _I; } } + } + }"; + const string testPart2 = @" + namespace A + { + using System; + public partial class A1 + { + public void Print() => Console.Write(_I); + } + }"; + const string fixtestPart1 = @" + namespace A + { + public partial class A1 + { + public A1(int i) + { + I = i; + } + public int I { get; } + } + }"; + const string fixtestPart2 = @" + namespace A + { + using System; + public partial class A1 + { + public void Print() => Console.Write(_I); + } + }"; + //Console.Write(_I); causes CS0103 The name '_I' does not exist in the current context + await VerifyCSharpFixAllAsync(oldSources: new string[] { testPart1, testPart2 }, newSources: new string[] { fixtestPart1, fixtestPart2 }, allowNewCompilerDiagnostics: true); + } } -} +} \ No newline at end of file From e6d44e596af62dcb89fa1b6fe10b2162e14b8b37 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 27 Apr 2017 15:54:10 +0200 Subject: [PATCH 273/358] Added CoalesceExpression to the list of possible parents in topSyntaxNode discovery. --- .../DisposableVariableNotDisposedAnalyzer.cs | 2 +- .../DisposableVariableNotDisposedTests.cs | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index 2a4b4c32f..3ed958b5f 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -40,7 +40,7 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) var originalNode = objectCreation; SyntaxNode topSyntaxNode = originalNode; - while (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CastExpression)) + while (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CastExpression, SyntaxKind.CoalesceExpression)) topSyntaxNode = topSyntaxNode.Parent; if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ReturnStatement, SyntaxKind.UsingStatement, SyntaxKind.YieldReturnStatement)) diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index d1ad9d3e9..e2f2a9fd9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -1577,5 +1577,26 @@ void Bar() }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task IgnoreWhenAssignedToFieldByNullCoalescingOperator() + { + const string source = @" +using System.IO; +public class Test : IDisposable +{ + private IDisposable _stream; + + public void Update() + { + _stream = _stream ?? new MemoryStream(); + } + + public void Dispose() + { + _stream.Dispose(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); } -} \ No newline at end of file +}} \ No newline at end of file From e74608cf2fd991ac3b353fb0d44671dd37e1e596 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 27 Apr 2017 16:12:09 +0200 Subject: [PATCH 274/358] Code formating. --- .../Usage/DisposableVariableNotDisposedTests.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index e2f2a9fd9..cb1437596 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -1578,10 +1578,10 @@ void Bar() await VerifyCSharpHasNoDiagnosticsAsync(source); } - [Fact] - public async Task IgnoreWhenAssignedToFieldByNullCoalescingOperator() - { - const string source = @" + [Fact] + public async Task IgnoreWhenAssignedToFieldByNullCoalescingOperator() + { + const string source = @" using System.IO; public class Test : IDisposable { @@ -1597,6 +1597,7 @@ public void Dispose() _stream.Dispose(); } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } -}} \ No newline at end of file +} \ No newline at end of file From 41aa788fc2752e83318edc600ccc73f11dadf37f Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 27 Apr 2017 18:05:34 +0200 Subject: [PATCH 275/358] Added support for Winforms property default value definition methods. --- .../RemovePrivateMethodNeverUsedAnalyzer.cs | 35 +++++++++ ...emovePrivateMethodNeverUsedAnalyzerTest.cs | 76 +++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs index 25bd20246..26b80458c 100644 --- a/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RemovePrivateMethodNeverUsedAnalyzer.cs @@ -44,6 +44,7 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) if (IsMethodUsed(methodDeclaration, context.SemanticModel)) return; if (IsMainMethodEntryPoint(methodDeclaration, context.SemanticModel)) return; if (methodDeclaration.Modifiers.Any(SyntaxKind.ExternKeyword)) return; + if (IsWinformsPropertyDefaultValueDefinitionMethod(methodDeclaration, context.SemanticModel)) return; var props = new Dictionary { { "identifier", methodDeclaration.Identifier.Text } }.ToImmutableDictionary(); var diagnostic = Diagnostic.Create(Rule, methodDeclaration.GetLocation(), props); context.ReportDiagnostic(diagnostic); @@ -125,5 +126,39 @@ private static bool IsMainMethodEntryPoint(MethodDeclarationSyntax methodTarget, if (!parameterType.OriginalDefinition.ToString().Equals("String[]", StringComparison.OrdinalIgnoreCase)) return false; return true; } + + // see https://msdn.microsoft.com/en-us/library/53b8022e(v=vs.110).aspx + private static bool IsWinformsPropertyDefaultValueDefinitionMethod(MethodDeclarationSyntax methodTarget, SemanticModel semanticModel) + { + var propertyName = GetPropertyNameForWinformDefaultValueMethods(methodTarget, semanticModel); + if (string.IsNullOrWhiteSpace(propertyName)) return false; + if (!ExistsProperty(propertyName, methodTarget, semanticModel)) return false; + return true; + } + + private static string GetPropertyNameForWinformDefaultValueMethods(MethodDeclarationSyntax methodTarget, SemanticModel semanticModel) => + GetPropertyNameForMethodWithSignature(methodTarget, semanticModel, "Reset", "Void") ?? + GetPropertyNameForMethodWithSignature(methodTarget, semanticModel, "ShouldSerialize", "Boolean"); + + private static string GetPropertyNameForMethodWithSignature(MethodDeclarationSyntax methodTarget, SemanticModel semanticModel, string startsWith, string returnType) + { + var methodName = methodTarget.Identifier.Text; + if (methodName.StartsWith(startsWith)) + if (methodTarget.ParameterList.Parameters.Count == 0) + { + var returnTypeInfo = semanticModel.GetTypeInfo(methodTarget.ReturnType).Type; + if (returnTypeInfo.Name.Equals(returnType, StringComparison.OrdinalIgnoreCase)) + return methodName.Substring(startsWith.Length); ; + } + return null; + } + + private static bool ExistsProperty(string propertyName, SyntaxNode nodeInType, SemanticModel semanticModel) + { + var typeDeclaration = nodeInType.AncestorsAndSelf().OfType().FirstOrDefault(); + if (typeDeclaration == null) return false; + var propertyDeclarations = typeDeclaration.DescendantNodes().OfType(); + return propertyDeclarations.Any(pd => pd.Identifier.Text == propertyName); + } } } diff --git a/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs b/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs index abc0c6e97..3c5383c1e 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs @@ -1,4 +1,5 @@ using CodeCracker.CSharp.Usage; +using Microsoft.CodeAnalysis; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -408,5 +409,80 @@ bool System.IEquatable.Equals(Foo other) }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + // see https://msdn.microsoft.com/en-us/library/53b8022e(v=vs.110).aspx + [Fact] + public async void WinFormsPropertyDefaultValueDefinitionMethodsShouldBeIgnored() + { + var source = @" +public int PropertyXXX { + get; + set; +} + +private bool ShouldSerializePropertyXXX() => true; + +private void ResetPropertyXXX() { }; +".WrapInCSharpClass(); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + private static DiagnosticResult CreateDiagnosticResult(int line, int column) => + new DiagnosticResult + { + Id = DiagnosticId.RemovePrivateMethodNeverUsed.ToDiagnosticId(), + Locations = new DiagnosticResultLocation[] { new DiagnosticResultLocation("Test0.cs", line, column) }, + Message = RemovePrivateMethodNeverUsedAnalyzer.Message, + Severity = DiagnosticSeverity.Info, + }; + + [Fact] + public async void WinFormsPropertyDefaultValueDefinitionMethodsMustHaveCorrectSignature() + { + var source = @" +public int Property1 { get; set; } +public int Property2 { get; set; } +public int Property3 { get; set; } + +private int ShouldSerializeProperty1() => 1; +private bool ShouldSerializeProperty2(int i) => true; +private void ShouldSerializeProperty3() { }; + +private bool ResetProperty1() => true; +private void ResetProperty2(int i) { }; +".WrapInCSharpClass(); + var result1 = CreateDiagnosticResult(13, 1); + var result2 = CreateDiagnosticResult(14, 1); + var result3 = CreateDiagnosticResult(15, 1); + var result4 = CreateDiagnosticResult(17, 1); + var result5 = CreateDiagnosticResult(18, 1); + await VerifyCSharpDiagnosticAsync(source, new DiagnosticResult[] { result1, result2, result3, result4, result5 }); + } + + [Fact] + public async void WinFormsPropertyDefaultValueDefinitionMethodsMustHaveCorrespondingProperty() + { + var source = @" +private bool ShouldSerializePropertyXXX() => true; + +private void ResetPropertyXXX() { }; +".WrapInCSharpClass(); + var result1 = CreateDiagnosticResult(9, 1); + var result2 = CreateDiagnosticResult(11, 1); + await VerifyCSharpDiagnosticAsync(source, new DiagnosticResult[] { result1, result2 }); + } + + [Fact] + public async void WinFormsPropertyDefaultValueDefinitionMethodsMustHaveASuffix() + { + var source = @" +private bool ShouldSerialize() => true; + +private void ResetProperty() { }; +".WrapInCSharpClass(); + var result1 = CreateDiagnosticResult(9, 1); + var result2 = CreateDiagnosticResult(11, 1); + await VerifyCSharpDiagnosticAsync(source, new DiagnosticResult[] { result1, result2 }); + } } } \ No newline at end of file From d8cc1f75f2b75dcb10d5f4a4082da4b918501e74 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 27 Apr 2017 15:54:10 +0200 Subject: [PATCH 276/358] Added CoalesceExpression to the list of possible parents in topSyntaxNode discovery. --- .../DisposableVariableNotDisposedAnalyzer.cs | 2 +- .../DisposableVariableNotDisposedTests.cs | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index 2a4b4c32f..3ed958b5f 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -40,7 +40,7 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) var originalNode = objectCreation; SyntaxNode topSyntaxNode = originalNode; - while (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CastExpression)) + while (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CastExpression, SyntaxKind.CoalesceExpression)) topSyntaxNode = topSyntaxNode.Parent; if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ReturnStatement, SyntaxKind.UsingStatement, SyntaxKind.YieldReturnStatement)) diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index d1ad9d3e9..e2f2a9fd9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -1577,5 +1577,26 @@ void Bar() }"; await VerifyCSharpHasNoDiagnosticsAsync(source); } + + [Fact] + public async Task IgnoreWhenAssignedToFieldByNullCoalescingOperator() + { + const string source = @" +using System.IO; +public class Test : IDisposable +{ + private IDisposable _stream; + + public void Update() + { + _stream = _stream ?? new MemoryStream(); + } + + public void Dispose() + { + _stream.Dispose(); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); } -} \ No newline at end of file +}} \ No newline at end of file From 98270b530444432601a68d937297ed47f4f52a04 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 27 Apr 2017 16:12:09 +0200 Subject: [PATCH 277/358] Code formating. --- .../Usage/DisposableVariableNotDisposedTests.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index e2f2a9fd9..cb1437596 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -1578,10 +1578,10 @@ void Bar() await VerifyCSharpHasNoDiagnosticsAsync(source); } - [Fact] - public async Task IgnoreWhenAssignedToFieldByNullCoalescingOperator() - { - const string source = @" + [Fact] + public async Task IgnoreWhenAssignedToFieldByNullCoalescingOperator() + { + const string source = @" using System.IO; public class Test : IDisposable { @@ -1597,6 +1597,7 @@ public void Dispose() _stream.Dispose(); } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + await VerifyCSharpHasNoDiagnosticsAsync(source); + } } -}} \ No newline at end of file +} \ No newline at end of file From 871d40f53d43ba7891c427349d6ae21722025b5a Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 19:38:39 -0300 Subject: [PATCH 278/358] Create a single dll for the nupkg Using ilmerge, we are merging the C# and VB dlls with the common dll, which generates a simpler experience for the user. --- .gitignore | 1 + .nuget/packages.config | 1 + build.ps1 | 13 ++- build.targets.ps1 | 99 ++++++++++++++----- src/CSharp/CodeCracker/CodeCracker.nuspec | 2 +- src/CodeCracker.nuspec | 30 ------ .../CodeCracker/CodeCracker.nuspec | 2 +- 7 files changed, 93 insertions(+), 55 deletions(-) delete mode 100644 src/CodeCracker.nuspec diff --git a/.gitignore b/.gitignore index 3da239e30..b5c6a38ac 100644 --- a/.gitignore +++ b/.gitignore @@ -192,3 +192,4 @@ ModelManifest.xml log/ .vs nuget.exe +*.nupkg diff --git a/.nuget/packages.config b/.nuget/packages.config index 5e0ac7672..964028c5c 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -2,4 +2,5 @@ + diff --git a/build.ps1 b/build.ps1 index d1a072785..95d279b16 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,4 +1,6 @@ $ErrorActionPreference = "Stop" +$tempDir = Join-Path "$([System.IO.Path]::GetTempPath())" "CodeCracker" +if (!(Test-Path $tempDir)) { mkdir $tempDir | Out-Null } # functions: function IsNugetVersion3OrAbove($theNugetExe) { @@ -47,7 +49,7 @@ function Download-Nuget { } function Import-Psake { - $psakeModule = "$PSScriptRoot\packages\psake.4.5.0\tools\psake.psm1" + $psakeModule = "$PSScriptRoot\packages\psake.4.6.0\tools\psake.psm1" if ((Test-Path $psakeModule) -ne $true) { Write-Host "Restoring $PSScriptRoot\.nuget with $script:nugetExe" . "$script:nugetExe" restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot @@ -55,12 +57,21 @@ function Import-Psake { Import-Module $psakeModule -force } +function Import-ILMerge { + $ilmergeExe = "$PSScriptRoot\packages\ilmerge.2.14.1208\tools\ILMerge.exe" + if ((Test-Path $ilmergeExe) -ne $true) { + Write-Host "Restoring $PSScriptRoot\.nuget with $script:nugetExe" + . "$script:nugetExe" restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot + } +} + # statements: $localNuget = "$PSScriptRoot\.nuget\nuget.exe" $nugetExe = "" Get-Nuget Import-Psake +Import-ILMerge if ($MyInvocation.UnboundArguments.Count -ne 0) { . $PSScriptRoot\psake.ps1 -taskList ($MyInvocation.UnboundArguments -join " ") } diff --git a/build.targets.ps1 b/build.targets.ps1 index d5c0cc057..253bf1955 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -10,24 +10,33 @@ Properties { $buildNumber = [Convert]::ToInt32($env:APPVEYOR_BUILD_NUMBER).ToString("0000") $nuspecPathCS = "$rootDir\src\CSharp\CodeCracker\CodeCracker.nuspec" $nuspecPathVB = "$rootDir\src\VisualBasic\CodeCracker\CodeCracker.nuspec" - $nuspecPathJoint = "$rootDir\src\CodeCracker.nuspec" $nugetExe = "$packagesDir\NuGet.CommandLine.3.3.0\tools\NuGet.exe" $nupkgPathCS = "$rootDir\src\CSharp\CodeCracker.CSharp.{0}.nupkg" $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" - $nupkgPathJoint = "$rootDir\CodeCracker.{0}.nupkg" $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe" $openCoverExe = "$packagesDir\OpenCover.4.6.519\tools\OpenCover.Console.exe" + $dllCS = "CodeCracker.CSharp.dll" + $dllVB = "CodeCracker.VisualBasic.dll" + $dllCommon = "CodeCracker.Common.dll" $testDllCS = "CodeCracker.Test.CSharp.dll" $testDllVB = "CodeCracker.Test.VisualBasic.dll" $testDirCS = "$testDir\CSharp\CodeCracker.Test\bin\Release" $testDirVB = "$testDir\VisualBasic\CodeCracker.Test\bin\Release" + $projectDirVB = "$srcDir\VisualBasic\CodeCracker" + $projectFileVB = "$projectDirVB\CodeCracker.vbproj" + $releaseDirVB = "$projectDirVB\bin\Release" + $projectDirCS = "$srcDir\CSharp\CodeCracker" + $projectFileCS = "$projectDirCS\CodeCracker.csproj" + $releaseDirCS = "$projectDirCS\bin\Release" $logDir = "$rootDir\log" $outputXml = "$logDir\CodeCoverageResults.xml" $reportGeneratorExe = "$packagesDir\ReportGenerator.2.5.6\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" $coverallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" + $ilmergeExe = "$packagesDir\ilmerge.2.14.1208\tools\ILMerge.exe" $isRelease = $isAppVeyor -and (($env:APPVEYOR_REPO_BRANCH -eq "release") -or ($env:APPVEYOR_REPO_TAG -eq "true")) $isPullRequest = $env:APPVEYOR_PULL_REQUEST_NUMBER -ne $null + $tempDir = Join-Path "$([System.IO.Path]::GetTempPath())" "CodeCracker" } FormatTaskName (("-"*25) + "[{0}]" + ("-"*25)) @@ -49,14 +58,16 @@ Task Build-CS -depends Prepare-Build, Build-Only-CS Task Build-VB -depends Prepare-Build, Build-Only-VB Task Build-Only -depends Build-Only-CS, Build-Only-VB -Task Build-Only-CS { +Task Build-Only-CS -depends Build-MSBuild-CS, ILMerge-CS +Task Build-MSBuild-CS { if ($isAppVeyor) { Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } } else { Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } } } -Task Build-Only-VB { +Task Build-Only-VB -depends Build-MSBuild-VB, ILMerge-VB +Task Build-MSBuild-VB { if ($isAppVeyor) { Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } } else { @@ -64,6 +75,49 @@ Task Build-Only-VB { } } +Task ILMerge-VB { ILMerge $releaseDirVB $dllVB $projectFileVB $projectDirVB } +Task ILMerge-CS { ILMerge $releaseDirCS $dllCS $projectFileCS $projectDirCS } + +function ILMerge($releaseDir, $dll, $projectFile, $projectDir) { + Write-Host "IL Merge:" + $mergedDir = $tempDir + if (!(Test-Path $mergedDir)) { mkdir "$mergedDir" } + $inputDll = "$releaseDir\$dll" + $inputDllCommon = "$releaseDir\$dllCommon" + $pdbCommon = Change-Extension $inputDllCommon "pdb" + if (Test-Path $inputDllCommon) { + if ((ls $inputDllCommon).LastWriteTime -gt (ls $inputDll).LastWriteTime) { + # common is newer, but no changes on main dll + Write-Host "Common dll is newer than $inputDll, stopping IL merge." + return + } + } else { + # no common dll, can't merge + Write-Host "Can't find common dll, stopping IL merge." + return + } + $mergedDll = "$mergedDir\$dll" + [xml]$proj = cat $projectFile + $libs = @() + foreach ($ref in $proj.Project.ItemGroup.Reference.HintPath) { + $dir += [System.IO.Path]::GetDirectoryName("$projectDir\$ref") + $libs += "/lib:`"$([System.IO.Path]::GetDirectoryName("$projectDir\$ref"))`" " + } + Exec { . $ilmergeExe $libs /out:"$mergedDll" "$inputDll" "$inputDllCommon" } + $releaseMergedDir = "$releaseDir\merged" + if (!(Test-Path $releaseMergedDir)) { mkdir $releaseMergedDir | Out-Null } + cp $mergedDll "$releaseMergedDir\" -Force + Write-Host " $dll -> $releaseMergedDir\$dll" + $mergedPdb = Change-Extension $mergedDll "pdb" + cp $mergedPdb "$releaseMergedDir\" -Force + $pdb = (ls $mergedPdb).Name + Write-Host " $pdb -> $releaseMergedDir\$pdb" +} + +function Change-Extension ($filename, $extension) { + Join-Path "$([System.IO.Path]::GetDirectoryName($filename))" "$([System.IO.Path]::GetFileNameWithoutExtension($filename)).$extension" +} + Task Clean { Exec { msbuild $solutionFileCS /t:Clean /v:quiet } Exec { msbuild $solutionFileVB /t:Clean /v:quiet } @@ -99,10 +153,7 @@ Task Test-No-Coverage-CSharp { RunTest "$testDirCS\$testDllCS" } -Task Update-Nuspec -precondition { return $isAppVeyor -and ($isRelease -ne $true) } -depends Update-Nuspec-Joint -Task Update-Nuspec-Joint -precondition { return $isAppVeyor -and ($isRelease -ne $true) } -depends Update-Nuspec-CSharp, Update-Nuspec-VB { - UpdateNuspec $nuspecPathJoint "joint package" -} +Task Update-Nuspec -precondition { return $isAppVeyor -and ($isRelease -ne $true) } -depends Update-Nuspec-CSharp, Update-Nuspec-VB Task Update-Nuspec-CSharp -precondition { return $isAppVeyor -and ($isRelease -ne $true) } { UpdateNuspec $nuspecPathCS "C#" } @@ -110,31 +161,35 @@ Task Update-Nuspec-VB -precondition { return $isAppVeyor -and ($isRelease -ne $t UpdateNuspec $nuspecPathVB "VB" } -Task Pack-Nuget -precondition { return $isAppVeyor } -depends Pack-Nuget-Joint -Task Pack-Nuget-Joint -precondition { return $isAppVeyor } -depends Pack-Nuget-Csharp, Pack-Nuget-VB { - #we won't be publishing the common package anymore - #PackNuget "Joint package" "$rootDir" $nuspecPathJoint $nupkgPathJoint -} +Task Pack-Nuget -precondition { return $isAppVeyor } -depends Pack-Nuget-Csharp, Pack-Nuget-VB Task Pack-Nuget-CSharp -precondition { return $isAppVeyor } { PackNuget "C#" "$rootDir\src\CSharp" $nuspecPathCS $nupkgPathCS } Task Pack-Nuget-VB -precondition { return $isAppVeyor } { PackNuget "VB" "$rootDir\src\VisualBasic" $nuspecPathVB $nupkgPathVB } +Task Pack-Nuget-Force -depends Pack-Nuget-Csharp-Force, Pack-Nuget-VB-Force +Task Pack-Nuget-Csharp-Force { + PackNuget "C#" "$rootDir\src\CSharp" $nuspecPathCS $nupkgPathCS +} +Task Pack-Nuget-VB-Force { + PackNuget "VB" "$rootDir\src\VisualBasic" $nuspecPathVB $nupkgPathVB +} Task Echo { echo echo } function PackNuget($language, $dir, $nuspecFile, $nupkgFile) { Write-Host "Packing nuget for $language..." - [xml]$xml = cat $nuspecFile + [xml]$xml = cat "$nuspecFile" $nupkgFile = $nupkgFile -f $xml.package.metadata.version - Write-Host "Nupkg path is $nupkgFile" - . $nugetExe pack $nuspecFile -OutputDirectory $dir - ls $nupkgFile - Write-Host "Nuget packed for $language!" - Write-Host "Pushing nuget artifact for $language..." - appveyor PushArtifact $nupkgFile - Write-Host "Nupkg pushed for $language!" + . $nugetExe pack "$nuspecFile" -OutputDirectory "$dir" + $nuspecFileName = (ls $nuspecFile).Name + Write-Host " $nuspecFileName ($language/$($xml.package.metadata.version)) -> $nupkgFile" + if ($isAppVeyor) { + Write-Host "Pushing nuget artifact for $language..." + appveyor PushArtifact $nupkgFile + Write-Host "Nupkg pushed for $language!" + } } function UpdateNuspec($nuspecPath, $language) { @@ -223,4 +278,4 @@ function RunTestWithCoverage($fullTestDllPaths) { Write-Host -ForegroundColor DarkBlue "Uploading coverage report to Coveralls.io" Exec { . $coverallsNetExe --opencover $outputXml --full-sources } } -} +} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/CodeCracker.nuspec b/src/CSharp/CodeCracker/CodeCracker.nuspec index fdfc1e815..91e3f5c70 100644 --- a/src/CSharp/CodeCracker/CodeCracker.nuspec +++ b/src/CSharp/CodeCracker/CodeCracker.nuspec @@ -22,7 +22,7 @@ This is a community project, free and open source. Everyone is invited to contri true - + diff --git a/src/CodeCracker.nuspec b/src/CodeCracker.nuspec deleted file mode 100644 index f5113b83b..000000000 --- a/src/CodeCracker.nuspec +++ /dev/null @@ -1,30 +0,0 @@ - - - - codecracker - 1.1.0 - CodeCracker for C# and VB - giggio,elemarjr,carloscds - giggio,elemarjr,carloscds - https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt - http://code-cracker.github.io/ - https://avatars1.githubusercontent.com/u/9695920?v=3&s=200 - true - A analyzer library for C# and VB that uses Roslyn to produce refactorings, code analysis, and other niceties. - -You probably don't want this package directly, search for the C# or Visual Basic specific packages (codecracker.CSharp and codecracker.VisualBasic). This will install both. - -This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. - See https://github.com/code-cracker/code-cracker/blob/master/CHANGELOG.md - Copyright CodeCracker 2014-2016 - roslyn, analyzers - - - - - - - - - - diff --git a/src/VisualBasic/CodeCracker/CodeCracker.nuspec b/src/VisualBasic/CodeCracker/CodeCracker.nuspec index 326c5ccb4..8c35dc85b 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.nuspec +++ b/src/VisualBasic/CodeCracker/CodeCracker.nuspec @@ -21,7 +21,7 @@ This is a community project, free and open source. Everyone is invited to contri - + From d37dbd240d893574d35c1f1fe322d1742aa5d961 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 19:44:52 -0300 Subject: [PATCH 279/358] Update dependencies --- .nuget/packages.config | 4 +- build.targets.ps1 | 3 +- psake.ps1 | 4 +- src/CSharp/CodeCracker/CodeCracker.csproj | 50 ++++++++----------- src/CSharp/CodeCracker/packages.config | 16 +++--- .../CodeCracker.Common.csproj | 28 +++++------ src/Common/CodeCracker.Common/packages.config | 12 ++--- .../CodeCracker/CodeCracker.vbproj | 38 ++++++-------- src/VisualBasic/CodeCracker/packages.config | 16 +++--- .../CodeCracker.Test/CodeCracker.Test.csproj | 44 +++++++--------- test/CSharp/CodeCracker.Test/packages.config | 24 ++++++--- .../CodeCracker.Test.Common.csproj | 45 ++++++++--------- .../CodeCracker.Test.Common/packages.config | 28 +++++++---- .../CodeCracker.Test/CodeCracker.Test.vbproj | 44 +++++++--------- .../CodeCracker.Test/packages.config | 24 ++++++--- 15 files changed, 188 insertions(+), 192 deletions(-) diff --git a/.nuget/packages.config b/.nuget/packages.config index 964028c5c..9707f7736 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,6 +1,6 @@  - - + + diff --git a/build.targets.ps1 b/build.targets.ps1 index 253bf1955..f5be72100 100644 --- a/build.targets.ps1 +++ b/build.targets.ps1 @@ -10,7 +10,8 @@ Properties { $buildNumber = [Convert]::ToInt32($env:APPVEYOR_BUILD_NUMBER).ToString("0000") $nuspecPathCS = "$rootDir\src\CSharp\CodeCracker\CodeCracker.nuspec" $nuspecPathVB = "$rootDir\src\VisualBasic\CodeCracker\CodeCracker.nuspec" - $nugetExe = "$packagesDir\NuGet.CommandLine.3.3.0\tools\NuGet.exe" + $nugetPackagesExe = "$packagesDir\NuGet.CommandLine.4.1.0\tools\NuGet.exe" + $nugetExe = if (Test-Path $nugetPackagesExe) { $nugetPackagesExe } else { 'nuget' } $nupkgPathCS = "$rootDir\src\CSharp\CodeCracker.CSharp.{0}.nupkg" $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe" diff --git a/psake.ps1 b/psake.ps1 index de6e34a2d..ce647902b 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -1,3 +1,3 @@ -Import-Module $PSScriptRoot\packages\psake.4.5.0\tools\psake.psm1 -force -Invoke-Expression("Invoke-psake -framework '4.5.2' build.targets.ps1 " + $MyInvocation.UnboundArguments -join " ") +Import-Module $PSScriptRoot\packages\psake.4.6.0\tools\psake.psm1 -force +Invoke-Expression("Invoke-psake -framework '4.5.2' $PSScriptRoot\build.targets.ps1 " + $MyInvocation.UnboundArguments -join " ") exit !($psake.build_success) \ No newline at end of file diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index a6d7d52d7..ea63f7981 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -222,37 +222,26 @@ - - {753d4757-fcba-43ba-b1be-89201acda192} - CodeCracker.Common - + + + + - - - - - - - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - - ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - False + + ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll @@ -274,11 +263,16 @@ ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll False - - ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll - False + + ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + {753d4757-fcba-43ba-b1be-89201acda192} + CodeCracker.Common + + diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index d1bbcab2c..fcde436eb 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,12 +1,12 @@  - - - - - - + + + + + + - - + + \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 3426e7d12..f20344f73 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -70,23 +70,20 @@ - - - - + + + + - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - - ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - False + + ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll @@ -108,9 +105,8 @@ ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll False - - ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll - False + + ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index d8681f9ca..847a13861 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,10 +1,10 @@  - - - - + + + + - - + + \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index e2deff9b9..02045debc 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -162,31 +162,26 @@ - - - - + + + + - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - False + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - - ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - False + + ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll @@ -208,9 +203,8 @@ ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll False - - ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll - False + + ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index 20b3df7df..bc11241d0 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,12 +1,12 @@  - - - - - - + + + + + + - - + + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 4198a1676..c45a93ec6 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -46,32 +46,27 @@ ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.Core.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - - ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll True @@ -95,9 +90,8 @@ True - - ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll - True + + ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll @@ -213,7 +207,7 @@ CodeCracker.Common - {FF1097FB-A890-461B-979E-064697891B96} + {ff1097fb-a890-461b-979e-064697891b96} CodeCracker @@ -232,10 +226,10 @@ - - - - + + + + diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config index e6e8b042c..22638264b 100644 --- a/test/CSharp/CodeCracker.Test/packages.config +++ b/test/CSharp/CodeCracker.Test/packages.config @@ -1,16 +1,24 @@  - + - - - - - + + + + + - - + + + + + + + + + + diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index fb0650aee..905792f36 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -41,33 +41,33 @@ ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.Core.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.0.0\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.0.0\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - - ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll True @@ -91,9 +91,8 @@ True - - ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll - True + + ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll @@ -130,10 +129,10 @@ - - - - + + + + diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config index b75a21670..c24c4bdc2 100644 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ b/test/Common/CodeCracker.Test.Common/packages.config @@ -1,21 +1,29 @@  - + - - - - - - - + + + + + + + - - + + + + + + + + + + diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index 77000d42d..a0ead244c 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -60,32 +60,27 @@ ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.Core.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.0.0\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.0.0\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll - True + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - - ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll True @@ -108,9 +103,8 @@ ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll True - - ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll - True + + ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll @@ -222,10 +216,10 @@ - - - - + + + + @@ -241,4 +235,4 @@ --> - + \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config index 8742f779c..4e3b70206 100644 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ b/test/VisualBasic/CodeCracker.Test/packages.config @@ -1,16 +1,24 @@  - + - - - - - + + + + + - - + + + + + + + + + + From ae3513041ad8e7cabba002ab60cfdba907c11775 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 19:53:51 -0300 Subject: [PATCH 280/358] Move build.targets.ps1 to default.ps1 to ease psake use Now we don't need to go through build.ps1 for eveything anymore, we can use psake directly as default.ps1 is the default file name for psake. --- CodeCracker.sln | 7 +++---- build.ps1 | 2 +- build.targets.ps1 => default.ps1 | 0 psake.ps1 | 3 --- 4 files changed, 4 insertions(+), 8 deletions(-) rename build.targets.ps1 => default.ps1 (100%) delete mode 100644 psake.ps1 diff --git a/CodeCracker.sln b/CodeCracker.sln index 8061066fb..64406cda0 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" EndProject @@ -42,8 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{234973E7 ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - build.targets.ps1 = build.targets.ps1 - psake.ps1 = psake.ps1 + default.ps1 = default.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6E93-4D2D-B6F0-141B977AFC9F}" diff --git a/build.ps1 b/build.ps1 index 95d279b16..821027472 100644 --- a/build.ps1 +++ b/build.ps1 @@ -73,7 +73,7 @@ Get-Nuget Import-Psake Import-ILMerge if ($MyInvocation.UnboundArguments.Count -ne 0) { - . $PSScriptRoot\psake.ps1 -taskList ($MyInvocation.UnboundArguments -join " ") + Invoke-Expression("Invoke-psake -framework '4.5.2' $PSScriptRoot\default.ps1 -taskList " + $MyInvocation.UnboundArguments -join " ") } else { . $PSScriptRoot\build.ps1 Build diff --git a/build.targets.ps1 b/default.ps1 similarity index 100% rename from build.targets.ps1 rename to default.ps1 diff --git a/psake.ps1 b/psake.ps1 deleted file mode 100644 index ce647902b..000000000 --- a/psake.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -Import-Module $PSScriptRoot\packages\psake.4.6.0\tools\psake.psm1 -force -Invoke-Expression("Invoke-psake -framework '4.5.2' $PSScriptRoot\build.targets.ps1 " + $MyInvocation.UnboundArguments -join " ") -exit !($psake.build_success) \ No newline at end of file From 163f6bfca19085a65b95a01180c8d357b01a3fd8 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 20:03:15 -0300 Subject: [PATCH 281/358] Adjust sln files to the new psake structure --- CodeCracker.2015.sln | 5 ++--- CodeCracker.CSharp.2015.sln | 7 +++---- CodeCracker.CSharp.sln | 7 +++---- CodeCracker.VisualBasic.2015.sln | 5 ++--- CodeCracker.VisualBasic.sln | 7 +++---- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/CodeCracker.2015.sln b/CodeCracker.2015.sln index 729d7ca60..61766491e 100644 --- a/CodeCracker.2015.sln +++ b/CodeCracker.2015.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" EndProject @@ -42,8 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{234973E7 ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - build.targets.ps1 = build.targets.ps1 - psake.ps1 = psake.ps1 + default.ps1 = default.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6E93-4D2D-B6F0-141B977AFC9F}" diff --git a/CodeCracker.CSharp.2015.sln b/CodeCracker.CSharp.2015.sln index 0600d9a27..f1ddbefd2 100644 --- a/CodeCracker.CSharp.2015.sln +++ b/CodeCracker.CSharp.2015.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F5240AD-2B4E-48A4-B9FC-7D19DACEF2CD}" ProjectSection(SolutionItems) = preProject @@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F5240 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker", "src\CSharp\CodeCracker\CodeCracker.csproj", "{FF1097FB-A890-461B-979E-064697891B96}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.2015.Vsix", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{6BAC4057-7239-485E-A04B-02E687A83BAA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{6BAC4057-7239-485E-A04B-02E687A83BAA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test", "test\CSharp\CodeCracker.Test\CodeCracker.Test.csproj", "{F7843158-046E-4B22-95D7-CAC7BB01283D}" EndProject @@ -36,8 +36,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{40545653 ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - build.targets.ps1 = build.targets.ps1 - psake.ps1 = psake.ps1 + default.ps1 = default.ps1 EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" diff --git a/CodeCracker.CSharp.sln b/CodeCracker.CSharp.sln index 2f52cf033..e075a10f0 100644 --- a/CodeCracker.CSharp.sln +++ b/CodeCracker.CSharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F5240AD-2B4E-48A4-B9FC-7D19DACEF2CD}" ProjectSection(SolutionItems) = preProject @@ -36,8 +36,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{40545653 ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - build.targets.ps1 = build.targets.ps1 - psake.ps1 = psake.ps1 + default.ps1 = default.ps1 EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" diff --git a/CodeCracker.VisualBasic.2015.sln b/CodeCracker.VisualBasic.2015.sln index 9d3b4ba56..cec5830dd 100644 --- a/CodeCracker.VisualBasic.2015.sln +++ b/CodeCracker.VisualBasic.2015.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" EndProject @@ -24,8 +24,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{D1591C8E ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - build.targets.ps1 = build.targets.ps1 - psake.ps1 = psake.ps1 + default.ps1 = default.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{22D6C608-E7F1-4236-BB07-BE5F97A4C810}" diff --git a/CodeCracker.VisualBasic.sln b/CodeCracker.VisualBasic.sln index 6b903192a..b338754d2 100644 --- a/CodeCracker.VisualBasic.sln +++ b/CodeCracker.VisualBasic.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" EndProject @@ -24,8 +24,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{D1591C8E ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - build.targets.ps1 = build.targets.ps1 - psake.ps1 = psake.ps1 + default.ps1 = default.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{22D6C608-E7F1-4236-BB07-BE5F97A4C810}" From 143c6861fd0c3858503066c5ba94b593807eda43 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 20:08:46 -0300 Subject: [PATCH 282/358] Remove vs 2015 solutions from psake file --- default.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.ps1 b/default.ps1 index f5be72100..d524aad28 100644 --- a/default.ps1 +++ b/default.ps1 @@ -5,7 +5,7 @@ Properties { $srcDir = "$rootDir\src" $testDir = "$rootDir\test" $isAppVeyor = $env:APPVEYOR -eq $true - $slns = ls "$rootDir\*.sln" + $slns = ls "$rootDir\*.sln" | ? { ! $_.Name.Contains('.2015.') } $packagesDir = "$rootDir\packages" $buildNumber = [Convert]::ToInt32($env:APPVEYOR_BUILD_NUMBER).ToString("0000") $nuspecPathCS = "$rootDir\src\CSharp\CodeCracker\CodeCracker.nuspec" From 6af54565725cae759e8b6469053ee3631d6f3ee0 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 20:27:06 -0300 Subject: [PATCH 283/358] Be more specific about nuget restore --- default.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.ps1 b/default.ps1 index d524aad28..a36f5fad6 100644 --- a/default.ps1 +++ b/default.ps1 @@ -205,7 +205,7 @@ function UpdateNuspec($nuspecPath, $language) { function RestorePkgs($sln) { Write-Host "Restoring $sln..." -ForegroundColor Green Retry { - . $nugetExe restore $sln + . $nugetExe restore "$sln" -MSBuildVersion 14 -NonInteractive -ConfigFile "$rootDir\nuget.config" if ($LASTEXITCODE) { throw "Nuget restore for $sln failed." } } } From 1e3e459407ac2661f634112b872325e29c31cd65 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 23 Jun 2017 02:08:26 +0200 Subject: [PATCH 284/358] Fix CC0014 casting rule bugs Closes #911 --- .../Style/TernaryOperatorCodeFixProvider.cs | 31 ++--------- .../Style/TernaryOperatorTests.cs | 55 +++++++++++++++++++ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 8444c0705..b36fa9584 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -222,21 +222,16 @@ private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionS if (!elseType.HasImplicitNumericConversion(ifType) && !IsEnumAndZero(ifType, elseExpression) && !IsEnumAndZero(elseType, ifExpression) - && (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType))) - trueExpression = CastToBaseType(ifExpression, ifType, elseType, trueExpression); + && (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType)) + && ifType != ifConvertedType) + trueExpression = CastToConvertedType(ifExpression, ifConvertedType); } private static bool IsEnumAndZero(ITypeSymbol type, ExpressionSyntax expression) => type?.BaseType?.SpecialType == SpecialType.System_Enum && expression?.ToString() == "0"; - private static ExpressionSyntax CastToBaseType(ExpressionSyntax ifExpression, ITypeSymbol ifType, ITypeSymbol elseType, ExpressionSyntax trueExpression) - { - var commonBaseType = ifType.GetCommonBaseType(elseType); - if (commonBaseType.Equals(ifType)) return trueExpression; - if (commonBaseType != null) - trueExpression = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(commonBaseType.Name).WithAdditionalAnnotations(Simplifier.Annotation), ifExpression); - return trueExpression; - } + private static ExpressionSyntax CastToConvertedType(ExpressionSyntax ifExpression, ITypeSymbol ifConvertedType) + => SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(ifConvertedType.ToString()).WithAdditionalAnnotations(Simplifier.Annotation), ifExpression); private static bool CanBeAssignedTo(this ITypeSymbol type, ITypeSymbol possibleBaseType) { @@ -252,21 +247,5 @@ private static bool CanBeAssignedTo(this ITypeSymbol type, ITypeSymbol possibleB } return false; } - - private static ITypeSymbol GetCommonBaseType(this ITypeSymbol type, ITypeSymbol otherType) - { - var baseType = type; - while (baseType != null) - { - var otherBaseType = otherType; - while (otherBaseType != null) - { - if (baseType.Equals(otherBaseType)) return baseType; - otherBaseType = otherBaseType.BaseType; - } - baseType = baseType.BaseType; - } - return null; - } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index c9c86f91c..ccfc31761 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -396,6 +396,23 @@ public void Foo() }".WrapInCSharpClass(); await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentToAnInterfaceVariableAFittingCastIsInserted() + { + var source = @" + System.Collections.Generic.IEnumerable e= null; + if (true) + e = new int[10]; + else + e = new System.Collections.Generic.List(); + ".WrapInCSharpMethod(); + var fixtest = @" + System.Collections.Generic.IEnumerable e= null; + e = true ? (System.Collections.Generic.IEnumerable)new int[10] : new System.Collections.Generic.List(); + ".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(source, fixtest); + } } public class TernaryOperatorWithReturnTests : CodeFixVerifier @@ -1327,5 +1344,43 @@ public Object Foo() }".WrapInCSharpClass(); await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenReturnTypeIsAnInterfaceAFittingCastIsInserted() + { + var source = @" + IComparable GetComparable() + { + if (true) + return 1; + else + return ""1""; + }".WrapInCSharpClass(); + var fixtest = @" + IComparable GetComparable() + { + return true?(IComparable)1 : ""1""; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithReturnTypeIsExplicitConvertable() + { + var source = @" + double GetNumber() + { + if (true) + return 1; + else + return 1.1; + }".WrapInCSharpClass(); + var fixtest = @" + double GetNumber() + { + return true?(double)1:1.1; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From bc88e5dc9ecec941224f5fc4a83af5875601f42f Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 21:10:18 -0300 Subject: [PATCH 285/358] Update .gitigore from master --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3da239e30..b5c6a38ac 100644 --- a/.gitignore +++ b/.gitignore @@ -192,3 +192,4 @@ ModelManifest.xml log/ .vs nuget.exe +*.nupkg From 4595fbe1696845b21f952f14c68ca19c6aa13168 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 23 Jun 2017 02:08:26 +0200 Subject: [PATCH 286/358] Fix CC0014 casting rule bugs Closes #911 --- .../Style/TernaryOperatorCodeFixProvider.cs | 31 +- .../Style/TernaryOperatorTests.cs | 659 ++++++++++++++++++ 2 files changed, 664 insertions(+), 26 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 97ebd2e3f..3c8c8a9f1 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -138,21 +138,16 @@ private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionS if (!elseType.HasImplicitNumericConversion(ifType) && !IsEnumAndZero(ifType, elseExpression) && !IsEnumAndZero(elseType, ifExpression) - && (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType))) - trueExpression = CastToBaseType(ifExpression, ifType, elseType, trueExpression); + && (!isNullable && !ifType.CanBeAssignedTo(elseType) || !elseType.CanBeAssignedTo(ifType)) + && ifType != ifConvertedType) + trueExpression = CastToConvertedType(ifExpression, ifConvertedType); } private static bool IsEnumAndZero(ITypeSymbol type, ExpressionSyntax expression) => type?.BaseType?.SpecialType == SpecialType.System_Enum && expression?.ToString() == "0"; - private static ExpressionSyntax CastToBaseType(ExpressionSyntax ifExpression, ITypeSymbol ifType, ITypeSymbol elseType, ExpressionSyntax trueExpression) - { - var commonBaseType = ifType.GetCommonBaseType(elseType); - if (commonBaseType.Equals(ifType)) return trueExpression; - if (commonBaseType != null) - trueExpression = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(commonBaseType.Name).WithAdditionalAnnotations(Simplifier.Annotation), ifExpression); - return trueExpression; - } + private static ExpressionSyntax CastToConvertedType(ExpressionSyntax ifExpression, ITypeSymbol ifConvertedType) + => SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(ifConvertedType.ToString()).WithAdditionalAnnotations(Simplifier.Annotation), ifExpression); private static bool CanBeAssignedTo(this ITypeSymbol type, ITypeSymbol possibleBaseType) { @@ -168,21 +163,5 @@ private static bool CanBeAssignedTo(this ITypeSymbol type, ITypeSymbol possibleB } return false; } - - private static ITypeSymbol GetCommonBaseType(this ITypeSymbol type, ITypeSymbol otherType) - { - var baseType = type; - while (baseType != null) - { - var otherBaseType = otherType; - while (otherBaseType != null) - { - if (baseType.Equals(otherBaseType)) return baseType; - otherBaseType = otherBaseType.BaseType; - } - baseType = baseType.BaseType; - } - return null; - } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs index 68d90f96d..ccfc31761 100644 --- a/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TernaryOperatorTests.cs @@ -334,6 +334,85 @@ public static void Foo() "; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultChangeToTernaryFixGetsArgsApplied() + { + var source = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + if (something) + { + a = Method(1); + } + else + { + a = Method(2); + } + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + a = Method(something?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentOfMethodResultWithComplexArgumentEvaluationChangeToTernaryFixGetsArgsApplied() + { + var source = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + if (something) + { + a = Method(1); + } + else + { + a = Method(2 + 2); + } + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a) => a; + + public void Foo() + { + var something = true; + int a; + a = Method(something?1:2 + 2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task WhenUsingIfAndElseWithAssignmentToAnInterfaceVariableAFittingCastIsInserted() + { + var source = @" + System.Collections.Generic.IEnumerable e= null; + if (true) + e = new int[10]; + else + e = new System.Collections.Generic.List(); + ".WrapInCSharpMethod(); + var fixtest = @" + System.Collections.Generic.IEnumerable e= null; + e = true ? (System.Collections.Generic.IEnumerable)new int[10] : new System.Collections.Generic.List(); + ".WrapInCSharpMethod(); + await VerifyCSharpFixAsync(source, fixtest); + } } public class TernaryOperatorWithReturnTests : CodeFixVerifier @@ -723,5 +802,585 @@ public static Base Foo() "; await VerifyCSharpFixAsync(source, fixtest); } + + [Fact] + public async Task WhenReturnStatementContainsMethodCallAnalyzerCreatesDiagnostic() + { + var source = @" + private int Method(int i) => i; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var expected = new DiagnosticResult + { + Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), + Message = "You can use a ternary operator.", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 17) } + }; + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithSingleDifferentArgumentGetsArgsApplied() + { + var source = @" + private int Method(int i) => i; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i) => i; + + public int Foo() + { + return Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereSingleDifferentGetsArgsApplied() + { + var source = @" + private int Method(int i, string t) => i; + + public int Foo() + { + if (true) + return Method(1, ""hello""); + else + return Method(2, ""hello""); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i, string t) => i; + + public int Foo() + { + return Method(true?1:2, ""hello""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodWithMultipleArgumentsWhereMultipleDifferentGetsArgsNotApplied() + { + var source = @" + private int Method(int i, string t) => i; + + public int Foo() + { + if (true) + return Method(1, ""hello1""); + else + return Method(2, ""hello2""); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int i, string t) => i; + + public int Foo() + { + return true?Method(1,""hello1""):Method(2, ""hello2""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodArgumentsGetCastedWhenGetsArgsApplied() + { + var source = @" + class Base { } + class A : Base { } + class B : Base { } + + private int Method(Base b, string t) => 1; + + public int Foo() + { + if (true) + return Method(new A(), ""hello""); + else + return Method(new B(), ""hello""); + }".WrapInCSharpClass(); + var fixtest = @" + class Base { } + class A : Base { } + class B : Base { } + + private int Method(Base b, string t) => 1; + + public int Foo() + { + return Method(true?(Base)new A():new B(),""hello""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithPrefixedMethodGetsArgsApplied() + { + var source = @" + private int Method(int a) => a; + + public int Foo() + { + if (true) + return this.Method(1); + else + return this.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + private int Method(int a) => a; + + public int Foo() + { + return this.Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfPropertyGetsArgsApplied() + { + var source = @" + class A { + private int Method(int a) => a; + } + + public int Foo() + { + var a=new A(); + if (true) + return a.Method(1); + else + return a.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + class A { + private int Method(int a) => a; + } + + public int Foo() + { + var a=new A(); + return a.Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentPropertyGetsArgsNotApplied() + { + var source = @" + class A { + public int Method(int a) => a; + } + A Prop1 { get { return new A(); } } + A Prop2 { get { return new A(); } } + + public int Foo() + { + if (true) + return this.Prop1.Method(1); + else + return this.Prop2.Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + class A { + public int Method(int a) => a; + } + A Prop1 { get { return new A(); } } + A Prop2 { get { return new A(); } } + + public int Foo() + { + return true?this.Prop1.Method(1):this.Prop2.Method(2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfSameOverloadGetsArgsApplied() + { + var source = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(2); + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + return Method(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentOverloadGetsArgsNotApplied() + { + var source = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + if (true) + return Method(1); + else + return Method(""2""); + }".WrapInCSharpClass(); + var fixtest = @" + int Method(int a)=>a; + int Method(string a)=>1; + + public int Foo() + { + return true?Method(1):Method(""2""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDifferentOverloadButCastingPossibleGetsArgsNotApplied() + { + var source = @" + public class A { } + public class B:A { } + void Method(A a) { }; + void Method(B b) { }; + + public int Foo() + { + if (true) + return Method(new A()); + else + return Method(new B()); + }".WrapInCSharpClass(); + var fixtest = @" + public class A { } + public class B:A { } + void Method(A a) { }; + void Method(B b) { }; + + public int Foo() + { + return true?Method(new A()):Method(new B()); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodNestedInMemberAccessGetsArgsNotApplied() + { + var source = @" + class A { + public int Prop { get; } + } + + A GetA(int i) => new A(); + + public int Foo() + { + if (true) + return GetA(1).Prop; + else + return GetA(2).Prop; + }".WrapInCSharpClass(); + var fixtest = @" + class A { + public int Prop { get; } + } + + A GetA(int i) => new A(); + + public int Foo() + { + return true?GetA(1).Prop:GetA(2).Prop; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodParamOverloadAndNumerOfArgsAreEqualGetsApplied() + { + var source = @" + private int M(params int[] args) { } + + public int Foo() + { + if (true) + return M(1,1); + else + return M(1,2); + }".WrapInCSharpClass(); + var fixtest = @" + private int M(params int[] args) { } + + public int Foo() + { + return M(1,true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodParamOverloadAndNumerOfArgsAreDifferentGetsNotApplied() + { + var source = @" + private int M(params int[] args) { } + + public int Foo() + { + if (true) + return M(1,1); + else + return M(1,2,3); + }".WrapInCSharpClass(); + var fixtest = @" + private int M(params int[] args) { } + + public int Foo() + { + return true?M(1,1):M(1,2,3); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDynamicObjGetsArgsNotApplied() + { + // Calls on dynamic objects get dispatched during runtime. + // Therefore the semantic would be changed if we apply to arguments + // and casting is involved: + // d.M(new A()) else d.M(new B()) -> d.M(cond?(Base)new A():new B()); + // is not the same as cond?d.M(new A()): d.M(new B()) on dynamic objects. + var source = @" + public class Base {} + public class A: Base {} + public class B: Base {} + + public int Foo() + { + dynamic d = new object(); + if (true) + return d.M(new A()); + else + return d.M(new B()); + }".WrapInCSharpClass(); + var fixtest = @" + public class Base {} + public class A: Base {} + public class B: Base {} + + public int Foo() + { + dynamic d = new object(); + return true?d.M(new A()):d.M(new B()); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithMethodOfDynamicObjGetsArgsNeverApplied() + { + // arguments on dynamic method calls are never applied even if it would be save. + // see comments above for why dynamic is dangerous. + var source = @" + public int Foo() + { + dynamic d = new object(); + if (true) + return d.M(1,1); + else + return d.M(1,2); + }".WrapInCSharpClass(); + var fixtest = @" + public int Foo() + { + dynamic d = new object(); + return true?d.M(1,1):d.M(1,2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorGetsArgsApplied() + { + var source = @" + public System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1); + else + return new System.Collections.Generic.List(2); + }".WrapInCSharpClass(); + var fixtest = @" + public System.Collections.Generic.List Foo() + { + return new System.Collections.Generic.List(true?1:2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithIdenticalInitializerGetsArgsApplied() + { + var source = @" + public new System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1) { 1 }; + else + return new System.Collections.Generic.List(2) { 1 }; + }".WrapInCSharpClass(); + var fixtest = @" + public new System.Collections.Generic.List Foo() + { + return new System.Collections.Generic.List(true?1:2) { 1 }; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithDifferentInitializerGetsArgsNotApplied() + { + var source = @" + public System.Collections.Generic.List Foo() + { + if (true) + return new System.Collections.Generic.List(1) { 1 }; + else + return new System.Collections.Generic.List(2) { 1, 2 }; + }".WrapInCSharpClass(); + var fixtest = @" + public System.Collections.Generic.List Foo() + { + return true?new System.Collections.Generic.List(1) { 1 } : new System.Collections.Generic.List(2) { 1, 2 }; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorWithDifferentOverloadsGetArgsNotApplied() + { + var source = @" + public class A + { + public A(int i) { } + public A(string s) { } + } + public A Foo() + { + if (true) + return new A(1); + else + return new A(""1""); + }".WrapInCSharpClass(); + var fixtest = @" + public class A + { + public A(int i) { } + public A(string s) { } + } + public A Foo() + { + return true?new A(1):new A(""1""); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithConstructorOfDifferentObjectsGetArgsNotApplied() + { + var source = @" + public class A + { + public A(int i) { } + } + public class B + { + public B(int i) { } + } + + public Object Foo() + { + if (true) + return new A(1); + else + return new B(2); + }".WrapInCSharpClass(); + var fixtest = @" + public class A + { + public A(int i) { } + } + public class B + { + public B(int i) { } + } + + public Object Foo() + { + return true?(object)new A(1):new B(2); + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task WhenReturnTypeIsAnInterfaceAFittingCastIsInserted() + { + var source = @" + IComparable GetComparable() + { + if (true) + return 1; + else + return ""1""; + }".WrapInCSharpClass(); + var fixtest = @" + IComparable GetComparable() + { + return true?(IComparable)1 : ""1""; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task FixWhenReturningWithReturnTypeIsExplicitConvertable() + { + var source = @" + double GetNumber() + { + if (true) + return 1; + else + return 1.1; + }".WrapInCSharpClass(); + var fixtest = @" + double GetNumber() + { + return true?(double)1:1.1; + }".WrapInCSharpClass(); + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From fe1b3ea9b9548a85d9e4aa2d85006795346f406c Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 21:40:04 -0300 Subject: [PATCH 287/358] Update TernaryOperatorCodeFixProvider.cs to match master branch --- .../Style/TernaryOperatorCodeFixProvider.cs | 98 +++++++++++++++++-- 1 file changed, 91 insertions(+), 7 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs index 3c8c8a9f1..b36fa9584 100644 --- a/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TernaryOperatorCodeFixProvider.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using System; namespace CodeCracker.CSharp.Style { @@ -37,11 +38,10 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var elseStatement = ifStatement.Else; var returnStatementInsideElse = (ReturnStatementSyntax)(elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement); var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - ExpressionSyntax trueExpression, falseExpression; - TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, semanticModel, out trueExpression, out falseExpression); + var conditionalExpression = TernaryOperatorCodeFixHelper.CreateExpressions(returnStatementInsideIf.Expression, returnStatementInsideElse.Expression, ifStatement.Condition, semanticModel); var ternary = SyntaxFactory.ReturnStatement( - SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression)) + conditionalExpression) .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(ifStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); @@ -76,14 +76,13 @@ private static async Task MakeTernaryAsync(Document document, Diagnost var assignmentExpressionInsideIf = (AssignmentExpressionSyntax)expressionInsideIf.Expression; var assignmentExpressionInsideElse = (AssignmentExpressionSyntax)expressionInsideElse.Expression; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - ExpressionSyntax trueExpression, falseExpression; - TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, semanticModel, out trueExpression, out falseExpression); + var conditionalExpression = TernaryOperatorCodeFixHelper.CreateExpressions(assignmentExpressionInsideIf.Right, assignmentExpressionInsideElse.Right, ifStatement.Condition, semanticModel); var ternary = SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( assignmentExpressionInsideIf.Kind(), assignmentExpressionInsideIf.Left, - SyntaxFactory.ConditionalExpression(ifStatement.Condition, trueExpression, falseExpression))) + conditionalExpression)) .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(ifStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); @@ -95,13 +94,98 @@ private static async Task MakeTernaryAsync(Document document, Diagnost internal static class TernaryOperatorCodeFixHelper { - public static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel, out ExpressionSyntax trueExpression, out ExpressionSyntax falseExpression) + public static ExpressionSyntax CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, ExpressionSyntax ifStatementCondition, SemanticModel semanticModel) + { + + var methodCallArgApplied = TryApplyArgsOnMethodCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (methodCallArgApplied != null) return methodCallArgApplied; + var constructorArgsApplied = TryApplyArgsOnConstructorCalls(ifStatementCondition, ifExpression, elseExpression, semanticModel); + if (constructorArgsApplied != null) return constructorArgsApplied; + var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); + var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); + var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + ExpressionSyntax trueExpression; ExpressionSyntax falseExpression; + CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, + ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); + } + + private static ExpressionSyntax TryApplyArgsOnConstructorCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + { + if (ifExpression is ObjectCreationExpressionSyntax && elseExpression is ObjectCreationExpressionSyntax) + { + var ifObjCreation = ifExpression as ObjectCreationExpressionSyntax; + var elseObjCreation = elseExpression as ObjectCreationExpressionSyntax; + if ((ifObjCreation.Initializer == null && elseObjCreation.Initializer == null) || + ifObjCreation.Initializer != null && elseObjCreation.Initializer != null && + ifObjCreation.Initializer.GetText().ContentEquals(elseObjCreation.Initializer.GetText())) // Initializer are either absent or text equals + { + var ifMethodinfo = semanticModel.GetSymbolInfo(ifObjCreation); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseObjCreation); + if (object.Equals(ifMethodinfo, elseMethodinfo)) //same constructor and overload + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifObjCreation.ArgumentList, elseObjCreation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.ObjectCreationExpression(ifObjCreation.Type, CreateMethodArgumentList(ifStatementCondition, ifObjCreation.ArgumentList, elseObjCreation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel), ifObjCreation.Initializer); + } + } + } + return null; + } + + private static ExpressionSyntax TryApplyArgsOnMethodCalls(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) + { + if (ifExpression is InvocationExpressionSyntax && elseExpression is InvocationExpressionSyntax) + { + var ifInvocation = ifExpression as InvocationExpressionSyntax; + var elseInvocation = elseExpression as InvocationExpressionSyntax; + var ifMethodinfo = semanticModel.GetSymbolInfo(ifInvocation.Expression); + var elseMethodinfo = semanticModel.GetSymbolInfo(elseInvocation.Expression); + if (object.Equals(ifMethodinfo, elseMethodinfo) && ifMethodinfo.CandidateReason != CandidateReason.LateBound) //same method and overload, but not dynamic + { + if (ifInvocation.Expression.GetText().ContentEquals(elseInvocation.Expression.GetText())) //same 'path' to the invocation + { + var findSingleArgumentIndexThatDiffers = FindSingleArgumentIndexThatDiffers(ifInvocation.ArgumentList, elseInvocation.ArgumentList, semanticModel); + if (findSingleArgumentIndexThatDiffers >= 0) + return SyntaxFactory.InvocationExpression(ifInvocation.Expression, CreateMethodArgumentList(ifStatementCondition, ifInvocation.ArgumentList, elseInvocation.ArgumentList, findSingleArgumentIndexThatDiffers, semanticModel)); + } + } + } + return null; + } + + private static ArgumentListSyntax CreateMethodArgumentList(ExpressionSyntax ifStatementCondition, ArgumentListSyntax argList1, ArgumentListSyntax argList2, int argumentIndexThatDiffers, SemanticModel semanticModel) + { + var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); + var argSelector = zipped.Select((args, i) => + (i == argumentIndexThatDiffers) ? + SyntaxFactory.Argument(GetConditionalExpressionForArgument(ifStatementCondition, args.a1.Expression, args.a2.Expression, semanticModel)) + : args.a1); + return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argSelector)); + } + + private static ConditionalExpressionSyntax GetConditionalExpressionForArgument(ExpressionSyntax ifStatementCondition, ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, SemanticModel semanticModel) { var ifTypeInfo = semanticModel.GetTypeInfo(ifExpression); var elseTypeInfo = semanticModel.GetTypeInfo(elseExpression); var typeSyntax = SyntaxFactory.IdentifierName(ifTypeInfo.ConvertedType.ToMinimalDisplayString(semanticModel, ifExpression.SpanStart)); + ExpressionSyntax trueExpression; ExpressionSyntax falseExpression; CreateExpressions(ifExpression, elseExpression, ifTypeInfo.Type, elseTypeInfo.Type, ifTypeInfo.ConvertedType, elseTypeInfo.ConvertedType, typeSyntax, semanticModel, out trueExpression, out falseExpression); + return SyntaxFactory.ConditionalExpression(ifStatementCondition, trueExpression, falseExpression); + } + + private static int FindSingleArgumentIndexThatDiffers(ArgumentListSyntax argList1, ArgumentListSyntax argList2, SemanticModel semanticModel) + { + if (argList1.Arguments.Count != argList2.Arguments.Count) return -1; // in case of 'params' + var zipped = argList1.Arguments.Zip(argList2.Arguments, (a1, a2) => new { a1, a2 }).Select((a, i) => new { a.a1, a.a2, i }); + var singleMissmatch = zipped.Where(args => + { + var a1Text = args.a1.GetText(); + var a2Text = args.a2.GetText(); + return !a1Text.ContentEquals(a2Text); + }).Take(2).ToList(); + return (singleMissmatch.Count == 1) ? singleMissmatch[0].i : -1; } private static void CreateExpressions(ExpressionSyntax ifExpression, ExpressionSyntax elseExpression, From a62c6c70f0d5ea7ada3c69b15590363b47766e16 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 23 Jun 2017 03:34:47 +0200 Subject: [PATCH 288/358] Create reusable strategy for fix all See IFixDocumentInternalsOnly. Also add a fix all provider for ReplaceWithGetterOnlyAutoPropertyCodeFixProvider --- ...thGetterOnlyAutoPropertyCodeFixProvider.cs | 61 +++-- .../CodeCracker.Common.csproj | 2 + .../DocumentCodeFixProviderAll.cs | 98 +++++++++ .../IFixDocumentInternalsOnly.cs | 16 ++ .../ReplaceWithGetterOnlyAutoPropertyTests.cs | 208 +++++++++++++++++- 5 files changed, 358 insertions(+), 27 deletions(-) create mode 100644 src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs create mode 100644 src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs diff --git a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs index d22626bae..d8b59a702 100644 --- a/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/ReplaceWithGetterOnlyAutoPropertyCodeFixProvider.cs @@ -12,15 +12,18 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using System; +using CodeCracker.FixAllProviders; namespace CodeCracker.CSharp.Refactoring { [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ReplaceWithGetterOnlyAutoPropertyCodeFixProvider)), Shared] - public class ReplaceWithGetterOnlyAutoPropertyCodeFixProvider : CodeFixProvider + public class ReplaceWithGetterOnlyAutoPropertyCodeFixProvider : CodeFixProvider, IFixDocumentInternalsOnly { + private static readonly FixAllProvider FixAllProvider = new DocumentCodeFixProviderAll(Resources.ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title); public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId()); - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public override FixAllProvider GetFixAllProvider() => FixAllProvider; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -35,19 +38,32 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) diagnostic); return Task.FromResult(0); } - private async static Task ReplaceByGetterOnlyAutoPropertyAsync(Document document, TextSpan propertyDeclarationSpan, CancellationToken cancellationToken) + private async Task ReplaceByGetterOnlyAutoPropertyAsync(Document document, TextSpan propertyDeclarationSpan, CancellationToken cancellationToken) { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var root = await document.GetSyntaxRootAsync(cancellationToken); - var token = root.FindToken(propertyDeclarationSpan.Start); - var property = token.Parent.AncestorsAndSelf().OfType().First(); - var fieldVariableDeclaratorSyntax = await GetFieldDeclarationSyntaxNodeAsync(property, cancellationToken, semanticModel); - if (fieldVariableDeclaratorSyntax == null) return document; - var fieldReferences = await GetFieldReferencesAsync(fieldVariableDeclaratorSyntax, cancellationToken, semanticModel); + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var node = root.FindNode(propertyDeclarationSpan); + return await FixDocumentAsync(node, document, cancellationToken).ConfigureAwait(false); + } + + public async Task FixDocumentAsync(SyntaxNode nodeWithDiagnostic, Document document, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false); + var newRoot = await ReplacePropertyInSyntaxRootAsync(nodeWithDiagnostic, cancellationToken, semanticModel, root).ConfigureAwait(false); + var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument; + } + + + private static async Task ReplacePropertyInSyntaxRootAsync(SyntaxNode propertyDeclarationSyntaxNode, CancellationToken cancellationToken, SemanticModel semanticModel, SyntaxNode root) + { + var property = propertyDeclarationSyntaxNode.AncestorsAndSelf().OfType().First(); + var fieldVariableDeclaratorSyntax = await GetFieldDeclarationSyntaxNodeAsync(property, cancellationToken, semanticModel).ConfigureAwait(false); + if (fieldVariableDeclaratorSyntax == null) return root; + var fieldReferences = await GetFieldReferencesAsync(fieldVariableDeclaratorSyntax, cancellationToken, semanticModel).ConfigureAwait(false); var nodesToUpdate = fieldReferences.Cast().Union(Enumerable.Repeat(property, 1)).Union(Enumerable.Repeat(fieldVariableDeclaratorSyntax, 1)); var newRoot = FixWithTrackNode(root, property, fieldVariableDeclaratorSyntax, nodesToUpdate); - var resultDocument = document.WithSyntaxRoot(newRoot); - return resultDocument; + return newRoot; } private static SyntaxNode FixWithTrackNode(SyntaxNode root, PropertyDeclarationSyntax property, VariableDeclaratorSyntax fieldVariableDeclaratorSyntax, IEnumerable nodesToUpdate) @@ -102,16 +118,19 @@ private static async Task> GetFieldReferencesA HashSet fieldReferences = null; var fieldSymbol = semanticModel.GetDeclaredSymbol(fieldDeclarationSyntax, cancellationToken); var declaredInType = fieldSymbol.ContainingType; - var reference = declaredInType.DeclaringSyntaxReferences[0]; - var allNodes = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); - var allFieldReferenceNodes = from n in allNodes.OfType() - where n.Identifier.Text == fieldSymbol.Name - let nodeSymbolInfo = semanticModel.GetSymbolInfo(n, cancellationToken) - where object.Equals(nodeSymbolInfo.Symbol, fieldSymbol) - select n; - foreach (var fieldReference in allFieldReferenceNodes) + var references = declaredInType.DeclaringSyntaxReferences.Where(r => r.SyntaxTree == semanticModel.SyntaxTree); + foreach (var reference in references) { - (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); + var allNodes = (await reference.GetSyntaxAsync(cancellationToken)).DescendantNodes(); + var allFieldReferenceNodes = from n in allNodes.OfType() + where n.Identifier.Text == fieldSymbol.Name + let nodeSymbolInfo = semanticModel.GetSymbolInfo(n, cancellationToken) + where object.Equals(nodeSymbolInfo.Symbol, fieldSymbol) + select n; + foreach (var fieldReference in allFieldReferenceNodes) + { + (fieldReferences ?? (fieldReferences = new HashSet())).Add(fieldReference); + } } return fieldReferences ?? Enumerable.Empty(); } diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index f20344f73..34f859b17 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -40,6 +40,8 @@ + + diff --git a/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs b/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs new file mode 100644 index 000000000..7a885fcef --- /dev/null +++ b/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs @@ -0,0 +1,98 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeCracker.FixAllProviders +{ + + public sealed class DocumentCodeFixProviderAll : FixAllProvider + { + private const string SyntaxAnnotationKey = "DocumentCodeFixProviderAllSyntaxAnnotation"; + + public DocumentCodeFixProviderAll(string codeFixTitle) + { + CodeFixTitle = codeFixTitle; + } + + private string CodeFixTitle { get; } + + public override Task GetFixAsync(FixAllContext fixAllContext) + { + switch (fixAllContext.Scope) + { + case FixAllScope.Document: + return Task.FromResult(CodeAction.Create(CodeFixTitle, + ct => GetFixedDocumentsAsync(fixAllContext, Enumerable.Repeat(fixAllContext.Document, 1)))); + case FixAllScope.Project: + return Task.FromResult(CodeAction.Create(CodeFixTitle, + ct => GetFixedDocumentsAsync(fixAllContext, fixAllContext.Project.Documents))); + case FixAllScope.Solution: + return Task.FromResult(CodeAction.Create(CodeFixTitle, + ct => GetFixedDocumentsAsync(fixAllContext, fixAllContext.Solution.Projects.SelectMany(p => p.Documents)))); + } + return null; + } + + private async static Task GetFixedDocumentsAsync(FixAllContext fixAllContext, IEnumerable documents) + { + var solution = fixAllContext.Solution; + var newDocuments = documents.ToDictionary(d => d.Id, d => GetFixedDocumentAsync(fixAllContext, d)); + await Task.WhenAll(newDocuments.Values).ConfigureAwait(false); + var changedDocuments = from kvp in newDocuments + where kvp.Value.Result != null + select new { DocumentId = kvp.Key, Document = kvp.Value.Result }; + foreach (var newDocument in changedDocuments) + solution = solution.WithDocumentSyntaxRoot(newDocument.DocumentId, await newDocument.Document.GetSyntaxRootAsync().ConfigureAwait(false)); + return solution; + } + + private async static Task GetFixedDocumentAsync(FixAllContext fixAllContext, Document document) + { + var codeFixer = fixAllContext.CodeFixProvider as IFixDocumentInternalsOnly; + if (codeFixer == null) throw new ArgumentException("This CodeFixAllProvider requires that your CodeFixProvider implements the IFixDocumentInternalsOnly."); + var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); + if (diagnostics.Length == 0) return null; + var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var nodes = diagnostics.Select(d => root.FindNode(d.Location.SourceSpan)).Where(n => !n.IsMissing); + var annotations = new List(); + var newRoot = root.ReplaceNodes(nodes, (original, rewritten) => + { + var annotation = new SyntaxAnnotation(SyntaxAnnotationKey); + annotations.Add(annotation); + var newNode = original.WithAdditionalAnnotations(annotation); + return newNode; + }); + var newDocument = document.WithSyntaxRoot(newRoot); + newDocument = await FixCodeForAnnotatedNodesAsync(newDocument, codeFixer, annotations, fixAllContext.CancellationToken).ConfigureAwait(false); + newDocument = await RemoveAnnontationsAsync(newDocument, annotations).ConfigureAwait(false); + return newDocument; + } + + private static async Task FixCodeForAnnotatedNodesAsync(Document document, IFixDocumentInternalsOnly codeFixer, IEnumerable annotations, CancellationToken cancellationToken) + { + foreach (var annotation in annotations) + { + var newRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var annotatedNodes = newRoot.GetAnnotatedNodes(annotation); + var node = annotatedNodes.FirstOrDefault(); + if (node == null) continue; + document = await codeFixer.FixDocumentAsync(node, document, cancellationToken).ConfigureAwait(false); + } + return document; + } + + private static async Task RemoveAnnontationsAsync(Document document, IEnumerable annotations) + { + var root = await document.GetSyntaxRootAsync().ConfigureAwait(false); + var nodes = annotations.SelectMany(annotation => root.GetAnnotatedNodes(annotation)); + root = root.ReplaceNodes(nodes, (original, rewritten) => original.WithoutAnnotations(annotations)); + var newDocument = document.WithSyntaxRoot(root); + return newDocument; + } + } +} \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs b/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs new file mode 100644 index 000000000..735c76cfa --- /dev/null +++ b/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs @@ -0,0 +1,16 @@ +using Microsoft.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeCracker.FixAllProviders +{ + /// + /// This interface must be implemented by the associated CodeFixProvider. The CodeFixProvider must operate on a single document and + /// should only change the document. This limits the possible operations of the CodeFixProvider to change only document internals without + /// effecting other parts of the solution. + /// + public interface IFixDocumentInternalsOnly + { + Task FixDocumentAsync(SyntaxNode nodeWithDiagnostic, Document document, CancellationToken cancellationToken); + } +} diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs index d7ffc711d..072643c56 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs @@ -430,7 +430,7 @@ class InnerClass { [Fact] public async Task FieldWithSameNameInOtherClassIsNotRenamed() { - var test = @" + const string test = @" using System; namespace App { public class C1 @@ -455,7 +455,7 @@ public class C2 readonly int _A; } }"; - var fixtest = @" + const string fixtest = @" using System; namespace App { public class C1 @@ -510,7 +510,7 @@ public TypeName(int A) } [Fact] - public async Task FieldReferencesInPartialClassesGetNotRenamedAndCasueCompilerErrorCS0103() + public async Task FieldReferencesInPartialClassesGetRenamedIfInTheSameDocument() { const string test = @" namespace A @@ -544,11 +544,10 @@ public A1(int i) } public partial class A1 { - public void Print() => Console.Write(_I); + public void Print() => Console.Write(I); } }"; - //Console.Write(_I); causes CS0103 The name '_I' does not exist in the current context - await VerifyCSharpFixAsync(oldSource: test, newSource: fixtest, allowNewCompilerDiagnostics: true); + await VerifyCSharpFixAsync(oldSource: test, newSource: fixtest, allowNewCompilerDiagnostics: false); } [Fact] @@ -600,5 +599,202 @@ public partial class A1 //Console.Write(_I); causes CS0103 The name '_I' does not exist in the current context await VerifyCSharpFixAllAsync(oldSources: new string[] { testPart1, testPart2 }, newSources: new string[] { fixtestPart1, fixtestPart2 }, allowNewCompilerDiagnostics: true); } + + #region FixAll Tests + + [Fact] + public async Task ReplaceMultiplePropertiesInOneClassFixAllTest() + { + var source1 = @" + readonly int _A; + readonly int _B; + readonly string _C; + + public TypeName(int a, int b, string c) + { + _A=a; + _B=b; + _C=c; + } + public int A { get { return _A; } } + public int B { get { return _B; } } + public string C { get { return _C; } } + ".WrapInCSharpClass(); + var fixtest1 = @" + public TypeName(int a, int b, string c) + { + A=a; + B=b; + C=c; + } + public int A { get; } + public int B { get; } + public string C { get; } + ".WrapInCSharpClass(); + await VerifyCSharpFixAllAsync(new[] { source1 }, new[] { fixtest1 }); + } + + [Fact] + public async Task ReplaceMultiplePropertiesInOneClassInMultipleDocumentsFixAllTest() + { + const string source1 = @" + namespace A + { + public class A1 + { + readonly int _A; + readonly int _B; + readonly string _C; + public A1(int a, int b, string c) + { + _A=a; + _B=b; + _C=c; + } + public int A { get { return _A; } } + public int B { get { return _B; } } + public string C { get { return _C; } } + } + }"; + const string source2 = @" + namespace A + { + public class A2 + { + readonly int _A; + readonly int _B; + readonly string _C; + public A2(int a, int b, string c) + { + _A=a; + _B=b; + _C=c; + } + public int A { get { return _A; } } + public int B { get { return _B; } } + public string C { get { return _C; } } + } + }"; + const string source3 = @" + namespace B + { + public class B1 + { + readonly int _A; + readonly int _B; + readonly string _C; + public B1(int a, int b, string c) + { + _A=a; + _B=b; + _C=c; + } + public int A { get { return _A; } } + public int B { get { return _B; } } + public string C { get { return _C; } } + } + }"; + const string fixtest1 = @" + namespace A + { + public class A1 + { + public A1(int a, int b, string c) + { + A=a; + B=b; + C=c; + } + public int A { get; } + public int B { get; } + public string C { get; } + } + }"; + const string fixtest2 = @" + namespace A + { + public class A2 + { + public A2(int a, int b, string c) + { + A=a; + B=b; + C=c; + } + public int A { get; } + public int B { get; } + public string C { get; } + } + }"; + const string fixtest3 = @" + namespace B + { + public class B1 + { + public B1(int a, int b, string c) + { + A=a; + B=b; + C=c; + } + public int A { get; } + public int B { get; } + public string C { get; } + } + }"; + await VerifyCSharpFixAllAsync(new[] { source1, source2, source3 }, new[] { fixtest1, fixtest2, fixtest3 }); + } + + [Fact] + public async Task ReplaceMultiplePropertiesInOneClassInMultipleDocumentsAndKeepExisitingDocumentsWithoutDiagnosticsFixAllTest() + { + const string source1 = @" + namespace A + { + public class A1 + { + readonly int _A; + readonly int _B; + readonly string _C; + public A1(int a, int b, string c) + { + _A=a; + _B=b; + _C=c; + } + public int A { get { return _A; } } + public int B { get { return _B; } } + public string C { get { return _C; } } + } + }"; + const string source2 = @" + namespace A + { + public class A2 + { + public A2() + { + } + } + }"; + const string fixtest1 = @" + namespace A + { + public class A1 + { + public A1(int a, int b, string c) + { + A=a; + B=b; + C=c; + } + public int A { get; } + public int B { get; } + public string C { get; } + } + }"; + await VerifyCSharpFixAllAsync(new[] { source1, source2 }, new[] { fixtest1, source2 }); + } + #endregion } } \ No newline at end of file From d6d7bdf720d5ddad627d744dcd8dea945b83420b Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Jun 2017 22:36:58 -0300 Subject: [PATCH 289/358] Fix typo --- .../FixAllProviders/DocumentCodeFixProviderAll.cs | 4 ++-- .../FixAllProviders/IFixDocumentInternalsOnly.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs b/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs index 7a885fcef..255dfc074 100644 --- a/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs +++ b/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs @@ -69,7 +69,7 @@ private async static Task GetFixedDocumentAsync(FixAllContext fixAllCo }); var newDocument = document.WithSyntaxRoot(newRoot); newDocument = await FixCodeForAnnotatedNodesAsync(newDocument, codeFixer, annotations, fixAllContext.CancellationToken).ConfigureAwait(false); - newDocument = await RemoveAnnontationsAsync(newDocument, annotations).ConfigureAwait(false); + newDocument = await RemoveAnnotationsAsync(newDocument, annotations).ConfigureAwait(false); return newDocument; } @@ -86,7 +86,7 @@ private static async Task FixCodeForAnnotatedNodesAsync(Document docum return document; } - private static async Task RemoveAnnontationsAsync(Document document, IEnumerable annotations) + private static async Task RemoveAnnotationsAsync(Document document, IEnumerable annotations) { var root = await document.GetSyntaxRootAsync().ConfigureAwait(false); var nodes = annotations.SelectMany(annotation => root.GetAnnotatedNodes(annotation)); diff --git a/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs b/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs index 735c76cfa..901942669 100644 --- a/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs +++ b/src/Common/CodeCracker.Common/FixAllProviders/IFixDocumentInternalsOnly.cs @@ -13,4 +13,4 @@ public interface IFixDocumentInternalsOnly { Task FixDocumentAsync(SyntaxNode nodeWithDiagnostic, Document document, CancellationToken cancellationToken); } -} +} \ No newline at end of file From 8f48dfea083cf3583b6af449981b9b76a76e0ab4 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 24 Jun 2017 00:12:33 -0300 Subject: [PATCH 290/358] Use latest msbuild --- build.ps1 | 2 +- default.ps1 | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/build.ps1 b/build.ps1 index 821027472..27cd8f2d8 100644 --- a/build.ps1 +++ b/build.ps1 @@ -73,7 +73,7 @@ Get-Nuget Import-Psake Import-ILMerge if ($MyInvocation.UnboundArguments.Count -ne 0) { - Invoke-Expression("Invoke-psake -framework '4.5.2' $PSScriptRoot\default.ps1 -taskList " + $MyInvocation.UnboundArguments -join " ") + Invoke-Expression("Invoke-psake -framework '4.6' $PSScriptRoot\default.ps1 -taskList " + $MyInvocation.UnboundArguments -join " ") } else { . $PSScriptRoot\build.ps1 Build diff --git a/default.ps1 b/default.ps1 index a36f5fad6..aef7b7d5d 100644 --- a/default.ps1 +++ b/default.ps1 @@ -38,6 +38,10 @@ Properties { $isRelease = $isAppVeyor -and (($env:APPVEYOR_REPO_BRANCH -eq "release") -or ($env:APPVEYOR_REPO_TAG -eq "true")) $isPullRequest = $env:APPVEYOR_PULL_REQUEST_NUMBER -ne $null $tempDir = Join-Path "$([System.IO.Path]::GetTempPath())" "CodeCracker" + # msbuild hack necessary until https://github.com/psake/psake/issues/201 is fixed: + $msbuild64 = Resolve-Path "$(if (${env:ProgramFiles(x86)}) { ${env:ProgramFiles(x86)} } else { $env:ProgramFiles } )\Microsoft Visual Studio\2017\*\MSBuild\15.0\Bin\msbuild.exe" + $msbuild32 = Resolve-Path "$(if (${env:ProgramFiles(x86)}) { ${env:ProgramFiles(x86)} } else { $env:ProgramFiles } )\Microsoft Visual Studio\2017\*\MSBuild\15.0\Bin\msbuild.exe" + $msbuild = if ($msbuild64) { $msbuild64 } else { $msbuild32 } } FormatTaskName (("-"*25) + "[{0}]" + ("-"*25)) @@ -62,17 +66,17 @@ Task Build-Only -depends Build-Only-CS, Build-Only-VB Task Build-Only-CS -depends Build-MSBuild-CS, ILMerge-CS Task Build-MSBuild-CS { if ($isAppVeyor) { - Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } + Exec { . $msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } } else { - Exec { msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } + Exec { . $msbuild $solutionFileCS /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } } } Task Build-Only-VB -depends Build-MSBuild-VB, ILMerge-VB Task Build-MSBuild-VB { if ($isAppVeyor) { - Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } + Exec { . $msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } } else { - Exec { msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } + Exec { . $msbuild $solutionFileVB /m /verbosity:minimal /p:Configuration=ReleaseNoVsix } } } @@ -120,8 +124,8 @@ function Change-Extension ($filename, $extension) { } Task Clean { - Exec { msbuild $solutionFileCS /t:Clean /v:quiet } - Exec { msbuild $solutionFileVB /t:Clean /v:quiet } + Exec { . $msbuild $solutionFileCS /t:Clean /v:quiet } + Exec { . $msbuild $solutionFileVB /t:Clean /v:quiet } } Task Set-Log { From 6de6d0745daf942454555887939e900cd54cf228 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Sat, 24 Jun 2017 05:35:29 +0200 Subject: [PATCH 291/358] Fix bug for CC0118 Remove to string The string is only removed if safe to do. Fixes #866. Implemented option 2 as requested in #866. This fix now looks up the types of both sides of the plus operator and tries removes those candidates, that might break things. It turned out, that some of the checks in CheckAddOperationOverloadsOfTypes are not needed (After the second check every other check returns false). Essentially right now the removal of "ToString" is only save if either the underlying type is a string (as in 1 + "a".ToString()) or the type on the other side of the plus operator is a string (as in "a" + 1.ToString()). I kept all the other checks for future enhancements to make clear that there are several cases to consider. Further I added lots of unit tests to cover these cases. The idea is that CheckAddOperationOverloadsOfTypes can easily be expanded in the future to support more cases without breaking anything. Those redundant checks are also very cheap and are essentially just simple comparisons. --- ...ryToStringInStringConcatenationAnalyzer.cs | 132 +++++++++++++- ...ssaryToStringInStringConcatenationTests.cs | 170 ++++++++++++++++-- 2 files changed, 288 insertions(+), 14 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs index d2c56f355..23fa9dcbe 100644 --- a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs @@ -3,9 +3,11 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; namespace CodeCracker.CSharp.Style { @@ -45,7 +47,9 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (!hasInvocationExpression) return; var invocationExpressionsThatHaveToStringCall = GetInvocationExpressionsThatHaveToStringCall(addExpression); - foreach (var expression in invocationExpressionsThatHaveToStringCall) + var redundantToStringCalls = FilterInvocationsThatAreRedundant(invocationExpressionsThatHaveToStringCall, addExpression, context.SemanticModel, context.CancellationToken); + + foreach (var expression in redundantToStringCalls) { var lastDot = expression.Expression.ChildNodesAndTokens().Last(x => x.IsKind(SyntaxKind.DotToken)); var toStringTextSpan = new TextSpan(lastDot.Span.Start, expression.ArgumentList.Span.End - lastDot.Span.Start); @@ -60,5 +64,131 @@ private static IEnumerable GetInvocationExpressionsT //Only default call to ToString method must be accepted .Where(x => x.Expression.ToString().EndsWith(@".ToString") && !x.ArgumentList.Arguments.Any()); } + + private static IEnumerable FilterInvocationsThatAreRedundant(IEnumerable invocationExpressionsThatHaveToStringCall, BinaryExpressionSyntax addExpression, SemanticModel semanticModel, CancellationToken cancellationToken) + { + foreach (var node in invocationExpressionsThatHaveToStringCall) + { + var toStringReceiver = GetTypeInfoOfReceiverOfToStringCall(node, semanticModel, cancellationToken); + //As long as the underlying type can not be resolved by the compiler (e.g. undefined type) + //removal is not save. + if (toStringReceiver == null || toStringReceiver.TypeKind==TypeKind.Error) + continue; + //If the underlying type is string, removal is save. + if (IsTypeSymbolSystem_String(toStringReceiver)) + yield return node; + var otherType = GetTypeInfoOfOtherNode(node, addExpression, semanticModel, cancellationToken); + if (otherType != null) + { + if (CheckAddOperationOverloadsOfTypes(toStringReceiver, otherType)) + { + yield return node; + } + } + } + } + + private static ITypeSymbol GetTypeInfoOfReceiverOfToStringCall(InvocationExpressionSyntax toStringCall, SemanticModel semanticModel, CancellationToken cancellationToken) + { + if (toStringCall.Expression is MemberAccessExpressionSyntax memberAccess) + { + return semanticModel.GetTypeInfo(memberAccess.Expression, cancellationToken).Type; + } + + return null; + } + + private static ITypeSymbol GetTypeInfoOfOtherNode(SyntaxNode toStringNode, BinaryExpressionSyntax addExpression, SemanticModel semanticModel, CancellationToken cancellationToken) + { + var otherNode = addExpression.Left == toStringNode + ? addExpression.Right + : addExpression.Right == toStringNode + ? addExpression.Left + : null; + if (otherNode != null) + { + return semanticModel.GetTypeInfo(otherNode, cancellationToken).Type; + } + + return null; + } + + private static bool CheckAddOperationOverloadsOfTypes(ITypeSymbol toStringReceiver, ITypeSymbol otherType) + { + //If the underlying type has a custom AddOperator this operator will take precedence over everything else + if (HasTypeCustomAddOperator(toStringReceiver)) + { + return false; + } + + //If the other side is a string the string concatenation will be applied and "ToString" will be implicit called by the concatenation operator + if (IsTypeSymbolSystem_String(otherType)) + { + return true; + } + + //If the underlying type is one of the build in types (numeric, datetime and so on) and the other side is not a string, + //the result a removal is hard to predict and might be wrong. + if (HasAdditionOperator(toStringReceiver)) + { + return false; + } + + //If both sides are delegates, the plus operator combines the delegates: + //https://msdn.microsoft.com/en-us/library/ms173175(v=vs.110).aspx + if (IsTypeSmybolDelegateType(toStringReceiver) && IsTypeSmybolDelegateType(otherType)) + { + return false; + } + + //There might be more cases were removal is save but for now we opt out. + return false; + } + + private static bool IsTypeSmybolDelegateType(ITypeSymbol typeSymbol) + => typeSymbol.TypeKind == TypeKind.Delegate; + + private static bool IsTypeSymbolSystem_String(ITypeSymbol typeSymbol) + => typeSymbol.SpecialType == SpecialType.System_String; + + + // see https://stackoverflow.com/a/41223159 + private static bool HasAdditionOperator(ITypeSymbol type) + { + switch (type.SpecialType) + { + case SpecialType.System_Enum: + case SpecialType.System_Boolean: + case SpecialType.System_Char: + case SpecialType.System_SByte: + case SpecialType.System_Byte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Decimal: + case SpecialType.System_Single: + case SpecialType.System_Double: + //String has an addition operator but we are looking for types other than string with an addition overload. + //case SpecialType.System_String: + case SpecialType.System_IntPtr: + case SpecialType.System_UIntPtr: + case SpecialType.System_DateTime: + return true; + } + if (type.TypeKind == TypeKind.Enum) + { + return true; + } + return false; + } + + private static bool HasTypeCustomAddOperator(ITypeSymbol type) + { + var customAdditionOperators = type.GetMembers("op_Addition").OfType(); + return customAdditionOperators.Any(ms => ms.MethodKind == MethodKind.UserDefinedOperator); + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs b/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs index 077f095e7..d6073bcad 100644 --- a/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs @@ -7,6 +7,19 @@ namespace CodeCracker.Test.CSharp.Style { public class UnnecessaryToStringInStringConcatenationTests : CodeFixVerifier { + private static DiagnosticResult CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(int expectedRow, int expectedColumn) + { + var expected = new DiagnosticResult + { + Id = DiagnosticId.UnnecessaryToStringInStringConcatenation.ToDiagnosticId(), + Message = "Unnecessary '.ToString()' call in string concatenation.", + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", expectedRow, expectedColumn) } + }; + + return expected; + } + [Fact] public async Task InstantiatingAnObjectAndCallToStringInsideAStringConcatenationShouldGenerateDiagnosticResult() { @@ -20,9 +33,9 @@ public async Task InstantiatingAnObjectAndCallToStringInsideAStringConcatenation [Fact] public async Task InstantiatingAnStringBuilderAndCallToStringInsideAStringConcatenationShouldGenerateDiagnosticResult() { - const string source = @"var foo = ""a"" + new System.Text.StringBuilder().ToString();"; + var source = @"var foo = ""a"" + new System.Text.StringBuilder().ToString();".WrapInCSharpMethod(); - var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(1, 48); + var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(10, 64); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -37,9 +50,9 @@ namespace ConsoleApplication1 { class AuxClass { - public override void ToString() + public override string ToString() { - return ""Test""; + return ""Test""; } } @@ -51,7 +64,7 @@ public void Foo() var bar = ""a"" + new AuxClass().ToString(); var foo = ""a"" + auxClass.ToString(); - var far = ""a"" + new AuxClass().ToString() + auxClass.ToString() + new object().ToString(""C""); + var far = ""a"" + new AuxClass().ToString() + auxClass.ToString() + new int().ToString(""C""); } } }"; @@ -66,6 +79,35 @@ public void Foo() await VerifyCSharpDiagnosticAsync(test, expected); } + [Fact] + public async Task CallToStringOnStringExpressionsShouldGenerateDiagnosticResult() + { + const string test = @"var t1 = (true ? ""1"" : ""2"") + new object().ToString();"; + + var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(1, 43); + + await VerifyCSharpDiagnosticAsync(test, expected); + } + + [Fact] + public async Task CallToStringFollowedByACallToAStringMethodShouldNotGenerateDiagnosticResult() + { + const string source = @"var salary = ""salary: "" + 1000.ToString().Trim();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task CallToLambdaNamedToStringShouldNotGenerateDiagnosticResult() + { + var source = @" + Func ToString = () => ""Dummy""; + var t = 1 + ToString(); + ".WrapInCSharpMethod(); + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + [Fact] public async Task CallToStringInsideAStringConcatenationWithAFormatParameterShouldNotGenerateDiagnosticResult() { @@ -83,18 +125,120 @@ public async Task CallToStringOutsideAStringConcatenationWithoutParameterShouldN await VerifyCSharpHasNoDiagnosticsAsync(source); } + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_NumericAddition_RightSide() + { + const string source = @"var value = 1 + 2.ToString();"; - private static DiagnosticResult CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(int expectedRow, int expectedColumn) + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_NumericAddition_LeftSide() { - var expected = new DiagnosticResult + const string source = @"var value = 2.ToString() + 1;"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_NumericAddition_WithExpression() + { + const string source = @"var value = (1 + 1) + 2.ToString();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_NumericAddition_Double() + { + const string source = @"var value = (true ? 1.1 : 0.99) + 2.ToString();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_NumericAddition_DateTime() + { + const string source = @"var value = new System.DateTime(2000, 1, 1) + 2.ToString();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_CompilerGeneratedEnumOperator() + { + const string source = @"var value = System.AttributeTargets.Assembly + System.AttributeTargets.Module.ToString();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_UnderlyingTypeDoesntHaveAddOperatorOverload() + { + const string source = @"var value = new System.Random() + new System.Random().ToString();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_UserDefinedOperator() + { + const string source = @" + namespace A + { + public class C1 + { + public static string operator +(C1 c, object o) => ""Dummy""; + } + + public class C2 + { + public void M() { - Id = DiagnosticId.UnnecessaryToStringInStringConcatenation.ToDiagnosticId(), - Message = "Unnecessary '.ToString()' call in string concatenation.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", expectedRow, expectedColumn) } - }; + var t = new C1().ToString() + ""a""; + } + } + } +"; - return expected; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfOtherOverloadsTakePrecedence_DelegateCombination() + { + var source = @" + var ea1 = new System.EventHandler((o, e) => { }); + var ea2 = new System.EventHandler((o, e) => { }); + var t = ea1 + ea2.ToString(); + ".WrapInCSharpMethod(); + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfTheTypesOfTheOperationAreNotResovable_ToStringReceiver() + { + const string source = @"var t = new UndefinedType().ToString() + ""a"""; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfTheTypesOfTheOperationAreNotResovable_OtherSide() + { + const string source = @"var t = 1.ToString() + new UndefinedType();"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task AStringConcatinationShouldNotBeRemovedIfTheTypesOfTheOperationAreNotResovable_SyntaxError() + { + const string source = @"var t = new System.Random().ToString() + new ThisIsAnSyntaxError"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); } [Fact] From 155634dae288bb7dafa2af7a7e82047d97d28983 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 28 Jun 2017 01:48:29 +0200 Subject: [PATCH 292/358] Use default fixall for IntroduceFieldFromConstructor/CC0071 From #940. --- src/CSharp/CodeCracker/CodeCracker.csproj | 1 - .../IntroduceFieldFromConstructorAnalyzer.cs | 9 ++- ...duceFieldFromConstructorCodeFixProvider.cs | 25 +++++-- ...eFieldFromConstructorCodeFixProviderAll.cs | 73 ------------------- .../Properties/Resources.Designer.cs | 45 ++++++++++++ .../Properties/Resources.resx | 15 ++++ 6 files changed, 83 insertions(+), 85 deletions(-) delete mode 100644 src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index ea63f7981..715a8f4ac 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -74,7 +74,6 @@ - diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs index 91562e3db..7b20fe932 100644 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorAnalyzer.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using CodeCracker.Properties; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -11,10 +12,10 @@ namespace CodeCracker.CSharp.Refactoring [DiagnosticAnalyzer(LanguageNames.CSharp)] public class IntroduceFieldFromConstructorAnalyzer : DiagnosticAnalyzer { - internal const string Title = "Consider introduce field for constructor parameters."; - internal const string MessageFormat = "Introduce a field for parameter: {0}"; internal const string Category = SupportedCategories.Refactoring; - const string Description = "Consider introduce field for constructor parameters."; + internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.IntroduceFieldFromConstructorAnalyzer_Title), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.IntroduceFieldFromConstructorAnalyzer_Description), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.IntroduceFieldFromConstructorAnalyzer_MessageFormat), Resources.ResourceManager, typeof(Resources)); internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.IntroduceFieldFromConstructor.ToDiagnosticId(), diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs index 085196f21..9351d73b9 100644 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProvider.cs @@ -1,3 +1,5 @@ +using CodeCracker.FixAllProviders; +using CodeCracker.Properties; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; @@ -14,12 +16,14 @@ namespace CodeCracker.CSharp.Refactoring { [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(IntroduceFieldFromConstructorCodeFixProvider)), Shared] - public class IntroduceFieldFromConstructorCodeFixProvider : CodeFixProvider + public sealed class IntroduceFieldFromConstructorCodeFixProvider : CodeFixProvider, IFixDocumentInternalsOnly { + private static readonly FixAllProvider FixAllProvider = new DocumentCodeFixProviderAll(Resources.IntroduceFieldFromConstructorCodeFixProvider_Title); + private static readonly string MessageFormat = Resources.IntroduceFieldFromConstructorCodeFixProvider_MessageFormat; + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.IntroduceFieldFromConstructor.ToDiagnosticId()); - public readonly static string MessageFormat = "Introduce field: {0} from constructor."; - public sealed override FixAllProvider GetFixAllProvider() => IntroduceFieldFromConstructorCodeFixAllProvider.Instance; + public sealed override FixAllProvider GetFixAllProvider() => FixAllProvider; public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -29,17 +33,24 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) return Task.FromResult(0); } - public async static Task IntroduceFieldFromConstructorDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + public async Task FixDocumentAsync(SyntaxNode nodeWithDiagnostic, Document document, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var diagnosticSpan = diagnostic.Location.SourceSpan; - var parameter = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - var constructor = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var parameter = nodeWithDiagnostic.AncestorsAndSelf().OfType().First(); + var constructor = nodeWithDiagnostic.AncestorsAndSelf().OfType().First(); var newRoot = IntroduceFieldFromConstructor(root, constructor, parameter); var newDocument = document.WithSyntaxRoot(newRoot); return document.WithSyntaxRoot(newRoot); } + public async Task IntroduceFieldFromConstructorDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var nodeWithDiagnostic = root.FindToken(diagnosticSpan.Start).Parent; + return await FixDocumentAsync(nodeWithDiagnostic, document, cancellationToken); + } + public static SyntaxNode IntroduceFieldFromConstructor(SyntaxNode root, ConstructorDeclarationSyntax constructorStatement, ParameterSyntax parameter) { // There are no constructors in interfaces, therefore all types remaining type (class and struct) are fine. diff --git a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs b/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs deleted file mode 100644 index 81d29b07e..000000000 --- a/src/CSharp/CodeCracker/Refactoring/IntroduceFieldFromConstructorCodeFixProviderAll.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Linq; -using System.Threading.Tasks; - -namespace CodeCracker.CSharp.Refactoring -{ - public sealed class IntroduceFieldFromConstructorCodeFixAllProvider : FixAllProvider - { - private static readonly SyntaxAnnotation introduceFieldAnnotation = new SyntaxAnnotation(nameof(IntroduceFieldFromConstructorCodeFixAllProvider)); - private IntroduceFieldFromConstructorCodeFixAllProvider() { } - public static readonly IntroduceFieldFromConstructorCodeFixAllProvider Instance = new IntroduceFieldFromConstructorCodeFixAllProvider(); - - public override Task GetFixAsync(FixAllContext fixAllContext) - { - switch (fixAllContext.Scope) - { - case FixAllScope.Document: - return Task.FromResult(CodeAction.Create(IntroduceFieldFromConstructorCodeFixProvider.MessageFormat, - async ct => fixAllContext.Document.WithSyntaxRoot(await GetFixedDocumentAsync(fixAllContext, fixAllContext.Document)))); - case FixAllScope.Project: - return Task.FromResult(CodeAction.Create(IntroduceFieldFromConstructorCodeFixProvider.MessageFormat, - ct => GetFixedProjectAsync(fixAllContext, fixAllContext.Project))); - case FixAllScope.Solution: - return Task.FromResult(CodeAction.Create(IntroduceFieldFromConstructorCodeFixProvider.MessageFormat, - ct => GetFixedSolutionAsync(fixAllContext))); - } - return null; - } - - private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) - { - var newSolution = fixAllContext.Solution; - foreach (var projectId in newSolution.ProjectIds) - newSolution = await GetFixedProjectAsync(fixAllContext, newSolution.GetProject(projectId)).ConfigureAwait(false); - return newSolution; - } - - private async static Task GetFixedProjectAsync(FixAllContext fixAllContext, Project project) - { - var solution = project.Solution; - var newDocuments = project.Documents.ToDictionary(d => d.Id, d => GetFixedDocumentAsync(fixAllContext, d)); - await Task.WhenAll(newDocuments.Values).ConfigureAwait(false); - foreach (var newDoc in newDocuments) - solution = solution.WithDocumentSyntaxRoot(newDoc.Key, newDoc.Value.Result); - return solution; - } - - private async static Task GetFixedDocumentAsync(FixAllContext fixAllContext, Document document) - { - var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); - var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); - var nodes = diagnostics.Select(d => root.FindNode(d.Location.SourceSpan)).Where(n => !n.IsMissing); - var newRoot = root.ReplaceNodes(nodes, (original, rewritten) => original.WithAdditionalAnnotations(introduceFieldAnnotation)); - var semanticModel = await document.GetSemanticModelAsync(fixAllContext.CancellationToken).ConfigureAwait(false); - while (true) - { - var annotatedNodes = newRoot.GetAnnotatedNodes(introduceFieldAnnotation); - var node = annotatedNodes.FirstOrDefault(); - if (node == null) break; - - var constructorMethod = (ConstructorDeclarationSyntax)node.Parent.Parent; - var parameter = (ParameterSyntax)node; - newRoot = IntroduceFieldFromConstructorCodeFixProvider.IntroduceFieldFromConstructor(newRoot, constructorMethod, parameter); - node = newRoot.GetAnnotatedNodes(introduceFieldAnnotation).First(); - newRoot = newRoot.ReplaceNode(node, node.WithoutAnnotations(introduceFieldAnnotation)); - } - return newRoot; - } - } -} diff --git a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs index 318839da0..17f3ec989 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs +++ b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs @@ -214,6 +214,51 @@ public static string InconsistentAccessibilityInPropertyType_Title { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Consider introduce field for constructor parameters. ähnelt. + /// + public static string IntroduceFieldFromConstructorAnalyzer_Description { + get { + return ResourceManager.GetString("IntroduceFieldFromConstructorAnalyzer_Description", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Introduce a field for parameter: {0} ähnelt. + /// + public static string IntroduceFieldFromConstructorAnalyzer_MessageFormat { + get { + return ResourceManager.GetString("IntroduceFieldFromConstructorAnalyzer_MessageFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Consider introduce field for constructor parameters. ähnelt. + /// + public static string IntroduceFieldFromConstructorAnalyzer_Title { + get { + return ResourceManager.GetString("IntroduceFieldFromConstructorAnalyzer_Title", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Introduce field: {0} from constructor. ähnelt. + /// + public static string IntroduceFieldFromConstructorCodeFixProvider_MessageFormat { + get { + return ResourceManager.GetString("IntroduceFieldFromConstructorCodeFixProvider_MessageFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Introduce fields for constructor parameters. ähnelt. + /// + public static string IntroduceFieldFromConstructorCodeFixProvider_Title { + get { + return ResourceManager.GetString("IntroduceFieldFromConstructorCodeFixProvider_Title", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Make method non async ähnelt. /// diff --git a/src/Common/CodeCracker.Common/Properties/Resources.resx b/src/Common/CodeCracker.Common/Properties/Resources.resx index accb497bd..aab3eb4fd 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.resx +++ b/src/Common/CodeCracker.Common/Properties/Resources.resx @@ -228,4 +228,19 @@ Simplify by using an getter-only auto-property + + Consider introduce field for constructor parameters. + + + Introduce a field for parameter: {0} + + + Consider introduce field for constructor parameters. + + + Introduce field: {0} from constructor. + + + Introduce fields for constructor parameters. + \ No newline at end of file From 7d7391c3c8ece06feaeb4910077fa649edcf9e09 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Wed, 28 Jun 2017 01:53:17 +0200 Subject: [PATCH 293/358] Added support for constructors in UseInvokeMethodToFireEventAnalyzer From #942. --- .../UseInvokeMethodToFireEventAnalyzer.cs | 2 +- .../Design/UseInvokeMethodToFireEventTests.cs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs index 1ae8992d4..6a30e2533 100644 --- a/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/UseInvokeMethodToFireEventAnalyzer.cs @@ -62,7 +62,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) private static bool HasCheckForNullThatReturns(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol) { - var method = invocation.FirstAncestorOfKind(SyntaxKind.MethodDeclaration) as MethodDeclarationSyntax; + var method = invocation.FirstAncestorOfKind(SyntaxKind.MethodDeclaration, SyntaxKind.ConstructorDeclaration) as BaseMethodDeclarationSyntax; if (method != null && method.Body != null) { var ifs = method.Body.Statements.OfKind(SyntaxKind.IfStatement); diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index 0ff013093..f392107bc 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -1134,6 +1134,23 @@ public void Bar() { var b = _filter != null && _filter(); } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(test.WrapInCSharpClass()); + } + + [Fact] + public async void IgnoreIfInConstructorAndThatCheckedForNotNull() + { + //https://github.com/code-cracker/code-cracker/issues/926 + const string test = @" +public class Foo +{ + public Foo(System.Action action) + { + if (action == null) + throw new System.ArgumentNullException(); + action(); + } }"; await VerifyCSharpHasNoDiagnosticsAsync(test.WrapInCSharpClass()); } From 4f5cd46f8e61009c5ae7cd6a91506bf1b6e81d3e Mon Sep 17 00:00:00 2001 From: baks Date: Thu, 31 Mar 2016 21:13:45 +0200 Subject: [PATCH 294/358] PropertyChangedEventArgs unnecessary allocation CodeFix provider & analyzer --- src/CSharp/CodeCracker/CodeCracker.csproj | 2 + ...dEventArgsUnnecessaryAllocationAnalyzer.cs | 244 ++++++++++++++ ...rgsUnnecessaryAllocationCodeFixProvider.cs | 93 +++++ src/Common/CodeCracker.Common/DiagnosticId.cs | 1 + .../Properties/Resources.Designer.cs | 144 +++++--- .../Properties/Resources.fr.resx | 12 + .../Properties/Resources.resx | 12 + .../CodeCracker.Test/CodeCracker.Test.csproj | 2 + ...tArgsUnnecessaryAllocationAnalyzerTests.cs | 169 ++++++++++ ...necessaryAllocationCodeFixProviderTests.cs | 318 ++++++++++++++++++ 10 files changed, 943 insertions(+), 54 deletions(-) create mode 100644 src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs create mode 100644 src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs create mode 100644 test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs create mode 100644 test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 715a8f4ac..22c6e50a0 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -69,6 +69,8 @@ + + diff --git a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs new file mode 100644 index 000000000..b1a15bf7f --- /dev/null +++ b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Immutable; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using CodeCracker.Properties; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +using static Microsoft.CodeAnalysis.CSharp.SyntaxFacts; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Microsoft.CodeAnalysis.CSharp.SyntaxKind; + +namespace CodeCracker.CSharp.Refactoring +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class PropertyChangedEventArgsUnnecessaryAllocationAnalyzer : DiagnosticAnalyzer + { + private const string PropertyChangedEventArgsClassName = "PropertyChangedEventArgs"; + + internal const string Category = SupportedCategories.Refactoring; + + private static readonly IdentifierExtractor ExtractIdentifier = new IdentifierExtractor(); + private static readonly IsArgumentALiteralOrNameof IsAnyArgumentLiteralOrNameof = new IsArgumentALiteralOrNameof(); + + internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.PropertyChangedEventArgsUnnecessaryAllocation_Title), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.PropertyChangedEventArgsUnnecessaryAllocation_Description), Resources.ResourceManager, typeof(Resources)); + internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.PropertyChangedEventArgsUnnecessaryAllocation_MessageFormat), Resources.ResourceManager, typeof(Resources)); + + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId(), + Title, + MessageFormat, + Category, + DiagnosticSeverity.Hidden, + isEnabledByDefault: true, + description: Description, + helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation)); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(LanguageVersion.CSharp6, PropertyChangedCreation, SyntaxKind.ObjectCreationExpression); + } + + private static void PropertyChangedCreation(SyntaxNodeAnalysisContext context) + { + var propertyChangedEventArgsCreationExpr = (ObjectCreationExpressionSyntax) context.Node; + var identifier = propertyChangedEventArgsCreationExpr.Type.Accept(ExtractIdentifier); + if (ShouldReportDiagnostic(propertyChangedEventArgsCreationExpr, identifier.ValueText)) + { + var data = new PropertyChangedEventArgsAnalyzerData(propertyChangedEventArgsCreationExpr); + + context.ReportDiagnostic(Diagnostic.Create(Rule, propertyChangedEventArgsCreationExpr.GetLocation(), data.ToDiagnosticProperties())); + } + } + + private static bool ShouldReportDiagnostic(ObjectCreationExpressionSyntax propertyChangedExpr, + string identifierName) => + IsPropertyChangedEventArgs(identifierName) + && propertyChangedExpr.ArgumentList.Accept(IsAnyArgumentLiteralOrNameof) + && !IsAlreadyStatic(propertyChangedExpr); + + private static bool IsPropertyChangedEventArgs(string s) + => string.Equals(PropertyChangedEventArgsClassName, s, StringComparison.Ordinal); + + private static bool IsAlreadyStatic(ObjectCreationExpressionSyntax objectCreationExpr) + { + var result = false; + var memberForObjectCreationExpr = objectCreationExpr.FirstAncestorOrSelfThatIsAMember(); + switch (memberForObjectCreationExpr.Kind()) + { + case SyntaxKind.ConstructorDeclaration: + var constructorDeclaration = (ConstructorDeclarationSyntax) memberForObjectCreationExpr; + result = ContainsStaticModifier(constructorDeclaration.Modifiers); + break; + case SyntaxKind.FieldDeclaration: + var fieldDeclaration = (FieldDeclarationSyntax)memberForObjectCreationExpr; + result = ContainsStaticModifier(fieldDeclaration.Modifiers); + break; + } + return result; + } + + private static bool ContainsStaticModifier(SyntaxTokenList modifiers) => modifiers.Any(StaticKeyword); + + private class IdentifierExtractor : CSharpSyntaxVisitor + { + public override SyntaxToken VisitIdentifierName(IdentifierNameSyntax node) => node.Identifier; + public override SyntaxToken VisitQualifiedName(QualifiedNameSyntax node) => VisitIdentifierName((IdentifierNameSyntax)node.Right); + } + + private class IsArgumentALiteralOrNameof : CSharpSyntaxVisitor + { + public override bool VisitArgumentList(ArgumentListSyntax node) => node.Arguments.Any(arg => arg.Accept(this)); + public override bool VisitArgument(ArgumentSyntax node) => node.Expression.Accept(this); + public override bool VisitLiteralExpression(LiteralExpressionSyntax node) => true; + + public override bool VisitIdentifierName(IdentifierNameSyntax node) + => string.Equals("nameof", node.Identifier.ValueText, StringComparison.Ordinal); + + public override bool VisitInvocationExpression(InvocationExpressionSyntax node) => node.Expression.Accept(this); + } + } + + public class PropertyChangedEventArgsAnalyzerData + { + private const string ArgumentKeyName = "Argument"; + private const string IsNullKeyName = "IsNull"; + private const string IsNameofKeyName = "NameOf"; + private const string TypeKeyName = "Type"; + private const string SuffixAllProperties = "AllProperties"; + + public readonly string FullTypeName; + public readonly string ArgumentName; + public readonly bool ArgumentIsNullLiteral; + public readonly bool ArgumentIsNameofExpression; + public readonly string StaticFieldIdentifierNameProposition; + + private PropertyChangedEventArgsAnalyzerData(string fullTypeName, string argumentName, string isNullLiteral, string isNameof) + { + this.FullTypeName = fullTypeName; + this.ArgumentName = argumentName ?? string.Empty; + this.ArgumentIsNullLiteral = bool.Parse(isNullLiteral); + this.ArgumentIsNameofExpression = bool.Parse(isNameof); + + this.StaticFieldIdentifierNameProposition = $"PropertyChangedEventArgsFor{SuffixForStaticInstance()}"; + } + + public PropertyChangedEventArgsAnalyzerData(ObjectCreationExpressionSyntax propertyChangedInstanceCreationExpr) + { + if (propertyChangedInstanceCreationExpr == null) + { + throw new ArgumentNullException(nameof(propertyChangedInstanceCreationExpr)); + } + + var analyzer = new PropertyChangedCreationSyntaxAnalyzer(); + propertyChangedInstanceCreationExpr.ArgumentList.Accept(analyzer); + + this.FullTypeName = propertyChangedInstanceCreationExpr.Type.ToString(); + this.ArgumentName = analyzer.IdentifierName; + this.ArgumentIsNullLiteral = analyzer.NullLiteralExpressionFound; + this.ArgumentIsNameofExpression = analyzer.NameofExpressionFound; + } + + public string StaticFieldIdentifierName(IEnumerable nameHints) => nameHints.Contains(StaticFieldIdentifierNameProposition) ? + CreateNewIdenfitierName(StaticFieldIdentifierNameProposition, 1, nameHints) : StaticFieldIdentifierNameProposition; + + public MemberDeclarationSyntax PropertyChangedEventArgsStaticField(IEnumerable nameHints) + { + return FieldDeclaration(List(), + TokenList(Token(PrivateKeyword), Token(StaticKeyword), Token(ReadOnlyKeyword)), + VariableDeclaration(FieldType(FullTypeName), VariableName(StaticFieldIdentifierName(nameHints)))); + } + + public ImmutableDictionary ToDiagnosticProperties() + { + var dict = ImmutableDictionary.CreateBuilder(); + + dict.Add(ArgumentKeyName, ArgumentName); + dict.Add(IsNullKeyName, ArgumentIsNullLiteral.ToString()); + dict.Add(IsNameofKeyName, ArgumentIsNameofExpression.ToString()); + dict.Add(TypeKeyName, FullTypeName); + + return dict.ToImmutable(); + } + + public static PropertyChangedEventArgsAnalyzerData FromDiagnosticProperties(ImmutableDictionary properties) + { + return new PropertyChangedEventArgsAnalyzerData( + properties[TypeKeyName], properties[ArgumentKeyName], properties[IsNullKeyName], properties[IsNameofKeyName]); + } + + private EqualsValueClauseSyntax PropertyChangedEventArgsInstance() => + EqualsValueClause(Token(EqualsToken), + ObjectCreationExpression(ParseTypeName(FullTypeName), + ArgumentList( + SingletonSeparatedList( + PropertyChangedEventArgsCtorArgument())), default(InitializerExpressionSyntax))); + + private ArgumentSyntax PropertyChangedEventArgsCtorArgument() => + Argument(ArgumentIsNameofExpression + ? ParseExpression($"nameof({ArgumentName})") + : ArgumentIsNullLiteral ? LiteralExpression(NullLiteralExpression) : StringLiteral(ArgumentName)); + + private string SuffixForStaticInstance() + { + return ArgumentIsNullLiteral || ArgumentNameIsStar() ? SuffixAllProperties : MakeValidIdentifier(ArgumentName); + } + + private SeparatedSyntaxList VariableName(string fieldName) => + SeparatedList(new[] + { + VariableDeclarator(fieldName) + .WithInitializer(PropertyChangedEventArgsInstance()) + }); + + private bool ArgumentNameIsStar() => string.Equals(ArgumentName, "*", StringComparison.OrdinalIgnoreCase); + + private static string MakeValidIdentifier(string s) => IsValidIdentifier(s) ? s : SanitizeIdentifierName(s); + + private static string SanitizeIdentifierName(string s) => s.ToCharArray() + .Aggregate(new StringBuilder(), + (sanitized, nextChar) => IsValidIdentifier($"{sanitized.ToString()}{nextChar}") ? sanitized.Append(nextChar) : sanitized) + .ToString(); + + private static LiteralExpressionSyntax StringLiteral(string s) => LiteralExpression(StringLiteralExpression, Literal(s)); + + private static IdentifierNameSyntax FieldType(string type) => IdentifierName(type); + + private static string CreateNewIdenfitierName(string oldName, int extension, IEnumerable nameHints) + { + var number = int.Parse(new string(oldName.ToCharArray().Reverse().TakeWhile(char.IsNumber).DefaultIfEmpty('0').ToArray())); + var proposition = $"{oldName}{number+extension}"; + return nameHints.Contains(proposition) ? CreateNewIdenfitierName(oldName, extension+1, nameHints) : proposition; + } + + private class PropertyChangedCreationSyntaxAnalyzer : CSharpSyntaxWalker + { + public bool NullLiteralExpressionFound { get; private set; } + public bool NameofExpressionFound { get; private set; } + public string IdentifierName { get; private set; } + + public override void VisitLiteralExpression(LiteralExpressionSyntax node) + { + NameofExpressionFound = false; + NullLiteralExpressionFound = node.IsKind(NullLiteralExpression); + IdentifierName = node.Token.ValueText; + } + + public override void VisitInvocationExpression(InvocationExpressionSyntax node) + { + NameofExpressionFound = true; + base.VisitInvocationExpression(node); + } + + public override void VisitIdentifierName(IdentifierNameSyntax node) => IdentifierName = node.Identifier.ValueText; + } + } +} \ No newline at end of file diff --git a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs new file mode 100644 index 000000000..f0defd319 --- /dev/null +++ b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs @@ -0,0 +1,93 @@ +using System.Collections.Immutable; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using CodeCracker.Properties; +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 Microsoft.CodeAnalysis.Text; + +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace CodeCracker.CSharp.Refactoring +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider)), Shared] + public sealed class PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider : CodeFixProvider + { + public LocalizableString CodeActionTitle = new LocalizableResourceString(nameof(Resources.PropertyChangedEventArgsUnnecessaryAllocation_CodeActionTitle), Resources.ResourceManager, typeof(Resources)); + + public override ImmutableArray FixableDiagnosticIds + => ImmutableArray.Create(DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId()); + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = context.Diagnostics.First(); + context.RegisterCodeFix( + CodeAction.Create(CodeActionTitle.ToString(), + token => ChangePropertyChangedEventArgsToStatic(context.Document, diagnostic.Location, diagnostic.Properties, token), + nameof(PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider)), diagnostic); + + return Task.FromResult(true); + } + + private static async Task ChangePropertyChangedEventArgsToStatic(Document document, Location location, + ImmutableDictionary properties, CancellationToken cancellationToken) + { + var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken); + var data = PropertyChangedEventArgsAnalyzerData.FromDiagnosticProperties(properties); + + var newSyntaxRoot = new PropertyChangedUnnecessaryAllocationRewriter(data, location.SourceSpan).Visit(syntaxRoot); + + return document.WithSyntaxRoot(newSyntaxRoot); + } + + private class PropertyChangedUnnecessaryAllocationRewriter : CSharpSyntaxRewriter + { + private readonly PropertyChangedEventArgsAnalyzerData ContextData; + private readonly TextSpan DiagnosticLocation; + + private bool DiagnosticLocationFound = false; + private IEnumerable nameHints; + + public PropertyChangedUnnecessaryAllocationRewriter(PropertyChangedEventArgsAnalyzerData contextData, TextSpan diagnosticLocation) + { + this.ContextData = contextData; + this.DiagnosticLocation = diagnosticLocation; + } + + public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) + { + nameHints = node.Members.OfType() + .SelectMany(fd => fd.Declaration.Variables.Select(vds => vds.Identifier.ValueText)); + + var traverseResult = base.VisitClassDeclaration(node) as ClassDeclarationSyntax; + var result = DiagnosticLocationFound ? AddPropertyChangedEventArgsStaticField(traverseResult, nameHints ?? Enumerable.Empty()) : traverseResult; + DiagnosticLocationFound = false; + return result; + } + + public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) + { + if(node.Span == DiagnosticLocation) + { + DiagnosticLocationFound = true; + + return ParseExpression(ContextData.StaticFieldIdentifierName(nameHints ?? Enumerable.Empty())) + .WithLeadingTrivia(node.GetLeadingTrivia()) + .WithTrailingTrivia(node.GetTrailingTrivia()); + } + return base.VisitObjectCreationExpression(node); + } + + private ClassDeclarationSyntax AddPropertyChangedEventArgsStaticField(ClassDeclarationSyntax declaration, IEnumerable nameHints) => declaration + .WithMembers(declaration.Members.Insert(0, ContextData.PropertyChangedEventArgsStaticField(nameHints).WithAdditionalAnnotations(Formatter.Annotation))); + } + } +} diff --git a/src/Common/CodeCracker.Common/DiagnosticId.cs b/src/Common/CodeCracker.Common/DiagnosticId.cs index 28feee0f8..4dfc7ecb6 100644 --- a/src/Common/CodeCracker.Common/DiagnosticId.cs +++ b/src/Common/CodeCracker.Common/DiagnosticId.cs @@ -80,6 +80,7 @@ public enum DiagnosticId NameOf_External = 108, StringFormatArgs_ExtraArgs = 111, AlwaysUseVarOnPrimitives = 105, + PropertyChangedEventArgsUnnecessaryAllocation = 106, UnnecessaryToStringInStringConcatenation = 118, SwitchCaseWithoutDefault = 120, ReadOnlyComplexTypes = 121, diff --git a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs index 17f3ec989..af567f32d 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs +++ b/src/Common/CodeCracker.Common/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -14,12 +14,12 @@ namespace CodeCracker.Properties { /// - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert - // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -34,7 +34,7 @@ internal Resources() { } /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { @@ -48,8 +48,8 @@ internal Resources() { } /// - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { @@ -62,7 +62,7 @@ internal Resources() { } /// - /// Sucht eine lokalisierte Zeichenfolge, die String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string. ähnelt. + /// Looks up a localized string similar to String interpolation allows for better reading of the resulting string when compared to Console.WriteLine arguments. You should use Console.WriteLine with arguments only when another method is supplying the format string.. /// public static string ConsoleWriteLineAnalyzer_Description { get { @@ -71,7 +71,7 @@ public static string ConsoleWriteLineAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation ähnelt. + /// Looks up a localized string similar to Use string interpolation. /// public static string ConsoleWriteLineAnalyzer_MessageFormat { get { @@ -80,7 +80,7 @@ public static string ConsoleWriteLineAnalyzer_MessageFormat { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation instead of arguments on Console.WriteLine ähnelt. + /// Looks up a localized string similar to Use string interpolation instead of arguments on Console.WriteLine. /// public static string ConsoleWriteLineAnalyzer_Title { get { @@ -89,7 +89,7 @@ public static string ConsoleWriteLineAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change to string interpolation ähnelt. + /// Looks up a localized string similar to Change to string interpolation. /// public static string ConsoleWriteLineCodeFixProvider_Title { get { @@ -98,7 +98,7 @@ public static string ConsoleWriteLineCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die An empty catch block suppress all errors and shouldn't be used.\r\nIf the error is expected consider logging it or changing the control flow such that it is explicit. ähnelt. + /// Looks up a localized string similar to An empty catch block suppress all errors and shouldn't be used.\r\nIf the error is expected consider logging it or changing the control flow such that it is explicit.. /// public static string EmptyCatchBlockAnalyzer_Description { get { @@ -107,7 +107,7 @@ public static string EmptyCatchBlockAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Empty Catch Block. ähnelt. + /// Looks up a localized string similar to Empty Catch Block.. /// public static string EmptyCatchBlockAnalyzer_Message { get { @@ -116,7 +116,7 @@ public static string EmptyCatchBlockAnalyzer_Message { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Catch block cannot be empty ähnelt. + /// Looks up a localized string similar to Catch block cannot be empty. /// public static string EmptyCatchBlockAnalyzer_Title { get { @@ -125,7 +125,7 @@ public static string EmptyCatchBlockAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Insert Exception class to Catch ähnelt. + /// Looks up a localized string similar to Insert Exception class to Catch. /// public static string EmptyCatchBlockCodeFixProvider_InsertException { get { @@ -134,7 +134,7 @@ public static string EmptyCatchBlockCodeFixProvider_InsertException { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Remove Empty Catch Block ähnelt. + /// Looks up a localized string similar to Remove Empty Catch Block. /// public static string EmptyCatchBlockCodeFixProvider_Remove { get { @@ -143,7 +143,7 @@ public static string EmptyCatchBlockCodeFixProvider_Remove { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Remove Empty Catch Block and Put a Documentation Link about Try...Catch use ähnelt. + /// Looks up a localized string similar to Remove Empty Catch Block and Put a Documentation Link about Try...Catch use. /// public static string EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation { get { @@ -152,7 +152,7 @@ public static string EmptyCatchBlockCodeFixProvider_RemoveAndDocumentation { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Remove wrapping Try Block ähnelt. + /// Looks up a localized string similar to Remove wrapping Try Block. /// public static string EmptyCatchBlockCodeFixProvider_RemoveTry { get { @@ -161,7 +161,7 @@ public static string EmptyCatchBlockCodeFixProvider_RemoveTry { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change field type '{0}' accessibility to be as accessible as field '{1}' ähnelt. + /// Looks up a localized string similar to Change field type '{0}' accessibility to be as accessible as field '{1}'. /// public static string InconsistentAccessibilityInFieldType_Title { get { @@ -170,7 +170,7 @@ public static string InconsistentAccessibilityInFieldType_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]' ähnelt. + /// Looks up a localized string similar to Change parameter type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. /// public static string InconsistentAccessibilityInIndexerParameter_Title { get { @@ -179,7 +179,7 @@ public static string InconsistentAccessibilityInIndexerParameter_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]' ähnelt. + /// Looks up a localized string similar to Change indexer return type '{0}' accessibility to be as accessible as indexer 'this[{1}]'. /// public static string InconsistentAccessibilityInIndexerReturnType_Title { get { @@ -188,7 +188,7 @@ public static string InconsistentAccessibilityInIndexerReturnType_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change parameter type '{0}' accessibility to be as accessible as method '{1}' ähnelt. + /// Looks up a localized string similar to Change parameter type '{0}' accessibility to be as accessible as method '{1}'. /// public static string InconsistentAccessibilityInMethodParameter_Title { get { @@ -197,7 +197,7 @@ public static string InconsistentAccessibilityInMethodParameter_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change return type '{0}' accessibility to be as accessible as method '{1}' ähnelt. + /// Looks up a localized string similar to Change return type '{0}' accessibility to be as accessible as method '{1}'. /// public static string InconsistentAccessibilityInMethodReturnType_Title { get { @@ -206,7 +206,7 @@ public static string InconsistentAccessibilityInMethodReturnType_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change property type '{0}' accessibility to be as accessible as property '{1}' ähnelt. + /// Looks up a localized string similar to Change property type '{0}' accessibility to be as accessible as property '{1}'. /// public static string InconsistentAccessibilityInPropertyType_Title { get { @@ -215,7 +215,7 @@ public static string InconsistentAccessibilityInPropertyType_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Consider introduce field for constructor parameters. ähnelt. + /// Looks up a localized string similar to Consider introduce field for constructor parameters.. /// public static string IntroduceFieldFromConstructorAnalyzer_Description { get { @@ -224,7 +224,7 @@ public static string IntroduceFieldFromConstructorAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Introduce a field for parameter: {0} ähnelt. + /// Looks up a localized string similar to Introduce a field for parameter: {0}. /// public static string IntroduceFieldFromConstructorAnalyzer_MessageFormat { get { @@ -233,7 +233,7 @@ public static string IntroduceFieldFromConstructorAnalyzer_MessageFormat { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Consider introduce field for constructor parameters. ähnelt. + /// Looks up a localized string similar to Consider introduce field for constructor parameters.. /// public static string IntroduceFieldFromConstructorAnalyzer_Title { get { @@ -242,7 +242,7 @@ public static string IntroduceFieldFromConstructorAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Introduce field: {0} from constructor. ähnelt. + /// Looks up a localized string similar to Introduce field: {0} from constructor.. /// public static string IntroduceFieldFromConstructorCodeFixProvider_MessageFormat { get { @@ -251,7 +251,7 @@ public static string IntroduceFieldFromConstructorCodeFixProvider_MessageFormat } /// - /// Sucht eine lokalisierte Zeichenfolge, die Introduce fields for constructor parameters. ähnelt. + /// Looks up a localized string similar to Introduce fields for constructor parameters.. /// public static string IntroduceFieldFromConstructorCodeFixProvider_Title { get { @@ -260,7 +260,7 @@ public static string IntroduceFieldFromConstructorCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Make method non async ähnelt. + /// Looks up a localized string similar to Make method non async. /// public static string MakeMethodNonAsyncCodeFixProvider_Title { get { @@ -269,7 +269,7 @@ public static string MakeMethodNonAsyncCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor. ähnelt. + /// Looks up a localized string similar to In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor.. /// public static string NameOfAnalyzer_Description { get { @@ -278,7 +278,7 @@ public static string NameOfAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use 'nameof({0})' instead of specifying the program element name. ähnelt. + /// Looks up a localized string similar to Use 'nameof({0})' instead of specifying the program element name.. /// public static string NameOfAnalyzer_MessageFormat { get { @@ -287,7 +287,7 @@ public static string NameOfAnalyzer_MessageFormat { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use nameof ähnelt. + /// Looks up a localized string similar to Use nameof. /// public static string NameOfAnalyzer_Title { get { @@ -296,7 +296,7 @@ public static string NameOfAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use nameof() ähnelt. + /// Looks up a localized string similar to Use nameof(). /// public static string NameOfCodeFixProvider_Title { get { @@ -305,7 +305,43 @@ public static string NameOfCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Getter only properties with backing read-only field can be converted to getter-only auto-properties. ähnelt. + /// Looks up a localized string similar to Create static PropertyChangedEventArgs instance and reuse. + /// + public static string PropertyChangedEventArgsUnnecessaryAllocation_CodeActionTitle { + get { + return ResourceManager.GetString("PropertyChangedEventArgsUnnecessaryAllocation_CodeActionTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Creating every time an instance of PropertyChangedEventArgs class causes unnecessary memory allocation. Instance can be created once and reused.. + /// + public static string PropertyChangedEventArgsUnnecessaryAllocation_Description { + get { + return ResourceManager.GetString("PropertyChangedEventArgsUnnecessaryAllocation_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation.. + /// + public static string PropertyChangedEventArgsUnnecessaryAllocation_MessageFormat { + get { + return ResourceManager.GetString("PropertyChangedEventArgsUnnecessaryAllocation_MessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PropertyChangedEventArgs unnecessary allocation. + /// + public static string PropertyChangedEventArgsUnnecessaryAllocation_Title { + get { + return ResourceManager.GetString("PropertyChangedEventArgsUnnecessaryAllocation_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Getter only properties with backing read-only field can be converted to getter-only auto-properties.. /// public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_Description { get { @@ -314,7 +350,7 @@ public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Property {0} can be converted to an getter-only auto-property. ähnelt. + /// Looks up a localized string similar to Property {0} can be converted to an getter-only auto-property.. /// public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_MessageFormat { get { @@ -323,7 +359,7 @@ public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_MessageFormat { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Property can be simplified by using an getter-only auto-property. ähnelt. + /// Looks up a localized string similar to Property can be simplified by using an getter-only auto-property.. /// public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_Title { get { @@ -332,7 +368,7 @@ public static string ReplaceWithGetterOnlyAutoPropertyAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Simplify by using an getter-only auto-property ähnelt. + /// Looks up a localized string similar to Simplify by using an getter-only auto-property. /// public static string ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title { get { @@ -341,7 +377,7 @@ public static string ReplaceWithGetterOnlyAutoPropertyCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string. ähnelt. + /// Looks up a localized string similar to String interpolation allows for better reading of the resulting string when compared to String.Format. You should use String.Format only when another method is supplying the format string.. /// public static string StringFormatAnalyzer_Description { get { @@ -350,7 +386,7 @@ public static string StringFormatAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation ähnelt. + /// Looks up a localized string similar to Use string interpolation. /// public static string StringFormatAnalyzer_MessageFormat { get { @@ -359,7 +395,7 @@ public static string StringFormatAnalyzer_MessageFormat { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use string interpolation instead of String.Format ähnelt. + /// Looks up a localized string similar to Use string interpolation instead of String.Format. /// public static string StringFormatAnalyzer_Title { get { @@ -368,7 +404,7 @@ public static string StringFormatAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change to string interpolation ähnelt. + /// Looks up a localized string similar to Change to string interpolation. /// public static string StringFormatCodeFixProvider_Title { get { @@ -377,7 +413,7 @@ public static string StringFormatCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties. ähnelt. + /// Looks up a localized string similar to Auto properties offer a more concise way of defining a property. If you are using simple getters and setters you are able to simplify your code with autoproperties.. /// public static string SwitchToAutoPropAnalyzer_Description { get { @@ -386,7 +422,7 @@ public static string SwitchToAutoPropAnalyzer_Description { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change {0} to an auto property ähnelt. + /// Looks up a localized string similar to Change {0} to an auto property. /// public static string SwitchToAutoPropAnalyzer_MessageFormat { get { @@ -395,7 +431,7 @@ public static string SwitchToAutoPropAnalyzer_MessageFormat { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Use auto property ähnelt. + /// Looks up a localized string similar to Use auto property. /// public static string SwitchToAutoPropAnalyzer_Title { get { @@ -404,7 +440,7 @@ public static string SwitchToAutoPropAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Change to auto property ähnelt. + /// Looks up a localized string similar to Change to auto property. /// public static string SwitchToAutoPropCodeFixProvider_Title { get { @@ -413,7 +449,7 @@ public static string SwitchToAutoPropCodeFixProvider_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die You have missing/unexistent parameters in Xml Docs ähnelt. + /// Looks up a localized string similar to You have missing/unexistent parameters in Xml Docs. /// public static string XmlDocumentationAnalyzer_Title { get { @@ -422,7 +458,7 @@ public static string XmlDocumentationAnalyzer_Title { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Create missing parameters in xml docs ähnelt. + /// Looks up a localized string similar to Create missing parameters in xml docs. /// public static string XmlDocumentationCreateMissingParametersCodeFixProvider_Title { get { @@ -431,7 +467,7 @@ public static string XmlDocumentationCreateMissingParametersCodeFixProvider_Titl } /// - /// Sucht eine lokalisierte Zeichenfolge, die Remove unexistent parameters in xml docs ähnelt. + /// Looks up a localized string similar to Remove unexistent parameters in xml docs. /// public static string XmlDocumentationRemoveNonExistentParametersCodeFixProvider_Title { get { diff --git a/src/Common/CodeCracker.Common/Properties/Resources.fr.resx b/src/Common/CodeCracker.Common/Properties/Resources.fr.resx index a7953b4d6..630db6544 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.fr.resx +++ b/src/Common/CodeCracker.Common/Properties/Resources.fr.resx @@ -214,4 +214,16 @@ Si l'erreur est attendu considérer ajouter du logging ou modifier le flow de co Enlever le block Catch vide et ajouter un lien vers la documentation des bonnes pratiques de Try...Catch + + Creating every time an instance of PropertyChangedEventArgs class causes unnecessary memory allocation. Instance can be created once and reused. + + + Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation. + + + PropertyChangedEventArgs unnecessary allocation + + + Create static PropertyChangedEventArgs instance and reuse + \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/Properties/Resources.resx b/src/Common/CodeCracker.Common/Properties/Resources.resx index aab3eb4fd..944e7b07e 100644 --- a/src/Common/CodeCracker.Common/Properties/Resources.resx +++ b/src/Common/CodeCracker.Common/Properties/Resources.resx @@ -243,4 +243,16 @@ Introduce fields for constructor parameters. + + Creating every time an instance of PropertyChangedEventArgs class causes unnecessary memory allocation. Instance can be created once and reused. + + + Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation. + + + PropertyChangedEventArgs unnecessary allocation + + + Create static PropertyChangedEventArgs instance and reuse + \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index c45a93ec6..902abbd5b 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -130,6 +130,8 @@ + + diff --git a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs new file mode 100644 index 000000000..a5707fa68 --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs @@ -0,0 +1,169 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using CodeCracker.CSharp.Refactoring; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Xunit; + +namespace CodeCracker.Test.CSharp.Refactoring +{ + public class PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests : CodeFixVerifier + { + public static IEnumerable SharedData + { + get + { + yield return new[] {"\"Name\""}; + yield return new[] {"nameof(Name)"}; + yield return new[] {"null"}; + } + } + + [Fact] + public async Task DoesNotTriggerDiagnosticWithEmptySourceCodeAsync() + { + const string source = @""; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreation(string ctorArg) + { + var source = $"var args = new PropertyChangedEventArgs({ctorArg})"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 12)); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInMethodInvocation(string ctorArg) + { + var source = $@" +public class Test +{{ + public void TestMethod() + {{ + PropertyChanged(new PropertyChangedEventArgs({ctorArg})) + }} +}}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(6, 25)); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInObjectInitializer(string ctorArg) + { + var source = $"object args = new {{ Name = new PropertyChangedEventArgs({ctorArg}) }}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 28)); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesNotTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInFieldAssignmentWhenFieldIsStatic(string ctorArg) + { + var source = $@" +public class Test +{{ + private static PropertyChangedEventArgs field = new PropertyChangedEventArgs({ctorArg}); +}}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DoesNotTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInStaticConstructor() + { + const string source = @" +public class Test +{ + private static PropertyChangedEventArgs field; + + static Test() + { + field = new PropertyChangedEventArgs(""Name""); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DoesNotTriggerDiagnosticAtObjectInstanceCreation() + { + const string source = @" +public class Test +{ + private object field = new object(); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DoesTriggerDiagnosticAtObjectInstanceCreationUsingQualifiedName() + { + const string source = @" +public class Test +{ + private object field = new System.ComponentModel.PropertyChangedEventArgs(null); +}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(4,28)); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesTriggerDiagnosticInLambdaExpression(string ctorArg) + { + var source = $@" +using System; +using System.ComponentModel; +public class Test +{{ + private PropertyChangedEventArgs field; + + public Test() + {{ + Action action = () => field = new PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(10,39)); + } + + [Fact] + public async Task DoesNotTriggerWhenArgumentIsNotLiteral() + { + var source = $@" +public class Test +{{ + public void TestMethod(string propertyName) + {{ + PropertyChanged(new PropertyChangedEventArgs(propertyName)) + }} +}}"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new PropertyChangedEventArgsUnnecessaryAllocationAnalyzer(); + } + + public static DiagnosticResult PropertyChangedUnnecessaryAllocationDiagnostic(int line, int column) + { + return new DiagnosticResult + { + Id = DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId(), + Message = "Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation.", + Severity = DiagnosticSeverity.Hidden, + Locations = new[] + { + new DiagnosticResultLocation("Test0.cs", line, column), + } + }; + } + } +} diff --git a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs new file mode 100644 index 000000000..f9a9ae410 --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs @@ -0,0 +1,318 @@ +using CodeCracker.CSharp.Refactoring; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace CodeCracker.Test.CSharp.Refactoring +{ + public class PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests : + CodeFixVerifier + + { + public static IEnumerable SharedData + { + get + { + yield return new[] { "\"Name\"", "Name" }; + yield return new[] { "nameof(Name)", "Name" }; + yield return new[] { "null", "AllProperties" }; + yield return new[] { "\"*\"", "AllProperties" }; + yield return new[] { "\"Name-\"", "Name" }; + } + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task ChangesPropertyChangedEventArgsInstanceToUseStaticField(string ctorArg, string fieldSuffix) + { + var source = $@" +using System.ComponentModel; +public class TestClass +{{ + public string Name {{ get;set; }} + + public void Foo() + {{ + var args = new PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + var fixedCode = $@" +using System.ComponentModel; +public class TestClass +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + + public string Name {{ get;set; }} + + public void Foo() + {{ + var args = PropertyChangedEventArgsFor{fieldSuffix}; + }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesFixWhenEventArgsUsedInMethodInvocation(string ctorArg, string fieldSuffix) + { + var source = $@" +using System.ComponentModel; +public class TestClass +{{ + public string Name {{ get;set; }} + + public void Foo() + {{ + On(new PropertyChangedEventArgs({ctorArg})); + }} + + public void On(PropertyChangedEventArgs args) {{ }} +}}"; + + var fixedCode = $@" +using System.ComponentModel; +public class TestClass +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + + public string Name {{ get;set; }} + + public void Foo() + {{ + On(PropertyChangedEventArgsFor{fieldSuffix}); + }} + + public void On(PropertyChangedEventArgs args) {{ }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task HandlesMultipleClassDeclarations(string ctorArg, string fieldSuffix) + { + var source = $@" +using System.ComponentModel; +public class TestClass +{{ + public string Name {{ get;set; }} + + public void Foo() + {{ + var args = new PropertyChangedEventArgs({ctorArg}); + }} +}} + +public class TestClass2 +{{ +}}"; + + var fixedCode = $@" +using System.ComponentModel; +public class TestClass +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + + public string Name {{ get;set; }} + + public void Foo() + {{ + var args = PropertyChangedEventArgsFor{fieldSuffix}; + }} +}} + +public class TestClass2 +{{ +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesFixWhenQualifiedNameUsed(string ctorArg, string fieldSuffix) + { + var source = $@" +public class TestClass +{{ + public string Name {{ get;set; }} + + public void Foo() + {{ + var args = new System.ComponentModel.PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + var fixedCode = $@" +public class TestClass +{{ + private static readonly System.ComponentModel.PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new System.ComponentModel.PropertyChangedEventArgs({ctorArg}); + + public string Name {{ get;set; }} + + public void Foo() + {{ + var args = PropertyChangedEventArgsFor{fieldSuffix}; + }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode, allowNewCompilerDiagnostics: true); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesFixWhenEventArgsCreatedInField(string ctorArg, string fieldSuffix) + { + var source = $@" +using System.ComponentModel; +public class TestClass +{{ + private PropertyChangedEventArgs field = new PropertyChangedEventArgs({ctorArg}); +}}"; + + var fixedCode = $@" +using System.ComponentModel; +public class TestClass +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + private PropertyChangedEventArgs field = PropertyChangedEventArgsFor{fieldSuffix}; +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesFixWhenEventArgsCreatedInObjectInitializer(string ctorArg, string fieldSuffix) + { + var source = $@" +using System.ComponentModel; +public class TestClass +{{ + public string Name {{ get;set; }} + + public void Foo() + {{ + object args = new {{ Name = new PropertyChangedEventArgs({ctorArg}) }}; + }} +}}"; + + var fixedCode = $@" +using System.ComponentModel; +public class TestClass +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + + public string Name {{ get;set; }} + + public void Foo() + {{ + object args = new {{ Name = PropertyChangedEventArgsFor{fieldSuffix} }}; + }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task HandlesNestedClass(string ctorArg, string fieldSuffix) + { + var source = $@" +using System.ComponentModel; +public class OuterClass +{{ + public class TestClass + {{ + private PropertyChangedEventArgs field = new PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + var fixedCode = $@" +using System.ComponentModel; +public class OuterClass +{{ + public class TestClass + {{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + private PropertyChangedEventArgs field = PropertyChangedEventArgsFor{fieldSuffix}; + }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesFixLambdaExpression(string ctorArg, string fieldSuffix) + { + var source = $@" +using System; +using System.ComponentModel; +public class Test +{{ + private PropertyChangedEventArgs field; + + public Test() + {{ + Action action = () => field = new PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + var fixedCode = $@" +using System; +using System.ComponentModel; +public class Test +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + private PropertyChangedEventArgs field; + + public Test() + {{ + Action action = () => field = PropertyChangedEventArgsFor{fieldSuffix}; + }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + + [Theory] + [MemberData(nameof(SharedData))] + public async Task DoesFixWhenFieldNameIsAlreadyUsed(string ctorArg, string fieldSuffix) + { + var source = $@" +using System; +using System.ComponentModel; +public class Test +{{ + private PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix}; + + public Test() + {{ + Action action = () => PropertyChangedEventArgsFor{fieldSuffix} = new PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + var fixedCode = $@" +using System; +using System.ComponentModel; +public class Test +{{ + private static readonly PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix}1 = new PropertyChangedEventArgs({ctorArg}); + private PropertyChangedEventArgs PropertyChangedEventArgsFor{fieldSuffix}; + + public Test() + {{ + Action action = () => PropertyChangedEventArgsFor{fieldSuffix} = PropertyChangedEventArgsFor{fieldSuffix}1; + }} +}}"; + + await VerifyCSharpFixAsync(source, fixedCode); + } + } +} From 40b7e1834fa218cc28c66cc19e0a368f425b5011 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 28 Jun 2017 18:42:14 -0300 Subject: [PATCH 295/358] Refactor PropertyChangedEventArgsUnnecessaryAllocation --- ...dEventArgsUnnecessaryAllocationAnalyzer.cs | 54 +++--- ...rgsUnnecessaryAllocationCodeFixProvider.cs | 45 ++--- .../CodeCracker.Test/CodeCracker.Test.csproj | 3 +- ...tArgsUnnecessaryAllocationAnalyzerTests.cs | 169 ---------------- ...gedEventArgsUnnecessaryAllocationTests.cs} | 180 ++++++++++++++++-- 5 files changed, 209 insertions(+), 242 deletions(-) delete mode 100644 test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs rename test/CSharp/CodeCracker.Test/Refactoring/{PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs => PropertyChangedEventArgsUnnecessaryAllocationTests.cs} (59%) diff --git a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs index b1a15bf7f..e9924b9d3 100644 --- a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs @@ -1,17 +1,15 @@ -using System; -using System.Collections.Immutable; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using CodeCracker.Properties; +using CodeCracker.Properties; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; - -using static Microsoft.CodeAnalysis.CSharp.SyntaxFacts; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFacts; using static Microsoft.CodeAnalysis.CSharp.SyntaxKind; namespace CodeCracker.CSharp.Refactoring @@ -49,7 +47,7 @@ public override void Initialize(AnalysisContext context) private static void PropertyChangedCreation(SyntaxNodeAnalysisContext context) { - var propertyChangedEventArgsCreationExpr = (ObjectCreationExpressionSyntax) context.Node; + var propertyChangedEventArgsCreationExpr = (ObjectCreationExpressionSyntax)context.Node; var identifier = propertyChangedEventArgsCreationExpr.Type.Accept(ExtractIdentifier); if (ShouldReportDiagnostic(propertyChangedEventArgsCreationExpr, identifier.ValueText)) { @@ -59,14 +57,12 @@ private static void PropertyChangedCreation(SyntaxNodeAnalysisContext context) } } - private static bool ShouldReportDiagnostic(ObjectCreationExpressionSyntax propertyChangedExpr, - string identifierName) => + private static bool ShouldReportDiagnostic(ObjectCreationExpressionSyntax propertyChangedExpr, string identifierName) => IsPropertyChangedEventArgs(identifierName) && propertyChangedExpr.ArgumentList.Accept(IsAnyArgumentLiteralOrNameof) && !IsAlreadyStatic(propertyChangedExpr); - private static bool IsPropertyChangedEventArgs(string s) - => string.Equals(PropertyChangedEventArgsClassName, s, StringComparison.Ordinal); + private static bool IsPropertyChangedEventArgs(string s) => string.Equals(PropertyChangedEventArgsClassName, s, StringComparison.Ordinal); private static bool IsAlreadyStatic(ObjectCreationExpressionSyntax objectCreationExpr) { @@ -75,7 +71,7 @@ private static bool IsAlreadyStatic(ObjectCreationExpressionSyntax objectCreatio switch (memberForObjectCreationExpr.Kind()) { case SyntaxKind.ConstructorDeclaration: - var constructorDeclaration = (ConstructorDeclarationSyntax) memberForObjectCreationExpr; + var constructorDeclaration = (ConstructorDeclarationSyntax)memberForObjectCreationExpr; result = ContainsStaticModifier(constructorDeclaration.Modifiers); break; case SyntaxKind.FieldDeclaration: @@ -123,31 +119,27 @@ public class PropertyChangedEventArgsAnalyzerData private PropertyChangedEventArgsAnalyzerData(string fullTypeName, string argumentName, string isNullLiteral, string isNameof) { - this.FullTypeName = fullTypeName; - this.ArgumentName = argumentName ?? string.Empty; - this.ArgumentIsNullLiteral = bool.Parse(isNullLiteral); - this.ArgumentIsNameofExpression = bool.Parse(isNameof); + FullTypeName = fullTypeName; + ArgumentName = argumentName ?? string.Empty; + ArgumentIsNullLiteral = bool.Parse(isNullLiteral); + ArgumentIsNameofExpression = bool.Parse(isNameof); - this.StaticFieldIdentifierNameProposition = $"PropertyChangedEventArgsFor{SuffixForStaticInstance()}"; + StaticFieldIdentifierNameProposition = $"PropertyChangedEventArgsFor{SuffixForStaticInstance()}"; } public PropertyChangedEventArgsAnalyzerData(ObjectCreationExpressionSyntax propertyChangedInstanceCreationExpr) { if (propertyChangedInstanceCreationExpr == null) - { throw new ArgumentNullException(nameof(propertyChangedInstanceCreationExpr)); - } - var analyzer = new PropertyChangedCreationSyntaxAnalyzer(); propertyChangedInstanceCreationExpr.ArgumentList.Accept(analyzer); - - this.FullTypeName = propertyChangedInstanceCreationExpr.Type.ToString(); - this.ArgumentName = analyzer.IdentifierName; - this.ArgumentIsNullLiteral = analyzer.NullLiteralExpressionFound; - this.ArgumentIsNameofExpression = analyzer.NameofExpressionFound; + FullTypeName = propertyChangedInstanceCreationExpr.Type.ToString(); + ArgumentName = analyzer.IdentifierName; + ArgumentIsNullLiteral = analyzer.NullLiteralExpressionFound; + ArgumentIsNameofExpression = analyzer.NameofExpressionFound; } - public string StaticFieldIdentifierName(IEnumerable nameHints) => nameHints.Contains(StaticFieldIdentifierNameProposition) ? + public string StaticFieldIdentifierName(IEnumerable nameHints) => nameHints.Contains(StaticFieldIdentifierNameProposition) ? CreateNewIdenfitierName(StaticFieldIdentifierNameProposition, 1, nameHints) : StaticFieldIdentifierNameProposition; public MemberDeclarationSyntax PropertyChangedEventArgsStaticField(IEnumerable nameHints) @@ -215,8 +207,8 @@ private static string SanitizeIdentifierName(string s) => s.ToCharArray() private static string CreateNewIdenfitierName(string oldName, int extension, IEnumerable nameHints) { var number = int.Parse(new string(oldName.ToCharArray().Reverse().TakeWhile(char.IsNumber).DefaultIfEmpty('0').ToArray())); - var proposition = $"{oldName}{number+extension}"; - return nameHints.Contains(proposition) ? CreateNewIdenfitierName(oldName, extension+1, nameHints) : proposition; + var proposition = $"{oldName}{number + extension}"; + return nameHints.Contains(proposition) ? CreateNewIdenfitierName(oldName, extension + 1, nameHints) : proposition; } private class PropertyChangedCreationSyntaxAnalyzer : CSharpSyntaxWalker diff --git a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs index f0defd319..834906f67 100644 --- a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider.cs @@ -1,11 +1,4 @@ -using System.Collections.Immutable; -using System.Collections.Generic; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using CodeCracker.Properties; +using CodeCracker.Properties; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; @@ -13,7 +6,12 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; - +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace CodeCracker.CSharp.Refactoring @@ -31,35 +29,32 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) var diagnostic = context.Diagnostics.First(); context.RegisterCodeFix( CodeAction.Create(CodeActionTitle.ToString(), - token => ChangePropertyChangedEventArgsToStatic(context.Document, diagnostic.Location, diagnostic.Properties, token), + token => ChangePropertyChangedEventArgsToStaticAsync(context.Document, diagnostic.Location, diagnostic.Properties, token), nameof(PropertyChangedEventArgsUnnecessaryAllocationCodeFixProvider)), diagnostic); return Task.FromResult(true); } - private static async Task ChangePropertyChangedEventArgsToStatic(Document document, Location location, + private static async Task ChangePropertyChangedEventArgsToStaticAsync(Document document, Location location, ImmutableDictionary properties, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken); var data = PropertyChangedEventArgsAnalyzerData.FromDiagnosticProperties(properties); - var newSyntaxRoot = new PropertyChangedUnnecessaryAllocationRewriter(data, location.SourceSpan).Visit(syntaxRoot); - return document.WithSyntaxRoot(newSyntaxRoot); } private class PropertyChangedUnnecessaryAllocationRewriter : CSharpSyntaxRewriter { - private readonly PropertyChangedEventArgsAnalyzerData ContextData; - private readonly TextSpan DiagnosticLocation; - - private bool DiagnosticLocationFound = false; + private readonly PropertyChangedEventArgsAnalyzerData contextData; + private readonly TextSpan diagnosticLocation; + private bool diagnosticLocationFound; private IEnumerable nameHints; public PropertyChangedUnnecessaryAllocationRewriter(PropertyChangedEventArgsAnalyzerData contextData, TextSpan diagnosticLocation) { - this.ContextData = contextData; - this.DiagnosticLocation = diagnosticLocation; + this.contextData = contextData; + this.diagnosticLocation = diagnosticLocation; } public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) @@ -68,18 +63,18 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) .SelectMany(fd => fd.Declaration.Variables.Select(vds => vds.Identifier.ValueText)); var traverseResult = base.VisitClassDeclaration(node) as ClassDeclarationSyntax; - var result = DiagnosticLocationFound ? AddPropertyChangedEventArgsStaticField(traverseResult, nameHints ?? Enumerable.Empty()) : traverseResult; - DiagnosticLocationFound = false; + var result = diagnosticLocationFound ? AddPropertyChangedEventArgsStaticField(traverseResult, nameHints ?? Enumerable.Empty()) : traverseResult; + diagnosticLocationFound = false; return result; } public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { - if(node.Span == DiagnosticLocation) + if(node.Span == diagnosticLocation) { - DiagnosticLocationFound = true; + diagnosticLocationFound = true; - return ParseExpression(ContextData.StaticFieldIdentifierName(nameHints ?? Enumerable.Empty())) + return ParseExpression(contextData.StaticFieldIdentifierName(nameHints ?? Enumerable.Empty())) .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); } @@ -87,7 +82,7 @@ public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressio } private ClassDeclarationSyntax AddPropertyChangedEventArgsStaticField(ClassDeclarationSyntax declaration, IEnumerable nameHints) => declaration - .WithMembers(declaration.Members.Insert(0, ContextData.PropertyChangedEventArgsStaticField(nameHints).WithAdditionalAnnotations(Formatter.Annotation))); + .WithMembers(declaration.Members.Insert(0, contextData.PropertyChangedEventArgsStaticField(nameHints).WithAdditionalAnnotations(Formatter.Annotation))); } } } diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 902abbd5b..dcf1020ca 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -130,8 +130,7 @@ - - + diff --git a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs deleted file mode 100644 index a5707fa68..000000000 --- a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests.cs +++ /dev/null @@ -1,169 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using CodeCracker.CSharp.Refactoring; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Xunit; - -namespace CodeCracker.Test.CSharp.Refactoring -{ - public class PropertyChangedEventArgsUnnecessaryAllocationAnalyzerTests : CodeFixVerifier - { - public static IEnumerable SharedData - { - get - { - yield return new[] {"\"Name\""}; - yield return new[] {"nameof(Name)"}; - yield return new[] {"null"}; - } - } - - [Fact] - public async Task DoesNotTriggerDiagnosticWithEmptySourceCodeAsync() - { - const string source = @""; - - await VerifyCSharpHasNoDiagnosticsAsync(source); - } - - [Theory] - [MemberData(nameof(SharedData))] - public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreation(string ctorArg) - { - var source = $"var args = new PropertyChangedEventArgs({ctorArg})"; - - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 12)); - } - - [Theory] - [MemberData(nameof(SharedData))] - public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInMethodInvocation(string ctorArg) - { - var source = $@" -public class Test -{{ - public void TestMethod() - {{ - PropertyChanged(new PropertyChangedEventArgs({ctorArg})) - }} -}}"; - - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(6, 25)); - } - - [Theory] - [MemberData(nameof(SharedData))] - public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInObjectInitializer(string ctorArg) - { - var source = $"object args = new {{ Name = new PropertyChangedEventArgs({ctorArg}) }}"; - - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 28)); - } - - [Theory] - [MemberData(nameof(SharedData))] - public async Task DoesNotTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInFieldAssignmentWhenFieldIsStatic(string ctorArg) - { - var source = $@" -public class Test -{{ - private static PropertyChangedEventArgs field = new PropertyChangedEventArgs({ctorArg}); -}}"; - await VerifyCSharpHasNoDiagnosticsAsync(source); - } - - [Fact] - public async Task DoesNotTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInStaticConstructor() - { - const string source = @" -public class Test -{ - private static PropertyChangedEventArgs field; - - static Test() - { - field = new PropertyChangedEventArgs(""Name""); - } -}"; - await VerifyCSharpHasNoDiagnosticsAsync(source); - } - - [Fact] - public async Task DoesNotTriggerDiagnosticAtObjectInstanceCreation() - { - const string source = @" -public class Test -{ - private object field = new object(); -}"; - await VerifyCSharpHasNoDiagnosticsAsync(source); - } - - [Fact] - public async Task DoesTriggerDiagnosticAtObjectInstanceCreationUsingQualifiedName() - { - const string source = @" -public class Test -{ - private object field = new System.ComponentModel.PropertyChangedEventArgs(null); -}"; - - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(4,28)); - } - - [Theory] - [MemberData(nameof(SharedData))] - public async Task DoesTriggerDiagnosticInLambdaExpression(string ctorArg) - { - var source = $@" -using System; -using System.ComponentModel; -public class Test -{{ - private PropertyChangedEventArgs field; - - public Test() - {{ - Action action = () => field = new PropertyChangedEventArgs({ctorArg}); - }} -}}"; - - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(10,39)); - } - - [Fact] - public async Task DoesNotTriggerWhenArgumentIsNotLiteral() - { - var source = $@" -public class Test -{{ - public void TestMethod(string propertyName) - {{ - PropertyChanged(new PropertyChangedEventArgs(propertyName)) - }} -}}"; - - await VerifyCSharpHasNoDiagnosticsAsync(source); - } - - protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() - { - return new PropertyChangedEventArgsUnnecessaryAllocationAnalyzer(); - } - - public static DiagnosticResult PropertyChangedUnnecessaryAllocationDiagnostic(int line, int column) - { - return new DiagnosticResult - { - Id = DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId(), - Message = "Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", line, column), - } - }; - } - } -} diff --git a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs similarity index 59% rename from test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs rename to test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs index f9a9ae410..9e004869e 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs @@ -1,16 +1,166 @@ using CodeCracker.CSharp.Refactoring; +using Microsoft.CodeAnalysis; using System.Collections.Generic; using System.Threading.Tasks; using Xunit; namespace CodeCracker.Test.CSharp.Refactoring { - public class PropertyChangedEventArgsUnnecessaryAllocationCodeFixProviderTests : - CodeFixVerifier - + public class PropertyChangedEventArgsUnnecessaryAllocationTests : CodeFixVerifier { - public static IEnumerable SharedData + public static IEnumerable SharedDataAnalyzer + { + get + { + yield return new[] { "\"Name\"" }; + yield return new[] { "nameof(Name)" }; + yield return new[] { "null" }; + } + } + + [Fact] + public async Task DoesNotTriggerDiagnosticWithEmptySourceCodeAsync() + { + const string source = @""; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Theory] + [MemberData(nameof(SharedDataAnalyzer))] + public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreation(string ctorArg) + { + var source = $"var args = new PropertyChangedEventArgs({ctorArg})"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 12)); + } + + [Theory] + [MemberData(nameof(SharedDataAnalyzer))] + public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInMethodInvocation(string ctorArg) + { + var source = $@" +public class Test +{{ + public void TestMethod() + {{ + PropertyChanged(new PropertyChangedEventArgs({ctorArg})) + }} +}}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(6, 25)); + } + + [Theory] + [MemberData(nameof(SharedDataAnalyzer))] + public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInObjectInitializer(string ctorArg) + { + var source = $"object args = new {{ Name = new PropertyChangedEventArgs({ctorArg}) }}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 28)); + } + + [Theory] + [MemberData(nameof(SharedDataAnalyzer))] + public async Task DoesNotTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInFieldAssignmentWhenFieldIsStatic(string ctorArg) + { + var source = $@" +public class Test +{{ + private static PropertyChangedEventArgs field = new PropertyChangedEventArgs({ctorArg}); +}}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DoesNotTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreationInStaticConstructor() + { + const string source = @" +public class Test +{ + private static PropertyChangedEventArgs field; + + static Test() + { + field = new PropertyChangedEventArgs(""Name""); + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DoesNotTriggerDiagnosticAtObjectInstanceCreation() + { + const string source = @" +public class Test +{ + private object field = new object(); +}"; + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + [Fact] + public async Task DoesTriggerDiagnosticAtObjectInstanceCreationUsingQualifiedName() + { + const string source = @" +public class Test +{ + private object field = new System.ComponentModel.PropertyChangedEventArgs(null); +}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(4, 28)); + } + + [Theory] + [MemberData(nameof(SharedDataAnalyzer))] + public async Task DoesTriggerDiagnosticInLambdaExpression(string ctorArg) + { + var source = $@" +using System; +using System.ComponentModel; +public class Test +{{ + private PropertyChangedEventArgs field; + + public Test() + {{ + Action action = () => field = new PropertyChangedEventArgs({ctorArg}); + }} +}}"; + + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(10, 39)); + } + + [Fact] + public async Task DoesNotTriggerWhenArgumentIsNotLiteral() + { + var source = $@" +public class Test +{{ + public void TestMethod(string propertyName) + {{ + PropertyChanged(new PropertyChangedEventArgs(propertyName)) + }} +}}"; + + await VerifyCSharpHasNoDiagnosticsAsync(source); + } + + public static DiagnosticResult PropertyChangedUnnecessaryAllocationDiagnostic(int line, int column) + { + return new DiagnosticResult + { + Id = DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId(), + Message = "Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation.", + Severity = DiagnosticSeverity.Hidden, + Locations = new[] + { + new DiagnosticResultLocation("Test0.cs", line, column), + } + }; + } + + public static IEnumerable SharedDataCodeFix { get { @@ -23,7 +173,7 @@ public static IEnumerable SharedData } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task ChangesPropertyChangedEventArgsInstanceToUseStaticField(string ctorArg, string fieldSuffix) { var source = $@" @@ -56,7 +206,7 @@ public void Foo() } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task DoesFixWhenEventArgsUsedInMethodInvocation(string ctorArg, string fieldSuffix) { var source = $@" @@ -93,7 +243,7 @@ public void On(PropertyChangedEventArgs args) {{ }} } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task HandlesMultipleClassDeclarations(string ctorArg, string fieldSuffix) { var source = $@" @@ -134,7 +284,7 @@ public class TestClass2 } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task DoesFixWhenQualifiedNameUsed(string ctorArg, string fieldSuffix) { var source = $@" @@ -165,7 +315,7 @@ public void Foo() } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task DoesFixWhenEventArgsCreatedInField(string ctorArg, string fieldSuffix) { var source = $@" @@ -187,7 +337,7 @@ public class TestClass } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task DoesFixWhenEventArgsCreatedInObjectInitializer(string ctorArg, string fieldSuffix) { var source = $@" @@ -220,7 +370,7 @@ public void Foo() } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task HandlesNestedClass(string ctorArg, string fieldSuffix) { var source = $@" @@ -248,7 +398,7 @@ public class TestClass } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task DoesFixLambdaExpression(string ctorArg, string fieldSuffix) { var source = $@" @@ -282,7 +432,7 @@ public Test() } [Theory] - [MemberData(nameof(SharedData))] + [MemberData(nameof(SharedDataCodeFix))] public async Task DoesFixWhenFieldNameIsAlreadyUsed(string ctorArg, string fieldSuffix) { var source = $@" @@ -315,4 +465,4 @@ public Test() await VerifyCSharpFixAsync(source, fixedCode); } } -} +} \ No newline at end of file From be103f0c4976446c5eb87b594c7940bf88368722 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Wed, 28 Jun 2017 18:50:16 -0300 Subject: [PATCH 296/358] Finally remove skip from tests --- .../CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs | 2 +- .../CodeCracker.Test/Style/RemoveCommentedCodeTests.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs b/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs index d94d0374d..a25c49944 100644 --- a/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/RemoveCommentedCodeAnalyzer.cs @@ -52,7 +52,7 @@ private void AnalyzeSingleLineCommentTrivia(SyntaxTreeAnalysisContext context) } } - readonly CSharpParseOptions options = new CSharpParseOptions(documentationMode: DocumentationMode.None);//todo:bring kind: SourceCodeKind.Interactive back, it is not supported at the current release + readonly CSharpParseOptions options = new CSharpParseOptions(documentationMode: DocumentationMode.None, kind: SourceCodeKind.Script); bool CouldBeSourceCode(string source) { source = source.Trim(); diff --git a/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs b/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs index ef4f222db..e21ce8c9a 100644 --- a/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs @@ -21,7 +21,7 @@ public async Task IgnoresRegularComments() await VerifyCSharpHasNoDiagnosticsAsync(test); } - [Fact(Skip ="Skipped until SourceCodeKind.Interactive can be set on CSharpParseOptions on the analyzer.")] + [Fact] public async Task CreateDiagnosticForSingleLineCommentedCode() { var test = @"// a = 10;".WrapInCSharpMethod(); @@ -49,7 +49,7 @@ public async Task RemovesCommentedCodePreservingRegularComments() await VerifyCSharpFixAsync(test, fixtest); } - [Fact(Skip ="Skipped until SourceCodeKind.Interactive can be set on CSharpParseOptions on the analyzer.")] + [Fact] public async Task CreateDiagnosticForMultipleLinesCommentedCode() { var test = @" @@ -68,7 +68,7 @@ public async Task CreateDiagnosticForMultipleLinesCommentedCode() await VerifyCSharpDiagnosticAsync(test, expected); } - [Fact(Skip ="Skipped until SourceCodeKind.Interactive can be set on CSharpParseOptions on the analyzer.")] + [Fact] public async Task RemovesCommentedMultilineCodePreservingRegularComments() { var test = @" @@ -103,7 +103,7 @@ class Foo await VerifyCSharpFixAsync(test, fixtest); } - [Fact(Skip ="Skipped until SourceCodeKind.Interactive can be set on CSharpParseOptions on the analyzer.")] + [Fact] public async Task RemovesNonPerfectIfCommentedCode() { var test = @" From 187501c5fb95fc4a38fc09a7b8fab41a26169264 Mon Sep 17 00:00:00 2001 From: John Ellison Date: Wed, 25 Oct 2017 10:30:28 -0400 Subject: [PATCH 297/358] Minor spelling fix (#950) --- src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs | 2 +- test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs b/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs index ffb335e6f..cf2376d77 100644 --- a/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/RethrowExceptionAnalyzer.cs @@ -43,7 +43,7 @@ private static void Analyzer(SyntaxNodeAnalysisContext context) if (catchClause == null) return; var catchExSymbol = context.SemanticModel.GetDeclaredSymbol(catchClause.Declaration); if (!catchExSymbol.Equals(exSymbol)) return; - var diagnostic = Diagnostic.Create(Rule, throwStatement.GetLocation(), "Throwing the same exception that was caught will loose the original stack trace."); + var diagnostic = Diagnostic.Create(Rule, throwStatement.GetLocation(), "Throwing the same exception that was caught will lose the original stack trace."); context.ReportDiagnostic(diagnostic); } } diff --git a/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs b/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs index 7dcd8ce82..4bec3f3fd 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs @@ -30,7 +30,7 @@ public async Task WhenThrowingOriginalExceptionAnalyzerCreatesDiagnostic() var expected = new DiagnosticResult { Id = DiagnosticId.RethrowException.ToDiagnosticId(), - Message = "Throwing the same exception that was caught will loose the original stack trace.", + Message = "Throwing the same exception that was caught will lose the original stack trace.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 21) } }; From fc13c29cb2df52fd8f04126be7eb0f52a0f9f859 Mon Sep 17 00:00:00 2001 From: hacking-god <33166103+hacking-god@users.noreply.github.com> Date: Sat, 28 Oct 2017 03:45:36 +0530 Subject: [PATCH 298/358] Documentation Code Cracker An analyzer library for C# and VB that uses Roslyn to produce refactorings, code analysis, and other niceties. Check the official project site on code-cracker.github.io. There you will find information on how to contribute, our task board, definition of done, definition of ready, etc. Build status Nuget count License Issues open Coverage Status Source Browser This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. Installing You may use CodeCracker in two ways: as an analyzer library that you install with Nuget into your project or as a Visual Studio extension. The way you want to use it depends on the scenario you are working on. You most likely want the Nuget package. If you want the analyzers to work during your build, and generate warnings and errors during the build, also on build servers, then you want to use the Nuget package. The package is available on nuget (C#, VB). If you want to be able to configure which analyzers are being used in your project, and which ones you will ignore, and commit those changes to source control and share with your team, then you also want the Nuget package. To install from Nuget, for the C# version: Install-Package CodeCracker.CSharp Or for the Visual Basic version: Install-Package CodeCracker.VisualBasic Or use the Package Manager in Visual Studio. There is also a version for both named CodeCracker only, but it makes not sense to get it, you should search for the C# or VB version. If you want the alpha builds that build on each push to the repo, add https://www.myget.org/F/codecrackerbuild/ to your nuget feed. We only push complete releases to Nuget.org, and commit builds go to Myget.org. If you want global analyzers that will work on every project you open in Visual Studio, then you want the Extension. Grab the extension at the Visual Studio Extensions Gallery (C#, VB). To build from source: git clone https://github.com/code-cracker/code-cracker.git cd CodeCracker 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. --- Documentation | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation diff --git a/Documentation b/Documentation new file mode 100644 index 000000000..bb9c50c19 --- /dev/null +++ b/Documentation @@ -0,0 +1,40 @@ +Code Cracker + +An analyzer library for C# and VB that uses Roslyn to produce refactorings, code analysis, and other niceties. + +Check the official project site on code-cracker.github.io. There you will find information on how to contribute, our task board, definition of done, definition of ready, etc. + +Build status Nuget count License Issues open Coverage Status Source Browser + +This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. + +Installing + +You may use CodeCracker in two ways: as an analyzer library that you install with Nuget into your project or as a Visual Studio extension. The way you want to use it depends on the scenario you are working on. You most likely want the Nuget package. + +If you want the analyzers to work during your build, and generate warnings and errors during the build, also on build servers, then you want to use the Nuget package. The package is available on nuget (C#, VB). If you want to be able to configure which analyzers are being used in your project, and which ones you will ignore, and commit those changes to source control and share with your team, then you also want the Nuget package. + +To install from Nuget, for the C# version: + +Install-Package CodeCracker.CSharp +Or for the Visual Basic version: + +Install-Package CodeCracker.VisualBasic +Or use the Package Manager in Visual Studio. + +There is also a version for both named CodeCracker only, but it makes not sense to get it, you should search for the C# or VB version. + +If you want the alpha builds that build on each push to the repo, add https://www.myget.org/F/codecrackerbuild/ to your nuget feed. We only push complete releases to Nuget.org, and commit builds go to Myget.org. + +If you want global analyzers that will work on every project you open in Visual Studio, then you want the Extension. Grab the extension at the Visual Studio Extensions Gallery (C#, VB). + +To build from source: + +git clone https://github.com/code-cracker/code-cracker.git +cd CodeCracker +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. From 464c3d353162e4c08129d0b16188e17888a3b3c6 Mon Sep 17 00:00:00 2001 From: love-ode <33171148+love-ode@users.noreply.github.com> Date: Sat, 28 Oct 2017 11:08:20 +0530 Subject: [PATCH 299/358] Create Readme Hacktoberfest Sign In Sheet 2017! The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! Instruction In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. Git and Pull Request Resources Github The Net Ninja Awesome-Git How to Create a Pull Request Click on the fork on the top to fork this repo. Go to your repo where you forked the project. Hit the clone button on your forked repo and copy the given link. On your terminal / command prompt, type "git clone [put the link here]". Change the index file in the folder. Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" Push the commit. For example, type "git push [remote-name] master". Go back to the original repo. Hit "new pull request" and compare between forks. Confirm the pull request and that's it! --- Create Readme | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Create Readme diff --git a/Create Readme b/Create Readme new file mode 100644 index 000000000..316700cd9 --- /dev/null +++ b/Create Readme @@ -0,0 +1,26 @@ +Hacktoberfest Sign In Sheet 2017! + +The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! + +Instruction + +In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. + +Git and Pull Request Resources + +Github +The Net Ninja +Awesome-Git +How to Create a Pull Request + +Click on the fork on the top to fork this repo. +Go to your repo where you forked the project. +Hit the clone button on your forked repo and copy the given link. +On your terminal / command prompt, type "git clone [put the link here]". +Change the index file in the folder. +Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. +Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" +Push the commit. For example, type "git push [remote-name] master". +Go back to the original repo. +Hit "new pull request" and compare between forks. +Confirm the pull request and that's it! From aac3be2efb548261641f770482403369c3991525 Mon Sep 17 00:00:00 2001 From: likeme <33179335+likeme@users.noreply.github.com> Date: Sun, 29 Oct 2017 04:58:20 +0530 Subject: [PATCH 300/358] Hacktoberfest Hacktoberfest Sign In Sheet 2017! The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! Instruction In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. Git and Pull Request Resources Github The Net Ninja Awesome-Git How to Create a Pull Request Click on the fork on the top to fork this repo. Go to your repo where you forked the project. Hit the clone button on your forked repo and copy the given link. On your terminal / command prompt, type "git clone [put the link here]". Change the index file in the folder. Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" Push the commit. For example, type "git push [remote-name] master". Go back to the original repo. Hit "new pull request" and compare between forks. Confirm the pull request and that's it! --- Hacktoberfest | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Hacktoberfest diff --git a/Hacktoberfest b/Hacktoberfest new file mode 100644 index 000000000..316700cd9 --- /dev/null +++ b/Hacktoberfest @@ -0,0 +1,26 @@ +Hacktoberfest Sign In Sheet 2017! + +The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! + +Instruction + +In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. + +Git and Pull Request Resources + +Github +The Net Ninja +Awesome-Git +How to Create a Pull Request + +Click on the fork on the top to fork this repo. +Go to your repo where you forked the project. +Hit the clone button on your forked repo and copy the given link. +On your terminal / command prompt, type "git clone [put the link here]". +Change the index file in the folder. +Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. +Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" +Push the commit. For example, type "git push [remote-name] master". +Go back to the original repo. +Hit "new pull request" and compare between forks. +Confirm the pull request and that's it! From 4813199b4d43bffe9720422e7cf4797fcc2eaa10 Mon Sep 17 00:00:00 2001 From: Bug Date: Mon, 30 Oct 2017 00:12:22 -0200 Subject: [PATCH 301/358] Another minor spelling fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e2117dfd..65e96c1c0 100644 --- a/README.md +++ b/README.md @@ -272,7 +272,7 @@ The maintainers have to: To become part of the core team one has to be invited. Invitations happen only if all the core team agrees. -If a member of the core team is not active for at least to months, they will probably be removed from the core team. +If a member of the core team is not active for at least two months, they will probably be removed from the core team. ## Contact From 7becb60f65033d4eea1e09ee083ca9ff6ad893d8 Mon Sep 17 00:00:00 2001 From: kiss-me1997 <33254635+kiss-me1997@users.noreply.github.com> Date: Tue, 31 Oct 2017 18:09:03 +0530 Subject: [PATCH 302/358] Readme Hacktoberfest Sign In Sheet 2017! The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! Instruction In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. Git and Pull Request Resources Github The Net Ninja Awesome-Git How to Create a Pull Request Click on the fork on the top to fork this repo. Go to your repo where you forked the project. Hit the clone button on your forked repo and copy the given link. On your terminal / command prompt, type "git clone [put the link here]". Change the index file in the folder. Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" Push the commit. For example, type "git push [remote-name] master". Go back to the original repo. Hit "new pull request" and compare between forks. Confirm the pull request and that's it! Installation Make sure git is installed. --- Readme | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Readme diff --git a/Readme b/Readme new file mode 100644 index 000000000..a8f1c6b0d --- /dev/null +++ b/Readme @@ -0,0 +1,29 @@ +Hacktoberfest Sign In Sheet 2017! + +The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! + +Instruction + +In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. + +Git and Pull Request Resources + +Github +The Net Ninja +Awesome-Git +How to Create a Pull Request + +Click on the fork on the top to fork this repo. +Go to your repo where you forked the project. +Hit the clone button on your forked repo and copy the given link. +On your terminal / command prompt, type "git clone [put the link here]". +Change the index file in the folder. +Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. +Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" +Push the commit. For example, type "git push [remote-name] master". +Go back to the original repo. +Hit "new pull request" and compare between forks. +Confirm the pull request and that's it! +Installation + +Make sure git is installed. From 85c8558b38988f33442a05a82c8ea37c17445ecd Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 11 Nov 2017 14:23:06 +0000 Subject: [PATCH 303/358] Add a newbie section to the installation. Added a TL;DR for the people who don't like big walls of text. Explains it very simply for newbies like myself to help them choose what they need. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 65e96c1c0..c12e0b877 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,9 @@ msbuild Then add a reference to CodeCracker.dll from within the Analyzers node inside References, in Visual Studio. +TL;DR: +If you want to use CodeCracker in all your projects, install the Visual Studio extension ([C#](https://visualstudiogallery.msdn.microsoft.com/ab588981-91a5-478c-8e65-74d0ff450862), [VB](https://visualstudiogallery.msdn.microsoft.com/1a5f9551-e831-4812-abd0-ac48603fc2c1)). If you want to use CodeCracker for just one project, install the Nuget package as described above. + ## SonarQube Plugin CodeCracker has a SonarQube Plugin that can downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). From 414cae960360a176edaf2633059e6ceb62641a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=A9ury=20Sim=C3=B5es=20Bazzo?= Date: Fri, 17 Nov 2017 17:30:13 -0200 Subject: [PATCH 304/358] first commit --- .../Style/TaskNameAsyncAnalyzer.cs | 13 +++++++- .../Style/TaskNameASyncTests.cs | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs index 6c0f8997c..8731f531c 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs @@ -7,6 +7,10 @@ namespace CodeCracker.CSharp.Style { + + + + [DiagnosticAnalyzer(LanguageNames.CSharp)] public class TaskNameAsyncAnalyzer : DiagnosticAnalyzer { @@ -32,7 +36,14 @@ public class TaskNameAsyncAnalyzer : DiagnosticAnalyzer private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; + var method = (MethodDeclarationSyntax)context.Node; + + //for teste + var semanticModel = context.SemanticModel; + if (method.IsImplementingInterface(semanticModel)) return; + + if (method.Identifier.ToString().EndsWith("Async")) return; if (method.Modifiers.Any(SyntaxKind.NewKeyword, SyntaxKind.OverrideKeyword)) return; @@ -44,7 +55,7 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) context.ReportDiagnostic(diag); return; } - var semanticModel = context.SemanticModel; + semanticModel = context.SemanticModel; var returnType = semanticModel.GetSymbolInfo(method.ReturnType).Symbol as INamedTypeSymbol; if (returnType == null) return; diff --git a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs index 76107647d..b8a56c098 100644 --- a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs @@ -7,6 +7,39 @@ namespace CodeCracker.Test.CSharp.Style { public class TaskNameAsyncTests : CodeFixVerifier { + + [Fact] + public async Task TaskNameAsyncMethodEqualsInterface() + { + const string source = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public interface IBar + { + Task Foo(); + } + + public class Bar : IBar + { + public Task Foo() + { } + } + }"; + + var expected = new DiagnosticResult + { + Id = DiagnosticId.TaskNameAsync.ToDiagnosticId(), + Message = string.Format(TaskNameAsyncAnalyzer.MessageFormat, "FooAsync"), + Severity = DiagnosticSeverity.Info, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 26) } + }; + + await VerifyCSharpDiagnosticAsync(source, expected); + } + + [Fact] public async Task TaskNameAsyncMethodCorrect() { From f7635048f02006f379943e6124418ea7ed14e776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=A9ury=20Sim=C3=B5es=20Bazzo?= Date: Sun, 19 Nov 2017 22:40:34 -0200 Subject: [PATCH 305/358] Last Commit --- .../CodeCracker/Style/TaskNameAsyncAnalyzer.cs | 13 ------------- .../CodeCracker.Test/Style/TaskNameASyncTests.cs | 6 ++---- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs index 8731f531c..daaf8019f 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs @@ -7,10 +7,6 @@ namespace CodeCracker.CSharp.Style { - - - - [DiagnosticAnalyzer(LanguageNames.CSharp)] public class TaskNameAsyncAnalyzer : DiagnosticAnalyzer { @@ -38,31 +34,22 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) if (context.IsGenerated()) return; var method = (MethodDeclarationSyntax)context.Node; - - //for teste var semanticModel = context.SemanticModel; if (method.IsImplementingInterface(semanticModel)) return; - - if (method.Identifier.ToString().EndsWith("Async")) return; if (method.Modifiers.Any(SyntaxKind.NewKeyword, SyntaxKind.OverrideKeyword)) return; - var errorMessage = method.Identifier.ToString() + "Async"; var diag = Diagnostic.Create(Rule, method.Identifier.GetLocation(), errorMessage); - if (method.Modifiers.Any(SyntaxKind.AsyncKeyword)) { context.ReportDiagnostic(diag); return; } - semanticModel = context.SemanticModel; var returnType = semanticModel.GetSymbolInfo(method.ReturnType).Symbol as INamedTypeSymbol; if (returnType == null) return; - if (returnType.ToString() != "System.Threading.Tasks.Task" && (!returnType.IsGenericType || returnType.ConstructedFrom.ToString() != "System.Threading.Tasks.Task")) return; - if (method.IsImplementingInterface(semanticModel)) return; context.ReportDiagnostic(diag); } } diff --git a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs index b8a56c098..80d73afea 100644 --- a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs @@ -7,9 +7,8 @@ namespace CodeCracker.Test.CSharp.Style { public class TaskNameAsyncTests : CodeFixVerifier { - [Fact] - public async Task TaskNameAsyncMethodEqualsInterface() + public async Task TaskNameAsyncMethodEqualsNameMethodInterface() { const string source = @" using System.Threading.Tasks; @@ -38,8 +37,7 @@ public Task Foo() await VerifyCSharpDiagnosticAsync(source, expected); } - - + [Fact] public async Task TaskNameAsyncMethodCorrect() { From e2a96e26edae3dab77338c003ed115e973feb1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=A9ury=20Sim=C3=B5es=20Bazzo?= Date: Mon, 20 Nov 2017 11:18:36 -0200 Subject: [PATCH 306/358] Fix Bug: CC0061: Implementing interface using async keyword should not raise a diagnostic #936 --- src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs | 1 - test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs index daaf8019f..160d792e2 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncAnalyzer.cs @@ -32,7 +32,6 @@ public class TaskNameAsyncAnalyzer : DiagnosticAnalyzer private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) return; - var method = (MethodDeclarationSyntax)context.Node; var semanticModel = context.SemanticModel; if (method.IsImplementingInterface(semanticModel)) return; diff --git a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs index 80d73afea..e897d37b1 100644 --- a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs @@ -26,7 +26,6 @@ public Task Foo() { } } }"; - var expected = new DiagnosticResult { Id = DiagnosticId.TaskNameAsync.ToDiagnosticId(), @@ -37,7 +36,7 @@ public Task Foo() await VerifyCSharpDiagnosticAsync(source, expected); } - + [Fact] public async Task TaskNameAsyncMethodCorrect() { From 3162618c943a3f7522761bac86bb624556e3e763 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Thu, 14 Dec 2017 20:44:45 +0100 Subject: [PATCH 307/358] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c12e0b877..a8cb57814 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ If you want to use CodeCracker in all your projects, install the Visual Studio e ## SonarQube Plugin -CodeCracker has a SonarQube Plugin that can downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). +CodeCracker has a SonarQube Plugin that can be downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). ## Contributing From b890c9aa19340f8bae05d7d7ed176d2c052db06a Mon Sep 17 00:00:00 2001 From: Matt Rouse Date: Mon, 18 Dec 2017 16:26:51 +0000 Subject: [PATCH 308/358] Fix issue/958 Don't suggest changes for Async Main --- .../Style/TaskNameAsyncCodeFixProvider.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs index ac8192347..198444fb5 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs @@ -22,10 +22,25 @@ public class TaskNameAsyncCodeFixProvider : CodeFixProvider public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); + + if (GetMethodName(diagnostic) == "Main" && IsUsingCSharp7(diagnostic)) + return Task.FromResult(0); + context.RegisterCodeFix(CodeAction.Create("Change method name including 'Async'.", c => ChangeMethodNameAsync(context.Document, diagnostic, c), nameof(TaskNameAsyncCodeFixProvider)), diagnostic); + return Task.FromResult(0); } + private static string GetMethodName(Diagnostic diagnostic) + { + return diagnostic.Location.SourceTree.ToString().Substring(diagnostic.Location.SourceSpan.Start, diagnostic.Location.SourceSpan.End - diagnostic.Location.SourceSpan.Start); + } + + private static bool IsUsingCSharp7(Diagnostic diagnostic) + { + return ((CSharpParseOptions)diagnostic.Location.SourceTree.Options).LanguageVersion.ToString() == "CSharp7"; + } + private static async Task ChangeMethodNameAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); From 5ffe60b48e091b424a6ccd0949c64a5b576afadc Mon Sep 17 00:00:00 2001 From: BugAgain Date: Tue, 30 Jan 2018 17:47:14 -0200 Subject: [PATCH 309/358] Not the cat We are not referring to the :cat: here --- .../Refactoring/AllowMembersOrderingAnalyzerTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs index 07c58f2cc..724a2cfd6 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs @@ -14,7 +14,7 @@ protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() [Theory] [InlineData("class")] [InlineData("struct")] - public async void AllowMembersOrderingForEmptyTypeShouldNotTiggerDiagnostic(string typeDeclaration) + public async void AllowMembersOrderingForEmptyTypeShouldNotTriggerDiagnostic(string typeDeclaration) { var test = @" " + typeDeclaration + @" Foo @@ -27,7 +27,7 @@ public async void AllowMembersOrderingForEmptyTypeShouldNotTiggerDiagnostic(stri [Theory] [InlineData("class")] [InlineData("struct")] - public async void AllowMembersOrderingForOneMemberShouldNotTiggerDiagnostic(string typeDeclaration) + public async void AllowMembersOrderingForOneMemberShouldNotTriggerDiagnostic(string typeDeclaration) { var test = @" " + typeDeclaration + @" Foo @@ -41,7 +41,7 @@ public async void AllowMembersOrderingForOneMemberShouldNotTiggerDiagnostic(stri [Theory] [InlineData("class")] [InlineData("struct")] - public async void AllowMembersOrderingForMoreThanOneMemberShouldTiggerDiagnostic(string typeDeclaration) + public async void AllowMembersOrderingForMoreThanOneMemberShouldTriggerDiagnostic(string typeDeclaration) { var test = @" " + typeDeclaration + @" Foo From 01d956f39f0e91802b30fb30dfc56d9938ab7162 Mon Sep 17 00:00:00 2001 From: codetriage-readme-bot Date: Mon, 26 Feb 2018 14:11:58 -0600 Subject: [PATCH 310/358] Add CodeTriage badge to code-cracker/code-cracker Adds a badge showing the number of people helping this repo on CodeTriage. [![Open Source Helpers](https://www.codetriage.com/code-cracker/code-cracker/badges/users.svg)](https://www.codetriage.com/code-cracker/code-cracker) ## What is CodeTriage? CodeTriage is an Open Source app that is designed to make contributing to Open Source projects easier. It works by sending subscribers a few open issues in their inbox. If subscribers get busy, there is an algorithm that backs off issue load so they do not get overwhelmed [Read more about the CodeTriage project](https://www.codetriage.com/what). ## Why am I getting this PR? Your project was picked by the human, @schneems. They selected it from the projects submitted to https://www.codetriage.com and hand edited the PR. How did your project get added to [CodeTriage](https://www.codetriage.com/what)? Roughly about 1 year ago, [andrecarlucci](https://github.com/andrecarlucci) added this project to CodeTriage in order to start contributing. Since then, 6 people have subscribed to help this repo. ## What does adding a badge accomplish? Adding a badge invites people to help contribute to your project. It also lets developers know that others are invested in the longterm success and maintainability of the project. You can see an example of a CodeTriage badge on these popular OSS READMEs: - [![Email clients like GMAIL do not render SVG images](https://www.codetriage.com/rails/rails/badges/users.svg)](https://www.codetriage.com/rails/rails) https://github.com/rails/rails - [![Email clients like GMAIL do not render SVG images](https://www.codetriage.com/crystal-lang/crystal/badges/users.svg)](https://www.codetriage.com/crystal-lang/crystal) https://github.com/crystal-lang/crystal ## Have a question or comment? While I am a bot, this PR was manually reviewed and monitored by a human - @schneems. My job is writing commit messages and handling PR logistics. If you have any questions, you can reply back to this PR and they will be answered by @schneems. If you do not want a badge right now, no worries, close the PR, you will not hear from me again. Thanks for making your project Open Source! Any feedback is greatly appreciated. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a8cb57814..3f104f6f0 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,9 @@ If you want to use CodeCracker in all your projects, install the Visual Studio e ## SonarQube Plugin -CodeCracker has a SonarQube Plugin that can be downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). +CodeCracker has a SonarQube Plugin that can be downloaded at [Plugins HomePage](http://docs.sonarqube.org/display/PLUG/Other+Plugins). -## Contributing +## Contributing [![Open Source Helpers](https://www.codetriage.com/code-cracker/code-cracker/badges/users.svg)](https://www.codetriage.com/code-cracker/code-cracker) The main supported IDE for development is Visual Studio 2015. If you want to use VS 2015 to contribute to Code Cracker use @@ -90,7 +90,7 @@ be assigned to this team. The easiest way to start is looking into the issues that are [up for grabs](https://github.com/code-cracker/code-cracker/labels/up-for-grabs). You -may ask to work on any of them, read below to see how. +may ask to work on any of them, read below to see how. You can also triage issues which may include reproducing bug reports, or asking for vital information such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to code-cracker on CodeTriage](https://www.codetriage.com/code-cracker/code-cracker). If you are just starting with Roslyn, want to contribute, and feel you are not yet ready to start working on full analyzers or code fixes, you can start helping with areas that are From fe14d752024d5d894bba6e9493a1c9bf4f2e3656 Mon Sep 17 00:00:00 2001 From: Justin Clareburt Date: Wed, 28 Feb 2018 09:40:58 -0800 Subject: [PATCH 311/358] Added release notes to VSIX manifest (C# and VB). Release notes point to ChangeLog. --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 1 + src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest | 1 + 2 files changed, 2 insertions(+) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 7af8869e2..aa1218012 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -9,6 +9,7 @@ Build status Nuget count Nuget downloads Issues open This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. http://code-cracker.github.io/ LICENSE.txt + http://code-cracker.github.io/changelog.html codecrackerlogo.png ccexample.png ReSharper, Refactoring, code analysis, analyzer, CodeRush, roslyn, roslyn c#, Refactoring c# Roslyn diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 6423f798e..3de517a30 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -9,6 +9,7 @@ Build status Nuget count Nuget downloads Issues open This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. http://code-cracker.github.io/ LICENSE.txt + http://code-cracker.github.io/changelog.html codecrackerlogo.png ccexample.png ReSharper, Refactoring, code analysis, analyzer, CodeRush, roslyn, roslyn c#, Refactoring c# Roslyn From e680450e1f2c93f6dac5b1171933f173aa776705 Mon Sep 17 00:00:00 2001 From: Justin Clareburt Date: Wed, 28 Feb 2018 10:16:37 -0800 Subject: [PATCH 312/358] Started adding features to ReadeMe file. Added Design features. --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 3f104f6f0..bb5318b6a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,20 @@ our task board, definition of done, definition of ready, etc. This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. +## Features + +The list of features is documented here: http://code-cracker.github.io/diagnostics.html + +#### Design +Code | Analyzer | Severity | Description +-- | -- | -- | -- +[CC0003](http://code-cracker.github.io/diagnostics/CC0003.html) | CatchEmptyAnalyzer | Warning | Catch statements with no Exception as an argument is not recommended. Consider adding an Exception class to the catch statement. +[CC0004](http://code-cracker.github.io/diagnostics/CC0004.html) | EmptyCatchBlockAnalyzer | Warning | An empty catch block suppress all errors and shouldn’t be used. If the error is expected consider logging it or changing the control flow such that it is explicit. +[CC0016](http://code-cracker.github.io/diagnostics/CC0016.html) | CopyEventToVariableBeforeFireAnalyzer | Warning | Events should always be checked for null before being invoked. As in a multi-threading context it is possible for an event to be unsuscribed between the moment where it is checked to be non-null and the moment it is raised, the event must be copied to a temporary variable before the check. +[CC0021](http://code-cracker.github.io/diagnostics/CC0021.html) | NameOfAnalyzer | Warning | In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor. +[CC0024](http://code-cracker.github.io/diagnostics/CC0024.html) | StaticConstructorExceptionAnalyzer | Warning | Static constructor are called before the first time a class is used but the caller doesn’t control when exactly. Exception thrown in this context force callers to use ‘try’ block around any useage of the class and should be avoided. +[CC0031](http://code-cracker.github.io/diagnostics/CC0031.html) | UseInvokeMethodToFireEventAnalyzer | Warning | In C#6 a delegate can be invoked using the null-propagating operator (?.) and it’s invoke method to avoid throwing a NullReference exception when there is no method attached to the delegate. + ## Installing You may use CodeCracker in two ways: as an analyzer library that you install with Nuget into your project or as a Visual Studio extension. From c5ffd288bbfcf70d85dd0bcafff084d3d9ae37c7 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 6 May 2018 21:33:24 -0300 Subject: [PATCH 313/358] Remove hacktober fest old files --- Create Readme | 26 -------------------------- Readme | 29 ----------------------------- 2 files changed, 55 deletions(-) delete mode 100644 Create Readme delete mode 100644 Readme diff --git a/Create Readme b/Create Readme deleted file mode 100644 index 316700cd9..000000000 --- a/Create Readme +++ /dev/null @@ -1,26 +0,0 @@ -Hacktoberfest Sign In Sheet 2017! - -The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! - -Instruction - -In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. - -Git and Pull Request Resources - -Github -The Net Ninja -Awesome-Git -How to Create a Pull Request - -Click on the fork on the top to fork this repo. -Go to your repo where you forked the project. -Hit the clone button on your forked repo and copy the given link. -On your terminal / command prompt, type "git clone [put the link here]". -Change the index file in the folder. -Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. -Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" -Push the commit. For example, type "git push [remote-name] master". -Go back to the original repo. -Hit "new pull request" and compare between forks. -Confirm the pull request and that's it! diff --git a/Readme b/Readme deleted file mode 100644 index a8f1c6b0d..000000000 --- a/Readme +++ /dev/null @@ -1,29 +0,0 @@ -Hacktoberfest Sign In Sheet 2017! - -The goal of this repo is to help beginners who are doing their first pull requests. Feel free to join! - -Instruction - -In the index file, look for the 'ol' tag. Then insert a 'li' tag with your link to your profile. - -Git and Pull Request Resources - -Github -The Net Ninja -Awesome-Git -How to Create a Pull Request - -Click on the fork on the top to fork this repo. -Go to your repo where you forked the project. -Hit the clone button on your forked repo and copy the given link. -On your terminal / command prompt, type "git clone [put the link here]". -Change the index file in the folder. -Afterward, on your terminal / command prompt, type "git add index.html"; then 'git commit -m "[type a message]" '. -Create a remote to link the repository on github to your local workspace. use "git remote add [remote-name] [put the github link here]" -Push the commit. For example, type "git push [remote-name] master". -Go back to the original repo. -Hit "new pull request" and compare between forks. -Confirm the pull request and that's it! -Installation - -Make sure git is installed. From 06ae9c914e692ae86c1871070b1e89184caba4ee Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 19 May 2018 23:26:59 -0300 Subject: [PATCH 314/358] Fix tabs and spaces on default.ps1 --- default.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/default.ps1 b/default.ps1 index aef7b7d5d..cf299c631 100644 --- a/default.ps1 +++ b/default.ps1 @@ -84,7 +84,7 @@ Task ILMerge-VB { ILMerge $releaseDirVB $dllVB $projectFileVB $projectDirVB } Task ILMerge-CS { ILMerge $releaseDirCS $dllCS $projectFileCS $projectDirCS } function ILMerge($releaseDir, $dll, $projectFile, $projectDir) { - Write-Host "IL Merge:" + Write-Host "IL Merge:" $mergedDir = $tempDir if (!(Test-Path $mergedDir)) { mkdir "$mergedDir" } $inputDll = "$releaseDir\$dll" @@ -112,11 +112,11 @@ function ILMerge($releaseDir, $dll, $projectFile, $projectDir) { $releaseMergedDir = "$releaseDir\merged" if (!(Test-Path $releaseMergedDir)) { mkdir $releaseMergedDir | Out-Null } cp $mergedDll "$releaseMergedDir\" -Force - Write-Host " $dll -> $releaseMergedDir\$dll" + Write-Host " $dll -> $releaseMergedDir\$dll" $mergedPdb = Change-Extension $mergedDll "pdb" cp $mergedPdb "$releaseMergedDir\" -Force - $pdb = (ls $mergedPdb).Name - Write-Host " $pdb -> $releaseMergedDir\$pdb" + $pdb = (ls $mergedPdb).Name + Write-Host " $pdb -> $releaseMergedDir\$pdb" } function Change-Extension ($filename, $extension) { @@ -189,7 +189,7 @@ function PackNuget($language, $dir, $nuspecFile, $nupkgFile) { $nupkgFile = $nupkgFile -f $xml.package.metadata.version . $nugetExe pack "$nuspecFile" -OutputDirectory "$dir" $nuspecFileName = (ls $nuspecFile).Name - Write-Host " $nuspecFileName ($language/$($xml.package.metadata.version)) -> $nupkgFile" + Write-Host " $nuspecFileName ($language/$($xml.package.metadata.version)) -> $nupkgFile" if ($isAppVeyor) { Write-Host "Pushing nuget artifact for $language..." appveyor PushArtifact $nupkgFile From 3cf1b2fbd8f680455e3a2b5885e5689afd3216ef Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 19 May 2018 23:39:05 -0300 Subject: [PATCH 315/358] Add .debug vsix projects to facilitate debug As we are il merging for release the vsix did not contain the common dll and failed on debug when running the vs instance. This fix it. --- CodeCracker.CSharp.sln | 11 +++ CodeCracker.VisualBasic.sln | 13 +++ CodeCracker.sln | 25 +++++ .../CodeCracker.Vsix.Debug.csproj | 93 +++++++++++++++++++ .../source.extension.debug.vsixmanifest | 34 +++++++ .../CodeCracker.Vsix.Debug.csproj | 93 +++++++++++++++++++ .../source.extension.debug.vsixmanifest | 34 +++++++ 7 files changed, 303 insertions(+) create mode 100644 src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj create mode 100644 src/CSharp/CodeCracker.Vsix/source.extension.debug.vsixmanifest create mode 100644 src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj create mode 100644 src/VisualBasic/CodeCracker.Vsix/source.extension.debug.vsixmanifest diff --git a/CodeCracker.CSharp.sln b/CodeCracker.CSharp.sln index e075a10f0..79a90944e 100644 --- a/CodeCracker.CSharp.sln +++ b/CodeCracker.CSharp.sln @@ -43,6 +43,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{E3B0C133-B97E-46B9-809D-16BB762EF74F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -89,6 +91,12 @@ Global {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.Build.0 = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -97,4 +105,7 @@ Global {051F1BE2-9A44-4B84-9DF8-6537852B7BBC} = {7B4F0131-D598-4692-9E2C-111E6C42C6AD} {40545653-8444-49E0-8DAD-BBB381F8A3B2} = {7B4F0131-D598-4692-9E2C-111E6C42C6AD} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {80743E34-82D0-4E0A-9514-0C85FF873E14} + EndGlobalSection EndGlobal diff --git a/CodeCracker.VisualBasic.sln b/CodeCracker.VisualBasic.sln index b338754d2..d9cc68f85 100644 --- a/CodeCracker.VisualBasic.sln +++ b/CodeCracker.VisualBasic.sln @@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.csproj", "{B7B513B4-0317-4F32-B560-4BFC4FAEC239}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -85,6 +87,14 @@ Global {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.Build.0 = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -93,4 +103,7 @@ Global {D1591C8E-982D-402F-B3CB-1D1662104425} = {3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6} {22D6C608-E7F1-4236-BB07-BE5F97A4C810} = {3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0D75A128-4A6D-4847-9699-93EF828F5B40} + EndGlobalSection EndGlobal diff --git a/CodeCracker.sln b/CodeCracker.sln index 64406cda0..223e057b8 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -55,6 +55,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6 test.ps1 = test.ps1 EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{E3B0C133-B97E-46B9-809D-16BB762EF74F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -123,6 +127,22 @@ Global {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.Build.0 = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.Build.0 = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU + {E3B0C133-B97E-46B9-809D-16BB762EF74F}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -136,5 +156,10 @@ Global {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} {234973E7-794D-4BC5-8D5F-FB98D8BFA967} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} {C5584F20-6E93-4D2D-B6F0-141B977AFC9F} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} + {E3B0C133-B97E-46B9-809D-16BB762EF74F} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EF50C6AB-1421-41AE-8CB3-927AB24A69EA} EndGlobalSection EndGlobal diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj new file mode 100644 index 000000000..b80feb9e7 --- /dev/null +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj @@ -0,0 +1,93 @@ + + + + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + 15.0 + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {E3B0C133-B97E-46B9-809D-16BB762EF74F} + Library + Properties + CodeCracker + CodeCracker.CSharp + v4.5.2 + false + false + false + false + false + false + Roslyn + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Program + $(DevEnvDir)devenv.exe + /rootsuffix Roslyn + + + + Designer + + + + + {753d4757-fcba-43ba-b1be-89201acda192} + CodeCracker.Common + + + {FF1097FB-A890-461B-979E-064697891B96} + CodeCracker + + + + + Always + true + + + Always + true + + + Always + true + + + + + + \ No newline at end of file diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.debug.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.debug.vsixmanifest new file mode 100644 index 000000000..e81a560f6 --- /dev/null +++ b/src/CSharp/CodeCracker.Vsix/source.extension.debug.vsixmanifest @@ -0,0 +1,34 @@ + + + + + Code Cracker for C# + 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. +Build status Nuget count Nuget downloads Issues open +This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. + http://code-cracker.github.io/ + LICENSE.txt + http://code-cracker.github.io/changelog.html + codecrackerlogo.png + ccexample.png + ReSharper, Refactoring, code analysis, analyzer, CodeRush, roslyn, roslyn c#, Refactoring c# Roslyn + + + + + + + + + + + + + + + + + + + diff --git a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj new file mode 100644 index 000000000..bee9c5a1c --- /dev/null +++ b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj @@ -0,0 +1,93 @@ + + + + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + 14.0 + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38} + Library + Properties + CodeCracker + CodeCracker.VisualBasic + v4.5.2 + false + false + false + false + false + false + Roslyn + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Program + $(DevEnvDir)devenv.exe + /rootsuffix Roslyn + + + + Designer + + + + + Always + true + + + Always + true + + + Always + true + + + + + {753d4757-fcba-43ba-b1be-89201acda192} + CodeCracker.Common + + + {41fa4971-d354-4647-a269-4a886da2ef4c} + CodeCracker + + + + + + \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.debug.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.debug.vsixmanifest new file mode 100644 index 000000000..6f6ab34bd --- /dev/null +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.debug.vsixmanifest @@ -0,0 +1,34 @@ + + + + + Code Cracker for Visual Basic + An analyzer library for VB that uses Roslyn to produce refactorings, code analysis, and other niceties. +Check the official project site on code-cracker.github.io. +Build status Nuget count Nuget downloads Issues open +This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. + http://code-cracker.github.io/ + LICENSE.txt + http://code-cracker.github.io/changelog.html + codecrackerlogo.png + ccexample.png + ReSharper, Refactoring, code analysis, analyzer, CodeRush, roslyn, roslyn c#, Refactoring c# Roslyn + + + + + + + + + + + + + + + + + + + From 1fb3fe15ed47d6d9697866af1416c73c1b71698e Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 19 May 2018 23:42:03 -0300 Subject: [PATCH 316/358] Remove support for VS 2015 --- CodeCracker.2015.sln | 140 ------------------ CodeCracker.CSharp.2015.sln | 100 ------------- CodeCracker.VisualBasic.2015.sln | 96 ------------ README.md | 6 +- default.ps1 | 2 +- .../CodeCracker.Vsix.2015.csproj | 84 ----------- .../CodeCracker.Vsix.2015.csproj | 84 ----------- 7 files changed, 3 insertions(+), 509 deletions(-) delete mode 100644 CodeCracker.2015.sln delete mode 100644 CodeCracker.CSharp.2015.sln delete mode 100644 CodeCracker.VisualBasic.2015.sln delete mode 100644 src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj delete mode 100644 src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj diff --git a/CodeCracker.2015.sln b/CodeCracker.2015.sln deleted file mode 100644 index 61766491e..000000000 --- a/CodeCracker.2015.sln +++ /dev/null @@ -1,140 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker", "src\CSharp\CodeCracker\CodeCracker.csproj", "{FF1097FB-A890-461B-979E-064697891B96}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{6BAC4057-7239-485E-A04B-02E687A83BAA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test", "test\CSharp\CodeCracker.Test\CodeCracker.Test.csproj", "{F7843158-046E-4B22-95D7-CAC7BB01283D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vb", "vb", "{11473308-7FD9-43CE-84CE-5912EEFDD1DC}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cs", "cs", "{90D62FF0-A374-4C14-B827-1FFA8E384E18}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{B7B513B4-0317-4F32-B560-4BFC4FAEC239}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker.Test", "test\VisualBasic\CodeCracker.Test\CodeCracker.Test.vbproj", "{5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{A26BEB5D-9C92-4F60-9789-563A327605C3}" - ProjectSection(SolutionItems) = preProject - src\CodeCracker.nuspec = src\CodeCracker.nuspec - nuget.config = nuget.config - .nuget\packages.config = .nuget\packages.config - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solution Items", ".Solution Items", "{E1B8ADBF-3442-4EF3-8C6B-146B576340E9}" - ProjectSection(SolutionItems) = preProject - .gitattributes = .gitattributes - .gitignore = .gitignore - CHANGELOG.md = CHANGELOG.md - README.md = README.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{234973E7-794D-4BC5-8D5F-FB98D8BFA967}" - ProjectSection(SolutionItems) = preProject - appveyor.yml = appveyor.yml - build.ps1 = build.ps1 - default.ps1 = default.ps1 - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6E93-4D2D-B6F0-141B977AFC9F}" - ProjectSection(SolutionItems) = preProject - test\CSharp\AnalyzeCecil.ps1 = test\CSharp\AnalyzeCecil.ps1 - test\CSharp\AnalyzeCoreFx.ps1 = test\CSharp\AnalyzeCoreFx.ps1 - test\CSharp\AnalyzeRoslyn.ps1 = test\CSharp\AnalyzeRoslyn.ps1 - runTestsCS.ps1 = runTestsCS.ps1 - runTestsVB.ps1 = runTestsVB.ps1 - test.ps1 = test.ps1 - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - DebugNoVsix|Any CPU = DebugNoVsix|Any CPU - Release|Any CPU = Release|Any CPU - ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.Build.0 = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {FF1097FB-A890-461B-979E-064697891B96} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} - {6BAC4057-7239-485E-A04B-02E687A83BAA} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} - {F7843158-046E-4B22-95D7-CAC7BB01283D} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} - {41FA4971-D354-4647-A269-4A886DA2EF4C} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} - {B7B513B4-0317-4F32-B560-4BFC4FAEC239} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} - {234973E7-794D-4BC5-8D5F-FB98D8BFA967} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} - {C5584F20-6E93-4D2D-B6F0-141B977AFC9F} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} - EndGlobalSection -EndGlobal diff --git a/CodeCracker.CSharp.2015.sln b/CodeCracker.CSharp.2015.sln deleted file mode 100644 index f1ddbefd2..000000000 --- a/CodeCracker.CSharp.2015.sln +++ /dev/null @@ -1,100 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F5240AD-2B4E-48A4-B9FC-7D19DACEF2CD}" - ProjectSection(SolutionItems) = preProject - nuget.config = nuget.config - .nuget\packages.config = .nuget\packages.config - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker", "src\CSharp\CodeCracker\CodeCracker.csproj", "{FF1097FB-A890-461B-979E-064697891B96}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{6BAC4057-7239-485E-A04B-02E687A83BAA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test", "test\CSharp\CodeCracker.Test\CodeCracker.Test.csproj", "{F7843158-046E-4B22-95D7-CAC7BB01283D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7B4F0131-D598-4692-9E2C-111E6C42C6AD}" - ProjectSection(SolutionItems) = preProject - .gitattributes = .gitattributes - .gitignore = .gitignore - CHANGELOG.md = CHANGELOG.md - README.md = README.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{051F1BE2-9A44-4B84-9DF8-6537852B7BBC}" - ProjectSection(SolutionItems) = preProject - test\CSharp\AnalyzeCecil.ps1 = test\CSharp\AnalyzeCecil.ps1 - test\CSharp\AnalyzeCoreFx.ps1 = test\CSharp\AnalyzeCoreFx.ps1 - test\CSharp\AnalyzeRoslyn.ps1 = test\CSharp\AnalyzeRoslyn.ps1 - runTestsCS.ps1 = runTestsCS.ps1 - test.ps1 = test.ps1 - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{40545653-8444-49E0-8DAD-BBB381F8A3B2}" - ProjectSection(SolutionItems) = preProject - appveyor.yml = appveyor.yml - build.ps1 = build.ps1 - default.ps1 = default.ps1 - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - DebugNoVsix|Any CPU = DebugNoVsix|Any CPU - Release|Any CPU = Release|Any CPU - ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.Release|Any CPU.Build.0 = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.Release|Any CPU.Build.0 = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {F7843158-046E-4B22-95D7-CAC7BB01283D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {051F1BE2-9A44-4B84-9DF8-6537852B7BBC} = {7B4F0131-D598-4692-9E2C-111E6C42C6AD} - {40545653-8444-49E0-8DAD-BBB381F8A3B2} = {7B4F0131-D598-4692-9E2C-111E6C42C6AD} - EndGlobalSection -EndGlobal diff --git a/CodeCracker.VisualBasic.2015.sln b/CodeCracker.VisualBasic.2015.sln deleted file mode 100644 index cec5830dd..000000000 --- a/CodeCracker.VisualBasic.2015.sln +++ /dev/null @@ -1,96 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker", "src\VisualBasic\CodeCracker\CodeCracker.vbproj", "{41FA4971-D354-4647-A269-4A886DA2EF4C}" -EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CodeCracker.Test", "test\VisualBasic\CodeCracker.Test\CodeCracker.Test.vbproj", "{5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6}" - ProjectSection(SolutionItems) = preProject - .gitattributes = .gitattributes - .gitignore = .gitignore - README.md = README.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{5413BEBC-2F00-4B54-98E9-B1A7618C3C2A}" - ProjectSection(SolutionItems) = preProject - nuget.config = nuget.config - .nuget\packages.config = .nuget\packages.config - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{D1591C8E-982D-402F-B3CB-1D1662104425}" - ProjectSection(SolutionItems) = preProject - appveyor.yml = appveyor.yml - build.ps1 = build.ps1 - default.ps1 = default.ps1 - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{22D6C608-E7F1-4236-BB07-BE5F97A4C810}" - ProjectSection(SolutionItems) = preProject - runTestsVB.ps1 = runTestsVB.ps1 - test.ps1 = test.ps1 - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Common", "src\Common\CodeCracker.Common\CodeCracker.Common.csproj", "{753D4757-FCBA-43BA-B1BE-89201ACDA192}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", "test\Common\CodeCracker.Test.Common\CodeCracker.Test.Common.csproj", "{1CD1A3EE-28CE-404B-A59E-AEACF762D938}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.2015", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.2015.csproj", "{B7B513B4-0317-4F32-B560-4BFC4FAEC239}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - DebugNoVsix|Any CPU = DebugNoVsix|Any CPU - Release|Any CPU = Release|Any CPU - ReleaseNoVsix|Any CPU = ReleaseNoVsix|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.Release|Any CPU.Build.0 = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Debug|Any CPU.Build.0 = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.ActiveCfg = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.Release|Any CPU.Build.0 = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {753D4757-FCBA-43BA-B1BE-89201ACDA192}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.Release|Any CPU.Build.0 = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {D1591C8E-982D-402F-B3CB-1D1662104425} = {3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6} - {22D6C608-E7F1-4236-BB07-BE5F97A4C810} = {3DB077DC-387D-4AAD-9ECE-96D3D24FB3A6} - EndGlobalSection -EndGlobal diff --git a/README.md b/README.md index bb5318b6a..3d2511162 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,8 @@ CodeCracker has a SonarQube Plugin that can be downloaded at [Plugins HomePage]( ## Contributing [![Open Source Helpers](https://www.codetriage.com/code-cracker/code-cracker/badges/users.svg)](https://www.codetriage.com/code-cracker/code-cracker) -The main supported IDE for development is Visual Studio 2015. -If you want to use VS 2015 to contribute to Code Cracker use -the *.2015.sln files. We recommend migrating to VS 2017 ASAP, as -we might make VS 2015 obsolete at any time. +The main supported IDE for development is Visual Studio 2017. +We do not support VS 2015 anymore. Questions, comments, bug reports, and pull requests are all welcome. Bug reports that include steps-to-reproduce (including code) are diff --git a/default.ps1 b/default.ps1 index cf299c631..35934cb00 100644 --- a/default.ps1 +++ b/default.ps1 @@ -5,7 +5,7 @@ Properties { $srcDir = "$rootDir\src" $testDir = "$rootDir\test" $isAppVeyor = $env:APPVEYOR -eq $true - $slns = ls "$rootDir\*.sln" | ? { ! $_.Name.Contains('.2015.') } + $slns = ls "$rootDir\*.sln" $packagesDir = "$rootDir\packages" $buildNumber = [Convert]::ToInt32($env:APPVEYOR_BUILD_NUMBER).ToString("0000") $nuspecPathCS = "$rootDir\src\CSharp\CodeCracker\CodeCracker.nuspec" diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj deleted file mode 100644 index 05f70110b..000000000 --- a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - Debug - AnyCPU - 2.0 - {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {6BAC4057-7239-485E-A04B-02E687A83BAA} - Library - Properties - CodeCracker - CodeCracker.CSharp - v4.5.2 - false - false - false - false - false - false - Roslyn - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - Program - $(DevEnvDir)devenv.exe - /rootsuffix Roslyn - - - - Designer - - - - - {FF1097FB-A890-461B-979E-064697891B96} - CodeCracker - - - - - Always - true - - - Always - true - - - Always - true - - - - - - \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj deleted file mode 100644 index dcdad50cf..000000000 --- a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.2015.csproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - Debug - AnyCPU - 2.0 - {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {B7B513B4-0317-4F32-B560-4BFC4FAEC239} - Library - Properties - CodeCracker - CodeCracker.VisualBasic - v4.5.2 - false - false - false - false - false - false - Roslyn - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - Program - $(DevEnvDir)devenv.exe - /rootsuffix Roslyn - - - - Designer - - - - - Always - true - - - Always - true - - - Always - true - - - - - {41fa4971-d354-4647-a269-4a886da2ef4c} - CodeCracker - - - - - - \ No newline at end of file From 60f441311c0a0811e768223d0c7bee7f2aa0abb3 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sat, 19 May 2018 23:44:15 -0300 Subject: [PATCH 317/358] Update Copyright to 2018 --- src/CSharp/CodeCracker.Vsix/LICENSE.txt | 2 +- src/CSharp/CodeCracker/Properties/AssemblyInfo.cs | 2 +- src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs | 2 +- src/VisualBasic/CodeCracker.Vsix/LICENSE.txt | 2 +- src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb | 2 +- src/VisualBasic/CodeCracker/Properties/AssemblyInfo.cs | 2 +- test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs | 2 +- test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs | 2 +- test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/LICENSE.txt b/src/CSharp/CodeCracker.Vsix/LICENSE.txt index 9d626bb93..2717e6ad3 100644 --- a/src/CSharp/CodeCracker.Vsix/LICENSE.txt +++ b/src/CSharp/CodeCracker.Vsix/LICENSE.txt @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014-2015 Giovanni Bassi and Elemar Jr. + Copyright 2014-2018 Giovanni Bassi and Elemar Jr. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs index f63d51c3e..8c689a126 100644 --- a/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/CSharp/CodeCracker/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CodeCracker")] -[assembly: AssemblyCopyright("Copyright © 2014-2015")] +[assembly: AssemblyCopyright("Copyright © 2014-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs index 6acd8b6ed..ff625b1e5 100644 --- a/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs +++ b/src/Common/CodeCracker.Common/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CodeCracker")] -[assembly: AssemblyCopyright("Copyright © 2014-2015")] +[assembly: AssemblyCopyright("Copyright © 2014-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/src/VisualBasic/CodeCracker.Vsix/LICENSE.txt b/src/VisualBasic/CodeCracker.Vsix/LICENSE.txt index 9d626bb93..2717e6ad3 100644 --- a/src/VisualBasic/CodeCracker.Vsix/LICENSE.txt +++ b/src/VisualBasic/CodeCracker.Vsix/LICENSE.txt @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014-2015 Giovanni Bassi and Elemar Jr. + Copyright 2014-2018 Giovanni Bassi and Elemar Jr. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb index 4cf3474fd..89f5f1675 100644 --- a/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb +++ b/src/VisualBasic/CodeCracker/My Project/AssemblyInfo.vb @@ -8,7 +8,7 @@ Imports System.Runtime.InteropServices - + diff --git a/src/VisualBasic/CodeCracker/Properties/AssemblyInfo.cs b/src/VisualBasic/CodeCracker/Properties/AssemblyInfo.cs index 68af67824..47c3f28ae 100644 --- a/src/VisualBasic/CodeCracker/Properties/AssemblyInfo.cs +++ b/src/VisualBasic/CodeCracker/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CodeCracker")] -[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyCopyright("Copyright © 2014-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs index db28a8bed..355d9badb 100644 --- a/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs +++ b/test/CSharp/CodeCracker.Test/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CodeCracker")] -[assembly: AssemblyCopyright("Copyright © 2014-2015")] +[assembly: AssemblyCopyright("Copyright © 2014-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs index b095e814c..c0189f778 100644 --- a/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs +++ b/test/Common/CodeCracker.Test.Common/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CodeCracker")] -[assembly: AssemblyCopyright("Copyright © 2014-2015")] +[assembly: AssemblyCopyright("Copyright © 2014-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb index 471e8e0cc..d3b84acfd 100644 --- a/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb +++ b/test/VisualBasic/CodeCracker.Test/My Project/AssemblyInfo.vb @@ -8,7 +8,7 @@ Imports System.Runtime.InteropServices - + From eeae7e78e290c32bc01c8a1933ca24644d05a357 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 00:47:00 -0300 Subject: [PATCH 318/358] Fix vsix debug build --- CodeCracker.CSharp.sln | 2 -- CodeCracker.VisualBasic.sln | 16 ++++----- CodeCracker.sln | 22 ++++-------- .../CodeCracker.Vsix.Debug.csproj | 11 ++---- .../CodeCracker.Vsix/CodeCracker.Vsix.csproj | 5 --- .../source.extension.vsixmanifest} | 0 .../CodeCracker.Vsix.Debug.csproj | 35 ++++++++----------- .../CodeCracker.Vsix/CodeCracker.Vsix.csproj | 9 ++--- .../source.extension.vsixmanifest} | 0 9 files changed, 33 insertions(+), 67 deletions(-) rename src/CSharp/CodeCracker.Vsix/{source.extension.debug.vsixmanifest => debug/source.extension.vsixmanifest} (100%) rename src/VisualBasic/CodeCracker.Vsix/{source.extension.debug.vsixmanifest => debug/source.extension.vsixmanifest} (100%) diff --git a/CodeCracker.CSharp.sln b/CodeCracker.CSharp.sln index 79a90944e..9090838a1 100644 --- a/CodeCracker.CSharp.sln +++ b/CodeCracker.CSharp.sln @@ -62,7 +62,6 @@ Global {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU @@ -95,7 +94,6 @@ Global {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.Build.0 = Release|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution diff --git a/CodeCracker.VisualBasic.sln b/CodeCracker.VisualBasic.sln index d9cc68f85..e4feebe4e 100644 --- a/CodeCracker.VisualBasic.sln +++ b/CodeCracker.VisualBasic.sln @@ -39,7 +39,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Test.Common", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.csproj", "{B7B513B4-0317-4F32-B560-4BFC4FAEC239}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{7F08D429-91E1-4B47-B3B2-A98754C8DFA7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -82,19 +82,15 @@ Global {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {1CD1A3EE-28CE-404B-A59E-AEACF762D938}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.Build.0 = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CodeCracker.sln b/CodeCracker.sln index 223e057b8..0ca6815d1 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -55,7 +55,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6 test.ps1 = test.ps1 EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\VisualBasic\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{7F08D429-91E1-4B47-B3B2-A98754C8DFA7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCracker.Vsix.Debug", "src\CSharp\CodeCracker.Vsix\CodeCracker.Vsix.Debug.csproj", "{E3B0C133-B97E-46B9-809D-16BB762EF74F}" EndProject @@ -84,7 +84,6 @@ Global {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {FF1097FB-A890-461B-979E-064697891B96}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BAC4057-7239-485E-A04B-02E687A83BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BAC4057-7239-485E-A04B-02E687A83BAA}.Release|Any CPU.Build.0 = Release|Any CPU @@ -106,7 +105,6 @@ Global {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {41FA4971-D354-4647-A269-4A886DA2EF4C}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7B513B4-0317-4F32-B560-4BFC4FAEC239}.Release|Any CPU.Build.0 = Release|Any CPU @@ -127,22 +125,16 @@ Global {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.Release|Any CPU.Build.0 = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.Release|Any CPU.Build.0 = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.DebugNoVsix|Any CPU.ActiveCfg = Debug|Any CPU - {E3B0C133-B97E-46B9-809D-16BB762EF74F}.DebugNoVsix|Any CPU.Build.0 = Debug|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E3B0C133-B97E-46B9-809D-16BB762EF74F}.Release|Any CPU.Build.0 = Release|Any CPU {E3B0C133-B97E-46B9-809D-16BB762EF74F}.ReleaseNoVsix|Any CPU.ActiveCfg = Release|Any CPU - {E3B0C133-B97E-46B9-809D-16BB762EF74F}.ReleaseNoVsix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,7 +148,7 @@ Global {5399E7A8-F8F1-4F2E-A5D2-9C96F3DD2A2D} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} {234973E7-794D-4BC5-8D5F-FB98D8BFA967} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} {C5584F20-6E93-4D2D-B6F0-141B977AFC9F} = {E1B8ADBF-3442-4EF3-8C6B-146B576340E9} - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7} = {11473308-7FD9-43CE-84CE-5912EEFDD1DC} {E3B0C133-B97E-46B9-809D-16BB762EF74F} = {90D62FF0-A374-4C14-B827-1FFA8E384E18} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj index b80feb9e7..a16c94bc4 100644 --- a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj @@ -4,11 +4,6 @@ 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 15.0 @@ -34,7 +29,7 @@ true full false - bin\Debug\ + debug\bin\Debug\ DEBUG;TRACE prompt 4 @@ -42,7 +37,7 @@ pdbonly true - bin\Release\ + debug\bin\Release\ TRACE prompt 4 @@ -53,7 +48,7 @@ /rootsuffix Roslyn - + Designer diff --git a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj index 12f744c47..94bd31424 100644 --- a/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj +++ b/src/CSharp/CodeCracker.Vsix/CodeCracker.Vsix.csproj @@ -4,11 +4,6 @@ 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 15.0 diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.debug.vsixmanifest b/src/CSharp/CodeCracker.Vsix/debug/source.extension.vsixmanifest similarity index 100% rename from src/CSharp/CodeCracker.Vsix/source.extension.debug.vsixmanifest rename to src/CSharp/CodeCracker.Vsix/debug/source.extension.vsixmanifest diff --git a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj index bee9c5a1c..55bfcbb15 100644 --- a/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj +++ b/src/VisualBasic/CodeCracker.Vsix/CodeCracker.Vsix.Debug.csproj @@ -1,14 +1,9 @@  - + 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 14.0 @@ -16,7 +11,7 @@ AnyCPU 2.0 {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {47FBCA0A-029D-4D7A-89F0-EF5D85E93F38} + {7F08D429-91E1-4B47-B3B2-A98754C8DFA7} Library Properties CodeCracker @@ -34,7 +29,7 @@ true full false - bin\Debug\ + debug\bin\Debug\ DEBUG;TRACE prompt 4 @@ -42,7 +37,7 @@ pdbonly true - bin\Release\ + debug\bin\Release\ TRACE prompt 4 @@ -53,10 +48,20 @@ /rootsuffix Roslyn - + Designer + + + {753d4757-fcba-43ba-b1be-89201acda192} + CodeCracker.Common + + + {41fa4971-d354-4647-a269-4a886da2ef4c} + CodeCracker + + Always @@ -71,16 +76,6 @@ true - - - {753d4757-fcba-43ba-b1be-89201acda192} - CodeCracker.Common - - - {41fa4971-d354-4647-a269-4a886da2ef4c} - CodeCracker - - - \ No newline at end of file + diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.debug.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/debug/source.extension.vsixmanifest similarity index 100% rename from src/VisualBasic/CodeCracker.Vsix/source.extension.debug.vsixmanifest rename to src/VisualBasic/CodeCracker.Vsix/debug/source.extension.vsixmanifest From 5d086f3e7d16a86dcc8d79a765454e78824c6600 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 01:06:12 -0300 Subject: [PATCH 319/358] Remove branch vnext from appveyor config --- appveyor.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ac50d45ed..a94277ef7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -62,13 +62,6 @@ deploy: skip_symbols: true on: branch: master -- provider: NuGet - server: https://www.myget.org/F/codecrackerbuild/api/v2/package - api_key: - secure: 42eslsnaZIIcMVVaeC9Qu5NI9yjzLzHWYUGl0HLhl0YurivQezpMyJOwgSVjiGmj - skip_symbols: true - on: - branch: vnext - provider: NuGet server: https://www.myget.org/F/codecrackerbuild/api/v2/package api_key: From 1adbd86401318177329c4f806982ef70d31fc5e8 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 01:22:57 -0300 Subject: [PATCH 320/358] Update Nuget key for AppVeyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a94277ef7..362ed41d3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -51,7 +51,7 @@ artifacts: deploy: - provider: NuGet api_key: - secure: s1aIT1sGbIeG5Ccgree7K+k/h7LOSzPfJOrsWcCuzgFGrcuexPZUwX/CfYnU9w4v + secure: CosNPh0GfqQtJs2da/qdtykCGRhaJ1keXXxAcEFR0jNGAmveTtj01kPfqIlLPjFv skip_symbols: true on: appveyor_repo_tag: true From 29f6d1e2c8e99d7ac3e624cc5298c2e7de407488 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 02:34:26 -0300 Subject: [PATCH 321/358] Update changelog --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b460cecb..38443cb46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,55 @@ ## [Unreleased](https://github.com/code-cracker/code-cracker/tree/HEAD) -[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.3...HEAD) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.1.0...HEAD) + +**Fixed bugs:** + +- TernaryOperatorWithReturnCodeFixProvider NullReferenceException [\#906](https://github.com/code-cracker/code-cracker/issues/906) + +- Update VS Code Galley page -- broken link for code-cracker.github.io [\#546](https://github.com/code-cracker/code-cracker/issues/546) +- Is there any way to config inspect severity? Some errors are not necessary but noisy [\#543](https://github.com/code-cracker/code-cracker/issues/543) +- Prefer "Count" to "Count\(\)" [\#489](https://github.com/code-cracker/code-cracker/issues/489) + +## [v1.1.0](https://github.com/code-cracker/code-cracker/tree/v1.1.0) (2018-05-20) +[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.3...v1.1.0) + +**Implemented enhancements:** + +- Create a reusable FixAllProvider based on IntroduceFieldFromConstructorCodeFixProviderAll [\#910](https://github.com/code-cracker/code-cracker/issues/910) +- Enable CodeCracker to work with .NET Core [\#871](https://github.com/code-cracker/code-cracker/issues/871) +- CC0068 \(Remove private method\): ShouldSerializeXXX\(\) and ResetXXX\(\) should not trigger the message [\#762](https://github.com/code-cracker/code-cracker/issues/762) +- Create PropertyChangedEventArgs statically [\#42](https://github.com/code-cracker/code-cracker/issues/42) + +- CC0013 Check for applicability as argument [\#522](https://github.com/code-cracker/code-cracker/issues/522) +- Make readonly \(for complex value types\) [\#808](https://github.com/code-cracker/code-cracker/issues/808) +- CC0120: Suggest default for switch statements \(C\#\) [\#780](https://github.com/code-cracker/code-cracker/issues/780) +- Remove Unnecessary ToString in String Concatenation [\#753](https://github.com/code-cracker/code-cracker/issues/753) +- Check consistency of optional parameter default value [\#575](https://github.com/code-cracker/code-cracker/issues/575) +- Make accessibility consistent \(code fix for CS0050 to CS0061\) [\#381](https://github.com/code-cracker/code-cracker/issues/381) +- Prefer "Any" to "Count\(\) \> 0" [\#490](https://github.com/code-cracker/code-cracker/issues/490) +- Extract Class to a New File [\#382](https://github.com/code-cracker/code-cracker/issues/382) +- Seal member if possible [\#372](https://github.com/code-cracker/code-cracker/issues/372) +- Remove virtual modifier if possible [\#371](https://github.com/code-cracker/code-cracker/issues/371) +- Remove async and return task directly [\#151](https://github.com/code-cracker/code-cracker/issues/151) +- Change from as operator to direct cast or the opposite [\#65](https://github.com/code-cracker/code-cracker/issues/65) +- Convert loop to linq expression [\#22](https://github.com/code-cracker/code-cracker/issues/22) + +**Fixed bugs:** + +- CC0061 shouldn't pop for async Main [\#958](https://github.com/code-cracker/code-cracker/issues/958) +- Bug: CC0061: Implementing interface using async keyword should not raise a diagnostic [\#936](https://github.com/code-cracker/code-cracker/issues/936) +- Bug CC0031 UseInvokeMethodToFireEventAnalyzer false positive in constructor [\#926](https://github.com/code-cracker/code-cracker/issues/926) +- BUG: CC0014 Casting to interface or implicit casts for the ternary operator are fixed wrong [\#911](https://github.com/code-cracker/code-cracker/issues/911) +- BUG: CC0022 failed to show fix with null coalesce operator [\#870](https://github.com/code-cracker/code-cracker/issues/870) +- BUG: CC0118 - Unnecessary '.ToString\(\)' call in string concatenation [\#866](https://github.com/code-cracker/code-cracker/issues/866) + +**Closed issues:** + +- Support Hacktoberfest event adding hacktoberfest tag. [\#949](https://github.com/code-cracker/code-cracker/issues/949) +- Using Extension & NuGet package together causes VS2017 to crash [\#944](https://github.com/code-cracker/code-cracker/issues/944) +- False postives and NullReferenceException when using eventhandler in code behind for UWP apps. [\#916](https://github.com/code-cracker/code-cracker/issues/916) +- Replace getter only properties with backing readonly field with getter-only auto-property [\#881](https://github.com/code-cracker/code-cracker/issues/881) ## [v1.0.3](https://github.com/code-cracker/code-cracker/tree/v1.0.3) (2017-03-20) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.2...v1.0.3) @@ -38,6 +86,7 @@ **Implemented enhancements:** +- developmentDependency not added when used with SonarLint [\#829](https://github.com/code-cracker/code-cracker/issues/829) - Auto generated files detection [\#773](https://github.com/code-cracker/code-cracker/issues/773) **Fixed bugs:** @@ -49,7 +98,7 @@ - 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) +- CC0061: Implementing interface using async pattern [\#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) @@ -225,6 +274,7 @@ - Update VB Allow Members Ordering to work with Modules [\#440](https://github.com/code-cracker/code-cracker/issues/440) - Provide an equivalence key on all code fix providers [\#417](https://github.com/code-cracker/code-cracker/issues/417) - Unit test methods raises CC0091 - "Make \ method static" [\#404](https://github.com/code-cracker/code-cracker/issues/404) +- Validate color from System.Drawing.ColorTranslator.FromHtml [\#1](https://github.com/code-cracker/code-cracker/issues/1) **Fixed bugs:** From ed8b7ed923fd1f059a6620798153ef7c9d030d0c Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 02:34:44 -0300 Subject: [PATCH 322/358] Add helpers to cound analyzers and update changelog --- default.ps1 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/default.ps1 b/default.ps1 index 35934cb00..da06d79a4 100644 --- a/default.ps1 +++ b/default.ps1 @@ -181,6 +181,30 @@ Task Pack-Nuget-VB-Force { PackNuget "VB" "$rootDir\src\VisualBasic" $nuspecPathVB $nupkgPathVB } +Task Count-Analyzers { + $count = $(ls $rootDir\src\*.cs -Recurse | ? { $_.Name.contains('Analyzer') } | ? { !((cat $_) -match 'abstract class') }).count + Write-Host "Found $count C# Analyzers" + $count = $(ls $rootDir\src\*.cs -Recurse | ? { $_.Name.contains('CodeFix') } | ? { !((cat $_) -match 'abstract class') }).count + Write-Host "Found $count C# Code Fixes" + $count = $(ls $rootDir\src\*.cs -Recurse | ? { $_.Name.contains('FixAll') } | ? { !((cat $_) -match 'abstract class') }).count + Write-Host "Found $count C# Code Fixes All" + $count = $(ls $rootDir\src\*.vb -Recurse | ? { $_.Name.contains('Analyzer') } | ? { !((cat $_) -match 'mustinherit class') }).count + Write-Host "Found $count VB Analyzers" + $count = $(ls $rootDir\src\*.vb -Recurse | ? { $_.Name.contains('CodeFix') } | ? { !((cat $_) -match 'mustinherit class') }).count + Write-Host "Found $count VB Code Fixes" + $count = $(ls $rootDir\src\*.vb -Recurse | ? { $_.Name.contains('FixAll') } | ? { !((cat $_) -match 'mustinherit class') }).count + Write-Host "Found $count VB Code Fixes All" +} + +Task Update-ChangeLog { + # invoke-psake default.ps1 -tasklist update-changelog -parameters @{"token"=""} + echo $token + return + Exec { + github_changelog_generator code-cracker/code-cracker --no-pull-requests --no-issues-wo-labels --exclude-labels "Can't repro","update readme",decision,docs,duplicate,question,invalid,wontfix,Duplicate,Question,Invalid,Wontfix -t $token + } +} + Task Echo { echo echo } function PackNuget($language, $dir, $nuspecFile, $nupkgFile) { From 5a4d7b9f2b36404b1d89416e45fb0749558e01fe Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 02:39:10 -0300 Subject: [PATCH 323/358] Fix changelog --- CHANGELOG.md | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38443cb46..d44726355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,5 @@ # Change Log -## [Unreleased](https://github.com/code-cracker/code-cracker/tree/HEAD) - -[Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.1.0...HEAD) - -**Fixed bugs:** - -- TernaryOperatorWithReturnCodeFixProvider NullReferenceException [\#906](https://github.com/code-cracker/code-cracker/issues/906) - -- Update VS Code Galley page -- broken link for code-cracker.github.io [\#546](https://github.com/code-cracker/code-cracker/issues/546) -- Is there any way to config inspect severity? Some errors are not necessary but noisy [\#543](https://github.com/code-cracker/code-cracker/issues/543) -- Prefer "Count" to "Count\(\)" [\#489](https://github.com/code-cracker/code-cracker/issues/489) - ## [v1.1.0](https://github.com/code-cracker/code-cracker/tree/v1.1.0) (2018-05-20) [Full Changelog](https://github.com/code-cracker/code-cracker/compare/v1.0.3...v1.1.0) @@ -29,6 +17,7 @@ - Check consistency of optional parameter default value [\#575](https://github.com/code-cracker/code-cracker/issues/575) - Make accessibility consistent \(code fix for CS0050 to CS0061\) [\#381](https://github.com/code-cracker/code-cracker/issues/381) - Prefer "Any" to "Count\(\) \> 0" [\#490](https://github.com/code-cracker/code-cracker/issues/490) +- Prefer "Count" to "Count\(\)" [\#489](https://github.com/code-cracker/code-cracker/issues/489) - Extract Class to a New File [\#382](https://github.com/code-cracker/code-cracker/issues/382) - Seal member if possible [\#372](https://github.com/code-cracker/code-cracker/issues/372) - Remove virtual modifier if possible [\#371](https://github.com/code-cracker/code-cracker/issues/371) @@ -42,6 +31,7 @@ - Bug: CC0061: Implementing interface using async keyword should not raise a diagnostic [\#936](https://github.com/code-cracker/code-cracker/issues/936) - Bug CC0031 UseInvokeMethodToFireEventAnalyzer false positive in constructor [\#926](https://github.com/code-cracker/code-cracker/issues/926) - BUG: CC0014 Casting to interface or implicit casts for the ternary operator are fixed wrong [\#911](https://github.com/code-cracker/code-cracker/issues/911) +- TernaryOperatorWithReturnCodeFixProvider NullReferenceException [\#906](https://github.com/code-cracker/code-cracker/issues/906) - BUG: CC0022 failed to show fix with null coalesce operator [\#870](https://github.com/code-cracker/code-cracker/issues/870) - BUG: CC0118 - Unnecessary '.ToString\(\)' call in string concatenation [\#866](https://github.com/code-cracker/code-cracker/issues/866) From 7b3e176a16856ec622bb4f4bbb7e178f04b3f37a Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Sun, 20 May 2018 04:31:34 -0300 Subject: [PATCH 324/358] Update dependencies --- .nuget/packages.config | 4 +- CodeCracker.sln | 2 +- build.ps1 | 4 +- default.ps1 => psakefile.ps1 | 10 ++--- src/CSharp/CodeCracker/CodeCracker.csproj | 5 +-- ...nconsistentAccessibilityCodeFixProvider.cs | 2 + .../CodeCracker/Design/NameOfAnalyzer.cs | 2 + .../Extensions/CSharpAnalyzerExtensions.cs | 9 ++++- .../AddBracesToSwitchSectionsAnalyzer.cs | 2 + ...dEventArgsUnnecessaryAllocationAnalyzer.cs | 2 + .../SplitIntoNestedIfFixAllProvider.cs | 3 +- .../Style/StringFormatFixAllProvider.cs | 3 +- .../SwitchToAutoPropCodeFixAllProvider.cs | 3 +- ...ryToStringInStringConcatenationAnalyzer.cs | 10 ++--- .../Style/UseEmptyStringCodeFixProviderAll.cs | 3 +- .../Style/UseStringEmptyCodeFixProviderAll.cs | 3 +- ...osableVariableNotDisposedFixAllProvider.cs | 3 +- .../RemoveUnreachableCodeFixAllProvider.cs | 3 +- .../UnusedParametersCodeFixAllProvider.cs | 3 +- src/CSharp/CodeCracker/packages.config | 2 +- .../CodeCracker.Common.csproj | 5 +-- .../DocumentCodeFixProviderAll.cs | 3 +- src/Common/CodeCracker.Common/packages.config | 2 +- .../CodeCracker/CodeCracker.vbproj | 5 +-- src/VisualBasic/CodeCracker/packages.config | 2 +- .../CodeCracker.Test/CodeCracker.Test.csproj | 40 ++++++++++--------- .../Refactoring/NumericLiteralTests.cs | 1 + .../ConvertToExpressionBodiedMemberTests.cs | 2 + .../Style/RemoveAsyncFromMethodTests.cs | 4 +- .../Usage/RemoveUnusedVariablesTest.cs | 14 ------- test/CSharp/CodeCracker.Test/packages.config | 20 +++++----- .../CodeCracker.Test.Common.csproj | 38 ++++++++++-------- .../CodeCracker.Test.Common/packages.config | 24 ++++++----- .../CodeCracker.Test/CodeCracker.Test.vbproj | 39 +++++++++--------- .../CodeCracker.Test/packages.config | 20 +++++----- 35 files changed, 164 insertions(+), 133 deletions(-) rename default.ps1 => psakefile.ps1 (97%) diff --git a/.nuget/packages.config b/.nuget/packages.config index 9707f7736..ad3995ace 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,6 +1,6 @@  - - + + diff --git a/CodeCracker.sln b/CodeCracker.sln index 0ca6815d1..4a19abe95 100644 --- a/CodeCracker.sln +++ b/CodeCracker.sln @@ -42,7 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{234973E7 ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.ps1 = build.ps1 - default.ps1 = default.ps1 + psakefile.ps1 = psakefile.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5584F20-6E93-4D2D-B6F0-141B977AFC9F}" diff --git a/build.ps1 b/build.ps1 index 27cd8f2d8..a5bf95542 100644 --- a/build.ps1 +++ b/build.ps1 @@ -49,7 +49,7 @@ function Download-Nuget { } function Import-Psake { - $psakeModule = "$PSScriptRoot\packages\psake.4.6.0\tools\psake.psm1" + $psakeModule = "$PSScriptRoot\packages\psake.4.7.0\tools\psake\psake.psm1" if ((Test-Path $psakeModule) -ne $true) { Write-Host "Restoring $PSScriptRoot\.nuget with $script:nugetExe" . "$script:nugetExe" restore $PSScriptRoot\.nuget\packages.config -SolutionDirectory $PSScriptRoot @@ -73,7 +73,7 @@ Get-Nuget Import-Psake Import-ILMerge if ($MyInvocation.UnboundArguments.Count -ne 0) { - Invoke-Expression("Invoke-psake -framework '4.6' $PSScriptRoot\default.ps1 -taskList " + $MyInvocation.UnboundArguments -join " ") + Invoke-Expression("Invoke-psake -framework '4.6' $PSScriptRoot\psakefile.ps1 -taskList " + $MyInvocation.UnboundArguments -join " ") } else { . $PSScriptRoot\build.ps1 Build diff --git a/default.ps1 b/psakefile.ps1 similarity index 97% rename from default.ps1 rename to psakefile.ps1 index da06d79a4..146b33f54 100644 --- a/default.ps1 +++ b/psakefile.ps1 @@ -10,11 +10,11 @@ Properties { $buildNumber = [Convert]::ToInt32($env:APPVEYOR_BUILD_NUMBER).ToString("0000") $nuspecPathCS = "$rootDir\src\CSharp\CodeCracker\CodeCracker.nuspec" $nuspecPathVB = "$rootDir\src\VisualBasic\CodeCracker\CodeCracker.nuspec" - $nugetPackagesExe = "$packagesDir\NuGet.CommandLine.4.1.0\tools\NuGet.exe" + $nugetPackagesExe = "$packagesDir\NuGet.CommandLine.4.6.2\tools\NuGet.exe" $nugetExe = if (Test-Path $nugetPackagesExe) { $nugetPackagesExe } else { 'nuget' } $nupkgPathCS = "$rootDir\src\CSharp\CodeCracker.CSharp.{0}.nupkg" $nupkgPathVB = "$rootDir\src\VisualBasic\CodeCracker.VisualBasic.{0}.nupkg" - $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.2.0\tools\xunit.console.x86.exe" + $xunitConsoleExe = "$packagesDir\xunit.runner.console.2.3.1\tools\net452\xunit.console.x86.exe" $openCoverExe = "$packagesDir\OpenCover.4.6.519\tools\OpenCover.Console.exe" $dllCS = "CodeCracker.CSharp.dll" $dllVB = "CodeCracker.VisualBasic.dll" @@ -31,9 +31,9 @@ Properties { $releaseDirCS = "$projectDirCS\bin\Release" $logDir = "$rootDir\log" $outputXml = "$logDir\CodeCoverageResults.xml" - $reportGeneratorExe = "$packagesDir\ReportGenerator.2.5.6\tools\ReportGenerator.exe" + $reportGeneratorExe = "$packagesDir\ReportGenerator.3.1.2\tools\ReportGenerator.exe" $coverageReportDir = "$logDir\codecoverage\" - $coverallsNetExe = "$packagesDir\coveralls.io.1.3.4\tools\coveralls.net.exe" + $coverallsNetExe = "$packagesDir\coveralls.io.1.4.2\tools\coveralls.net.exe" $ilmergeExe = "$packagesDir\ilmerge.2.14.1208\tools\ILMerge.exe" $isRelease = $isAppVeyor -and (($env:APPVEYOR_REPO_BRANCH -eq "release") -or ($env:APPVEYOR_REPO_TAG -eq "true")) $isPullRequest = $env:APPVEYOR_PULL_REQUEST_NUMBER -ne $null @@ -233,7 +233,7 @@ function UpdateNuspec($nuspecPath, $language) { function RestorePkgs($sln) { Write-Host "Restoring $sln..." -ForegroundColor Green Retry { - . $nugetExe restore "$sln" -MSBuildVersion 14 -NonInteractive -ConfigFile "$rootDir\nuget.config" + . $nugetExe restore "$sln" -NonInteractive -ConfigFile "$rootDir\nuget.config" if ($LASTEXITCODE) { throw "Nuget restore for $sln failed." } } } diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index 22c6e50a0..337211dff 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -1,5 +1,5 @@  - + 11.0 @@ -223,8 +223,7 @@ - - + diff --git a/src/CSharp/CodeCracker/Design/InconsistentAccessibility/InconsistentAccessibilityCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/InconsistentAccessibility/InconsistentAccessibilityCodeFixProvider.cs index d8937aca7..f99e9e991 100644 --- a/src/CSharp/CodeCracker/Design/InconsistentAccessibility/InconsistentAccessibilityCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/InconsistentAccessibility/InconsistentAccessibilityCodeFixProvider.cs @@ -72,6 +72,8 @@ private static async Task GetInconsistentAccessib case InconsistentAccessibilityInIndexerParameterCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInIndexerParameter(); break; + default: + break; } return await inconsistentAccessibilityProvider.GetInconsistentAccessibilityInfoAsync(document, diagnostic, cancellationToken).ConfigureAwait(false); diff --git a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs index 9681645cc..1631dc9f9 100644 --- a/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs +++ b/src/CSharp/CodeCracker/Design/NameOfAnalyzer.cs @@ -114,6 +114,8 @@ private static string GetParameterNameThatMatchStringLiteral(LiteralExpressionSy break; case SyntaxKind.AttributeList: break; + default: + break; } parameterName = GetParameterWithIdentifierEqualToStringLiteral(stringLiteral, parameters)?.Identifier.Text; } diff --git a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs index 0ccb8b5a6..6b79daa2b 100644 --- a/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs +++ b/src/CSharp/CodeCracker/Extensions/CSharpAnalyzerExtensions.cs @@ -317,6 +317,8 @@ private static string GetLastIdentifierValueText(CSharpSyntaxNode node) case SyntaxKind.AliasQualifiedName: result = ((AliasQualifiedNameSyntax)node).Name.Identifier.ValueText; break; + default: + break; } return result; } @@ -336,8 +338,9 @@ public static SyntaxToken GetIdentifier(this BaseMethodDeclarationSyntax method) case SyntaxKind.DestructorDeclaration: result = ((DestructorDeclarationSyntax)method).Identifier; break; + default: + return result; } - return result; } @@ -392,6 +395,8 @@ public static MemberDeclarationSyntax WithModifiers(this MemberDeclarationSyntax case SyntaxKind.EventDeclaration: result = ((EventDeclarationSyntax)declaration).WithModifiers(newModifiers); break; + default: + break; } return result; @@ -428,6 +433,8 @@ public static SyntaxTokenList GetModifiers(this MemberDeclarationSyntax memberDe case SyntaxKind.EventDeclaration: result = ((BasePropertyDeclarationSyntax)memberDeclaration).Modifiers; break; + default: + break; } return result; diff --git a/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs index 33012a4af..6ef64c506 100644 --- a/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/AddBracesToSwitchSectionsAnalyzer.cs @@ -47,6 +47,8 @@ internal static bool HasBraces(SwitchSectionSyntax section) if (section.Statements.First() is BlockSyntax && section.Statements.Last() is BreakStatementSyntax) return true; break; + default: + break; } return false; } diff --git a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs index e9924b9d3..a3f061c3e 100644 --- a/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationAnalyzer.cs @@ -78,6 +78,8 @@ private static bool IsAlreadyStatic(ObjectCreationExpressionSyntax objectCreatio var fieldDeclaration = (FieldDeclarationSyntax)memberForObjectCreationExpr; result = ContainsStaticModifier(fieldDeclaration.Modifiers); break; + default: + break; } return result; } diff --git a/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs b/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs index 568e8af7c..3ca46c2ef 100644 --- a/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/SplitIntoNestedIfFixAllProvider.cs @@ -25,8 +25,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(SplitIntoNestedIfCodeFixProvider.MessageFormat, ct => GetFixedSolutionAsync(fixAllContext))); + default: + return null; } - return null; } private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) diff --git a/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs b/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs index 1c3416c81..055b0e517 100644 --- a/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Style/StringFormatFixAllProvider.cs @@ -26,8 +26,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(Resources.StringFormatCodeFixProvider_Title, ct => GetFixedSolutionAsync(fixAllContext))); + default: + return null; } - return null; } private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) diff --git a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs index 5499d07c8..8fa876860 100644 --- a/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Style/SwitchToAutoPropCodeFixAllProvider.cs @@ -27,8 +27,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(Resources.SwitchToAutoPropCodeFixProvider_Title, async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Solution)))); + default: + return null; } - return null; } private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Solution solution) diff --git a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs index 23fa9dcbe..20bc013e4 100644 --- a/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/UnnecessaryToStringInStringConcatenationAnalyzer.cs @@ -70,7 +70,7 @@ private static IEnumerable FilterInvocationsThatAreR foreach (var node in invocationExpressionsThatHaveToStringCall) { var toStringReceiver = GetTypeInfoOfReceiverOfToStringCall(node, semanticModel, cancellationToken); - //As long as the underlying type can not be resolved by the compiler (e.g. undefined type) + //As long as the underlying type can not be resolved by the compiler (e.g. undefined type) //removal is not save. if (toStringReceiver == null || toStringReceiver.TypeKind==TypeKind.Error) continue; @@ -115,7 +115,7 @@ private static ITypeSymbol GetTypeInfoOfOtherNode(SyntaxNode toStringNode, Binar private static bool CheckAddOperationOverloadsOfTypes(ITypeSymbol toStringReceiver, ITypeSymbol otherType) { - //If the underlying type has a custom AddOperator this operator will take precedence over everything else + //If the underlying type has a custom AddOperator this operator will take precedence over everything else if (HasTypeCustomAddOperator(toStringReceiver)) { return false; @@ -128,7 +128,7 @@ private static bool CheckAddOperationOverloadsOfTypes(ITypeSymbol toStringReceiv } //If the underlying type is one of the build in types (numeric, datetime and so on) and the other side is not a string, - //the result a removal is hard to predict and might be wrong. + //the result a removal is hard to predict and might be wrong. if (HasAdditionOperator(toStringReceiver)) { return false; @@ -177,11 +177,11 @@ private static bool HasAdditionOperator(ITypeSymbol type) case SpecialType.System_UIntPtr: case SpecialType.System_DateTime: return true; + default: + break; } if (type.TypeKind == TypeKind.Enum) - { return true; - } return false; } diff --git a/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs b/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs index a26d828df..0b0915ee3 100644 --- a/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs +++ b/src/CSharp/CodeCracker/Style/UseEmptyStringCodeFixProviderAll.cs @@ -42,8 +42,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(UseEmptyStringCodeFixProvider.MessageFormat, ct => GetFixedSolutionAsync(fixAllContext.WithCancellationToken(ct)))); + default: + return null; } - return null; } private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) diff --git a/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs b/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs index 0498b21d0..6d7e92057 100644 --- a/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs +++ b/src/CSharp/CodeCracker/Style/UseStringEmptyCodeFixProviderAll.cs @@ -42,8 +42,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(UseStringEmptyCodeFixProvider.MessageFormat, ct => GetFixedSolutionAsync(fixAllContext.WithCancellationToken(ct)))); + default: + return null; } - return null; } private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs index d49053746..d34c097b0 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedFixAllProvider.cs @@ -25,8 +25,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(DisposableVariableNotDisposedCodeFixProvider.MessageFormat, ct => GetFixedSolutionAsync(fixAllContext))); + default: + return null; } - return null; } private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) diff --git a/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs index 936cb1ef5..499cbd6b7 100644 --- a/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Usage/RemoveUnreachableCodeFixAllProvider.cs @@ -25,8 +25,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(RemoveUnreachableCodeCodeFixProvider.Message, ct => GetFixedSolutionAsync(fixAllContext))); + default: + return null; } - return null; } private async static Task GetFixedSolutionAsync(FixAllContext fixAllContext) diff --git a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs index e41a8fa8b..74650b882 100644 --- a/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs +++ b/src/CSharp/CodeCracker/Usage/UnusedParametersCodeFixAllProvider.cs @@ -27,8 +27,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(message, async ct => await GetFixedSolutionAsync(fixAllContext, await GetSolutionWithDocsAsync(fixAllContext, fixAllContext.Solution)))); + default: + return null; } - return null; } private async static Task GetSolutionWithDocsAsync(FixAllContext fixAllContext, Solution solution) diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config index fcde436eb..28a6ce22f 100644 --- a/src/CSharp/CodeCracker/packages.config +++ b/src/CSharp/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 34f859b17..f2b05c246 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -1,5 +1,5 @@  - + 11.0 @@ -72,8 +72,7 @@ - - + diff --git a/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs b/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs index 255dfc074..c74833924 100644 --- a/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs +++ b/src/Common/CodeCracker.Common/FixAllProviders/DocumentCodeFixProviderAll.cs @@ -34,8 +34,9 @@ public override Task GetFixAsync(FixAllContext fixAllContext) case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(CodeFixTitle, ct => GetFixedDocumentsAsync(fixAllContext, fixAllContext.Solution.Projects.SelectMany(p => p.Documents)))); + default: + return null; } - return null; } private async static Task GetFixedDocumentsAsync(FixAllContext fixAllContext, IEnumerable documents) diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config index 847a13861..324cafb10 100644 --- a/src/Common/CodeCracker.Common/packages.config +++ b/src/Common/CodeCracker.Common/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 02045debc..31f867607 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -1,5 +1,5 @@  - + 11.0 @@ -162,8 +162,7 @@ - - + diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config index bc11241d0..4ce3c94b7 100644 --- a/src/VisualBasic/CodeCracker/packages.config +++ b/src/VisualBasic/CodeCracker/packages.config @@ -1,6 +1,6 @@  - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index dcf1020ca..4d186cfbe 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -1,6 +1,7 @@  - - + + + Debug AnyCPU @@ -40,11 +41,8 @@ false - - ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.dll - - - ..\..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.Core.dll + + ..\..\..\packages\FluentAssertions.5.3.0\lib\net45\FluentAssertions.dll ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll @@ -61,8 +59,8 @@ ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll - - ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll @@ -93,6 +91,9 @@ ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll + + ..\..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll + @@ -101,14 +102,14 @@ ..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - - ..\..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll + + ..\..\..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll - - ..\..\..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll + + ..\..\..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll - - ..\..\..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll + + ..\..\..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll @@ -227,18 +228,21 @@ - - + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + + + + \ No newline at end of file diff --git a/src/CSharp/CodeCracker/packages.config b/src/CSharp/CodeCracker/packages.config deleted file mode 100644 index 28a6ce22f..000000000 --- a/src/CSharp/CodeCracker/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index f2b05c246..0ab0253ad 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -35,6 +35,15 @@ prompt 4 + + win + true + + + + + + @@ -56,11 +65,6 @@ - - - Designer - - ResXFileCodeGenerator @@ -71,51 +75,5 @@ Resources.Designer.cs - - - - - - - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - - - ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - - - ..\..\..\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.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - \ No newline at end of file diff --git a/src/Common/CodeCracker.Common/packages.config b/src/Common/CodeCracker.Common/packages.config deleted file mode 100644 index 324cafb10..000000000 --- a/src/Common/CodeCracker.Common/packages.config +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 31f867607..9a425da8f 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -9,6 +9,7 @@ Library CodeCracker.VisualBasic CodeCracker.VisualBasic + CodeCracker.VisualBasic.NewIdRequiredDueToNuGetBug en-US {14182A97-F7F0-4C62-8B27-98AA8AE2109A};{F184B08F-C81C-45F6-A57F-5ABD9991F28F} Profile7 @@ -54,12 +55,18 @@ On + + win + true + + + + + + - - Designer - PreserveNewest @@ -161,57 +168,5 @@ CodeCracker.Common - - - - - - - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll - - - ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - - - ..\..\..\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.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - \ No newline at end of file diff --git a/src/VisualBasic/CodeCracker/packages.config b/src/VisualBasic/CodeCracker/packages.config deleted file mode 100644 index 4ce3c94b7..000000000 --- a/src/VisualBasic/CodeCracker/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 4d186cfbe..5eef509d5 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -1,7 +1,5 @@  - - Debug AnyCPU @@ -41,76 +39,19 @@ false - - ..\..\..\packages\FluentAssertions.5.3.0\lib\net45\FluentAssertions.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll - - - ..\..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll - True - - - ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - ..\..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll - - - ..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - - - ..\..\..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll - - - ..\..\..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll - - - ..\..\..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll - + + + + + + @@ -199,9 +140,6 @@ - - Designer - @@ -227,27 +165,5 @@ - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/packages.config b/test/CSharp/CodeCracker.Test/packages.config deleted file mode 100644 index a23582940..000000000 --- a/test/CSharp/CodeCracker.Test/packages.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 64b167733..0f296cd69 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -1,7 +1,5 @@  - - Debug @@ -37,82 +35,19 @@ 4 - - ..\..\..\packages\FluentAssertions.5.3.0\lib\net45\FluentAssertions.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll - - - ..\..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll - True - - - ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - ..\..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll - - - ..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - - - ..\..\..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll - - - ..\..\..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll - - - ..\..\..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll - + + + + + + @@ -125,32 +60,5 @@ - - - Designer - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/packages.config b/test/Common/CodeCracker.Test.Common/packages.config deleted file mode 100644 index eed89eef8..000000000 --- a/test/Common/CodeCracker.Test.Common/packages.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index c5e096782..e27355417 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -1,7 +1,5 @@  - - Debug @@ -55,73 +53,16 @@ On - - ..\..\..\packages\FluentAssertions.5.3.0\lib\net45\FluentAssertions.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.3.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll - - - ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll - - - ..\..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll - True - - - ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll - True - - - ..\..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - ..\..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll - - - ..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - - - ..\..\..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll - - - ..\..\..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll - - - ..\..\..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll - + + + + + + @@ -195,9 +136,6 @@ My Settings.Designer.vb - - Designer - @@ -216,26 +154,5 @@ CodeCracker.Test.Common - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/packages.config b/test/VisualBasic/CodeCracker.Test/packages.config deleted file mode 100644 index e47b5ab69..000000000 --- a/test/VisualBasic/CodeCracker.Test/packages.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 0ed68e234dd4974239cd2bd963940068a90eb043 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Sun, 9 Sep 2018 23:51:54 -0500 Subject: [PATCH 328/358] Use DiagnosticResult from Microsoft.CodeAnalysis.Testing --- nuget.config | 2 + src/CSharp/CodeCracker/CodeCracker.csproj | 4 +- .../CodeCracker.Common.csproj | 2 +- .../CodeCracker/CodeCracker.vbproj | 4 +- .../CodeCracker.Test/CodeCracker.Test.csproj | 2 +- .../Design/MakeMethodStaticTests.cs | 31 +-- .../CodeCracker.Test/Design/NameOfTests.cs | 11 +- .../Design/StaticConstructorExceptionTests.cs | 11 +- .../Design/UseInvokeMethodToFireEventTests.cs | 201 ++++++------------ .../Maintainability/XmlDocumentationTests.cs | 21 +- .../Performance/EmptyFinalizerTests.cs | 31 +-- ...ocalVariablesConstWhenItIsPossibleTests.cs | 31 +-- .../RemoveWhereWhenItIsPossibleTests.cs | 11 +- .../Performance/SealedAttributeTests.cs | 21 +- .../Performance/StringBuilderInLoopTests.cs | 111 +++------- .../Performance/UseStaticRegexIsMatchTests.cs | 11 +- .../AddBracesToSwitchSectionsTests.cs | 31 +-- .../AllowMembersOrderingAnalyzerTests.cs | 11 +- .../Refactoring/ChangeAnyToAllTests.cs | 41 ++-- .../Refactoring/ComputeExpressionTests.cs | 11 +- .../Refactoring/InvertForTests.cs | 31 +-- .../Refactoring/MergeNestedIfTest.cs | 11 +- .../Refactoring/NumericLiteralTests.cs | 15 +- ...ngedEventArgsUnnecessaryAllocationTests.cs | 18 +- .../ReplaceWithGetterOnlyAutoPropertyTests.cs | 92 ++------ .../Refactoring/SplitIntoNestedIfTests.cs | 11 +- .../Refactoring/StringRepresentationTests.cs | 21 +- .../UseConfigureAwaitFalseTests.cs | 11 +- .../Style/AlwaysUseVarTests.cs | 31 +-- .../Style/ConsoleWriteLineTests.cs | 31 +-- ...nvertLambdaExpressionToMethodGroupTests.cs | 31 +-- .../ConvertToExpressionBodiedMemberTests.cs | 51 ++--- .../Style/ConvertToSwitchTests.cs | 21 +- .../Style/EmptyObjectInitializerTests.cs | 11 +- .../Style/ExistenceOperatorTests.cs | 21 +- .../CodeCracker.Test/Style/ForInArrayTests.cs | 71 ++----- .../Style/InterfaceNameTests.cs | 11 +- .../Style/ObjectInitializerTests.cs | 31 +-- .../Style/PropertyPrivateSetTests.cs | 11 +- .../Style/RemoveAsyncFromMethodTests.cs | 11 +- .../Style/RemoveCommentedCodeTests.cs | 21 +- .../Style/RemoveTrailingWhitespaceTests.cs | 12 +- .../Style/StringFormatTests.cs | 51 ++--- .../Style/SwitchToAutoPropTests.cs | 11 +- .../Style/TaskNameASyncTests.cs | 41 ++-- .../Style/TernaryOperatorTests.cs | 31 +-- .../Style/UnnecessaryParenthesisTests.cs | 11 +- ...ssaryToStringInStringConcatenationTests.cs | 13 +- .../Style/UseEmptyStringTest.cs | 15 +- .../Style/UseStringEmptyTests.cs | 41 ++-- ...stractClassShouldNotHavePublicCtorTests.cs | 11 +- .../Usage/ArgumentExceptionTests.cs | 51 ++--- .../CallExtensionMethodAsExtensionTests.cs | 61 ++---- .../Usage/DisposableFieldNotDisposedTests.cs | 111 +++------- .../DisposableVariableNotDisposedTests.cs | 101 +++------ ...posablesShouldCallSuppressFinalizeTests.cs | 21 +- .../Usage/IPAddressAnalyzerTests.cs | 10 +- .../Usage/IfReturnTrueTests.cs | 21 +- .../Usage/JsonNetAnalyzerTests.cs | 10 +- .../Usage/NoPrivateReadonlyFieldTest.cs | 15 +- .../Usage/ReadonlyFieldTests.cs | 171 +++++---------- .../Usage/RedundantFieldAssignmentTests.cs | 131 ++++-------- .../CodeCracker.Test/Usage/RegexTests.cs | 21 +- ...emovePrivateMethodNeverUsedAnalyzerTest.cs | 15 +- .../Usage/RemoveRedundantElseClauseTests.cs | 21 +- .../Usage/RethrowExceptionTests.cs | 11 +- ...implifyRedundantBooleanComparisonsTests.cs | 11 +- .../Usage/StringFormatArgsTests.cs | 81 +++---- .../Usage/UnusedParametersTests.cs | 11 +- .../Usage/UriAnalyzerTests.cs | 11 +- .../Usage/VirtualMethodOnConstructorTests.cs | 37 ++-- .../CodeCracker.Test.Common.csproj | 2 +- .../Helpers/DiagnosticResult.cs | 86 -------- .../Verifiers/DiagnosticVerifier.cs | 28 +-- .../CodeCracker.Test/CodeCracker.Test.vbproj | 2 +- .../CodeCracker.Test/Design/NameOfTests.vb | 11 +- .../Design/StaticConstructorExceptionTests.vb | 10 +- ...ocalVariablesConstWhenItIsPossibleTests.vb | 31 +-- .../RemoveWhereWhenItIsPossibleTests.vb | 11 +- .../Performance/SealedAttributeTests.vb | 21 +- .../Performance/StringBuilderInLoopTests.vb | 61 ++---- .../AllowMembersOrderingAnalyzerTests.vb | 10 +- .../Refactoring/ChangeAnyToAllTests.vb | 10 +- .../UseConfigureAwaitFalseTests.vb | 10 +- .../Style/InterfaceNameTests.vb | 10 +- .../Style/TernaryOperatorTests.vb | 28 +-- .../Usage/ArgumentExceptionTests.vb | 28 +-- .../Usage/DisposableFieldNotDisposedTests.vb | 111 +++------- ...posablesShouldCallSuppressFinalizeTests.vb | 19 +- .../Usage/IPAddressAnalyzerTests.vb | 9 +- .../Usage/JsonNetAnalyzerTests.vb | 10 +- ...lassShouldNotHavePublicConstructorTests.vb | 10 +- .../Usage/UnusedParametersTests.vb | 10 +- .../Usage/UriAnalyzerTests.vb | 10 +- 94 files changed, 910 insertions(+), 1949 deletions(-) delete mode 100644 test/Common/CodeCracker.Test.Common/Helpers/DiagnosticResult.cs diff --git a/nuget.config b/nuget.config index ffae90ba7..f42466e87 100644 --- a/nuget.config +++ b/nuget.config @@ -4,10 +4,12 @@ + + \ No newline at end of file diff --git a/src/CSharp/CodeCracker/CodeCracker.csproj b/src/CSharp/CodeCracker/CodeCracker.csproj index fdeef9f24..d81e8eee9 100644 --- a/src/CSharp/CodeCracker/CodeCracker.csproj +++ b/src/CSharp/CodeCracker/CodeCracker.csproj @@ -14,7 +14,7 @@ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Profile7 v4.5 - AD0001 + AD0001,RS1010,RS1016,RS1017,RS1022 true @@ -41,7 +41,7 @@ - + diff --git a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj index 0ab0253ad..8f502cca1 100644 --- a/src/Common/CodeCracker.Common/CodeCracker.Common.csproj +++ b/src/Common/CodeCracker.Common/CodeCracker.Common.csproj @@ -41,7 +41,7 @@ - + diff --git a/src/VisualBasic/CodeCracker/CodeCracker.vbproj b/src/VisualBasic/CodeCracker/CodeCracker.vbproj index 9a425da8f..877bee09b 100644 --- a/src/VisualBasic/CodeCracker/CodeCracker.vbproj +++ b/src/VisualBasic/CodeCracker/CodeCracker.vbproj @@ -14,7 +14,7 @@ {14182A97-F7F0-4C62-8B27-98AA8AE2109A};{F184B08F-C81C-45F6-A57F-5ABD9991F28F} Profile7 v4.5 - AD0001 + AD0001,RS1010,RS1016,RS1017,RS1022 true @@ -61,7 +61,7 @@ - + diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 5eef509d5..87c9508c5 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -49,7 +49,7 @@ - + diff --git a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs index 9a1590393..2d8829a4a 100644 --- a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Design; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -100,13 +101,9 @@ class C : I public async Task WithDiagnostic(string code) { var source = code.WrapInCSharpClass(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.MakeMethodStatic.ToDiagnosticId(), - Message = string.Format(MakeMethodStaticAnalyzer.MessageFormat, "Foo"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 18) } - }; + var expected = new DiagnosticResult(DiagnosticId.MakeMethodStatic.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 18) + .WithMessage(string.Format(MakeMethodStaticAnalyzer.MessageFormat, "Foo")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -1014,13 +1011,9 @@ public void M() } public static void N() { } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.MakeMethodStatic.ToDiagnosticId(), - Message = string.Format(MakeMethodStaticAnalyzer.MessageFormat, "M"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.MakeMethodStatic.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 17) + .WithMessage(string.Format(MakeMethodStaticAnalyzer.MessageFormat, "M")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -1053,13 +1046,9 @@ public void GetEnumerator() public static void N() { } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.MakeMethodStatic.ToDiagnosticId(), - Message = string.Format(MakeMethodStaticAnalyzer.MessageFormat, "GetEnumerator"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.MakeMethodStatic.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 17) + .WithMessage(string.Format(MakeMethodStaticAnalyzer.MessageFormat, "GetEnumerator")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs b/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs index 982738bef..819252585 100644 --- a/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/NameOfTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Design; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -728,13 +729,9 @@ void Foo(TypeName d) private static DiagnosticResult CreateNameofDiagnosticResult(string nameofArgument, int diagnosticLine, int diagnosticColumn, DiagnosticId id = DiagnosticId.NameOf) { - return new DiagnosticResult - { - Id = id.ToDiagnosticId(), - Message = $"Use 'nameof({nameofArgument})' instead of specifying the program element name.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", diagnosticLine, diagnosticColumn) } - }; + return new DiagnosticResult(id.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(diagnosticLine, diagnosticColumn) + .WithMessage($"Use 'nameof({nameofArgument})' instead of specifying the program element name."); } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs b/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs index f6ba9d8a0..a8697697b 100644 --- a/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/StaticConstructorExceptionTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Design; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -19,13 +20,9 @@ static MyClass() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StaticConstructorException.ToDiagnosticId(), - Message = "Don't throw exceptions inside static constructors.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.StaticConstructorException.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 25) + .WithMessage("Don't throw exceptions inside static constructors."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs index f392107bc..90acb1bdd 100644 --- a/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/UseInvokeMethodToFireEventTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Design; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Design @@ -20,13 +21,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -45,13 +42,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -78,13 +71,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(16, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -111,13 +100,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(16, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -144,13 +129,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(16, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -178,13 +159,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(17, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -212,13 +189,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(17, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -237,13 +210,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -267,13 +236,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(13, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -298,13 +263,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(14, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -332,13 +293,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(17, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -366,13 +323,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 17, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(17, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -410,13 +363,9 @@ public class MyClass public void Execute() => MyEvent(this, System.EventArgs.Empty); }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -460,13 +409,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(13, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -492,13 +437,9 @@ public void Execute() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "MyEvent"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 15, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(15, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "MyEvent")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -548,13 +489,9 @@ public static void Execute(System.Action action) action(); } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "action")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -571,13 +508,9 @@ public static void Execute(System.Action action) action(); } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "action")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -593,13 +526,9 @@ public static void Execute(System.Action action) if (action == null) throw new Exception(); } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 25) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "action")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -683,13 +612,9 @@ public static void Execute(System.Action action) if (null == action) action(); }".WrapInCSharpClass(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "action"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 9) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(12, 9) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "action")); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -799,13 +724,9 @@ public static TReturn Method(System.Func getter) where T { return getter(default(T)); }".WrapInCSharpClass(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), - Message = string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat.ToString(), "getter"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 12) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseInvokeMethodToFireEvent.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(11, 12) + .WithMessage(string.Format(UseInvokeMethodToFireEventAnalyzer.MessageFormat, "getter")); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs b/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs index 4e060ac36..db37a35fa 100644 --- a/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs +++ b/test/CSharp/CodeCracker.Test/Maintainability/XmlDocumentationTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Maintainability; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -110,13 +111,9 @@ protected async static Task GetSortedDiagnosticsFromDocumentsAsync } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.XmlDocumentation_MissingInCSharp.ToDiagnosticId(), - Message = "You have missing/unexistent parameters in Xml Docs", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 16) } - }; + var expected = new DiagnosticResult(DiagnosticId.XmlDocumentation_MissingInCSharp.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 16) + .WithMessage("You have missing/unexistent parameters in Xml Docs"); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -141,13 +138,9 @@ public static Project CreateProject(string[] sources, out AdhocWorkspace workspa } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.XmlDocumentation_MissingInXml.ToDiagnosticId(), - Message = "You have missing/unexistent parameters in Xml Docs", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 16) } - }; + var expected = new DiagnosticResult(DiagnosticId.XmlDocumentation_MissingInXml.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 16) + .WithMessage("You have missing/unexistent parameters in Xml Docs"); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Performance/EmptyFinalizerTests.cs b/test/CSharp/CodeCracker.Test/Performance/EmptyFinalizerTests.cs index f86dde304..aef768752 100644 --- a/test/CSharp/CodeCracker.Test/Performance/EmptyFinalizerTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/EmptyFinalizerTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Performance; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -19,13 +20,9 @@ public class MyClass } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.EmptyFinalizer.ToDiagnosticId(), - Message = "Remove Empty Finalizers", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.EmptyFinalizer.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 21) + .WithMessage("Remove Empty Finalizers"); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -42,13 +39,9 @@ public class MyClass } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.EmptyFinalizer.ToDiagnosticId(), - Message = "Remove Empty Finalizers", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.EmptyFinalizer.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 21) + .WithMessage("Remove Empty Finalizers"); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -68,13 +61,9 @@ public class MyClass } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.EmptyFinalizer.ToDiagnosticId(), - Message = "Remove Empty Finalizers", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.EmptyFinalizer.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 21) + .WithMessage("Remove Empty Finalizers"); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs index e37f52a46..61b2311b3 100644 --- a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Performance; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -64,13 +65,9 @@ public async Task IgnoresPointerDeclarations() public async Task CreateDiagnosticsWhenAssigningAPotentialConstant() { var test = @"int a = 10;".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), - Message = "This variable can be made const.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 17) + .WithMessage("This variable can be made const."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -79,13 +76,9 @@ public async Task CreateDiagnosticsWhenAssigningAPotentialConstantInAVarDeclarat { var test = @"var a = 10;".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), - Message = "This variable can be made const.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 17) + .WithMessage("This variable can be made const."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -94,13 +87,9 @@ public async Task CreateDiagnosticsWhenAssigningNullToAReferenceType() { var test = @"Foo a = null;".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), - Message = "This variable can be made const.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 17) + .WithMessage("This variable can be made const."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs index c6e4b622a..64de3af7c 100644 --- a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Performance; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -32,13 +33,9 @@ public async Task DoSomething() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), - Message = "You can remove 'Where' moving the predicate to '" + method + "'.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(11, 23) + .WithMessage("You can remove 'Where' moving the predicate to '" + method + "'."); await VerifyCSharpDiagnosticAsync(test, expected); diff --git a/test/CSharp/CodeCracker.Test/Performance/SealedAttributeTests.cs b/test/CSharp/CodeCracker.Test/Performance/SealedAttributeTests.cs index e14f5e926..ce0fe3dfa 100644 --- a/test/CSharp/CodeCracker.Test/Performance/SealedAttributeTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/SealedAttributeTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Performance; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -16,13 +17,9 @@ public class MyAttribute : System.Attribute }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.SealedAttribute.ToDiagnosticId(), - Message = "Mark 'MyAttribute' as sealed.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 2, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.SealedAttribute.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(2, 30) + .WithMessage("Mark 'MyAttribute' as sealed."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -41,13 +38,9 @@ public class OtherAttribute : MyAttribute }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.SealedAttribute.ToDiagnosticId(), - Message = "Mark 'OtherAttribute' as sealed.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.SealedAttribute.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(7, 30) + .WithMessage("Mark 'OtherAttribute' as sealed."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs b/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs index 9f14bdcb5..75f557017 100644 --- a/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/StringBuilderInLoopTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -50,13 +51,9 @@ public async Task WhileWithStringConcatOnLocalVariableCreatesDiagnostic() { myString += """"; }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(14, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -78,13 +75,9 @@ public void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(11, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -107,13 +100,9 @@ public void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "MyString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(11, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "MyString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -128,20 +117,12 @@ public async Task WhileWithStringConcatWithSeveralConcatsOnDifferentVarsCreatesS myString1 += """"; myString2 += """"; }".WrapInCSharpMethod(); - var expected1 = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString1"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 15, 21) } - }; - var expected2 = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString2"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 21) } - }; + var expected1 = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(15, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString1")); + var expected2 = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(16, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString2")); await VerifyCSharpDiagnosticAsync(source, expected1, expected2); } @@ -154,13 +135,9 @@ public async Task WhileWithStringConcatWithSimpleAssignmentCreatesDiagnostic() { myString = myString + """"; }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(14, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -387,13 +364,9 @@ public async Task ForWithStringConcatOnLocalVariableCreatesDiagnostic() { myString += """"; }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(14, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -443,13 +416,9 @@ public async Task ForeachWithtStringConcatOnLocalVariableCreatesDiagnostic() { myString += """"; }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(14, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -483,13 +452,9 @@ public async Task DoWithtStringConcatOnLocalVariableCreatesDiagnostic() { myString += """"; } while (DateTime.Now.Second % 2 == 0);".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(14, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -537,13 +502,9 @@ public void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "someObject.A"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(16, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "someObject.A")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -570,13 +531,9 @@ public void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), - Message = string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "someObject.A[DateTime.Now.Second]"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 16, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringBuilderInLoop.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(16, 21) + .WithMessage(string.Format(StringBuilderInLoopAnalyzer.MessageFormat, "someObject.A[DateTime.Now.Second]")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs b/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs index c16424c06..5d4d8f76c 100644 --- a/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/UseStaticRegexIsMatchTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Performance; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -26,13 +27,9 @@ public async Task Foo() [Fact] public async Task CreatesDiagnosticsWhenDeclaringALocalRegexAndUsingIsMatch() { - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseStaticRegexIsMatch.ToDiagnosticId(), - Message = UseStaticRegexIsMatchAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseStaticRegexIsMatch.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(12, 17) + .WithMessage(UseStaticRegexIsMatchAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs index eab5fc7bb..9f8dfb62c 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Refactoring @@ -69,13 +70,9 @@ public async Task CreateDiagnosticWhenSingleSwitchSectionHasNoBraces() Foo(); break; }"; - var diagnostic = new DiagnosticResult - { - Id = DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), - Message = "Add braces for each section in this switch", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] {new DiagnosticResultLocation("Test0.cs", 10, 17)} - }; + var diagnostic = new DiagnosticResult(DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 17) + .WithMessage("Add braces for each section in this switch"); await VerifyCSharpDiagnosticAsync(test.WrapInCSharpMethod(), diagnostic); } @@ -98,13 +95,9 @@ public async Task CreateDiagnosticWhenNotAllSwitchSectionsHaveBraces() break; } }"; - var diagnostic = new DiagnosticResult - { - Id = DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), - Message = "Add braces for each section in this switch", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var diagnostic = new DiagnosticResult(DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 17) + .WithMessage("Add braces for each section in this switch"); await VerifyCSharpDiagnosticAsync(test.WrapInCSharpMethod(), diagnostic); } @@ -127,13 +120,9 @@ public async Task CreateDiagnosticWhenDefaultSectionsHasNoBraces() Baz(); break; }"; - var diagnostic = new DiagnosticResult - { - Id = DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), - Message = "Add braces for each section in this switch", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var diagnostic = new DiagnosticResult(DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 17) + .WithMessage("Add braces for each section in this switch"); await VerifyCSharpDiagnosticAsync(test.WrapInCSharpMethod(), diagnostic); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs index 724a2cfd6..bbede299f 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.cs @@ -1,6 +1,7 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Refactoring { @@ -50,13 +51,9 @@ public async void AllowMembersOrderingForMoreThanOneMemberShouldTriggerDiagnosti void car() { } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.AllowMembersOrdering.ToDiagnosticId(), - Message = AllowMembersOrderingAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 2, 14 + typeDeclaration.Length) } - }; + var expected = new DiagnosticResult(DiagnosticId.AllowMembersOrdering.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(2, 14 + typeDeclaration.Length) + .WithMessage(AllowMembersOrderingAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs index 5413edb7e..86ca15d52 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -29,13 +30,9 @@ public class ChangeAnyToAllTests : CodeFixVerifier i == 1); }} }}"; - var expected = new DiagnosticResult - { - Id = diagnosticId.ToDiagnosticId(), - Message = diagnosticId == DiagnosticId.ChangeAnyToAll ? ChangeAnyToAllAnalyzer.MessageAny : ChangeAnyToAllAnalyzer.MessageAll, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 43) } - }; + var expected = new DiagnosticResult(diagnosticId.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(13, 43) + .WithMessage(diagnosticId == DiagnosticId.ChangeAnyToAll ? ChangeAnyToAllAnalyzer.MessageAny : ChangeAnyToAllAnalyzer.MessageAll); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -246,13 +239,9 @@ class TypeName private System.Collections.Generic.IList xs; bool Foo() => xs.{methodName}(i => i == 1); }}"; - var expected = new DiagnosticResult - { - Id = diagnosticId.ToDiagnosticId(), - Message = diagnosticId == DiagnosticId.ChangeAnyToAll ? ChangeAnyToAllAnalyzer.MessageAny : ChangeAnyToAllAnalyzer.MessageAll, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 22) } - }; + var expected = new DiagnosticResult(diagnosticId.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(7, 22) + .WithMessage(diagnosticId == DiagnosticId.ChangeAnyToAll ? ChangeAnyToAllAnalyzer.MessageAny : ChangeAnyToAllAnalyzer.MessageAll); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -280,13 +269,9 @@ public async Task NegationWithCoalesceExpressionCreatesDiagnostic(string methodN var source = $@" var ints = new [] {{ 1 }}; var query = !ints?.{methodName}(i => i == 1) ?? true;"; - var expected = new DiagnosticResult - { - Id = diagnosticId.ToDiagnosticId(), - Message = diagnosticId == DiagnosticId.ChangeAnyToAll ? ChangeAnyToAllAnalyzer.MessageAny : ChangeAnyToAllAnalyzer.MessageAll, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 20) } - }; + var expected = new DiagnosticResult(diagnosticId.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(13, 20) + .WithMessage(diagnosticId == DiagnosticId.ChangeAnyToAll ? ChangeAnyToAllAnalyzer.MessageAny : ChangeAnyToAllAnalyzer.MessageAll); await VerifyCSharpDiagnosticAsync(source.WrapInCSharpMethod(usings: "\nusing System.Linq;"), expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs index e7a40762e..64f244a6c 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -38,13 +39,9 @@ public async Task BinaryExpressionWithLiteralOnLeftAndRightCreatesDiagnostic(str { var source = original.WrapInCSharpMethod(); var expression = original.Substring(columnOffset, original.Length - columnOffset - columnRightTrim - 1); - var expected = new DiagnosticResult - { - Id = DiagnosticId.ComputeExpression.ToDiagnosticId(), - Message = string.Format(ComputeExpressionAnalyzer.Message, expression), - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17 + columnOffset) } - }; + var expected = new DiagnosticResult(DiagnosticId.ComputeExpression.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 17 + columnOffset) + .WithMessage(string.Format(ComputeExpressionAnalyzer.Message, expression)); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/InvertForTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/InvertForTests.cs index 89bcb57b9..c46800685 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/InvertForTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/InvertForTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -125,13 +126,9 @@ public async Task CreateDiagnosticsWithForLoopsFrom0ToN() { var test = WrapInCSharpMethod(@"for (var i = 0; i < n; i++){}"); - var expected = new DiagnosticResult - { - Id = DiagnosticId.InvertFor.ToDiagnosticId(), - Message = "Make it a for loop that decrement the counter.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.InvertFor.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 17) + .WithMessage("Make it a for loop that decrement the counter."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -141,13 +138,9 @@ public async Task CreateDiagnosticsWithForLoopsTheUsesAnDeclaredVariableAsCounte { var test = WrapInCSharpMethod(@"int i = 0; for (i = 0; i < n; i++){}"); - var expected = new DiagnosticResult - { - Id = DiagnosticId.InvertFor.ToDiagnosticId(), - Message = "Make it a for loop that decrement the counter.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 28) } - }; + var expected = new DiagnosticResult(DiagnosticId.InvertFor.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 28) + .WithMessage("Make it a for loop that decrement the counter."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -157,13 +150,9 @@ public async Task CreateDiagnosticsWithForLoopsFromNTo0() { var test = WrapInCSharpMethod(@"for (var i = n - 1; i >= 0; i--){}"); - var expected = new DiagnosticResult - { - Id = DiagnosticId.InvertFor.ToDiagnosticId(), - Message = "Make it a for loop that increment the counter.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.InvertFor.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 17) + .WithMessage("Make it a for loop that increment the counter."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs b/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs index 1bcda1b72..32911a9f5 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/MergeNestedIfTest.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -39,13 +40,9 @@ public async Task NestedIfCreatesDiagnostic() var a = 1; } }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.MergeNestedIf.ToDiagnosticId(), - Message = MergeNestedIfAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.MergeNestedIf.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(11, 17) + .WithMessage(MergeNestedIfAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs index 74fce5482..feae0f6f6 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -80,13 +81,11 @@ void Foo() await VerifyCSharpFixAsync(source, fixtest); } - private static DiagnosticResult CreateDiagnosticResult(string literal, bool isDecimal, int row = 10, int col = 25) => - new DiagnosticResult - { - Id = DiagnosticId.NumericLiteral.ToDiagnosticId(), - Message = string.Format(NumericLiteralAnalyzer.Message, literal, isDecimal ? "hexadecimal" : "decimal"), - Severity = DiagnosticSeverity.Hidden, - Locations = new[] {new DiagnosticResultLocation("Test0.cs", row, col)} - }; + private static DiagnosticResult CreateDiagnosticResult(string literal, bool isDecimal, int row = 10, int col = 25) + { + return new DiagnosticResult(DiagnosticId.NumericLiteral.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(row, col) + .WithMessage(string.Format(NumericLiteralAnalyzer.Message, literal, isDecimal ? "hexadecimal" : "decimal")); + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs index 9e004869e..27fcfbb2f 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/PropertyChangedEventArgsUnnecessaryAllocationTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Collections.Generic; using System.Threading.Tasks; using Xunit; @@ -32,7 +33,7 @@ public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreatio { var source = $"var args = new PropertyChangedEventArgs({ctorArg})"; - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 12)); + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(1, 12)); } [Theory] @@ -57,7 +58,7 @@ public async Task DoesTriggerDiagnosticAtPropertyChangedEventArgsInstanceCreatio { var source = $"object args = new {{ Name = new PropertyChangedEventArgs({ctorArg}) }}"; - await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(0, 28)); + await VerifyCSharpDiagnosticAsync(source, PropertyChangedUnnecessaryAllocationDiagnostic(1, 28)); } [Theory] @@ -148,16 +149,9 @@ public void TestMethod(string propertyName) public static DiagnosticResult PropertyChangedUnnecessaryAllocationDiagnostic(int line, int column) { - return new DiagnosticResult - { - Id = DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId(), - Message = "Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] - { - new DiagnosticResultLocation("Test0.cs", line, column), - } - }; + return new DiagnosticResult(DiagnosticId.PropertyChangedEventArgsUnnecessaryAllocation.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(line, column) + .WithMessage("Create PropertyChangedEventArgs static instance and reuse it to avoid unecessary memory allocation."); } public static IEnumerable SharedDataCodeFix diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs index 072643c56..528ab9f0d 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ReplaceWithGetterOnlyAutoPropertyTests.cs @@ -1,6 +1,7 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -30,16 +31,9 @@ public async Task SimplePropertyGetsTransformed() public string Value { get { return _value; } } ".WrapInCSharpClass(); - var expected = new DiagnosticResult - { - Id = "CC0125", - Message = GetDiagnosticMessage("Value"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 16, 27) - } - }; + var expected = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(16, 27) + .WithMessage(GetDiagnosticMessage("Value")); await VerifyCSharpDiagnosticAsync(test, expected); @@ -83,16 +77,9 @@ public async Task FieldInitializerIsPreserved() public string Value { get { return this.value; } } ".WrapInCSharpClass(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("Value"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 16, 27) - } - }; + var expected = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(16, 27) + .WithMessage(GetDiagnosticMessage("Value")); await VerifyCSharpDiagnosticAsync(test, expected); @@ -125,26 +112,12 @@ public async Task MultiplePropertiesPerClassGetTranformed() public string Value2 { get { return this.value2; } } ".WrapInCSharpClass(); - var expected1 = new DiagnosticResult - { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("Value"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 17, 27) - } - }; - var expected2 = new DiagnosticResult - { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("Value2"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 18, 27) - } - }; + var expected1 = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(17, 27) + .WithMessage(GetDiagnosticMessage("Value")); + var expected2 = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(18, 27) + .WithMessage(GetDiagnosticMessage("Value2")); await VerifyCSharpDiagnosticAsync(test, new DiagnosticResult[] { expected1, expected2 }); @@ -176,26 +149,12 @@ public async Task MultiplePropertiesPerClassWithFieldInitilizerAndUnusedFieldsGe public string Value { get { return this.value; } } public string Value2 { get { return this.value2; } } ".WrapInCSharpClass(); - var expected1 = new DiagnosticResult - { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("Value"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 17, 27) - } - }; - var expected2 = new DiagnosticResult - { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("Value2"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 18, 27) - } - }; + var expected1 = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(17, 27) + .WithMessage(GetDiagnosticMessage("Value")); + var expected2 = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(18, 27) + .WithMessage(GetDiagnosticMessage("Value2")); await VerifyCSharpDiagnosticAsync(test, new DiagnosticResult[] { expected1, expected2 }); @@ -229,16 +188,9 @@ public async Task TypeOfPropertyMustFitTypeOfBackingField() public IEnumerable Value { get { return this.value; } } public IList Value2 { get { return this.value2; } } ".WrapInCSharpClass(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), - Message = GetDiagnosticMessage("Value2"), - Severity = DiagnosticSeverity.Hidden, - Locations = - new[] { - new DiagnosticResultLocation("Test0.cs", 18, 34) - } - }; + var expected = new DiagnosticResult(DiagnosticId.ReplaceWithGetterOnlyAutoProperty.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(18, 34) + .WithMessage(GetDiagnosticMessage("Value2")); await VerifyCSharpDiagnosticAsync(test, expected); diff --git a/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs index bf3507e67..b99818c1c 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -32,13 +33,9 @@ public async Task IfWithElseDoesNotCreateDiagnostic() public async Task IfWithAndCreatesDiagnostic() { var source = "if (true && true) { }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.SplitIntoNestedIf.ToDiagnosticId(), - Message = string.Format(SplitIntoNestedIfAnalyzer.Message), - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.SplitIntoNestedIf.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, 21) + .WithMessage(string.Format(SplitIntoNestedIfAnalyzer.Message)); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/StringRepresentationTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/StringRepresentationTests.cs index 8a97aca6f..d716b7a01 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/StringRepresentationTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/StringRepresentationTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Refactoring; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Xunit; @@ -55,13 +56,9 @@ void M() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringRepresentation_RegularString.ToDiagnosticId(), - Message = "Change to regular string", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringRepresentation_RegularString.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(6, 17) + .WithMessage("Change to regular string"); return VerifyCSharpDiagnosticAsync(source, expected); } @@ -77,13 +74,9 @@ void M() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringRepresentation_VerbatimString.ToDiagnosticId(), - Message = "Change to verbatim string", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringRepresentation_VerbatimString.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(6, 17) + .WithMessage("Change to verbatim string"); return VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs b/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs index b0aaf74ff..c8e981b55 100644 --- a/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs +++ b/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Reliability; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -18,13 +19,9 @@ public async Task WhenAwaitingTaskAnalyzerCreatesDiagnostic(string sample, int c { var test = sample.WrapInCSharpMethod(isAsync: true); - var expected = new DiagnosticResult - { - Id = DiagnosticId.UseConfigureAwaitFalse.ToDiagnosticId(), - Message = "Consider using ConfigureAwait(false) on the awaited task.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, column) } - }; + var expected = new DiagnosticResult(DiagnosticId.UseConfigureAwaitFalse.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(10, column) + .WithMessage("Consider using ConfigureAwait(false) on the awaited task."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs b/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs index d78489fbc..54f83e00d 100644 --- a/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/AlwaysUseVarTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Style; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -130,13 +131,9 @@ void Foo() dynamic Fee() { return 42; } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.AlwaysUseVar.ToDiagnosticId(), - Message = "Use 'var' instead of specifying the type name.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.AlwaysUseVar.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(9, 17) + .WithMessage("Use 'var' instead of specifying the type name."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -158,13 +155,9 @@ public async Task Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.AlwaysUseVarOnPrimitives.ToDiagnosticId(), - Message = "Use 'var' instead of specifying the type name.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.AlwaysUseVarOnPrimitives.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 17) + .WithMessage("Use 'var' instead of specifying the type name."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -187,13 +180,9 @@ public async Task Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.AlwaysUseVar.ToDiagnosticId(), - Message = "Use 'var' instead of specifying the type name.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.AlwaysUseVar.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 17) + .WithMessage("Use 'var' instead of specifying the type name."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/ConsoleWriteLineTests.cs b/test/CSharp/CodeCracker.Test/Style/ConsoleWriteLineTests.cs index 1335bc5df..ad678d592 100644 --- a/test/CSharp/CodeCracker.Test/Style/ConsoleWriteLineTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ConsoleWriteLineTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Style; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -174,13 +175,9 @@ void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), - Message = ConsoleWriteLineAnalyzer.MessageFormat.ToString(), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(11, 17) + .WithMessage(ConsoleWriteLineAnalyzer.MessageFormat.ToString()); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -200,13 +197,9 @@ void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), - Message = ConsoleWriteLineAnalyzer.MessageFormat.ToString(), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 17) + .WithMessage(ConsoleWriteLineAnalyzer.MessageFormat.ToString()); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -404,13 +397,9 @@ void Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), - Message = ConsoleWriteLineAnalyzer.MessageFormat.ToString(), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConsoleWriteLine.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(11, 17) + .WithMessage(ConsoleWriteLineAnalyzer.MessageFormat.ToString()); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs b/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs index b82e826f1..0a968adf9 100644 --- a/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Style; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -12,13 +13,9 @@ public class ConvertLambdaExpressionToMethodGroupTests public async Task CreateDiagnosticForSimpleLambdaExpression() { const string test = @"var f = a.Where(item => filter(item));"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), - Message = "You should remove the lambda expression and pass just 'filter' instead.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 1, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(1, 17) + .WithMessage("You should remove the lambda expression and pass just 'filter' instead."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -27,13 +24,9 @@ public async Task CreateDiagnosticForSimpleLambdaExpression() public async Task CreateDiagnosticForSimpleLambdaExpressionWithBlockInBody() { const string test = @"var f = a.Where(item => { return filter(item); });"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), - Message = "You should remove the lambda expression and pass just 'filter' instead.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 1, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(1, 17) + .WithMessage("You should remove the lambda expression and pass just 'filter' instead."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -42,13 +35,9 @@ public async Task CreateDiagnosticForSimpleLambdaExpressionWithBlockInBody() public async Task CreateDiagnosticForParenthesizedLambdaExpressionWithBlockInBody() { const string test = @"var f = a.Foo((param1, param2) => { return filter(param1, param2); });"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), - Message = "You should remove the lambda expression and pass just 'filter' instead.", - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 1, 15) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertLambdaExpressionToMethodGroup.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(1, 15) + .WithMessage("You should remove the lambda expression and pass just 'filter' instead."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/ConvertToExpressionBodiedMemberTests.cs b/test/CSharp/CodeCracker.Test/Style/ConvertToExpressionBodiedMemberTests.cs index 331b8282a..ef0170df5 100644 --- a/test/CSharp/CodeCracker.Test/Style/ConvertToExpressionBodiedMemberTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ConvertToExpressionBodiedMemberTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Style; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -177,13 +178,9 @@ public async Task Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), - Message = ConvertToExpressionBodiedMemberAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 13) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(8, 13) + .WithMessage(ConvertToExpressionBodiedMemberAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -204,13 +201,9 @@ class TypeName } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), - Message = ConvertToExpressionBodiedMemberAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 13) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(8, 13) + .WithMessage(ConvertToExpressionBodiedMemberAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -231,13 +224,9 @@ public static implicit operator string(TypeName n) } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), - Message = ConvertToExpressionBodiedMemberAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 13) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(8, 13) + .WithMessage(ConvertToExpressionBodiedMemberAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -258,13 +247,9 @@ public Foo this[int id] } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), - Message = ConvertToExpressionBodiedMemberAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 13) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(8, 13) + .WithMessage(ConvertToExpressionBodiedMemberAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -285,13 +270,9 @@ public string Foo } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), - Message = ConvertToExpressionBodiedMemberAnalyzer.MessageFormat, - Severity = DiagnosticSeverity.Hidden, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 13) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToExpressionBodiedMember.ToDiagnosticId(), DiagnosticSeverity.Hidden) + .WithLocation(8, 13) + .WithMessage(ConvertToExpressionBodiedMemberAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/ConvertToSwitchTests.cs b/test/CSharp/CodeCracker.Test/Style/ConvertToSwitchTests.cs index b4fb48bf0..bcdb5d47d 100644 --- a/test/CSharp/CodeCracker.Test/Style/ConvertToSwitchTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ConvertToSwitchTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Style; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -38,13 +39,9 @@ public async Task Foo(string s) } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToSwitch.ToDiagnosticId(), - Message = "You could use 'switch' instead of 'if'.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToSwitch.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 17) + .WithMessage("You could use 'switch' instead of 'if'."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -76,13 +73,9 @@ public async Task Foo(string s) } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ConvertToSwitch.ToDiagnosticId(), - Message = "You could use 'switch' instead of 'if'.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ConvertToSwitch.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 17) + .WithMessage("You could use 'switch' instead of 'if'."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs b/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs index 129824e22..2c978823b 100644 --- a/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/EmptyObjectInitializerTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Style; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -11,13 +12,9 @@ public class EmptyObjectInitializerTests : CodeFixVerifier action = (p) => { throw new ArgumentException(""message"", ""paramName""); }; "); - var expected = new DiagnosticResult - { - Id = DiagnosticId.ArgumentException.ToDiagnosticId(), - Message = "Type argument 'paramName' is not in the argument list.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 82) } - }; + var expected = new DiagnosticResult(DiagnosticId.ArgumentException.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(9, 82) + .WithMessage("Type argument 'paramName' is not in the argument list."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs index 31de8f5c7..07d98a122 100644 --- a/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/CallExtensionMethodAsExtensionTests.cs @@ -1,6 +1,7 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -64,13 +65,9 @@ public void Bar() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), - Message = "Do not call 'Any' method of class 'Enumerable' as a static method", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 33) + .WithMessage("Do not call 'Any' method of class 'Enumerable' as a static method"); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -91,13 +88,9 @@ public void Bar() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), - Message = "Do not call 'Any' method of class 'Enumerable' as a static method", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 33) + .WithMessage("Do not call 'Any' method of class 'Enumerable' as a static method"); await VerifyCSharpDiagnosticAsync(source, expected, LanguageVersion.CSharp5); } @@ -116,13 +109,9 @@ public static class C { public static string M(this string s) => s; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), - Message = "Do not call 'M' method of class 'C' as a static method", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 9) } - }; + var expected = new DiagnosticResult(DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 9) + .WithMessage("Do not call 'M' method of class 'C' as a static method"); await VerifyCSharpDiagnosticAsync(source, expected, LanguageVersion.CSharp5); } @@ -142,13 +131,9 @@ public void Bar() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), - Message = "Do not call 'Any' method of class 'Enumerable' as a static method", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(9, 33) + .WithMessage("Do not call 'Any' method of class 'Enumerable' as a static method"); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -358,13 +343,9 @@ public void Bar() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), - Message = "Do not call 'Any' method of class 'Enumerable' as a static method", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 37) } - }; + var expected = new DiagnosticResult(DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(11, 37) + .WithMessage("Do not call 'Any' method of class 'Enumerable' as a static method"); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -383,13 +364,9 @@ public class Foo } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), - Message = "Do not call 'Any' method of class 'Enumerable' as a static method", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 51) } - }; + var expected = new DiagnosticResult(DiagnosticId.CallExtensionMethodAsExtension.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(8, 51) + .WithMessage("Do not call 'Any' method of class 'Enumerable' as a static method"); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs index 1c46e93f2..2337557a8 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -85,13 +86,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -131,20 +128,12 @@ class D : IDisposable public void Dispose() { } } }"; - var expected1 = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field1"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; - var expected2 = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field2"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 41) } - }; + var expected1 = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field1")); + var expected2 = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 41) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field2")); await VerifyCSharpDiagnosticAsync(source, expected1, expected2); } @@ -169,13 +158,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -199,13 +184,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -297,13 +278,9 @@ struct D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -328,13 +305,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -360,13 +333,9 @@ public void Dispose() { } public void Dispose(bool arg) { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -392,13 +361,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -418,13 +383,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(7, 23) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -445,13 +406,9 @@ class D : IDisposable public void Dispose() { } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - Message = string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 33) + .WithMessage(string.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index cb1437596..daad3e39a 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -157,13 +158,9 @@ public async Task IteratorWithIndirectReturnDoesNotCreateDiagnostic() public async Task DisposableVariableCreatesDiagnostic() { var source = "new System.IO.MemoryStream();".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 17) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -178,13 +175,9 @@ public async Task IgnoresDisposableObjectsCreatedWithUsingStatement() public async Task DisposableVariableDeclaredWithAnotherVariableCreatesOnlyOneDiagnostic() { var source = "System.IO.MemoryStream a, b = new System.IO.MemoryStream();".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 47) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 47) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -336,13 +329,9 @@ static void Foo() void Register(System.Action f) { } } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 34) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(7, 34) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -362,13 +351,9 @@ static void Foo() void Register(System.Action f) { } } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 32) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 32) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -388,13 +373,9 @@ static void Foo() void Register(System.Action f) { } } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 32) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 32) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -414,13 +395,9 @@ static void Foo() void Register(System.Action f) { } } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 32) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(8, 32) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -468,13 +445,9 @@ void System.IDisposable.Dispose() { } public async Task DisposableVariablePassedAsParamCreatesDiagnostic() { var source = "string.Format(\"\", new System.IO.MemoryStream());".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 35) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 35) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -483,13 +456,9 @@ public async Task DisposableVariableCallsIncorrectDisposeCreatesDiagnostic() { var source = @"var m = new System.IO.MemoryStream(); m.Dispose(true);".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 25) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -511,13 +480,9 @@ void System.IDisposable.Dispose() { } public void Dispose() { } } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "Disposable"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 33) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "Disposable")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -563,13 +528,9 @@ void System.IDisposable.Dispose() { } void IOtherDisposable.Dispose() { } } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), - Message = string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "Disposable"), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 33) + .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "Disposable")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs index 487f2b557..437626d9d 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -57,13 +58,9 @@ public void Dispose() } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), - Message = "'MyType' should call GC.SuppressFinalize inside the Dispose method.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 33) + .WithMessage("'MyType' should call GC.SuppressFinalize inside the Dispose method."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -263,13 +260,9 @@ public void Dispose() ~MyType() {} }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), - Message = "'MyType' should call GC.SuppressFinalize inside the Dispose method.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(4, 33) + .WithMessage("'MyType' should call GC.SuppressFinalize inside the Dispose method."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs index ccf94d7e4..ca83c566c 100644 --- a/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/IPAddressAnalyzerTests.cs @@ -4,6 +4,7 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -78,12 +79,9 @@ public async Task IfAbbreviateParseIdentifierFoundAndParameterIsNotStringLiteral private static DiagnosticResult CreateDiagnosticResult(int line, int column, Action getErrorMessageAction) { - return new DiagnosticResult { - Id = DiagnosticId.IPAddress.ToDiagnosticId(), - Message = GetErrorMessage(getErrorMessageAction), - Severity = DiagnosticSeverity.Error, - Locations = new[] {new DiagnosticResultLocation("Test0.cs", line, column)} - }; + return new DiagnosticResult(DiagnosticId.IPAddress.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(line, column) + .WithMessage(GetErrorMessage(getErrorMessageAction)); } private static string GetErrorMessage(Action action) diff --git a/test/CSharp/CodeCracker.Test/Usage/IfReturnTrueTests.cs b/test/CSharp/CodeCracker.Test/Usage/IfReturnTrueTests.cs index f45326646..27b4ad1f0 100644 --- a/test/CSharp/CodeCracker.Test/Usage/IfReturnTrueTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/IfReturnTrueTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -153,13 +154,9 @@ public int Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.IfReturnTrue.ToDiagnosticId(), - Message = "You should return the boolean directly.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.IfReturnTrue.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(9, 17) + .WithMessage("You should return the boolean directly."); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -186,13 +183,9 @@ public int Foo() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.IfReturnTrue.ToDiagnosticId(), - Message = "You should return the boolean directly.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 9, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.IfReturnTrue.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(9, 17) + .WithMessage("You should return the boolean directly."); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs index d94b0be0b..32b49198b 100644 --- a/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/JsonNetAnalyzerTests.cs @@ -2,6 +2,7 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -94,12 +95,9 @@ public async Task IfJArrayParseIdentifierFoundAndJsonTextIsCorrectDoesNotCreates } private static DiagnosticResult CreateDiagnosticResult(int line, int column) { - return new DiagnosticResult { - Id = DiagnosticId.JsonNet.ToDiagnosticId(), - Message = "Unexpected end when reading JSON. Path '', line 1, position 3.", - Severity = DiagnosticSeverity.Error, - Locations = new[] {new DiagnosticResultLocation("Test0.cs", line, column)} - }; + return new DiagnosticResult(DiagnosticId.JsonNet.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(line, column) + .WithMessage("Unexpected end when reading JSON. Path '', line 1, position 3."); } protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() => new JsonNetAnalyzer(); diff --git a/test/CSharp/CodeCracker.Test/Usage/NoPrivateReadonlyFieldTest.cs b/test/CSharp/CodeCracker.Test/Usage/NoPrivateReadonlyFieldTest.cs index 2c707711a..f1fb1e715 100644 --- a/test/CSharp/CodeCracker.Test/Usage/NoPrivateReadonlyFieldTest.cs +++ b/test/CSharp/CodeCracker.Test/Usage/NoPrivateReadonlyFieldTest.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Xunit; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; namespace CodeCracker.Test.CSharp.Usage { @@ -10,14 +11,12 @@ public class NoPrivateReadonlyFieldTests : CodeFixVerifier { protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() => new NoPrivateReadonlyFieldAnalyzer(); - static DiagnosticResult CreateExpectedDiagnosticResult(int line, int column, string fieldName = "i") => - new DiagnosticResult - { - Id = DiagnosticId.NoPrivateReadonlyField.ToDiagnosticId(), - Message = string.Format(NoPrivateReadonlyFieldAnalyzer.Message, fieldName), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", line, column) } - }; + static DiagnosticResult CreateExpectedDiagnosticResult(int line, int column, string fieldName = "i") + { + return new DiagnosticResult(DiagnosticId.NoPrivateReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(line, column) + .WithMessage(string.Format(NoPrivateReadonlyFieldAnalyzer.Message, fieldName)); + } [Fact] public async Task PrivateFieldWithAssignmentOnDeclarationCreatesNoDiagnostic() diff --git a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs index e49637973..8639541c5 100644 --- a/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/ReadonlyFieldTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -182,13 +183,9 @@ class TypeName private int i = 1; } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -203,13 +200,9 @@ class TypeName int i = 1; } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 17) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -225,20 +218,12 @@ class TypeName private int j = 1; } }"; - var expected1 = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; - var expected2 = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "j"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 25) } - }; + var expected1 = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); + var expected2 = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "j")); await VerifyCSharpDiagnosticAsync(source, expected1, expected2); } @@ -259,34 +244,18 @@ class TypeName2 private int l = 1; } }"; - var expected1 = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; - var expected2 = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "j"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 25) } - }; - var expected3 = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "k"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 25) } - }; - var expected4 = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "l"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 25) } - }; + var expected1 = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); + var expected2 = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(7, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "j")); + var expected3 = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(11, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "k")); + var expected4 = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(12, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "l")); await VerifyCSharpDiagnosticAsync(source, new[] { expected1, expected2, expected3, expected4 }); } @@ -304,13 +273,9 @@ class TypeName } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 8, 29) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(8, 29) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -325,13 +290,9 @@ struct TypeName private int i = 1; } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -401,13 +362,9 @@ class TypeName } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -426,13 +383,9 @@ class TypeName } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 25) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -491,13 +444,9 @@ class TypeName private int i, j = 1; } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "j"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 28) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 28) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "j")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -747,13 +696,9 @@ static TypeName() } } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 32) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 32) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -768,13 +713,9 @@ class TypeName private static int i = 1; } }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "i"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 32) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 32) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "i")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -953,13 +894,9 @@ private enum VehicleType } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "car"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 33) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "car")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -981,13 +918,9 @@ public Person(string name) } "; - var expected = new DiagnosticResult - { - Id = DiagnosticId.ReadonlyField.ToDiagnosticId(), - Message = string.Format(ReadonlyFieldAnalyzer.Message, "name"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 28) } - }; + var expected = new DiagnosticResult(DiagnosticId.ReadonlyField.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(6, 28) + .WithMessage(string.Format(ReadonlyFieldAnalyzer.Message, "name")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/RedundantFieldAssignmentTests.cs b/test/CSharp/CodeCracker.Test/Usage/RedundantFieldAssignmentTests.cs index 97caea241..f24ccfc5b 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RedundantFieldAssignmentTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RedundantFieldAssignmentTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -170,13 +171,9 @@ class TypeName { private int i = 0; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", 0), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 17) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", 0)); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -188,13 +185,9 @@ class TypeName { private int i = default(int); }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "default(int)"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 17) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "default(int)")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -206,13 +199,9 @@ class TypeName { private string s = null; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "s", "null"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 20) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 20) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "s", "null")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -224,13 +213,9 @@ class TypeName { private long i = 0L; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "0L"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 18) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 18) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "0L")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -242,13 +227,9 @@ class TypeName { private long i = 0; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "0"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 18) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 18) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "0")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -260,13 +241,9 @@ class TypeName { private System.IntPtr i = System.IntPtr.Zero; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "System.IntPtr.Zero"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 27) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 27) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "System.IntPtr.Zero")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -279,13 +256,9 @@ class TypeName { private IntPtr i = IntPtr.Zero; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "IntPtr.Zero"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 5, 20) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(5, 20) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "IntPtr.Zero")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -297,13 +270,9 @@ class TypeName { private System.UIntPtr i = System.UIntPtr.Zero; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "System.UIntPtr.Zero"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 28) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 28) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "i", "System.UIntPtr.Zero")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -315,13 +284,9 @@ class TypeName { private System.DateTime d = System.DateTime.MinValue; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "d", "System.DateTime.MinValue"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 29) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 29) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "d", "System.DateTime.MinValue")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -334,13 +299,9 @@ class TypeName { private E e = 0; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "e", "0"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 5, 15) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(5, 15) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "e", "0")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -353,13 +314,9 @@ class TypeName { private E e = 0.0; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "e", "0.0"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 5, 15) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(5, 15) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "e", "0.0")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -371,13 +328,9 @@ class TypeName { private bool b = false; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "b", "false"), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 18) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 18) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "b", "false")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -389,13 +342,9 @@ class TypeName { private int i, j, k = 0; }"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), - Message = string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "k", 0), - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, 23) } - }; + var expected = new DiagnosticResult(DiagnosticId.RedundantFieldAssignment.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(4, 23) + .WithMessage(string.Format(RedundantFieldAssignmentAnalyzer.MessageFormat, "k", 0)); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/RegexTests.cs b/test/CSharp/CodeCracker.Test/Usage/RegexTests.cs index 6ffda204c..8feee163a 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RegexTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RegexTests.cs @@ -1,6 +1,7 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using System; using System.Threading.Tasks; using Xunit; @@ -76,13 +77,9 @@ public async Task Foo() message = e.Message; } - var expected = new DiagnosticResult - { - Id = DiagnosticId.Regex.ToDiagnosticId(), - Message = message, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 64) } - }; + var expected = new DiagnosticResult(DiagnosticId.Regex.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(11, 64) + .WithMessage(message); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -116,13 +113,9 @@ public async Task Foo() message = e.Message; } - var expected = new DiagnosticResult - { - Id = DiagnosticId.Regex.ToDiagnosticId(), - Message = message, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 33) } - }; + var expected = new DiagnosticResult(DiagnosticId.Regex.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(11, 33) + .WithMessage(message); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs b/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs index 3c5383c1e..ee42e29a9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RemovePrivateMethodNeverUsedAnalyzerTest.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -427,14 +428,12 @@ public int PropertyXXX { await VerifyCSharpHasNoDiagnosticsAsync(source); } - private static DiagnosticResult CreateDiagnosticResult(int line, int column) => - new DiagnosticResult - { - Id = DiagnosticId.RemovePrivateMethodNeverUsed.ToDiagnosticId(), - Locations = new DiagnosticResultLocation[] { new DiagnosticResultLocation("Test0.cs", line, column) }, - Message = RemovePrivateMethodNeverUsedAnalyzer.Message, - Severity = DiagnosticSeverity.Info, - }; + private static DiagnosticResult CreateDiagnosticResult(int line, int column) + { + return new DiagnosticResult(DiagnosticId.RemovePrivateMethodNeverUsed.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(line, column) + .WithMessage(RemovePrivateMethodNeverUsedAnalyzer.Message); + } [Fact] public async void WinFormsPropertyDefaultValueDefinitionMethodsMustHaveCorrectSignature() diff --git a/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs b/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs index 82904f6f5..9849a0655 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -120,13 +121,9 @@ public async Task CreateDiagnosticsWhenEmptyElse() { var test = @"if(1 == 2){ return 1; } else { }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), - Message = "Remove redundant else", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 41) } - }; + var expected = new DiagnosticResult(DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 41) + .WithMessage("Remove redundant else"); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -136,13 +133,9 @@ public async Task CreateDiagnosticsWhenEmptyElseWithoutBlockOnIf() { var test = @"if(1 == 2) return 1; else { }".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), - Message = "Remove redundant else", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 38) } - }; + var expected = new DiagnosticResult(DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, 38) + .WithMessage("Remove redundant else"); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs b/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs index 4bec3f3fd..f32efd7e2 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RethrowExceptionTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -27,13 +28,9 @@ public void Foo() [Fact] public async Task WhenThrowingOriginalExceptionAnalyzerCreatesDiagnostic() { - var expected = new DiagnosticResult - { - Id = DiagnosticId.RethrowException.ToDiagnosticId(), - Message = "Throwing the same exception that was caught will lose the original stack trace.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 21) } - }; + var expected = new DiagnosticResult(DiagnosticId.RethrowException.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(12, 21) + .WithMessage("Throwing the same exception that was caught will lose the original stack trace."); await VerifyCSharpDiagnosticAsync(sourceWithUsingSystem, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs index 714e2bc3c..b1fa44b3f 100644 --- a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -31,13 +32,9 @@ public async Task WhenComparingWithBoolAnalyzerCreatesDiagnostic(string sample, column += 10; // adjust column for added declaration var test = sample.WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.SimplifyRedundantBooleanComparisons.ToDiagnosticId(), - Message = "You can remove this comparison.", - Severity = DiagnosticSeverity.Info, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, column) } - }; + var expected = new DiagnosticResult(DiagnosticId.SimplifyRedundantBooleanComparisons.ToDiagnosticId(), DiagnosticSeverity.Info) + .WithLocation(10, column) + .WithMessage("You can remove this comparison."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs index 5b6cf0257..b5ffbb6e9 100644 --- a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs @@ -3,6 +3,7 @@ using Xunit; using Microsoft.CodeAnalysis.Diagnostics; using CodeCracker.CSharp.Usage; +using Microsoft.CodeAnalysis.Testing; namespace CodeCracker.Test.CSharp.Usage { @@ -82,13 +83,9 @@ public async Task IgnoresMethodsCalledWithIncorrectParameterTypes() public async Task NoParametersCreatesError() { var source = @"var result = string.Format(""{0}"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(10, 30) + .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -96,13 +93,9 @@ public async Task NoParametersCreatesError() public async Task LessParametersCreatesError() { var source = @"var result = string.Format(""one {0} two {1}"", ""a"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(10, 30) + .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -110,13 +103,9 @@ public async Task LessParametersCreatesError() public async Task MoreArgumentsCreatesWarning() { var source = @"var result = string.Format(""one {0} two {1}"", ""a"", ""b"", ""c"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 30) + .WithMessage(StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -145,13 +134,9 @@ public async Task MethodWithParamtersReferencingSingleAndFormatSpecifiersArgumen public async Task TwoParametersReferencingSamePlaceholderCreatesWarning() { var source = @"var result = string.Format(""one {0} two {0}"", ""a"", ""b"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 30) + .WithMessage(StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -183,13 +168,9 @@ public async Task VerbatimStringWithMissingArgCreatesError() var noun = ""Giovanni""; var s = string.Format(@""This {0} is """"{1}""""."", noun);".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 25) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(12, 25) + .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -197,13 +178,9 @@ public async Task VerbatimStringWithMissingArgCreatesError() public async Task InvalidArgumentReferenceCreatesError() { var source = @"var result = string.Format(""one {1}"", ""a"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(10, 30) + .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -211,13 +188,9 @@ public async Task InvalidArgumentReferenceCreatesError() public async Task NonIntegerPlaceholderCreatesError() { var source = @"var result = string.Format(""one {notZero}"", ""a"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.InvalidArgsReferenceMessage, - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 30) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(10, 30) + .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -225,13 +198,9 @@ public async Task NonIntegerPlaceholderCreatesError() public async Task UnusedArgsCreatesWarning() { var source = @"string.Format(""{0}{1}{3}{5}"", ""a"", ""b"", ""c"", ""d"", ""e"", ""f"");".WrapInCSharpMethod(); - var expected = new DiagnosticResult - { - Id = DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), - Message = StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 10, 17) } - }; + var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(10, 17) + .WithMessage(StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage); await VerifyCSharpDiagnosticAsync(source, expected); } } diff --git a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs index 2b08add48..2bee868b0 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UnusedParametersTests.cs @@ -1,5 +1,6 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; using System.Threading.Tasks; using Xunit; @@ -330,13 +331,9 @@ await VerifyCSharpDiagnosticAsync(source, public static DiagnosticResult CreateDiagnosticResult(string parameterName, int line, int column) { - return new DiagnosticResult - { - Id = DiagnosticId.UnusedParameters.ToDiagnosticId(), - Message = string.Format(UnusedParametersAnalyzer.Message, parameterName), - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", line, column) } - }; + return new DiagnosticResult(DiagnosticId.UnusedParameters.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(line, column) + .WithMessage(string.Format(UnusedParametersAnalyzer.Message, parameterName)); } [Fact] diff --git a/test/CSharp/CodeCracker.Test/Usage/UriAnalyzerTests.cs b/test/CSharp/CodeCracker.Test/Usage/UriAnalyzerTests.cs index 8a947ea9a..e48b9a1f8 100644 --- a/test/CSharp/CodeCracker.Test/Usage/UriAnalyzerTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/UriAnalyzerTests.cs @@ -3,6 +3,7 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Usage @@ -93,13 +94,9 @@ public void Test() { private static DiagnosticResult CreateDiagnosticResult(int line, int column, Action getErrorMessageAction) { - return new DiagnosticResult - { - Id = DiagnosticId.Uri.ToDiagnosticId(), - Message = GetErrorMessage(getErrorMessageAction), - Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", line, column) } - }; + return new DiagnosticResult(DiagnosticId.Uri.ToDiagnosticId(), DiagnosticSeverity.Error) + .WithLocation(line, column) + .WithMessage(GetErrorMessage(getErrorMessageAction)); } private static string GetErrorMessage(Action action) diff --git a/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs b/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs index 6d55294df..1c3800de0 100644 --- a/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/VirtualMethodOnConstructorTests.cs @@ -2,6 +2,7 @@ using CodeCracker.CSharp.Usage; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace CodeCracker.Test.CSharp.Usage { @@ -21,12 +22,9 @@ public virtual void DoFoo(string foo) { } }"; - var expected = new DiagnosticResult { - Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), - Message = VirtualMethodOnConstructorAnalyzer.Message, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 3) } - }; + var expected = new DiagnosticResult(DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 3) + .WithMessage(VirtualMethodOnConstructorAnalyzer.Message); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -45,12 +43,9 @@ public virtual void DoFoo(string foo) { } }"; - var expected = new DiagnosticResult { - Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), - Message = VirtualMethodOnConstructorAnalyzer.Message, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 3) } - }; + var expected = new DiagnosticResult(DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 3) + .WithMessage(VirtualMethodOnConstructorAnalyzer.Message); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -110,18 +105,12 @@ public virtual void DoFoo2(string foo) { } }"; - var expected = new DiagnosticResult { - Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), - Message = VirtualMethodOnConstructorAnalyzer.Message, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 6, 3) } - }; - var expected2 = new DiagnosticResult { - Id = DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), - Message = VirtualMethodOnConstructorAnalyzer.Message, - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 3) } - }; + var expected = new DiagnosticResult(DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(6, 3) + .WithMessage(VirtualMethodOnConstructorAnalyzer.Message); + var expected2 = new DiagnosticResult(DiagnosticId.VirtualMethodOnConstructor.ToDiagnosticId(), DiagnosticSeverity.Warning) + .WithLocation(7, 3) + .WithMessage(VirtualMethodOnConstructorAnalyzer.Message); await VerifyCSharpDiagnosticAsync(test, expected, expected2); } diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index 0f296cd69..db5e82f6f 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -44,6 +44,7 @@ + @@ -53,7 +54,6 @@ - diff --git a/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticResult.cs b/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticResult.cs deleted file mode 100644 index 46d38366e..000000000 --- a/test/Common/CodeCracker.Test.Common/Helpers/DiagnosticResult.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Microsoft.CodeAnalysis; -using System; - -namespace CodeCracker.Test -{ - /// - /// Location where the diagnostic appears, as determined by path, line number, and column number. - /// - public struct DiagnosticResultLocation - { - public DiagnosticResultLocation(string path, int line, int column) - { - if (line < 0 && column < 0) - { - throw new ArgumentOutOfRangeException("At least one of line and column must be > 0"); - } - if (line < -1 || column < -1) - { - throw new ArgumentOutOfRangeException("Both line and column must be >= -1"); - } - - Path = path; - Line = line; - Column = column; - } - - public string Path { get; set; } - public int Line { get; set; } - public int Column { get; set; } - } - - /// - /// Struct that stores information about a Diagnostic appearing in a source - /// - public struct DiagnosticResult - { - private DiagnosticResultLocation[] locations; - - public DiagnosticResultLocation[] Locations - { - get - { - if (locations == null) - { - locations = new DiagnosticResultLocation[] { }; - } - return locations; - } - - set - { - locations = value; - } - } - - public DiagnosticSeverity Severity { get; set; } - - public string Id { get; set; } - - public string Message { get; set; } - - public string Path - { - get - { - return Locations.Length > 0 ? Locations[0].Path : ""; - } - } - - public int Line - { - get - { - return Locations.Length > 0 ? Locations[0].Line : -1; - } - } - - public int Column - { - get - { - return Locations.Length > 0 ? Locations[0].Column : -1; - } - } - } -} \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs b/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs index 6163123c2..d692a8e10 100644 --- a/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs +++ b/test/Common/CodeCracker.Test.Common/Verifiers/DiagnosticVerifier.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using System.Collections.Generic; using System.Linq; using System.Text; @@ -113,7 +114,8 @@ protected async Task VerifyBasicDiagnosticAsync(string[] sources, DiagnosticResu private async static Task VerifyDiagnosticsAsync(string[] sources, string language, DiagnosticAnalyzer analyzer, DiagnosticResult[] expected, LanguageVersion languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersionVB) { var diagnostics = await GetSortedDiagnosticsAsync(sources, language, analyzer, languageVersionCSharp, languageVersionVB).ConfigureAwait(true); - VerifyDiagnosticResults(diagnostics, analyzer, expected); + var defaultFilePath = language == LanguageNames.CSharp ? CSharpDefaultFilePath : VisualBasicDefaultFilePath; + VerifyDiagnosticResults(diagnostics, analyzer, defaultFilePath, expected); } @@ -124,7 +126,7 @@ private async static Task VerifyDiagnosticsAsync(string[] sources, string langua /// The Diagnostics found by the compiler after running the analyzer on the source code /// The analyzer that was being run on the sources /// Diagnsotic Results that should have appeared in the code - private static void VerifyDiagnosticResults(IEnumerable actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) + private static void VerifyDiagnosticResults(IEnumerable actualResults, DiagnosticAnalyzer analyzer, string defaultFilePath, params DiagnosticResult[] expectedResults) { var expectedCount = expectedResults.Length; var actualCount = actualResults.Count(); @@ -139,9 +141,9 @@ private static void VerifyDiagnosticResults(IEnumerable actualResult for (int i = 0; i < expectedResults.Length; i++) { var actual = actualResults.ElementAt(i); - var expected = expectedResults[i]; + var expected = expectedResults[i].WithDefaultPath(defaultFilePath); - if (expected.Line == -1 && expected.Column == -1) + if (!expected.HasLocation) { if (actual.Location != Location.None) { @@ -150,17 +152,17 @@ private static void VerifyDiagnosticResults(IEnumerable actualResult } else { - VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First()); + VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Spans.First()); var additionalLocations = actual.AdditionalLocations.ToArray(); - if (additionalLocations.Length != expected.Locations.Length - 1) + if (additionalLocations.Length != expected.Spans.Length - 1) { - Assert.True(false, $"Expected {expected.Locations.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:\r\n {FormatDiagnostics(analyzer, actual)}\r\n"); + Assert.True(false, $"Expected {expected.Spans.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:\r\n {FormatDiagnostics(analyzer, actual)}\r\n"); } for (int j = 0; j < additionalLocations.Length; ++j) { - VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); + VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Spans[j + 1]); } } @@ -182,7 +184,7 @@ private static void VerifyDiagnosticResults(IEnumerable actualResult /// The diagnostic that was found in the code /// The Location of the Diagnostic found in the code /// The DiagnosticResultLocation that should have been found - private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) + private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, FileLinePositionSpan expected) { var actualSpan = actual.GetLineSpan(); @@ -193,13 +195,13 @@ private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagno // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) - if (actualLinePosition.Line + 1 != expected.Line) - Assert.True(false, $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); + if (actualLinePosition.Line != expected.StartLinePosition.Line) + Assert.True(false, $"Expected diagnostic to be on line \"{expected.StartLinePosition.Line + 1}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) - if (actualLinePosition.Character + 1 != expected.Column) - Assert.True(false, $"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); + if (actualLinePosition.Character != expected.StartLinePosition.Character) + Assert.True(false, $"Expected diagnostic to start at column \"{expected.StartLinePosition.Character + 1}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } /// diff --git a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj index e27355417..7f18764a2 100644 --- a/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj +++ b/test/VisualBasic/CodeCracker.Test/CodeCracker.Test.vbproj @@ -60,7 +60,7 @@ - + diff --git a/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb b/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb index 641b65c8e..f5b70fa98 100644 --- a/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Design/NameOfTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Design +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Design @@ -591,13 +592,9 @@ End Class" End Function Private Function CreateNameofDiagnosticResult(nameofArgument As String, diagnosticLine As Integer, diagnosticColumn As Integer, Optional id As DiagnosticId = DiagnosticId.NameOf) As DiagnosticResult - Return New DiagnosticResult With - { - .Id = id.ToDiagnosticId(), - .Message = $"Use 'NameOf({nameofArgument})' instead of specifying the program element name.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", diagnosticLine, diagnosticColumn)} - } + Return New DiagnosticResult(id.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(diagnosticLine, diagnosticColumn) _ + .WithMessage($"Use 'NameOf({nameofArgument})' instead of specifying the program element name.") End Function End Class End Namespace \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/Design/StaticConstructorExceptionTests.vb b/test/VisualBasic/CodeCracker.Test/Design/StaticConstructorExceptionTests.vb index 9501ea066..de4131a19 100644 --- a/test/VisualBasic/CodeCracker.Test/Design/StaticConstructorExceptionTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Design/StaticConstructorExceptionTests.vb @@ -1,5 +1,6 @@ Imports CodeCracker.VisualBasic.Design Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Testing Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.IO @@ -18,12 +19,9 @@ Public Class TestClass End Sub End Class" - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.StaticConstructorException.ToDiagnosticId(), - .Message = "Don't throw exceptions inside static constructors.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 4, 9)} - } + Dim expected = New DiagnosticResult(DiagnosticId.StaticConstructorException.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(4, 9) _ + .WithMessage("Don't throw exceptions inside static constructors.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.vb b/test/VisualBasic/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.vb index b1f8d1987..aca8cb0da 100644 --- a/test/VisualBasic/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.vb @@ -1,5 +1,6 @@ Imports CodeCracker.VisualBasic.Performance Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Performance @@ -39,39 +40,27 @@ Namespace Performance Public Async Function CreateDiagnosticsWhenAssigningAPotentialConstant() As Task Dim test = "Dim a As Integer = 10".WrapInVBMethod() - Dim expected = New DiagnosticResult With - { - .Id = MakeLocalVariableConstWhenPossibleAnalyzer.Id, - .Message = "This variable can be made const.", - .Severity = DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 13)} - } + Dim expected = New DiagnosticResult(MakeLocalVariableConstWhenPossibleAnalyzer.Id, DiagnosticSeverity.Info) _ + .WithLocation(6, 13) _ + .WithMessage("This variable can be made const.") Await VerifyBasicDiagnosticAsync(test, expected) End Function Public Async Function CreateDiagnosticsWhenAssigningAPotentialConstantUsingTypeInference() As Task Dim test = "Dim a = 10".WrapInVBMethod() - Dim expected = New DiagnosticResult With - { - .Id = MakeLocalVariableConstWhenPossibleAnalyzer.Id, - .Message = "This variable can be made const.", - .Severity = DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 13)} - } + Dim expected = New DiagnosticResult(MakeLocalVariableConstWhenPossibleAnalyzer.Id, DiagnosticSeverity.Info) _ + .WithLocation(6, 13) _ + .WithMessage("This variable can be made const.") Await VerifyBasicDiagnosticAsync(test, expected) End Function Public Async Function CreateDiagnosticsWhenAssigningNothingToAReferenceType() As Task Dim test = "Dim a As Foo = Nothing".WrapInVBMethod() - Dim expected = New DiagnosticResult With - { - .Id = MakeLocalVariableConstWhenPossibleAnalyzer.Id, - .Message = "This variable can be made const.", - .Severity = DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 13)} - } + Dim expected = New DiagnosticResult(MakeLocalVariableConstWhenPossibleAnalyzer.Id, DiagnosticSeverity.Info) _ + .WithLocation(6, 13) _ + .WithMessage("This variable can be made const.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.vb b/test/VisualBasic/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.vb index ce396c0d5..e4176f42e 100644 --- a/test/VisualBasic/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Performance +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Performance @@ -26,13 +27,9 @@ Namespace Sample End Class End Namespace" - Dim expected = New DiagnosticResult With - { - .Id = RemoveWhereWhenItIsPossibleAnalyzer.Id, - .Message = "You can remove 'Where' moving the predicate to '" + method + "'.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 7, 23)} - } + Dim expected = New DiagnosticResult(RemoveWhereWhenItIsPossibleAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(7, 23) _ + .WithMessage("You can remove 'Where' moving the predicate to '" + method + "'.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Performance/SealedAttributeTests.vb b/test/VisualBasic/CodeCracker.Test/Performance/SealedAttributeTests.vb index ec0f627bb..23c231e93 100644 --- a/test/VisualBasic/CodeCracker.Test/Performance/SealedAttributeTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Performance/SealedAttributeTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Performance +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Performance @@ -12,13 +13,9 @@ Public Class MyAttribute Inherits System.Attribute End Class" - Dim expected = New DiagnosticResult With - { - .Id = SealedAttributeAnalyzer.Id, - .Message = "Mark 'MyAttribute' as NotInheritable.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 2, 14)} - } + Dim expected = New DiagnosticResult(SealedAttributeAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(2, 14) _ + .WithMessage("Mark 'MyAttribute' as NotInheritable.") Await VerifyBasicDiagnosticAsync(test, expected) @@ -35,13 +32,9 @@ Public Class OtherAttribute Inherits MyAttribute End Class" - Dim expected = New DiagnosticResult With - { - .Id = SealedAttributeAnalyzer.Id, - .Message = "Mark 'OtherAttribute' as NotInheritable.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 14)} - } + Dim expected = New DiagnosticResult(SealedAttributeAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(6, 14) _ + .WithMessage("Mark 'OtherAttribute' as NotInheritable.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb b/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb index 02db187a8..01d6f79a7 100644 --- a/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Performance/StringBuilderInLoopTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Performance +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Performance @@ -75,19 +76,16 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As DiagnosticResult = GetExpected() - expected.Locations(0).Line = 7 - expected.Locations(0).Column = 17 + Dim expected = New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(7, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a")) Await VerifyBasicDiagnosticAsync(source, expected) End Function Private Shared Function GetExpected() As DiagnosticResult - Return New DiagnosticResult With { - .Id = StringBuilderInLoopAnalyzer.Id, - .Message = String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 9, 17)} - } + Return New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(9, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a")) End Function @@ -116,9 +114,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As DiagnosticResult = GetExpected() - expected.Locations(0).Line = 7 - expected.Locations(0).Column = 17 + Dim expected = New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(7, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -134,19 +132,12 @@ End Namespace" Console.WriteLine(myString2) ".WrapInVBMethod() - Dim expected1 As New DiagnosticResult With { - .Id = StringBuilderInLoopAnalyzer.Id, - .Message = String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 10, 17)} - } - - Dim expected2 As New DiagnosticResult With { - .Id = StringBuilderInLoopAnalyzer.Id, - .Message = String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString2"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 11, 17)} - } + Dim expected1 = New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(10, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a")) + Dim expected2 = New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(11, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "myString2")) Await VerifyBasicDiagnosticAsync(source, expected1, expected2) End Function @@ -392,13 +383,9 @@ End Namespace" a += """" Next".WrapInVBMethod - Dim expected As New DiagnosticResult With - { - .Id = StringBuilderInLoopAnalyzer.Id, - .Message = String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 9, 17)} - } + Dim expected = New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(9, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -430,13 +417,9 @@ End Namespace" Loop Until DateTime.Now.Second Mod 2 = 0 ".WrapInVBMethod - Dim expected As New DiagnosticResult With - { - .Id = StringBuilderInLoopAnalyzer.Id, - .Message = String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 9, 17)} - } + Dim expected = New DiagnosticResult(StringBuilderInLoopAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(9, 17) _ + .WithMessage(String.Format(StringBuilderInLoopAnalyzer.MessageFormat, "a")) Await VerifyBasicDiagnosticAsync(source, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.vb b/test/VisualBasic/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.vb index c4ad336f1..2d65a860e 100644 --- a/test/VisualBasic/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Refactoring/AllowMembersOrderingAnalyzerTests.vb @@ -1,6 +1,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports CodeCracker.VisualBasic.Refactoring Imports Xunit +Imports Microsoft.CodeAnalysis.Testing Namespace Refactoring Public Class AllowMembersOrderingAnalyzerTests @@ -43,12 +44,9 @@ End {0}", typeDeclaration) End Sub End {0}", typeDeclaration) - Dim expected = New DiagnosticResult With { - .Id = AllowMembersOrderingAnalyzer.Id, - .Message = AllowMembersOrderingAnalyzer.MessageFormat, - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Hidden, - .Locations = {New DiagnosticResultLocation("Test0.vb", 2, 14 + typeDeclaration.Length)} - } + Dim expected = New DiagnosticResult(AllowMembersOrderingAnalyzer.Id, Microsoft.CodeAnalysis.DiagnosticSeverity.Hidden) _ + .WithLocation(2, 14 + typeDeclaration.Length) _ + .WithMessage(AllowMembersOrderingAnalyzer.MessageFormat) Await VerifyBasicDiagnosticAsync(test, expected) End Function End Class diff --git a/test/VisualBasic/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.vb b/test/VisualBasic/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.vb index feb3b99d3..64856acaf 100644 --- a/test/VisualBasic/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Refactoring/ChangeAnyToAllTests.vb @@ -1,5 +1,6 @@ Imports CodeCracker.VisualBasic.Refactoring Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Testing Imports System.Threading.Tasks Imports Xunit @@ -29,12 +30,9 @@ Namespace Refactoring Public Async Function AnyAndAllWithLinqCreatesDiagnostic(code As String, column As Integer, diagnosticId As DiagnosticId) As Task Dim source = code.WrapInVBMethod(imports:=" Imports System.Linq") - Dim expected = New DiagnosticResult With { - .Id = diagnosticId.ToDiagnosticId(), - .Message = If(diagnosticId = DiagnosticId.ChangeAnyToAll, ChangeAnyToAllAnalyzer.MessageAny, ChangeAnyToAllAnalyzer.MessageAll), - .Severity = DiagnosticSeverity.Hidden, - .Locations = {New DiagnosticResultLocation("Test0.vb", 9, column)} - } + Dim expected = New DiagnosticResult(diagnosticId.ToDiagnosticId(), DiagnosticSeverity.Hidden) _ + .WithLocation(9, column) _ + .WithMessage(If(diagnosticId = DiagnosticId.ChangeAnyToAll, ChangeAnyToAllAnalyzer.MessageAny, ChangeAnyToAllAnalyzer.MessageAll)) Await VerifyBasicDiagnosticAsync(source, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.vb b/test/VisualBasic/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.vb index f98bc3847..7c03192f9 100644 --- a/test/VisualBasic/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Reliability +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Reliability @@ -14,12 +15,9 @@ Namespace Reliability Public Async Function WhenAwaitingTaskAnalyzerCreatesDiagnostic(sample As String, column As Integer) As Task Dim test = sample.WrapInVBMethod(isAsync:=True) - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.UseConfigureAwaitFalse.ToDiagnosticId(), - .Message = "Consider using ConfigureAwait(False) on the awaited task.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Hidden, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, column)} - } + Dim expected = New DiagnosticResult(DiagnosticId.UseConfigureAwaitFalse.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Hidden) _ + .WithLocation(6, column) _ + .WithMessage("Consider using ConfigureAwait(False) on the awaited task.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Style/InterfaceNameTests.vb b/test/VisualBasic/CodeCracker.Test/Style/InterfaceNameTests.vb index 28adafc53..0c61b24b8 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/InterfaceNameTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/InterfaceNameTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Style +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Style @@ -23,12 +24,9 @@ End Namespace" End Interface End Namespace" - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.InterfaceName.ToDiagnosticId(), - .Message = InterfaceNameAnalyzer.MessageFormat, - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 2, 5)} - } + Dim expected = New DiagnosticResult(DiagnosticId.InterfaceName.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(2, 5) _ + .WithMessage(InterfaceNameAnalyzer.MessageFormat) Await VerifyBasicDiagnosticAsync(source, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb index 4e1c8a3a2..0a956c38a 100644 --- a/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Style/TernaryOperatorTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Style +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Style @@ -144,12 +145,9 @@ End Namespace" Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task - Dim expected As New DiagnosticResult With { - .Id = DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), - .Message = "You can use a ternary operator.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 8, 13)} - } + Dim expected = New DiagnosticResult(DiagnosticId.TernaryOperator_Assignment.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(8, 13) _ + .WithMessage("You can use a ternary operator.") Await VerifyBasicDiagnosticAsync(sourceAssign, expected) End Function @@ -793,12 +791,9 @@ End Namespace" Public Async Function WhenUsingIfAndElseWithDirectReturnAnalyzerCreatesDiagnostic() As Task - Dim expected As New DiagnosticResult With { - .Id = DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), - .Message = "You can use a ternary operator.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 13)} - } + Dim expected = New DiagnosticResult(DiagnosticId.TernaryOperator_Return.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(6, 13) _ + .WithMessage("You can use a ternary operator.") Await VerifyBasicDiagnosticAsync(sourceReturn, expected) End Function @@ -1005,12 +1000,9 @@ Class MyType End Function End Class" - Dim expected As New DiagnosticResult With { - .Id = DiagnosticId.TernaryOperator_Iif.ToDiagnosticId(), - .Message = "You can use a ternary operator.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 16)} - } + Dim expected = New DiagnosticResult(DiagnosticId.TernaryOperator_Iif.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(5, 16) _ + .WithMessage("You can use a ternary operator.") Await VerifyBasicDiagnosticAsync(source, expected) Await VerifyBasicFixAsync(source, fix) diff --git a/test/VisualBasic/CodeCracker.Test/Usage/ArgumentExceptionTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/ArgumentExceptionTests.vb index 681fe9584..b2ac9db8d 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/ArgumentExceptionTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/ArgumentExceptionTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Usage +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -24,12 +25,9 @@ Public Async Function Foo(a As Integer, b As Integer) As Task End Function ") - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.ArgumentException.ToDiagnosticId(), - .Message = "Type argument 'c' is not in the argument list.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 8, 44)} - } + Dim expected = New DiagnosticResult(DiagnosticId.ArgumentException.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(8, 44) _ + .WithMessage("Type argument 'c' is not in the argument list.") Await VerifyBasicDiagnosticAsync(test, expected) End Function @@ -42,12 +40,9 @@ Public Sub New(a As Integer, b As Integer) End Sub ") - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.ArgumentException.ToDiagnosticId(), - .Message = "Type argument 'c' is not in the argument list.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 8, 44)} - } + Dim expected = New DiagnosticResult(DiagnosticId.ArgumentException.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(8, 44) _ + .WithMessage("Type argument 'c' is not in the argument list.") Await VerifyBasicDiagnosticAsync(test, expected) End Function @@ -147,12 +142,9 @@ End Sub End Set End Property ") - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.ArgumentException.ToDiagnosticId(), - .Message = "Type argument 'paramName' is not in the argument list.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 11, 56)} - } + Dim expected = New DiagnosticResult(DiagnosticId.ArgumentException.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(11, 56) _ + .WithMessage("Type argument 'paramName' is not in the argument list.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.vb index ad742040d..f1f583c6d 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/DisposableFieldNotDisposedTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Usage +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -35,13 +36,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(5, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -83,20 +80,12 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 17)} - } - Dim expected2 As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field2"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(5, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) + Dim expected2 = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(6, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field2")) Await VerifyBasicDiagnosticAsync(source, expected, expected2) End Function @@ -122,13 +111,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(5, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -154,13 +139,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(6, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -208,13 +189,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 7, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(7, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -240,13 +217,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 8, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(8, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -273,13 +246,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(6, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -307,13 +276,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 6, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(6, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -334,13 +299,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Created.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(5, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function @@ -361,13 +322,9 @@ Namespace ConsoleApplication1 End Class End Namespace" - Dim expected As New DiagnosticResult With - { - .Id = DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), - .Message = String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field"), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 17)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposableFieldNotDisposed_Returned.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Info) _ + .WithLocation(5, 17) _ + .WithMessage(String.Format(DisposableFieldNotDisposedAnalyzer.MessageFormat, "field")) Await VerifyBasicDiagnosticAsync(source, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.vb index ecdd57888..89ea62f97 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/DisposablesShouldCallSuppressFinalizeTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Usage +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -15,12 +16,9 @@ Public Class MyType End Sub End Class " - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), - .Message = "'MyType' should call GC.SuppressFinalize inside the Dispose method.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 16)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(5, 16) _ + .WithMessage("'MyType' should call GC.SuppressFinalize inside the Dispose method.") Await VerifyBasicDiagnosticAsync(test, expected) End Function @@ -109,12 +107,9 @@ Public NotInheritable Class MyType End Class " - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), - .Message = "'MyType' should call GC.SuppressFinalize inside the Dispose method.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 5, 16)} - } + Dim expected = New DiagnosticResult(DiagnosticId.DisposablesShouldCallSuppressFinalize.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(5, 16) _ + .WithMessage("'MyType' should call GC.SuppressFinalize inside the Dispose method.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Usage/IPAddressAnalyzerTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/IPAddressAnalyzerTests.vb index c2c4a62cf..83b260e86 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/IPAddressAnalyzerTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/IPAddressAnalyzerTests.vb @@ -2,6 +2,7 @@ Imports CodeCracker.VisualBasic Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Public Class IPAddressAnalyzerTests @@ -53,11 +54,9 @@ End Namespace" End Function Private Function CreateDiagnosticResult(line As Integer, column As Integer, errorMessageAction As Action) As DiagnosticResult - Return New DiagnosticResult With { - .Id = DiagnosticId.IPAddress.ToDiagnosticId(), - .Message = GetErrorMessage(errorMessageAction), - .Severity = DiagnosticSeverity.Error, - .Locations = {New DiagnosticResultLocation("Test0.vb", line, column)}} + Return New DiagnosticResult(DiagnosticId.IPAddress.ToDiagnosticId(), DiagnosticSeverity.Error) _ + .WithLocation(line, column) _ + .WithMessage(GetErrorMessage(errorMessageAction)) End Function Private Shared Function GetErrorMessage(action As Action) As String diff --git a/test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb index a1b921ef7..6b573b250 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/JsonNetAnalyzerTests.vb @@ -1,5 +1,6 @@ Imports CodeCracker.VisualBasic.Usage Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -19,12 +20,9 @@ Namespace ConsoleApplication1 End Namespace" Private Shared Function CreateDiagnosticResult(line As Integer, column As Integer) As DiagnosticResult - Return New DiagnosticResult With { - .Id = DiagnosticId.JsonNet.ToDiagnosticId(), - .Message = "Unexpected end when reading JSON. Path '', line 1, position 3.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Error, - .Locations = {New DiagnosticResultLocation("Test0.vb", line, column)} - } + Return New DiagnosticResult(DiagnosticId.JsonNet.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Error) _ + .WithLocation(line, column) _ + .WithMessage("Unexpected end when reading JSON. Path '', line 1, position 3.") End Function Protected Overrides Function GetDiagnosticAnalyzer() As DiagnosticAnalyzer diff --git a/test/VisualBasic/CodeCracker.Test/Usage/MustInheritClassShouldNotHavePublicConstructorTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/MustInheritClassShouldNotHavePublicConstructorTests.vb index 30093ff9e..3ec7ccf1e 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/MustInheritClassShouldNotHavePublicConstructorTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/MustInheritClassShouldNotHavePublicConstructorTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Usage +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -14,12 +15,9 @@ MustInherit Class Foo End Sub End Class" - Dim expected = New DiagnosticResult With { - .Id = DiagnosticId.AbstractClassShouldNotHavePublicCtors.ToDiagnosticId(), - .Message = "Constructor should not be public.", - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", 3, 5)} - } + Dim expected = New DiagnosticResult(DiagnosticId.AbstractClassShouldNotHavePublicCtors.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(3, 5) _ + .WithMessage("Constructor should not be public.") Await VerifyBasicDiagnosticAsync(test, expected) End Function diff --git a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb index e6c044c9c..1031f3a59 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/UnusedParametersTests.vb @@ -1,4 +1,5 @@ Imports CodeCracker.VisualBasic.Usage +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -704,12 +705,9 @@ End Class" End Function Private Function CreateDiagnosticResult(parameterName As String, line As Integer, column As Integer) As DiagnosticResult - Return New DiagnosticResult With { - .Id = DiagnosticId.UnusedParameters.ToDiagnosticId(), - .Message = String.Format(UnusedParametersAnalyzer.Message, parameterName), - .Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning, - .Locations = {New DiagnosticResultLocation("Test0.vb", line, column)} - } + Return New DiagnosticResult(DiagnosticId.UnusedParameters.ToDiagnosticId(), Microsoft.CodeAnalysis.DiagnosticSeverity.Warning) _ + .WithLocation(line, column) _ + .WithMessage(String.Format(UnusedParametersAnalyzer.Message, parameterName)) End Function End Class End Namespace \ No newline at end of file diff --git a/test/VisualBasic/CodeCracker.Test/Usage/UriAnalyzerTests.vb b/test/VisualBasic/CodeCracker.Test/Usage/UriAnalyzerTests.vb index 92978725d..bb54fcd57 100644 --- a/test/VisualBasic/CodeCracker.Test/Usage/UriAnalyzerTests.vb +++ b/test/VisualBasic/CodeCracker.Test/Usage/UriAnalyzerTests.vb @@ -1,6 +1,7 @@ Imports CodeCracker.VisualBasic.Usage Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Testing Imports Xunit Namespace Usage @@ -78,12 +79,9 @@ End Namespace" End Function Private Shared Function CreateDiagnosticResult(line As Integer, column As Integer, getErrorMessageAction As Action) As DiagnosticResult - Return New DiagnosticResult() With { - .Id = DiagnosticId.Uri.ToDiagnosticId(), - .Message = GetErrorMessage(getErrorMessageAction), - .Severity = DiagnosticSeverity.[Error], - .Locations = New DiagnosticResultLocation() {New DiagnosticResultLocation("Test0.vb", line, column)} - } + Return New DiagnosticResult(DiagnosticId.Uri.ToDiagnosticId(), DiagnosticSeverity.Error) _ + .WithLocation(line, column) _ + .WithMessage(GetErrorMessage(getErrorMessageAction)) End Function Private Shared Function GetErrorMessage(action As Action) As String From 9a6b8fe89672d2cc5f423d313a7eccc6d170e5d4 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Sun, 9 Sep 2018 23:55:08 -0500 Subject: [PATCH 329/358] Add verifier helpers for testing --- .../CSharpCodeFixVerifier`2+Test.cs | 33 +++++++++++++ .../CSharpCodeFixVerifier`2.cs | 49 +++++++++++++++++++ .../CodeCracker.Test.Common.csproj | 6 +++ .../CodeCracker.Test.Common/EmptyAnalyzer.cs | 17 +++++++ .../VisualBasicCodeFixVerifier`2+Test.cs | 33 +++++++++++++ .../VisualBasicCodeFixVerifier`2.cs | 49 +++++++++++++++++++ 6 files changed, 187 insertions(+) create mode 100644 test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2+Test.cs create mode 100644 test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2.cs create mode 100644 test/Common/CodeCracker.Test.Common/EmptyAnalyzer.cs create mode 100644 test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2+Test.cs create mode 100644 test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2.cs diff --git a/test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2+Test.cs b/test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2+Test.cs new file mode 100644 index 000000000..00993b8c5 --- /dev/null +++ b/test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2+Test.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace CodeCracker.Test +{ + public static partial class CSharpCodeFixVerifier + { + public class Test : CodeFixTest + { + public override string Language => LanguageNames.CSharp; + + protected override string DefaultFileExt => "cs"; + + protected override CompilationOptions CreateCompilationOptions() + => new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true); + + protected override IEnumerable GetDiagnosticAnalyzers() + { + yield return new TAnalyzer(); + } + + protected override IEnumerable GetCodeFixProviders() + { + yield return new TCodeFix(); + } + } + } +} diff --git a/test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2.cs b/test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2.cs new file mode 100644 index 000000000..7e64e1b0c --- /dev/null +++ b/test/Common/CodeCracker.Test.Common/CSharpCodeFixVerifier`2.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace CodeCracker.Test +{ + public static partial class CSharpCodeFixVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : CodeFixProvider, new() + { + public static DiagnosticResult Diagnostic() + => CSharpCodeFixVerifier.Diagnostic(); + + public static DiagnosticResult Diagnostic(string diagnosticId) + => CSharpCodeFixVerifier.Diagnostic(diagnosticId); + + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => new DiagnosticResult(descriptor); + + public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test { TestCode = source }; + test.ExpectedDiagnostics.AddRange(expected); + return test.RunAsync(); + } + + public static Task VerifyCodeFixAsync(string source, string fixedSource) + => VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); + + public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) + => VerifyCodeFixAsync(source, new[] { expected }, fixedSource); + + public static Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) + { + var test = new Test + { + TestCode = source, + FixedCode = fixedSource, + }; + + test.ExpectedDiagnostics.AddRange(expected); + return test.RunAsync(); + } + } +} diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index db5e82f6f..ee17f57f6 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -45,6 +45,7 @@ + @@ -52,6 +53,9 @@ + + + @@ -59,6 +63,8 @@ + + \ No newline at end of file diff --git a/test/Common/CodeCracker.Test.Common/EmptyAnalyzer.cs b/test/Common/CodeCracker.Test.Common/EmptyAnalyzer.cs new file mode 100644 index 000000000..0d1f5200e --- /dev/null +++ b/test/Common/CodeCracker.Test.Common/EmptyAnalyzer.cs @@ -0,0 +1,17 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace CodeCracker.Test +{ + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public class EmptyAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics + => ImmutableArray.Empty; + + public override void Initialize(AnalysisContext context) + { + } + } +} diff --git a/test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2+Test.cs b/test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2+Test.cs new file mode 100644 index 000000000..f41652de3 --- /dev/null +++ b/test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2+Test.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic; + +namespace CodeCracker.Test +{ + public static partial class VisualBasicCodeFixVerifier + { + public class Test : CodeFixTest + { + public override string Language => LanguageNames.VisualBasic; + + protected override string DefaultFileExt => "vb"; + + protected override CompilationOptions CreateCompilationOptions() + => new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + + protected override IEnumerable GetDiagnosticAnalyzers() + { + yield return new TAnalyzer(); + } + + protected override IEnumerable GetCodeFixProviders() + { + yield return new TCodeFix(); + } + } + } +} diff --git a/test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2.cs b/test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2.cs new file mode 100644 index 000000000..76964fad3 --- /dev/null +++ b/test/Common/CodeCracker.Test.Common/VisualBasicCodeFixVerifier`2.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic.Testing; + +namespace CodeCracker.Test +{ + public static partial class VisualBasicCodeFixVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : CodeFixProvider, new() + { + public static DiagnosticResult Diagnostic() + => VisualBasicCodeFixVerifier.Diagnostic(); + + public static DiagnosticResult Diagnostic(string diagnosticId) + => VisualBasicCodeFixVerifier.Diagnostic(diagnosticId); + + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => new DiagnosticResult(descriptor); + + public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test { TestCode = source }; + test.ExpectedDiagnostics.AddRange(expected); + return test.RunAsync(); + } + + public static Task VerifyCodeFixAsync(string source, string fixedSource) + => VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); + + public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) + => VerifyCodeFixAsync(source, new[] { expected }, fixedSource); + + public static Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) + { + var test = new Test + { + TestCode = source, + FixedCode = fixedSource, + }; + + test.ExpectedDiagnostics.AddRange(expected); + return test.RunAsync(); + } + } +} From 415d5e9409e2ef5b0e383824f33ec3cf9c0698e0 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 10 Sep 2018 00:34:29 -0500 Subject: [PATCH 330/358] Convert CatchEmptyTests to the new test library --- .../Design/CatchEmptyTests.cs | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs b/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs index 7dd1728bc..cd1582067 100644 --- a/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/CatchEmptyTests.cs @@ -1,12 +1,13 @@ -using CodeCracker.CSharp.Design; -using System.Threading.Tasks; +using System.Threading.Tasks; +using CodeCracker.CSharp.Design; using Xunit; namespace CodeCracker.Test.CSharp.Design { - public class CatchEmptyTests : CodeFixVerifier - { + using Verify = CSharpCodeFixVerifier; + public class CatchEmptyTests + { [Fact] public async Task CatchEmptyAnalyserCreateDiagnostic() { @@ -17,7 +18,7 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public async {|CS0246:Task|} {|CS0161:{|CS1983:Foo|}|}() { try { @@ -31,7 +32,7 @@ public async Task Foo() } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + await Verify.VerifyAnalyzerAsync(source); } [Fact] @@ -44,7 +45,7 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public async {|CS0246:Task|} {|CS0161:{|CS1983:Foo|}|}() { try { @@ -57,7 +58,7 @@ public async Task Foo() } } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + await Verify.VerifyAnalyzerAsync(source); } [Fact] @@ -87,7 +88,7 @@ public void Foo() } } }"; - await VerifyCSharpHasNoDiagnosticsAsync(source); + await Verify.VerifyAnalyzerAsync(source); } [Fact] public async Task NotAllowedToReturnOutOfEmtpyCatchBlock() @@ -106,13 +107,13 @@ public void Foo() { // do something } - catch + [|catch { if (x == 1) throw; else return; - } + }|] } } }"; @@ -129,19 +130,19 @@ public void Foo() { try { - // do something - } - catch (Exception ex) - { - if (x == 1) - throw; - else - return; + // do something } + catch (Exception ex) + { + if (x == 1) + throw; + else + return; } } + } }"; - await VerifyCSharpFixAsync(test, fixtest, 0, allowNewCompilerDiagnostics: true); + await Verify.VerifyCodeFixAsync(test, fixtest); } [Fact] public async Task WhenFindCatchEmptyThenPutExceptionClass() @@ -159,10 +160,10 @@ public void Foo() { // do something } - catch + [|catch { int x = 0; - } + }|] } } }"; @@ -180,14 +181,14 @@ public void Foo() { // do something } - catch (Exception ex) - { - int x = 0; - } + catch (Exception ex) + { + int x = 0; } } + } }"; - await VerifyCSharpFixAsync(test, fixtest, 0, allowNewCompilerDiagnostics: true); + await Verify.VerifyCodeFixAsync(test, fixtest); } [Fact] public async Task AddCatchEvenIfThereIsReturnInBlock() @@ -205,11 +206,11 @@ public void Foo() { // do something } - catch + [|catch { int x = 0; return; - } + }|] } } }"; @@ -227,15 +228,15 @@ public void Foo() { // do something } - catch (Exception ex) - { - int x = 0; - return; - } + catch (Exception ex) + { + int x = 0; + return; } } + } }"; - await VerifyCSharpFixAsync(test, fixtest, 0, allowNewCompilerDiagnostics: true); + await Verify.VerifyCodeFixAsync(test, fixtest); } } } \ No newline at end of file From b50066614aa98a8813d3f79594469c6581a457c9 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 10 Sep 2018 00:50:01 -0500 Subject: [PATCH 331/358] Convert EmptyCatchBlockTests to the new test library --- .../Design/EmptyCatchBlockTests.cs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs b/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs index 0ecab7be1..87ea33784 100644 --- a/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/EmptyCatchBlockTests.cs @@ -4,7 +4,9 @@ namespace CodeCracker.Test.CSharp.Design { - public class EmptyCatchBlockTests : CodeFixVerifier + using Verify = CSharpCodeFixVerifier; + + public class EmptyCatchBlockTests { readonly string test = @" using System; @@ -20,9 +22,9 @@ public async Task Foo() { // do something } - catch + [|catch { - } + }|] } } }"; @@ -36,7 +38,7 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public async {|CS0246:Task|} {|CS0161:{|CS1983:Foo|}|}() { try { @@ -49,7 +51,7 @@ public async Task Foo() } } }"; - await VerifyCSharpHasNoDiagnosticsAsync(test); + await Verify.VerifyAnalyzerAsync(test); } [Fact] @@ -72,7 +74,7 @@ public async Task Foo() } } }"; - await VerifyCSharpFixAsync(test, fixtest, 0, allowNewCompilerDiagnostics: false, formatBeforeCompare: true); + await Verify.VerifyCodeFixAsync(test, fixtest); } [Fact] @@ -88,15 +90,20 @@ class TypeName { public async Task Foo() { - { - // do something - } - //TODO: Consider reading MSDN Documentation about how to use Try...Catch => http://msdn.microsoft.com/en-us/library/0yd65esw.aspx + { + // do something } + //TODO: Consider reading MSDN Documentation about how to use Try...Catch => http://msdn.microsoft.com/en-us/library/0yd65esw.aspx + } } }"; - await VerifyCSharpFixAsync(test, fixtest, 1, allowNewCompilerDiagnostics: false, formatBeforeCompare: true); + await new Verify.Test + { + TestCode = test, + FixedCode = fixtest, + CodeFixIndex = 1, + }.RunAsync(); } [Fact] @@ -116,14 +123,19 @@ public async Task Foo() { // do something } - catch (Exception ex) - { - throw; - } + catch (Exception ex) + { + throw; } } + } }"; - await VerifyCSharpFixAsync(test, fixtest, 2, allowNewCompilerDiagnostics: true, formatBeforeCompare: true); + await new Verify.Test + { + TestCode = test, + FixedCode = fixtest, + CodeFixIndex = 2, + }.RunAsync(); } @@ -137,16 +149,16 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public async {|CS0246:Task|} {|CS0161:{|CS1983:Foo|}|}() { int x; try { // do something } - catch (System.ArgumentException ae) + [|catch (System.ArgumentException ae) { - } + }|] catch (System.Exception ex) { x = 1; @@ -162,7 +174,7 @@ namespace ConsoleApplication1 { class TypeName { - public async Task Foo() + public async {|CS0246:Task|} {|CS0161:{|CS1983:Foo|}|}() { int x; try @@ -176,7 +188,7 @@ public async Task Foo() } } }"; - await VerifyCSharpFixAsync(test, fixtest, 0); + await Verify.VerifyCodeFixAsync(test, fixtest); } } } \ No newline at end of file From eba2e8d68bbdf5e07167ff1fce35d4484668ac30 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 10 Sep 2018 01:02:38 -0500 Subject: [PATCH 332/358] Convert InconsistentAccessibilityTests to the new test library --- ...entAccessibilityTests.FieldPropertyType.cs | 25 ++++--- ...cessibilityTests.MethodIndexerParameter.cs | 71 +++++++++---------- ...essibilityTests.MethodIndexerReturnType.cs | 21 +++--- 3 files changed, 61 insertions(+), 56 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.FieldPropertyType.cs b/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.FieldPropertyType.cs index f90adea3e..b7d198c6d 100644 --- a/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.FieldPropertyType.cs +++ b/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.FieldPropertyType.cs @@ -1,16 +1,19 @@ using System.Threading.Tasks; +using CodeCracker.CSharp.Design.InconsistentAccessibility; using Xunit; namespace CodeCracker.Test.CSharp.Design { - public partial class InconsistentAccessibilityTests : CodeFixVerifier + using Verify = CSharpCodeFixVerifier; + + public partial class InconsistentAccessibilityTests { [Fact] public async Task ShouldFixInconsistentAccessibilityErrorInClassFieldTypeAsync() { const string testCode = @"public class Dependent { - public DependedUpon field; + public DependedUpon {|CS0052:field|}; } class DependedUpon @@ -25,7 +28,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -33,7 +36,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInClassFieldTypeWhenQua { const string testCode = @"public class Dependent { - internal Dependent.DependedUpon field; + internal Dependent.DependedUpon {|CS0052:field|}; class DependedUpon { @@ -49,7 +52,7 @@ internal class DependedUpon } }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -57,7 +60,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInStructFieldTypeAsync( { const string testCode = @"public struct Dependent { - public DependedUpon field, field1; + public DependedUpon {|CS0052:field|}, {|CS0052:field1|}; } class DependedUpon @@ -72,7 +75,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -80,7 +83,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInPropertyTypeAsync() { const string testCode = @"public class Dependent { - public DependedUpon Property + public DependedUpon {|CS0053:Property|} { get { return null; } set { } @@ -104,7 +107,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -112,7 +115,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInPropertyTypeWhenUsing { const string testCode = @"public class Dependent { - public DependedUpon Property + public DependedUpon {|CS0053:Property|} { get; set; @@ -136,7 +139,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } } } diff --git a/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerParameter.cs b/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerParameter.cs index 822d16141..34b11d5ef 100644 --- a/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerParameter.cs +++ b/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerParameter.cs @@ -1,11 +1,12 @@ -using CodeCracker.CSharp.Design.InconsistentAccessibility; -using Microsoft.CodeAnalysis.CodeFixes; -using System.Threading.Tasks; +using System.Threading.Tasks; +using CodeCracker.CSharp.Design.InconsistentAccessibility; using Xunit; namespace CodeCracker.Test.CSharp.Design { - public partial class InconsistentAccessibilityTests : CodeFixVerifier + using Verify = CSharpCodeFixVerifier; + + public partial class InconsistentAccessibilityTests { [Theory] [InlineData("class","internal")] @@ -17,11 +18,11 @@ public async Task ShouldChangeAccessibilityWhenErrorInConstructor(string type, s var sourceCode = @" public " + type + @" Dependent { - public Dependent(int a, DependendedUpon d, string b) + public {|CS0051:Dependent|}(int a, DependendedUpon d, string b) { } } -" + dependedUponModfifier + @" class DependendedUpon +" + dependedUponModfifier + (dependedUponModfifier.Length > 0 ? " " : "") + @"class DependendedUpon { }"; @@ -36,7 +37,7 @@ public class DependendedUpon { }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Theory] @@ -49,7 +50,7 @@ public class DependendedUpon [InlineData("protected", "internal /* comment */", "protected /* comment */")] [InlineData("protected", "private", "protected")] [InlineData("protected internal", "", "protected internal")] - [InlineData("protected internal", " protected ", " protected internal ")] + [InlineData("protected internal", " protected ", "protected internal")] [InlineData("protected internal", "internal", "protected internal")] [InlineData("internal protected", "private", "protected internal")] [InlineData("internal", "protected", "internal")] @@ -59,11 +60,11 @@ public async Task ShouldChangeAccessibilityWhenErrrorInMethod(string methodModif var sourceCode = @" public class Dependent { - " + methodModifier + @" void SomeMethod(DependendedUpon d) + " + methodModifier + @" void {|CS0051:SomeMethod|}(DependendedUpon d) { } - " + dependedUponModifier + @" class DependendedUpon + " + dependedUponModifier + (dependedUponModifier.Length > 0 ? " " : "") + @"class DependendedUpon { } }"; @@ -80,7 +81,7 @@ public class Dependent } }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Theory] @@ -91,9 +92,9 @@ public async Task ShouldChangeAccessibilityWhenErrorInInterface(string interface var sourceCode = @" " + interfaceAccessibilityModifier + @" interface Dependent { - void SomeMethod(DependendedUpon d); + void {|CS0051:SomeMethod|}(DependendedUpon d); } -" + dependedUponModifier + @" class DependendedUpon +" + dependedUponModifier + (dependedUponModifier.Length > 0 ? " " : "") + @"class DependendedUpon { }"; @@ -106,7 +107,7 @@ public async Task ShouldChangeAccessibilityWhenErrorInInterface(string interface { }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -115,7 +116,7 @@ public async Task ShouldChangeAccessibilityWhenQualifiedNameIsUsedForParameterTy const string sourceCode = @" public class Dependent { - public Dependent(Dependent.DependendedUpon d) + public {|CS0051:Dependent|}(Dependent.DependendedUpon d) { } @@ -136,7 +137,7 @@ public class DependendedUpon } }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -145,7 +146,7 @@ public async Task ShouldChangeAccessibilityWhenAliasQualifiedNameIsUsedForParame const string sourceCode = @" public class Dependent { - public Dependent(global::DependendedUpon d) + public {|CS0051:Dependent|}(global::DependendedUpon d) { } } @@ -164,7 +165,7 @@ public class DependendedUpon { }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -173,7 +174,7 @@ public async Task ShouldChangeAccessibilityWhenUsingDelegateAsParameter() const string sourceCode = @" public class Dependent { - public Dependent(DependedUpon d) + public {|CS0051:Dependent|}(DependedUpon d) { } } @@ -188,7 +189,7 @@ public Dependent(DependedUpon d) } public delegate void DependedUpon(int a);"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -197,7 +198,7 @@ public async Task ShouldChangeAccessibilityWhenUsingEnumAsParameter() const string sourceCode = @" public class Dependent { - public Dependent(DependedUpon d) + public {|CS0051:Dependent|}(DependedUpon d) { } } @@ -212,7 +213,7 @@ public Dependent(DependedUpon d) } public enum DependedUpon {}"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -221,7 +222,7 @@ public async Task ShouldChangeAccessibilityWhenUsingInterfaceAsParameter() const string sourceCode = @" public class Dependent { - public Dependent(DependedUpon d) + public {|CS0051:Dependent|}(DependedUpon d) { } } @@ -236,7 +237,7 @@ public Dependent(DependedUpon d) } public interface DependedUpon {}"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -245,7 +246,7 @@ public async Task ShouldChangeAccessibilityWhenUsingGenericClassAsParameter() const string sourceCode = @" public class Dependent { - public Dependent(DependedUpon d) + public {|CS0051:Dependent|}(DependedUpon d) { } } @@ -260,7 +261,7 @@ public Dependent(DependedUpon d) } public class DependedUpon {}"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -269,7 +270,7 @@ public async Task ShouldChangeAccessibilityToAllPartialDeclarationsAsync() const string sourceCode = @" public class Dependent { - public Dependent(DependedUpon d) + public {|CS0051:Dependent|}(DependedUpon d) { } } @@ -288,7 +289,7 @@ public partial class DependedUpon {} class SomeClass {} public partial class DependedUpon {}"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -296,7 +297,7 @@ public async Task ShouldChangeAccessibilityWhenErrorInIndexerParameterAsync() { const string sourceCode = @"public class Dependent { - public int this[int idx, DependedUpon dependedUpon] + public int {|CS0055:this|}[int idx, DependedUpon dependedUpon] { get { return 0; } set { } @@ -320,7 +321,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -328,7 +329,7 @@ public async Task ShouldChangeAccessibilityWhenErrorInIndexerParameterUsingQuali { const string sourceCode = @"public class Dependent { - public int this[int idx, Dependent.DependedUpon dependedUpon] + public int {|CS0055:this|}[int idx, Dependent.DependedUpon dependedUpon] { get { return 0; } set { } @@ -352,7 +353,7 @@ public class DependedUpon } }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -360,7 +361,7 @@ public async Task ShouldChangeAccessibilityWhenErrorInMoreThanOneIndexerParamete { const string sourceCode = @"public class Dependent { - public int this[int idx, Dependent.DependedUpon dependedUpon, DependedUpon2 dependedUpon2] + public int {|CS0055:{|CS0055:this|}|}[int idx, Dependent.DependedUpon dependedUpon, DependedUpon2 dependedUpon2] { get { return 0; } set { } @@ -392,9 +393,7 @@ public class DependedUpon2 { }"; - await VerifyCSharpFixAsync(sourceCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(sourceCode, fixedCode).ConfigureAwait(false); } - - protected override CodeFixProvider GetCodeFixProvider() => new InconsistentAccessibilityCodeFixProvider(); } } diff --git a/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerReturnType.cs b/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerReturnType.cs index e397c7a4f..7b5d324a2 100644 --- a/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerReturnType.cs +++ b/test/CSharp/CodeCracker.Test/Design/InconsistentAccessibilityTests.MethodIndexerReturnType.cs @@ -1,16 +1,19 @@ using System.Threading.Tasks; +using CodeCracker.CSharp.Design.InconsistentAccessibility; using Xunit; namespace CodeCracker.Test.CSharp.Design { - public partial class InconsistentAccessibilityTests : CodeFixVerifier + using Verify = CSharpCodeFixVerifier; + + public partial class InconsistentAccessibilityTests { [Fact] public async Task ShouldFixInconsistentAccessibilityErrorInMethodReturnTypeAsync() { const string testCode = @"public class Dependent { - public DependedUpon Method() + public DependedUpon {|CS0050:Method|}() { return null; } @@ -31,7 +34,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -39,7 +42,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInMethodReturnTypeWhenQ { const string testCode = @"public class Dependent { - public Dependent.DependedUpon Method() + public Dependent.DependedUpon {|CS0050:Method|}() { return null; } @@ -60,7 +63,7 @@ public class DependedUpon } }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -68,7 +71,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInIndexerReturnTypeAsyn { const string testCode = @"public class Dependent { - public DependedUpon this[int a] + public DependedUpon {|CS0054:this|}[int a] { get { return null; } set { } @@ -91,7 +94,7 @@ public class DependedUpon { }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } [Fact] @@ -99,7 +102,7 @@ public async Task ShouldFixInconsistentAccessibilityErrorInIndexerReturnTypeWhen { const string testCode = @"public class Dependent { - public Dependent.DependedUpon this[int a] + public Dependent.DependedUpon {|CS0054:this|}[int a] { get { return null; } set { } @@ -122,7 +125,7 @@ public class DependedUpon } }"; - await VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); + await Verify.VerifyCodeFixAsync(testCode, fixedCode).ConfigureAwait(false); } } } From a6e63422ca8f0081af6896d6c7fad4055e61d4e9 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 10 Sep 2018 14:02:17 -0500 Subject: [PATCH 333/358] Unindent code in WrapInCSharpClass and WrapInCSharpMethod --- .../Design/MakeMethodStaticTests.cs | 2 +- ...ocalVariablesConstWhenItIsPossibleTests.cs | 6 +-- .../AddBracesToSwitchSectionsTests.cs | 6 +-- .../Refactoring/ComputeExpressionTests.cs | 2 +- .../Refactoring/NumericLiteralTests.cs | 2 +- .../Refactoring/SplitIntoNestedIfTests.cs | 2 +- .../UseConfigureAwaitFalseTests.cs | 12 +++--- .../Style/RemoveCommentedCodeTests.cs | 2 +- .../Style/StringFormatTests.cs | 4 +- ...ssaryToStringInStringConcatenationTests.cs | 2 +- .../Style/UseEmptyStringTest.cs | 4 +- .../Style/UseStringEmptyTests.cs | 4 +- .../DisposableVariableNotDisposedTests.cs | 8 ++-- .../Usage/RemoveRedundantElseClauseTests.cs | 4 +- ...implifyRedundantBooleanComparisonsTests.cs | 32 +++++++-------- .../Usage/StringFormatArgsTests.cs | 14 +++---- .../Helpers/Extensions.cs | 40 ++++++++++++------- 17 files changed, 78 insertions(+), 68 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs index 2d8829a4a..eb64ea7dc 100644 --- a/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs +++ b/test/CSharp/CodeCracker.Test/Design/MakeMethodStaticTests.cs @@ -102,7 +102,7 @@ public async Task WithDiagnostic(string code) { var source = code.WrapInCSharpClass(); var expected = new DiagnosticResult(DiagnosticId.MakeMethodStatic.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(8, 18) + .WithLocation(8, 14) .WithMessage(string.Format(MakeMethodStaticAnalyzer.MessageFormat, "Foo")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs index 61b2311b3..5ab66e579 100644 --- a/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/MakeLocalVariablesConstWhenItIsPossibleTests.cs @@ -66,7 +66,7 @@ public async Task CreateDiagnosticsWhenAssigningAPotentialConstant() { var test = @"int a = 10;".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage("This variable can be made const."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -77,7 +77,7 @@ public async Task CreateDiagnosticsWhenAssigningAPotentialConstantInAVarDeclarat var test = @"var a = 10;".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage("This variable can be made const."); await VerifyCSharpDiagnosticAsync(test, expected); } @@ -88,7 +88,7 @@ public async Task CreateDiagnosticsWhenAssigningNullToAReferenceType() var test = @"Foo a = null;".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.MakeLocalVariableConstWhenItIsPossible.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage("This variable can be made const."); await VerifyCSharpDiagnosticAsync(test, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs index 9f8dfb62c..086e7287f 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/AddBracesToSwitchSectionsTests.cs @@ -71,7 +71,7 @@ public async Task CreateDiagnosticWhenSingleSwitchSectionHasNoBraces() break; }"; var diagnostic = new DiagnosticResult(DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage("Add braces for each section in this switch"); await VerifyCSharpDiagnosticAsync(test.WrapInCSharpMethod(), diagnostic); } @@ -96,7 +96,7 @@ public async Task CreateDiagnosticWhenNotAllSwitchSectionsHaveBraces() } }"; var diagnostic = new DiagnosticResult(DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage("Add braces for each section in this switch"); await VerifyCSharpDiagnosticAsync(test.WrapInCSharpMethod(), diagnostic); } @@ -121,7 +121,7 @@ public async Task CreateDiagnosticWhenDefaultSectionsHasNoBraces() break; }"; var diagnostic = new DiagnosticResult(DiagnosticId.AddBracesToSwitchSections.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage("Add braces for each section in this switch"); await VerifyCSharpDiagnosticAsync(test.WrapInCSharpMethod(), diagnostic); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs index 64f244a6c..66f89503c 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/ComputeExpressionTests.cs @@ -40,7 +40,7 @@ public async Task BinaryExpressionWithLiteralOnLeftAndRightCreatesDiagnostic(str var source = original.WrapInCSharpMethod(); var expression = original.Substring(columnOffset, original.Length - columnOffset - columnRightTrim - 1); var expected = new DiagnosticResult(DiagnosticId.ComputeExpression.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 17 + columnOffset) + .WithLocation(10, 13 + columnOffset) .WithMessage(string.Format(ComputeExpressionAnalyzer.Message, expression)); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs index feae0f6f6..00949a8b8 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/NumericLiteralTests.cs @@ -81,7 +81,7 @@ void Foo() await VerifyCSharpFixAsync(source, fixtest); } - private static DiagnosticResult CreateDiagnosticResult(string literal, bool isDecimal, int row = 10, int col = 25) + private static DiagnosticResult CreateDiagnosticResult(string literal, bool isDecimal, int row = 10, int col = 21) { return new DiagnosticResult(DiagnosticId.NumericLiteral.ToDiagnosticId(), DiagnosticSeverity.Hidden) .WithLocation(row, col) diff --git a/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs b/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs index b99818c1c..41da694f2 100644 --- a/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs +++ b/test/CSharp/CodeCracker.Test/Refactoring/SplitIntoNestedIfTests.cs @@ -34,7 +34,7 @@ public async Task IfWithAndCreatesDiagnostic() { var source = "if (true && true) { }".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.SplitIntoNestedIf.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 21) + .WithLocation(10, 17) .WithMessage(string.Format(SplitIntoNestedIfAnalyzer.Message)); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs b/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs index c8e981b55..ef2e99a68 100644 --- a/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs +++ b/test/CSharp/CodeCracker.Test/Reliability/UseConfigureAwaitFalseTests.cs @@ -9,12 +9,12 @@ namespace CodeCracker.Test.CSharp.Reliability public class UseConfigureAwaitFalseTests : CodeFixVerifier { [Theory] - [InlineData("System.Threading.Tasks.Task t; await t;", 48)] - [InlineData("System.Threading.Tasks.Task t; await t.ContinueWith(_ => 42);", 48)] - [InlineData("await System.Threading.Tasks.Task.Delay(1000);", 17)] - [InlineData("await System.Threading.Tasks.Task.FromResult(0);", 17)] - [InlineData("await System.Threading.Tasks.Task.Run(() => {});", 17)] - [InlineData("Func f; await f();", 54)] + [InlineData("System.Threading.Tasks.Task t; await t;", 44)] + [InlineData("System.Threading.Tasks.Task t; await t.ContinueWith(_ => 42);", 44)] + [InlineData("await System.Threading.Tasks.Task.Delay(1000);", 13)] + [InlineData("await System.Threading.Tasks.Task.FromResult(0);", 13)] + [InlineData("await System.Threading.Tasks.Task.Run(() => {});", 13)] + [InlineData("Func f; await f();", 50)] public async Task WhenAwaitingTaskAnalyzerCreatesDiagnostic(string sample, int column) { var test = sample.WrapInCSharpMethod(isAsync: true); diff --git a/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs b/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs index eba8b1ad0..e287e5941 100644 --- a/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/RemoveCommentedCodeTests.cs @@ -27,7 +27,7 @@ public async Task CreateDiagnosticForSingleLineCommentedCode() { var test = @"// a = 10;".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.RemoveCommentedCode.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage(RemoveCommentedCodeAnalyzer.MessageFormat); await VerifyCSharpDiagnosticAsync(test, expected); diff --git a/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs b/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs index bab1ee836..fdd944a07 100644 --- a/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/StringFormatTests.cs @@ -631,10 +631,10 @@ public async Task NestedStringFormatCreatesDiagnostic() { var source = @"var foo = string.Format(""{0}"", string.Format(""{0}"", 1 ) );".WrapInCSharpMethod(); var expected1 = new DiagnosticResult(DiagnosticId.StringFormat.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 27) + .WithLocation(10, 23) .WithMessage(StringFormatAnalyzer.MessageFormat.ToString()); var expected2 = new DiagnosticResult(DiagnosticId.StringFormat.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 48) + .WithLocation(10, 44) .WithMessage(StringFormatAnalyzer.MessageFormat.ToString()); await VerifyCSharpDiagnosticAsync(source, expected1, expected2); } diff --git a/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs b/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs index 3f049ba98..75af07ac2 100644 --- a/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/UnnecessaryToStringInStringConcatenationTests.cs @@ -30,7 +30,7 @@ public async Task InstantiatingAnStringBuilderAndCallToStringInsideAStringConcat { var source = @"var foo = ""a"" + new System.Text.StringBuilder().ToString();".WrapInCSharpMethod(); - var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(10, 64); + var expected = CreateUnnecessaryToStringInStringConcatenationDiagnosticResult(10, 60); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Style/UseEmptyStringTest.cs b/test/CSharp/CodeCracker.Test/Style/UseEmptyStringTest.cs index 500739bbf..84eb26fdf 100644 --- a/test/CSharp/CodeCracker.Test/Style/UseEmptyStringTest.cs +++ b/test/CSharp/CodeCracker.Test/Style/UseEmptyStringTest.cs @@ -194,8 +194,8 @@ public async Task FixAllInSolutionChangeMethodToStringEmpty() public async Task TwoEmptyStringsGenerateTwoDiagnostics() { var test = "var s = string.Empty + string.Empty;".WrapInCSharpMethod(); - var expected1 = CreateEmptyStringDiagnosticResult(10, 25); - var expected2 = CreateEmptyStringDiagnosticResult(10, 40); + var expected1 = CreateEmptyStringDiagnosticResult(10, 21); + var expected2 = CreateEmptyStringDiagnosticResult(10, 36); await VerifyCSharpDiagnosticAsync(test, expected1, expected2); } diff --git a/test/CSharp/CodeCracker.Test/Style/UseStringEmptyTests.cs b/test/CSharp/CodeCracker.Test/Style/UseStringEmptyTests.cs index 9134c2bca..9e492b404 100644 --- a/test/CSharp/CodeCracker.Test/Style/UseStringEmptyTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/UseStringEmptyTests.cs @@ -187,10 +187,10 @@ public async Task TwoEmptyStringsGenerateTwoDiagnostics() { var test = @"var s = """" + """";".WrapInCSharpMethod(); var expected1 = new DiagnosticResult(DiagnosticId.UseStringEmpty.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 25) + .WithLocation(10, 21) .WithMessage("Use 'String.Empty' instead of \"\""); var expected2 = new DiagnosticResult(DiagnosticId.UseStringEmpty.ToDiagnosticId(), DiagnosticSeverity.Hidden) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage("Use 'String.Empty' instead of \"\""); await VerifyCSharpDiagnosticAsync(test, expected1, expected2); } diff --git a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs index daad3e39a..590f108de 100644 --- a/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/DisposableVariableNotDisposedTests.cs @@ -159,7 +159,7 @@ public async Task DisposableVariableCreatesDiagnostic() { var source = "new System.IO.MemoryStream();".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -176,7 +176,7 @@ public async Task DisposableVariableDeclaredWithAnotherVariableCreatesOnlyOneDia { var source = "System.IO.MemoryStream a, b = new System.IO.MemoryStream();".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 47) + .WithLocation(10, 43) .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -446,7 +446,7 @@ public async Task DisposableVariablePassedAsParamCreatesDiagnostic() { var source = "string.Format(\"\", new System.IO.MemoryStream());".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 35) + .WithLocation(10, 31) .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -457,7 +457,7 @@ public async Task DisposableVariableCallsIncorrectDisposeCreatesDiagnostic() var source = @"var m = new System.IO.MemoryStream(); m.Dispose(true);".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.DisposableVariableNotDisposed.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 25) + .WithLocation(10, 21) .WithMessage(string.Format(DisposableVariableNotDisposedAnalyzer.MessageFormat, "MemoryStream")); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs b/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs index 9849a0655..82a32d51a 100644 --- a/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/RemoveRedundantElseClauseTests.cs @@ -122,7 +122,7 @@ public async Task CreateDiagnosticsWhenEmptyElse() var test = @"if(1 == 2){ return 1; } else { }".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 41) + .WithLocation(10, 37) .WithMessage("Remove redundant else"); await VerifyCSharpDiagnosticAsync(test, expected); @@ -134,7 +134,7 @@ public async Task CreateDiagnosticsWhenEmptyElseWithoutBlockOnIf() var test = @"if(1 == 2) return 1; else { }".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.RemoveRedundantElseClause.ToDiagnosticId(), DiagnosticSeverity.Info) - .WithLocation(10, 38) + .WithLocation(10, 34) .WithMessage("Remove redundant else"); await VerifyCSharpDiagnosticAsync(test, expected); diff --git a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs index b1fa44b3f..e5fe06e4d 100644 --- a/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/SimplifyRedundantBooleanComparisonsTests.cs @@ -10,22 +10,22 @@ public class SimplifyRedundantBooleanComparisonsTests : CodeFixVerifier { [Theory] - [InlineData("if (foo == true) {}", 21)] - [InlineData("if (true == foo) {}", 21)] - [InlineData("var fee = (foo == true);", 28)] - [InlineData("var fee = (true == foo);", 28)] - [InlineData("if (foo == false) {}", 21)] - [InlineData("if (false == foo) {}", 21)] - [InlineData("var fee = (foo == false);", 28)] - [InlineData("var fee = (false == foo);", 28)] - [InlineData("if (foo != true) {}", 21)] - [InlineData("if (true != foo) {}", 21)] - [InlineData("var fee = (foo != true);", 28)] - [InlineData("var fee = (true != foo);", 28)] - [InlineData("if (foo != false) {}", 21)] - [InlineData("if (false != foo) {}", 21)] - [InlineData("var fee = (foo != false);", 28)] - [InlineData("var fee = (false != true);", 28)] + [InlineData("if (foo == true) {}", 17)] + [InlineData("if (true == foo) {}", 17)] + [InlineData("var fee = (foo == true);", 24)] + [InlineData("var fee = (true == foo);", 24)] + [InlineData("if (foo == false) {}", 17)] + [InlineData("if (false == foo) {}", 17)] + [InlineData("var fee = (foo == false);", 24)] + [InlineData("var fee = (false == foo);", 24)] + [InlineData("if (foo != true) {}", 17)] + [InlineData("if (true != foo) {}", 17)] + [InlineData("var fee = (foo != true);", 24)] + [InlineData("var fee = (true != foo);", 24)] + [InlineData("if (foo != false) {}", 17)] + [InlineData("if (false != foo) {}", 17)] + [InlineData("var fee = (foo != false);", 24)] + [InlineData("var fee = (false != true);", 24)] public async Task WhenComparingWithBoolAnalyzerCreatesDiagnostic(string sample, int column) { sample = "bool foo; " + sample; // add declaration of foo diff --git a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs index b5ffbb6e9..ebd90f4c7 100644 --- a/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs +++ b/test/CSharp/CodeCracker.Test/Usage/StringFormatArgsTests.cs @@ -84,7 +84,7 @@ public async Task NoParametersCreatesError() { var source = @"var result = string.Format(""{0}"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -94,7 +94,7 @@ public async Task LessParametersCreatesError() { var source = @"var result = string.Format(""one {0} two {1}"", ""a"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -104,7 +104,7 @@ public async Task MoreArgumentsCreatesWarning() { var source = @"var result = string.Format(""one {0} two {1}"", ""a"", ""b"", ""c"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage(StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -135,7 +135,7 @@ public async Task TwoParametersReferencingSamePlaceholderCreatesWarning() { var source = @"var result = string.Format(""one {0} two {0}"", ""a"", ""b"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage(StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -179,7 +179,7 @@ public async Task InvalidArgumentReferenceCreatesError() { var source = @"var result = string.Format(""one {1}"", ""a"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -189,7 +189,7 @@ public async Task NonIntegerPlaceholderCreatesError() { var source = @"var result = string.Format(""one {notZero}"", ""a"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_InvalidArgs.ToDiagnosticId(), DiagnosticSeverity.Error) - .WithLocation(10, 30) + .WithLocation(10, 26) .WithMessage(StringFormatArgsAnalyzer.InvalidArgsReferenceMessage); await VerifyCSharpDiagnosticAsync(source, expected); } @@ -199,7 +199,7 @@ public async Task UnusedArgsCreatesWarning() { var source = @"string.Format(""{0}{1}{3}{5}"", ""a"", ""b"", ""c"", ""d"", ""e"", ""f"");".WrapInCSharpMethod(); var expected = new DiagnosticResult(DiagnosticId.StringFormatArgs_ExtraArgs.ToDiagnosticId(), DiagnosticSeverity.Warning) - .WithLocation(10, 17) + .WithLocation(10, 13) .WithMessage(StringFormatArgsAnalyzer.IncorrectNumberOfArgsMessage); await VerifyCSharpDiagnosticAsync(source, expected); } diff --git a/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs b/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs index 082843818..7b6e955ab 100644 --- a/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs +++ b/test/Common/CodeCracker.Test.Common/Helpers/Extensions.cs @@ -4,33 +4,43 @@ public static class Extensions { public static string WrapInCSharpClass(this string code, string typeName = "TypeName", string usings = "") { + if (!code.StartsWith("\r") || code.StartsWith("\n")) + { + code = " " + code; + } + return $@" - using System;{usings} +using System;{usings} - namespace ConsoleApplication1 +namespace ConsoleApplication1 +{{ + class {typeName} {{ - class {typeName} - {{ - {code} - }} - }}"; +{code} + }} +}}"; } public static string WrapInCSharpMethod(this string code, bool isAsync = false, string typeName = "TypeName", string usings = "") { + if (!code.StartsWith("\r") || code.StartsWith("\n")) + { + code = " " + code; + } + return $@" - using System;{usings} +using System;{usings} - namespace ConsoleApplication1 +namespace ConsoleApplication1 +{{ + class {typeName} {{ - class {typeName} + public {(isAsync ? "async " : "")}void Foo() {{ - public {(isAsync ? "async " : "")}void Foo() - {{ - {code} - }} +{code} }} - }}"; + }} +}}"; } public static string WrapInVBClass(this string code, From 0dc53ea33c9cc11daf5694bf290e9ddd10b25dae Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Oct 2018 15:02:23 -0500 Subject: [PATCH 334/358] Fixed many spelling and grammar issues There were tons of spelling errors that I spotted in the code. Along with fixing these, I have provided grammatical fixes as well. --- README.md | 59 ++++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index c6e7048ee..bfb59721e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ You can find this document in the following languages [![Brazilian Portuguese](https://img.shields.io/badge/language-brazilan%20portuguese-brightgreen.svg)](https://github.com/code-cracker/code-cracker/blob/master/README.pt.md) -This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this +This is a community project, free and open source. Everyone is invited to contribute, fork, share and use the code. No money shall be charged by this software, nor it will be. Ever. ## Features @@ -30,23 +30,23 @@ Code | Analyzer | Severity | Description -- | -- | -- | -- [CC0003](http://code-cracker.github.io/diagnostics/CC0003.html) | CatchEmptyAnalyzer | Warning | Catch statements with no Exception as an argument is not recommended. Consider adding an Exception class to the catch statement. [CC0004](http://code-cracker.github.io/diagnostics/CC0004.html) | EmptyCatchBlockAnalyzer | Warning | An empty catch block suppress all errors and shouldn’t be used. If the error is expected consider logging it or changing the control flow such that it is explicit. -[CC0016](http://code-cracker.github.io/diagnostics/CC0016.html) | CopyEventToVariableBeforeFireAnalyzer | Warning | Events should always be checked for null before being invoked. As in a multi-threading context it is possible for an event to be unsuscribed between the moment where it is checked to be non-null and the moment it is raised, the event must be copied to a temporary variable before the check. -[CC0021](http://code-cracker.github.io/diagnostics/CC0021.html) | NameOfAnalyzer | Warning | In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produce code that is easier to refactor. -[CC0024](http://code-cracker.github.io/diagnostics/CC0024.html) | StaticConstructorExceptionAnalyzer | Warning | Static constructor are called before the first time a class is used but the caller doesn’t control when exactly. Exception thrown in this context force callers to use ‘try’ block around any useage of the class and should be avoided. -[CC0031](http://code-cracker.github.io/diagnostics/CC0031.html) | UseInvokeMethodToFireEventAnalyzer | Warning | In C#6 a delegate can be invoked using the null-propagating operator (?.) and it’s invoke method to avoid throwing a NullReference exception when there is no method attached to the delegate. +[CC0016](http://code-cracker.github.io/diagnostics/CC0016.html) | CopyEventToVariableBeforeFireAnalyzer | Warning | Events should always be checked for null before being invoked. As in a multi-threading context, it is possible for an event to be unsubscribed between the moment where it is checked to be non-null and the moment it is raised, the event must be copied to a temporary variable before the check. +[CC0021](http://code-cracker.github.io/diagnostics/CC0021.html) | NameOfAnalyzer | Warning | In C#6 the nameof() operator should be used to specify the name of a program element instead of a string literal as it produces code that is easier to refactor. +[CC0024](http://code-cracker.github.io/diagnostics/CC0024.html) | StaticConstructorExceptionAnalyzer | Warning | Static constructor are called before the first time a class is used but the caller doesn’t control when exactly. Exceptions thrown in this context force callers to use ‘try’ block around any usage of the class and should be avoided. +[CC0031](http://code-cracker.github.io/diagnostics/CC0031.html) | UseInvokeMethodToFireEventAnalyzer | Warning | In C#6 a delegate can be invoked using the null-propagating operator (?.) and its invoke method to avoid throwing a NullReference exception when there is no method attached to the delegate. ## Installing -You may use CodeCracker in two ways: as an analyzer library that you install with Nuget into your project or as a Visual Studio extension. +You may use CodeCracker in two ways: as an analyzer library that you install with NuGet into your project, or as a Visual Studio extension. The way you want to use it depends on the scenario you are working on. You most likely want the Nuget package. If you want the analyzers to work during your build, and generate warnings and errors during the build, also on build servers, then you want -to use the Nuget package. The package is available on nuget ([C#](https://www.nuget.org/packages/codecracker.CSharp), +to use the Nuget package. The package is available on NuGet ([C#](https://www.nuget.org/packages/codecracker.CSharp), [VB](https://www.nuget.org/packages/codecracker.VisualBasic)). If you want to be able to configure which analyzers are being used in your project, and which ones you will ignore, and commit those changes to source control and share with your team, then you also want the Nuget package. -To install from Nuget, for the C# version: +To install from NuGet, for the C# version: ```powershell Install-Package CodeCracker.CSharp @@ -62,7 +62,7 @@ Or use the Package Manager in Visual Studio. There is also a version for both named `CodeCracker` only, but it makes no sense to get it, you should search for the C# or VB version. -If you want the alpha builds that build on each push to the repo, add https://www.myget.org/F/codecrackerbuild/ to your Nuget feed. +If you want the alpha builds that build on each push to the repo, add [this](https://www.myget.org/F/codecrackerbuild/) to your NuGet feed. We only push complete releases to Nuget.org, and commit builds go to Myget.org. If you want global analyzers that will work on every project you open in Visual Studio, then you want the Extension. @@ -92,13 +92,13 @@ The main supported IDE for development is Visual Studio 2017. We do not support VS 2015 anymore. Questions, comments, bug reports, and pull requests are all welcome. -Bug reports that include steps-to-reproduce (including code) are +Bug reports that include steps to reproduce (including code) are preferred. Even better, make them in the form of pull requests. Before you start to work on an existing issue, check if it is not assigned to anyone yet, and if it is, talk to that person. -Also check the project [board](https://huboard.com/code-cracker/code-cracker/) +Also, check the project [board](https://huboard.com/code-cracker/code-cracker/) and verify it is not being worked on (it will be tagged with the `Working` tag). -If it is not being worked on, before you start check if the item is `Ready`. +If it is not being worked on, check if the item is `Ready` before you start. If the issue has the `Working` tag (working swimlane on Huboard) and has no Assignee then it is not being worked on by somebody on the core team. Check the issue's description to find out who it is (if it is not there it has to be on the comments). @@ -108,7 +108,7 @@ be assigned to this team. The easiest way to start is looking into the issues that are [up for grabs](https://github.com/code-cracker/code-cracker/labels/up-for-grabs). You -may ask to work on any of them, read below to see how. You can also triage issues which may include reproducing bug reports, or asking for vital information such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to code-cracker on CodeTriage](https://www.codetriage.com/code-cracker/code-cracker). +may ask to work on any of them, read below to see how. You can also triage issues which may include reproducing bug reports or asking for vital information such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to code-cracker on CodeTriage](https://www.codetriage.com/code-cracker/code-cracker). If you are just starting with Roslyn, want to contribute, and feel you are not yet ready to start working on full analyzers or code fixes, you can start helping with areas that are @@ -116,8 +116,7 @@ less demanding. We have identified a few: * Fixing bugs - Still demands knowledge of Roslyn internals but it is easier than coming up with a full - analyzer or code fix. Look for the [bugs that are up for grabs](https://github.com/code-cracker/code-cracker/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Abug+label%3Aup-for-grabs). + Still demands knowledge of Roslyn internals but it is easier than coming up with a full analyzer or code fix. Look for the [bugs that are up for grabs](https://github.com/code-cracker/code-cracker/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Abug+label%3Aup-for-grabs). * Documentation @@ -126,10 +125,8 @@ less demanding. We have identified a few: * Localization/Translation - We are starting to translate the analyzers and code fixes messages to other languages. If you want CodeCracker - on your language feel free to create an issue and start working on it. If you want to help with an ongoing translation, - comment on the existing issue and say you are ready to help. We also need to update existing analyzers, which were - not created ready for localization. + We are starting to translate the analyzers and code fixes messages to other languages. If you want CodeCracker on your language feel free to create an issue and start working on it. If you want to help with an ongoing translation, + comment on the existing issue and say you are ready to help. We also need to update existing analyzers, which were not created ready for localization. ## Issues and task board @@ -145,7 +142,7 @@ defined ready as: 2. If it has an analyzer then 1. The warning level of the analyzer must be in the issue's description (`Hidden`, `Information`, `Warning`, or `Error`) - 2. The diagnostics it provides should already have numeric ids defined formated as `CC0000`. + 2. The diagnostics it provides should already have numeric ids defined formatted as `CC0000`. 3. If it has a code fix then the category should be in the issue's description. The supported categories are listed on the `SupportedCategories.cs` file. 4. Have some of the maintainers verify it (cannot be the same one who wrote the issue and/or test cases) @@ -161,9 +158,9 @@ and [#10](https://github.com/code-cracker/code-cracker/issues/10). These are the 4 severity levels supported on Roslyn and how they are understood on the Code Cracker project: 1. **Hidden**: Only used for refactorings. See #66 (and its comments) to understand why. -2. **Info**: An alternative way (ex: replacing for with foreach). Clearly a matter of opinion and/or current way could be correct, or maybe the new code could be correct. We cannot determine. +2. **Info**: An alternative way (ex: replacing for with foreach). Clearly, a matter of opinion and/or current way could be correct, or maybe the new code could be correct. We cannot determine. 3. **Warning**: Code that could/should be improved. It is a code smell and most likely is wrong, but there are situations where the pattern is acceptable or desired. -4. **Error**: Clearly a mistake (ex: throwing ArgumentException with an non-existent parameter). There is no situation where this code could be correct. There are no differences of opinion. +4. **Error**: Clearly a mistake (ex: throwing ArgumentException with a non-existent parameter). There is no situation where this code could be correct. There are no differences of opinion. You can read [directly on Microsoft's source code](http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/Diagnostic/DiagnosticSeverity.cs,e70281df673d47f6,references) how they interpret these levels. @@ -182,7 +179,7 @@ The DoD is still evolving. At the present time the checklist is as follows: 5. Code fixes should follow the guidelines for names 1. Always named `CodeFixProvider` - 2. Always use the same diagnostic id added to the `DiagnosticIds.cs` file, unless you are writing a code fix for a diagnostic id raised by the C# compiler itself (staring with `CS`). + 2. Always use the same diagnostic id added to the `DiagnosticIds.cs` file, unless you are writing a code fix for a diagnostic id raised by the C# compiler itself (starting with `CS`). 6. Fix all scenarios (fix all in document, fix all in project and fix all in solution) work. You might need to write a `FixAllProvider`. Check the `DisposableVariableNotDisposedFixAllProvider` as an example. 7. Follow the coding standards present on the project code files. 8. Works in Visual Studio @@ -190,11 +187,11 @@ The DoD is still evolving. At the present time the checklist is as follows: ### Start working -Once it is Ready and agreed on by any one from the core team, just state in +Once it is Ready and agreed on by anyone from the core team, just state in a comment that you intend to start working on that item and mention any/all the maintainers (use @code-cracker/owners) so they can tag it correctly and move it on the board. -If you are not familiar with the way Github works you might want to check the [Github guides](https://guides.github.com/), specially +If you are not familiar with the way Github works you might want to check the [Github guides](https://guides.github.com/), especially the [Github flow](https://guides.github.com/introduction/flow/) one. The [GitHub for the Roslyn Team video](http://channel9.msdn.com/Blogs/dotnet/github-for-the-roslyn-team) might help you as well, and it also explains some Git concepts. @@ -203,7 +200,7 @@ To start working fork the project on Github to your own account and clone it **f from the main CodeCracker repository. Before you start coding create a new branch and name it in a way that makes sense for the issue that you will be working on. Don't work on the `master` branch because that may make things harder if you have to update your pull request or your repository later, assume your `master` branch -is always equals the main repo `master` branch, and code on a different branch. +always equals the main repo `master` branch, and code on a different branch. When you commit, mention the issue number use the pound sign (#). Avoid making a lot of small commits unless they are meaningful. For most analyzers and code fixes a single commit should be enough. If you @@ -239,9 +236,9 @@ git merge master # solve integration conflicts ```` -You can solve the conflicts in your favorite text editor, or, if you are using Visual Studio, you can use it as well. +You can solve the conflicts in your favorite text editor or Visual Studio. Visual Studio actually presents the conflict in a very nice way to solve them. -Also, on the `go back to your working branch` step you can go back to using Visual Studio to control git, if you +Also, on the `go back to your working branch` step you can go back to using Visual Studio to control git if you prefer that. If you know git well, you can rebase your changes instead of merging them. If not, it is ok to merge them. @@ -270,7 +267,7 @@ discussing and fixing they are accepted. Work with the community to get it to be * Your pull requested will be commented by the Coveralls bot. Make sure code coverage has not gone down significantly. Ideally, it should go up. If you work on something that you have not yet discussed with the maintainers -there is a chance the code might be denied because they might find the analyzer/fix is not necessary, or duplicated, or some other reason. +there is a chance the code might be denied because they might find the analyzer/fix is not necessary, duplicated, or some other reason. They are easily reachable through Twitter or on Github. Before you code discuss it with it them. Small code changes or updates outside code files will eventually be made by the core team directly on `master`, without a PR. @@ -284,7 +281,7 @@ Small code changes or updates outside code files will eventually be made by the Contributors can be found at the [contributors](https://github.com/code-cracker/code-cracker/graphs/contributors) page on Github. -### What are the maintainers responsibilities? +### What are the maintainers' responsibilities? The maintainers have to: @@ -307,5 +304,5 @@ Please see our [contact page](http://code-cracker.github.io/contact.html). This software is open source, licensed under the Apache License, Version 2.0. See [LICENSE.txt](https://github.com/code-cracker/code-cracker/blob/master/LICENSE.txt) for details. Check out the terms of the license before you contribute, fork, copy or do anything -with the code. If you decide to contribute you agree to grant copyright of all your contribution to this project, and agree to +with the code. If you decide to contribute you agree to grant copyright of all your contribution to this project and agree to mention clearly if do not agree to these terms. Your work will be licensed with the project at Apache V2, along the rest of the code. From cd95c2f4b39fdd979ae103f4e47b353185769236 Mon Sep 17 00:00:00 2001 From: Manish17292000 <43097382+Manish17292000@users.noreply.github.com> Date: Tue, 2 Oct 2018 19:34:38 +0530 Subject: [PATCH 335/358] Create hello.cpp --- hello.cpp | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 hello.cpp diff --git a/hello.cpp b/hello.cpp new file mode 100644 index 000000000..5df26f4c2 --- /dev/null +++ b/hello.cpp @@ -0,0 +1,7 @@ +#include + +int main() +{ + std::cout << "Hello, World!"; + return 0; +} From 7ad7ad8f1bf9d7af9f08fbee754df73d3bbd0486 Mon Sep 17 00:00:00 2001 From: Carl Troll Date: Sat, 6 Oct 2018 13:19:27 +0200 Subject: [PATCH 336/358] Enhancement for #922 --- .../Style/TaskNameAsyncCodeFixProvider.cs | 29 +++- .../Style/TaskNameASyncTests.cs | 132 ++++++++++++++++++ 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs index 198444fb5..01b9aa6d3 100644 --- a/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/TaskNameAsyncCodeFixProvider.cs @@ -12,7 +12,7 @@ namespace CodeCracker.CSharp.Style { - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(TaskNameAsyncCodeFixProvider)), Shared] + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CodeFixProvider)), Shared] public class TaskNameAsyncCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.TaskNameAsync.ToDiagnosticId()); @@ -46,7 +46,12 @@ private static async Task ChangeMethodNameAsync(Document document, Dia var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var methodStatement = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType().First(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var newName = methodStatement.Identifier.ToString() + "Async"; + var oldName = methodStatement.Identifier.ToString(); + if (HasAsyncCorrectlyInName(oldName)) + { + oldName = oldName.Remove(oldName.IndexOf("Async"), "Async".Length); + } + var newName = oldName + "Async"; var solution = document.Project.Solution; var symbol = semanticModel.GetDeclaredSymbol(methodStatement, cancellationToken); var options = solution.Workspace.Options; @@ -54,5 +59,25 @@ private static async Task ChangeMethodNameAsync(Document document, Dia options, cancellationToken).ConfigureAwait(false); return newSolution; } + + private static bool HasAsyncCorrectlyInName(string name) + { + var index = name.IndexOf("Async"); + if (index < 0) + { + return false; + } + + var postAsyncLetterIndex = index + "Async".Length; + if (postAsyncLetterIndex >= name.Length) + { + return false; + } + + var valueAfterAsync = name[postAsyncLetterIndex]; + return char.IsDigit(valueAfterAsync) + || (char.IsLetter(valueAfterAsync) && char.IsUpper(valueAfterAsync)) + || valueAfterAsync == '_'; + } } } \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs index e897d37b1..8074e4809 100644 --- a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs @@ -262,5 +262,137 @@ Task IBar.Foo() }; await VerifyCSharpDiagnosticAsync(source, expected); } + + [Fact] + public async Task ChangeTaskNameWithAsyncNotAtTheEndWithUpperCaseLetter() + { + const string source = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public class Foo + { + public methodTest() + { + await Test(); + } + + public Task TestAsyncFoo() + { + return true; + } + } + + }"; + const string fixtest = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public class Foo + { + public methodTest() + { + await TestAsync(); + } + + public Task TestFooAsync() + { + return true; + } + } + + }"; + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task ChangeTaskNameWithAsyncNotAtTheEndWithUnderline() + { + const string source = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public class Foo + { + public methodTest() + { + await Test(); + } + + public Task TestAsync_Foo() + { + return true; + } + } + + }"; + const string fixtest = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public class Foo + { + public methodTest() + { + await TestAsync(); + } + + public Task Test_FooAsync() + { + return true; + } + } + + }"; + await VerifyCSharpFixAsync(source, fixtest); + } + + [Fact] + public async Task ChangeTaskNameWithAsyncNotAtTheEndWithDigit() + { + const string source = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public class Foo + { + public methodTest() + { + await Test(); + } + + public Task TestAsync0Foo() + { + return true; + } + } + + }"; + const string fixtest = @" + using System.Threading.Tasks; + + namespace ConsoleApplication1 + { + public class Foo + { + public methodTest() + { + await TestAsync(); + } + + public Task Test0FooAsync() + { + return true; + } + } + + }"; + await VerifyCSharpFixAsync(source, fixtest); + } } } \ No newline at end of file From 8beb4cddaef68c447fab64f79dcd09ef7f61bf62 Mon Sep 17 00:00:00 2001 From: Carl Troll Date: Sat, 6 Oct 2018 14:18:27 +0200 Subject: [PATCH 337/358] #922 test fix --- .../CodeCracker.Test/Style/TaskNameASyncTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs index 8074e4809..44299b862 100644 --- a/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/TaskNameASyncTests.cs @@ -275,7 +275,7 @@ public class Foo { public methodTest() { - await Test(); + await TestAsyncFoo(); } public Task TestAsyncFoo() @@ -294,7 +294,7 @@ public class Foo { public methodTest() { - await TestAsync(); + await TestFooAsync(); } public Task TestFooAsync() @@ -319,7 +319,7 @@ public class Foo { public methodTest() { - await Test(); + await TestAsync_Foo(); } public Task TestAsync_Foo() @@ -338,7 +338,7 @@ public class Foo { public methodTest() { - await TestAsync(); + await Test_FooAsync(); } public Task Test_FooAsync() @@ -363,7 +363,7 @@ public class Foo { public methodTest() { - await Test(); + await TestAsync0Foo(); } public Task TestAsync0Foo() @@ -382,7 +382,7 @@ public class Foo { public methodTest() { - await TestAsync(); + await Test0FooAsync(); } public Task Test0FooAsync() From 9b66639413cbf1afdfe52e2acc107446c6f5b1da Mon Sep 17 00:00:00 2001 From: Carl Troll Date: Mon, 8 Oct 2018 10:16:02 +0200 Subject: [PATCH 338/358] Make CC0011 work with IQueryable and Async methods --- .../RemoveWhereWhenItIsPossibleAnalyzer.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs index aa7fbda5e..a38da9608 100644 --- a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs @@ -25,8 +25,17 @@ public class RemoveWhereWhenItIsPossibleAnalyzer : DiagnosticAnalyzer "Any", "Single", "SingleOrDefault", - "Count" + "Count", + "FirstAsync", + "FirstOrDefaultAsync", + "LastAsync", + "LastOrDefaultAsync", + "AnyAsync", + "SingleAsync", + "SingleOrDefaultAsync", + "CountAsync" }; + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), Title, From 965944d0557db706cab329f576d2e6599c681424 Mon Sep 17 00:00:00 2001 From: carlilord Date: Mon, 8 Oct 2018 10:26:05 +0200 Subject: [PATCH 339/358] Delete RemoveWhereWhenItIsPossibleAnalyzer.cs --- .../RemoveWhereWhenItIsPossibleAnalyzer.cs | 90 ------------------- 1 file changed, 90 deletions(-) delete mode 100644 src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs diff --git a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs deleted file mode 100644 index a38da9608..000000000 --- a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; - -namespace CodeCracker.CSharp.Performance -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class RemoveWhereWhenItIsPossibleAnalyzer : DiagnosticAnalyzer - { - internal const string Title = "You should remove the 'Where' invocation when it is possible."; - internal const string MessageFormat = "You can remove 'Where' moving the predicate to '{0}'."; - internal const string Category = SupportedCategories.Performance; - const string Description = "When a linq operator support a predicate parameter it should be used instead of " - + "using 'Where' followed by the operator"; - - static readonly string[] supportedMethods = new[] { - "First", - "FirstOrDefault", - "Last", - "LastOrDefault", - "Any", - "Single", - "SingleOrDefault", - "Count", - "FirstAsync", - "FirstOrDefaultAsync", - "LastAsync", - "LastOrDefaultAsync", - "AnyAsync", - "SingleAsync", - "SingleOrDefaultAsync", - "CountAsync" - }; - - internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), - Title, - MessageFormat, - Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: Description, - helpLinkUri: HelpLink.ForDiagnostic(DiagnosticId.RemoveWhereWhenItIsPossible)); - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); - - public override void Initialize(AnalysisContext context) => - context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); - - private static void AnalyzeNode(SyntaxNodeAnalysisContext context) - { - if (context.IsGenerated()) return; - var whereInvoke = (InvocationExpressionSyntax)context.Node; - var nameOfWhereInvoke = GetNameOfTheInvokedMethod(whereInvoke); - if (nameOfWhereInvoke?.ToString() != "Where") return; - if (ArgumentsDoNotMatch(whereInvoke)) return; - - var nextMethodInvoke = whereInvoke.Parent. - FirstAncestorOrSelf(); - if (nextMethodInvoke == null) return; - - var candidate = GetNameOfTheInvokedMethod(nextMethodInvoke)?.ToString(); - if (!supportedMethods.Contains(candidate)) return; - - if (nextMethodInvoke.ArgumentList.Arguments.Any()) return; - var properties = new Dictionary { { "methodName", candidate } }.ToImmutableDictionary(); - var diagnostic = Diagnostic.Create(Rule, nameOfWhereInvoke.GetLocation(), properties, candidate); - context.ReportDiagnostic(diagnostic); - } - - private static bool ArgumentsDoNotMatch(InvocationExpressionSyntax whereInvoke) - { - var arguments = whereInvoke.ArgumentList.Arguments; - if (arguments.Count != 1) return true; - var expression = arguments.First()?.Expression; - if (expression == null) return true; - if (expression is SimpleLambdaExpressionSyntax) return false; - var parenthesizedLambda = expression as ParenthesizedLambdaExpressionSyntax; - if (parenthesizedLambda == null) return true; - return parenthesizedLambda.ParameterList.Parameters.Count != 1; - } - - private static SimpleNameSyntax GetNameOfTheInvokedMethod(InvocationExpressionSyntax invoke) => - invoke.ChildNodes().OfType().FirstOrDefault()?.Name; - } -} \ No newline at end of file From a6c1d1b93a81efd3da2dfce464963e127a26f16d Mon Sep 17 00:00:00 2001 From: carlilord Date: Mon, 8 Oct 2018 10:28:24 +0200 Subject: [PATCH 340/358] Make CC0011 work with IQueryable and Async methods Fixes #905 --- .../RemoveWhereWhenItIsPossibleAnalyzer.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs index aa7fbda5e..9ba262a53 100644 --- a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs @@ -25,8 +25,17 @@ public class RemoveWhereWhenItIsPossibleAnalyzer : DiagnosticAnalyzer "Any", "Single", "SingleOrDefault", - "Count" + "Count", + "FirstAsync", + "FirstOrDefaultAsync", + "LastAsync", + "LastOrDefaultAsync", + "AnyAsync", + "SingleAsync", + "SingleOrDefaultAsync", + "CountAsync" }; + internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), Title, @@ -78,4 +87,4 @@ private static bool ArgumentsDoNotMatch(InvocationExpressionSyntax whereInvoke) private static SimpleNameSyntax GetNameOfTheInvokedMethod(InvocationExpressionSyntax invoke) => invoke.ChildNodes().OfType().FirstOrDefault()?.Name; } -} \ No newline at end of file +} From ba0b8e496b24497a0b39cde87ce650e754c3547d Mon Sep 17 00:00:00 2001 From: Carl Troll Date: Mon, 8 Oct 2018 10:32:37 +0200 Subject: [PATCH 341/358] Revert --- .../Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs index a38da9608..1332ab9a1 100644 --- a/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs +++ b/src/CSharp/CodeCracker/Performance/RemoveWhereWhenItIsPossibleAnalyzer.cs @@ -25,15 +25,7 @@ public class RemoveWhereWhenItIsPossibleAnalyzer : DiagnosticAnalyzer "Any", "Single", "SingleOrDefault", - "Count", - "FirstAsync", - "FirstOrDefaultAsync", - "LastAsync", - "LastOrDefaultAsync", - "AnyAsync", - "SingleAsync", - "SingleOrDefaultAsync", - "CountAsync" + "Count" }; internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( From 9342e9f804712c7090eccdc11af93d7f3c9f98f3 Mon Sep 17 00:00:00 2001 From: Umang Raval Date: Mon, 8 Oct 2018 20:02:45 +0530 Subject: [PATCH 342/358] corrected grammatical errors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfb59721e..24b95237a 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ The DoD is still evolving. At the present time the checklist is as follows: 1. Always named `CodeFixProvider` 2. Always use the same diagnostic id added to the `DiagnosticIds.cs` file, unless you are writing a code fix for a diagnostic id raised by the C# compiler itself (starting with `CS`). -6. Fix all scenarios (fix all in document, fix all in project and fix all in solution) work. You might need to write a `FixAllProvider`. Check the `DisposableVariableNotDisposedFixAllProvider` as an example. +6. Fix all scenarios (fix all in a document, fix all in a project and fix all in solution) work. You might need to write a `FixAllProvider`. Check the `DisposableVariableNotDisposedFixAllProvider` as an example. 7. Follow the coding standards present on the project code files. 8. Works in Visual Studio 9. Uses localizable strings From c35c6cb1364267782a66c48e0578ee649dbecf6d Mon Sep 17 00:00:00 2001 From: Isuru40 Date: Sat, 20 Oct 2018 11:30:52 +0530 Subject: [PATCH 343/358] Update Hacktoberfest --- Hacktoberfest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hacktoberfest b/Hacktoberfest index 316700cd9..28c43036f 100644 --- a/Hacktoberfest +++ b/Hacktoberfest @@ -23,4 +23,4 @@ Create a remote to link the repository on github to your local workspace. use "g Push the commit. For example, type "git push [remote-name] master". Go back to the original repo. Hit "new pull request" and compare between forks. -Confirm the pull request and that's it! +Confirm the pull request and that's it!!! From 9ccc2bb21012d0845156af28fab4e56f15cd8474 Mon Sep 17 00:00:00 2001 From: Neil Bostrom Date: Sun, 18 Nov 2018 22:06:00 +0000 Subject: [PATCH 344/358] Fixes #930 CC0020 cannot be used when types are declared --- ...ertLambdaExpressionToMethodGroupAnalyzer.cs | 8 +++++++- ...onvertLambdaExpressionToMethodGroupTests.cs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs b/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs index 671e55349..bb335f76d 100644 --- a/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs +++ b/src/CSharp/CodeCracker/Style/ConvertLambdaExpressionToMethodGroupAnalyzer.cs @@ -65,7 +65,13 @@ internal static InvocationExpressionSyntax GetInvocationIfAny(SyntaxNode node) : (node as ParenthesizedLambdaExpressionSyntax)?.Body; var invocation = body as InvocationExpressionSyntax; - if (invocation != null) return invocation; + + if (invocation != null) + { + if (invocation.Expression is GenericNameSyntax && (((GenericNameSyntax)invocation.Expression).TypeArgumentList.Arguments.Count > 0)) return null; + + return invocation; + } var possibleBlock = body as BlockSyntax; if (possibleBlock == null || possibleBlock.Statements.Count != 1) return null; diff --git a/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs b/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs index 0a968adf9..f26fcd8b9 100644 --- a/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/ConvertLambdaExpressionToMethodGroupTests.cs @@ -598,5 +598,23 @@ public static Task Finally(this Task task, Func(); + xs.Select(x => Func(x)); + } + object Func(object x) => x; +}"; + await VerifyCSharpHasNoDiagnosticsAsync(oldCode); + } + } } \ No newline at end of file From 80f53b29811fdf36a57a8b8119eea8fc33f25456 Mon Sep 17 00:00:00 2001 From: carlilord Date: Fri, 23 Nov 2018 10:08:54 +0100 Subject: [PATCH 345/358] #905 added unit test --- .../CodeCracker.Test/CodeCracker.Test.csproj | 1 + .../Helpers/IQueriableExtensions.cs | 43 +++++ .../RemoveWhereWhenItIsPossibleTests.cs | 160 ++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 test/CSharp/CodeCracker.Test/Helpers/IQueriableExtensions.cs diff --git a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj index 4d186cfbe..7796725c8 100644 --- a/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj +++ b/test/CSharp/CodeCracker.Test/CodeCracker.Test.csproj @@ -120,6 +120,7 @@ + diff --git a/test/CSharp/CodeCracker.Test/Helpers/IQueriableExtensions.cs b/test/CSharp/CodeCracker.Test/Helpers/IQueriableExtensions.cs new file mode 100644 index 000000000..c37c9ebf4 --- /dev/null +++ b/test/CSharp/CodeCracker.Test/Helpers/IQueriableExtensions.cs @@ -0,0 +1,43 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeCracker.Test.CSharp.Helpers +{ + public static class IQueriableExtensions + { +#pragma warning disable CC0057 // Unused parameters + public static Task FirstAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => null; + + public static Task FirstOrDefaultAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => null; + + public static Task LastAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => null; + + public static Task LastOrDefaultAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => null; + + public static Task AnyAsync(this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => Task.FromResult(false); + + public static Task SingleAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => null; + + public static Task SingleOrDefaultAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => null; + + public static Task CountAsync( + this IQueryable source, + CancellationToken cancellationToken = default(CancellationToken)) => Task.FromResult(0); + +#pragma warning restore CC0057 // Unused parameters + } +} \ No newline at end of file diff --git a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs index c6e4b622a..17222105f 100644 --- a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs @@ -154,6 +154,166 @@ public async Task DoSomething() var expected = @" using System.Linq; +namespace Sample +{ + public class Foo + { + public async Task DoSomething() + { + var a = new int[10]; + var f = a.OrderBy(item => item)." + method + @"(item => item > 10); + } + } +}"; + + await VerifyCSharpFixAsync(test, expected); + + } + + // Async + [Theory] + [InlineData("FirstAsync")] + [InlineData("FirstOrDefaultAsync")] + [InlineData("LastAsync")] + [InlineData("LastOrDefaultAsync")] + [InlineData("AnyAsync")] + [InlineData("SingleAsync")] + [InlineData("SingleOrDefaultAsync")] + [InlineData("CountAsync")] + public async Task CreateDiagnosticWhenUsingWhereWithAsync(string method) + { + var test = @" +using System.Linq; + +namespace Sample +{ + public class Foo + { + public async Task DoSomething() + { + var a = new int[10]; + var f = a.Where(item => item > 10)." + method + @"(); + } + } +}"; + var expected = new DiagnosticResult + { + Id = DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), + Message = "You can remove 'Where' moving the predicate to '" + method + "'.", + Severity = DiagnosticSeverity.Warning, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 23) } + }; + + await VerifyCSharpDiagnosticAsync(test, expected); + + } + + [Theory] + [InlineData("FirstAsync")] + [InlineData("FirstOrDefaultAsync")] + [InlineData("LastAsync")] + [InlineData("LastOrDefaultAsync")] + [InlineData("AnyAsync")] + [InlineData("SingleAsync")] + [InlineData("SingleOrDefaultAsync")] + [InlineData("CountAsync")] + public async Task DoNotCreateDiagnosticWhenUsingWhereAndAnotherMethodWithPredicatesAsync(string method) + { + var test = @" +using System.Linq; + +namespace Sample +{ + public class Foo + { + public async Task DoSomething() + { + var a = new int[10]; + var f = a.Where(item => item > 10)." + method + @"(item => item < 50); + } + } +}"; + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Fact] + public async Task DoNotCreateDiagnosticWhenWhereUsesIndexerAsync() + { + var test = @" +var first = Enumerable.Range(1, 10).ToList(); +var second = Enumerable.Range(1, 10); +var isNotMatch = second.Where((t, i) => first[i] != t).Any(); +".WrapInCSharpMethod(usings: "using System.Linq;"); + await VerifyCSharpHasNoDiagnosticsAsync(test); + } + + [Theory] + [InlineData("FirstAsync")] + [InlineData("FirstOrDefaultAsync")] + [InlineData("LastAsync")] + [InlineData("LastOrDefaultAsync")] + [InlineData("AnyAsync")] + [InlineData("SingleAsync")] + [InlineData("SingleOrDefaultAsync")] + [InlineData("CountAsync")] + public async Task FixRemovesWhereMovingPredicateToAsync(string method) + { + var test = @" +namespace Sample +{ + public class Foo + { + public async Task DoSomething() + { + var a = new int[10]; + var f = a.Where((item) => item > 10)." + method + @"(); + } + } +}"; + var expected = @" +namespace Sample +{ + public class Foo + { + public async Task DoSomething() + { + var a = new int[10]; + var f = a." + method + @"((item) => item > 10); + } + } +}"; + await VerifyCSharpFixAsync(test, expected); + } + + [Theory] + [InlineData("FirstAsync")] + [InlineData("FirstOrDefaultAsync")] + [InlineData("LastAsync")] + [InlineData("LastOrDefaultAsync")] + [InlineData("AnyAsync")] + [InlineData("SingleAsync")] + [InlineData("SingleOrDefaultAsync")] + [InlineData("CountAsync")] + public async Task FixRemovesWherePreservingPreviousExpressionsMovingPredicateToAsync(string method) + { + var test = @" +using System.Linq; + +namespace Sample +{ + public class Foo + { + public async Task DoSomething() + { + var a = new int[10]; + var f = a.OrderBy(item => item).Where(item => item > 10)." + method + @"(); + } + } +}"; + + var expected = @" +using System.Linq; + namespace Sample { public class Foo From 1536af459849daac58cd182bfa2131c1ae5461a1 Mon Sep 17 00:00:00 2001 From: carlilord Date: Fri, 23 Nov 2018 10:20:07 +0100 Subject: [PATCH 346/358] build fix --- .../Performance/RemoveWhereWhenItIsPossibleTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs index 17222105f..3d55fa490 100644 --- a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs @@ -170,7 +170,6 @@ public async Task DoSomething() } - // Async [Theory] [InlineData("FirstAsync")] [InlineData("FirstOrDefaultAsync")] From ee521d7400df52b4f3e7734297d44111b0b4c2a9 Mon Sep 17 00:00:00 2001 From: carlilord Date: Fri, 23 Nov 2018 10:23:10 +0100 Subject: [PATCH 347/358] test adaption --- .../RemoveWhereWhenItIsPossibleTests.cs | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs index 3d55fa490..a953a1360 100644 --- a/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs +++ b/test/CSharp/CodeCracker.Test/Performance/RemoveWhereWhenItIsPossibleTests.cs @@ -170,43 +170,6 @@ public async Task DoSomething() } - [Theory] - [InlineData("FirstAsync")] - [InlineData("FirstOrDefaultAsync")] - [InlineData("LastAsync")] - [InlineData("LastOrDefaultAsync")] - [InlineData("AnyAsync")] - [InlineData("SingleAsync")] - [InlineData("SingleOrDefaultAsync")] - [InlineData("CountAsync")] - public async Task CreateDiagnosticWhenUsingWhereWithAsync(string method) - { - var test = @" -using System.Linq; - -namespace Sample -{ - public class Foo - { - public async Task DoSomething() - { - var a = new int[10]; - var f = a.Where(item => item > 10)." + method + @"(); - } - } -}"; - var expected = new DiagnosticResult - { - Id = DiagnosticId.RemoveWhereWhenItIsPossible.ToDiagnosticId(), - Message = "You can remove 'Where' moving the predicate to '" + method + "'.", - Severity = DiagnosticSeverity.Warning, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", 11, 23) } - }; - - await VerifyCSharpDiagnosticAsync(test, expected); - - } - [Theory] [InlineData("FirstAsync")] [InlineData("FirstOrDefaultAsync")] From 62c719a8526fe68d7c1707ea690d4736c56b3fe1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 4 Jan 2019 16:22:19 +0100 Subject: [PATCH 348/358] Insert missing link Insert missing link to issue #66 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24b95237a..d30381db7 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ and [#10](https://github.com/code-cracker/code-cracker/issues/10). These are the 4 severity levels supported on Roslyn and how they are understood on the Code Cracker project: -1. **Hidden**: Only used for refactorings. See #66 (and its comments) to understand why. +1. **Hidden**: Only used for refactorings. See [#66](https://github.com/code-cracker/code-cracker/issues/66) (and its comments) to understand why. 2. **Info**: An alternative way (ex: replacing for with foreach). Clearly, a matter of opinion and/or current way could be correct, or maybe the new code could be correct. We cannot determine. 3. **Warning**: Code that could/should be improved. It is a code smell and most likely is wrong, but there are situations where the pattern is acceptable or desired. 4. **Error**: Clearly a mistake (ex: throwing ArgumentException with a non-existent parameter). There is no situation where this code could be correct. There are no differences of opinion. From cda01dbd1c28f8c5bdbc0cfd13bf8cca40aeaa0a Mon Sep 17 00:00:00 2001 From: Matthieu Penant Date: Wed, 3 Apr 2019 11:54:45 -0400 Subject: [PATCH 349/358] VS2019 Support fix the errors on prerequisites --- .../CodeCracker.Vsix/debug/source.extension.vsixmanifest | 4 ++-- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 4 ++-- .../CodeCracker.Vsix/debug/source.extension.vsixmanifest | 4 ++-- .../CodeCracker.Vsix/source.extension.vsixmanifest | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/CSharp/CodeCracker.Vsix/debug/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/debug/source.extension.vsixmanifest index e81a560f6..e0b59f52d 100644 --- a/src/CSharp/CodeCracker.Vsix/debug/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/debug/source.extension.vsixmanifest @@ -28,7 +28,7 @@ This is a community project, free and open source. Everyone is invited to contri - - + + diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index aa1218012..7931195c2 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -27,7 +27,7 @@ This is a community project, free and open source. Everyone is invited to contri - - + + diff --git a/src/VisualBasic/CodeCracker.Vsix/debug/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/debug/source.extension.vsixmanifest index 6f6ab34bd..0595693d0 100644 --- a/src/VisualBasic/CodeCracker.Vsix/debug/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/debug/source.extension.vsixmanifest @@ -28,7 +28,7 @@ This is a community project, free and open source. Everyone is invited to contri - - + + diff --git a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest index 3de517a30..01fa41c09 100644 --- a/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/VisualBasic/CodeCracker.Vsix/source.extension.vsixmanifest @@ -27,7 +27,7 @@ This is a community project, free and open source. Everyone is invited to contri - - + + From b706ff895d3fbeba106b3146b62d4d84002b5e7c Mon Sep 17 00:00:00 2001 From: Mithilesh Zavar Date: Sat, 6 Apr 2019 19:36:12 +0100 Subject: [PATCH 350/358] BUG: CC0065 "Remove trailing whitespace" bug with pragmas --- .../RemoveTrailingWhitespaceCodeFixProvider.cs | 2 +- .../Style/RemoveTrailingWhitespaceTests.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceCodeFixProvider.cs b/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceCodeFixProvider.cs index 0190ed41b..b4a94ff25 100644 --- a/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Style/RemoveTrailingWhitespaceCodeFixProvider.cs @@ -35,7 +35,7 @@ private static async Task RemoveTrailingWhiteSpaceAsync(Document docum { newRoot = root.ReplaceTrivia(trivia, new SyntaxTrivia[] { }); } - else if (trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia, SyntaxKind.MultiLineDocumentationCommentTrivia)) + else if (trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia, SyntaxKind.MultiLineDocumentationCommentTrivia, SyntaxKind.PragmaWarningDirectiveTrivia)) { var commentText = trivia.ToFullString(); var commentLines = commentText.Split(new[] { Environment.NewLine }, StringSplitOptions.None); diff --git a/test/CSharp/CodeCracker.Test/Style/RemoveTrailingWhitespaceTests.cs b/test/CSharp/CodeCracker.Test/Style/RemoveTrailingWhitespaceTests.cs index de6b62bae..2130d04d4 100644 --- a/test/CSharp/CodeCracker.Test/Style/RemoveTrailingWhitespaceTests.cs +++ b/test/CSharp/CodeCracker.Test/Style/RemoveTrailingWhitespaceTests.cs @@ -135,5 +135,21 @@ class Foo { }"; class Foo { }"; await VerifyCSharpFixAsync(source, expected, formatBeforeCompare: false); } + + [Fact] + public async Task PragmaWithTrailingSpace() + { + const string source = @" +#pragma warning disable CC0072 +#pragma warning restore CC0072 +"; + + const string expected = @" +#pragma warning disable CC0072 +#pragma warning restore CC0072 +"; + + await VerifyCSharpFixAsync(source, expected, formatBeforeCompare: false); + } } } \ No newline at end of file From 5d274c23236037ef02168eef7a27a0d2be169484 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Mon, 27 May 2019 14:19:35 +0200 Subject: [PATCH 351/358] Add property name to ExportCodeFixProviderAttribute. --- .../Design/StaticConstructorExceptionCodeFixProvider.cs | 2 +- .../XmlDocumentationMissingInCSharpCodeFixProvider.cs | 2 +- .../XmlDocumentationMissingInXmlCodeFixProvider.cs | 2 +- .../Refactoring/StringRepresentationCodeFixProvider.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.cs b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.cs index 38d620ba6..44ff21625 100644 --- a/src/CSharp/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Design/StaticConstructorExceptionCodeFixProvider.cs @@ -10,7 +10,7 @@ namespace CodeCracker.CSharp.Design { - [ExportCodeFixProvider(LanguageNames.CSharp, nameof(StaticConstructorExceptionCodeFixProvider)), Shared] + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StaticConstructorExceptionCodeFixProvider)), Shared] public class StaticConstructorExceptionCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs index 232533605..b0d5f4e9d 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInCSharpCodeFixProvider.cs @@ -12,7 +12,7 @@ namespace CodeCracker.CSharp.Maintainability { - [ExportCodeFixProvider(LanguageNames.CSharp, nameof(XmlDocumentationCodeFixProvider)), Shared] + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(XmlDocumentationCodeFixProvider)), Shared] public sealed class XmlDocumentationMissingInCSharpCodeFixProvider : XmlDocumentationCodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.XmlDocumentation_MissingInCSharp.ToDiagnosticId()); diff --git a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs index be54bc846..36e268fca 100644 --- a/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Maintainability/XmlDocumentationMissingInXmlCodeFixProvider.cs @@ -12,7 +12,7 @@ namespace CodeCracker.CSharp.Maintainability { - [ExportCodeFixProvider(LanguageNames.CSharp, nameof(XmlDocumentationCodeFixProvider)), Shared] + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(XmlDocumentationCodeFixProvider)), Shared] public sealed class XmlDocumentationMissingInXmlCodeFixProvider : XmlDocumentationCodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticId.XmlDocumentation_MissingInXml.ToDiagnosticId()); diff --git a/src/CSharp/CodeCracker/Refactoring/StringRepresentationCodeFixProvider.cs b/src/CSharp/CodeCracker/Refactoring/StringRepresentationCodeFixProvider.cs index 3f1934ac1..bd8d714c6 100644 --- a/src/CSharp/CodeCracker/Refactoring/StringRepresentationCodeFixProvider.cs +++ b/src/CSharp/CodeCracker/Refactoring/StringRepresentationCodeFixProvider.cs @@ -13,7 +13,7 @@ namespace CodeCracker.CSharp.Refactoring { - [ExportCodeFixProvider(LanguageNames.CSharp, nameof(StringRepresentationCodeFixProvider)), Shared] + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StringRepresentationCodeFixProvider)), Shared] public class StringRepresentationCodeFixProvider : CodeFixProvider { public const string Id = nameof(StringRepresentationCodeFixProvider); From cf422cc5031c13659250f2ad44a82d1f350ce2b5 Mon Sep 17 00:00:00 2001 From: sunny kumar Date: Tue, 1 Oct 2019 13:10:35 +0530 Subject: [PATCH 352/358] Change : added << endl in hello.cpp --- hello.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hello.cpp b/hello.cpp index 5df26f4c2..378706961 100644 --- a/hello.cpp +++ b/hello.cpp @@ -2,6 +2,6 @@ int main() { - std::cout << "Hello, World!"; + std::cout << "Hello, World!" << endl; return 0; } From 83f23667f3cb5748d979ece4158ef53ce83cccbf Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Thu, 21 Nov 2019 14:26:55 -0300 Subject: [PATCH 353/358] Version 2019 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index 7931195c2..b3b107180 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Code Cracker for C# 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. From 5cab9bfd2aabf83e687377ecfdbf9762db9880cd Mon Sep 17 00:00:00 2001 From: Carlos dos Santos Date: Thu, 21 Nov 2019 14:41:30 -0300 Subject: [PATCH 354/358] VSIX 2019 --- src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest index b3b107180..a495c36ac 100644 --- a/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest +++ b/src/CSharp/CodeCracker.Vsix/source.extension.vsixmanifest @@ -2,7 +2,7 @@ - Code Cracker for C# + Code Cracker for C# (2019) 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. Build status Nuget count Nuget downloads Issues open From 2e44309a8dd7febcf9e2fb1d85c0ed17734d3082 Mon Sep 17 00:00:00 2001 From: "dsharov@devpark.ru" Date: Tue, 22 Mar 2022 17:39:58 +0600 Subject: [PATCH 355/358] Added parser for inline using --- .../DisposableVariableNotDisposedAnalyzer.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs index 3ed958b5f..83544effa 100644 --- a/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs +++ b/src/CSharp/CodeCracker/Usage/DisposableVariableNotDisposedAnalyzer.cs @@ -78,6 +78,28 @@ private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) var usingStatement = variableDeclaration?.Parent as UsingStatementSyntax; if (usingStatement != null) return; statement = variableDeclaration.Parent as LocalDeclarationStatementSyntax; + if (statement != null) + { + //Check inline using + var isUsing = false; + var isSemicolon = false; + var firstToken = statement.GetFirstToken(); + if (firstToken != null) + { + isUsing = firstToken.Text == "using"; + } + + var lastToken = statement.GetLastToken(); + if (lastToken != null) + { + isSemicolon = lastToken.Text == ";"; + } + + var isVariableDeclaration = statement.ChildNodes().First() is VariableDeclarationSyntax; + + if (isUsing && isVariableDeclaration && isSemicolon) return; + } + if ((statement?.FirstAncestorOrSelf()) == null) return; } else if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression)) From a3536314991e0e8958348388a3581526d98b8a9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jun 2022 00:01:24 +0000 Subject: [PATCH 356/358] Bump NuGet.CommandLine from 4.6.2 to 4.9.5 in /.nuget Bumps NuGet.CommandLine from 4.6.2 to 4.9.5. --- updated-dependencies: - dependency-name: NuGet.CommandLine dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .nuget/packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nuget/packages.config b/.nuget/packages.config index b1704a67b..87d34f8af 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,6 +1,6 @@  - + From 39202fbde4d63a722519cb2847b9b8ba7bb0dc9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Dec 2022 01:35:12 +0000 Subject: [PATCH 357/358] Bump Newtonsoft.Json in /test/Common/CodeCracker.Test.Common Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 11.0.2 to 13.0.2. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/11.0.2...13.0.2) --- updated-dependencies: - dependency-name: Newtonsoft.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../CodeCracker.Test.Common/CodeCracker.Test.Common.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj index ee17f57f6..ab8625db9 100644 --- a/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj +++ b/test/Common/CodeCracker.Test.Common/CodeCracker.Test.Common.csproj @@ -48,7 +48,7 @@ - + From 15a265d6e8c1566ad145df8bfcb252753a1c43e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 22:56:09 +0000 Subject: [PATCH 358/358] Bump NuGet.CommandLine from 4.9.5 to 5.11.5 in /.nuget Bumps [NuGet.CommandLine](https://github.com/NuGet/NuGet.Client) from 4.9.5 to 5.11.5. - [Release notes](https://github.com/NuGet/NuGet.Client/releases) - [Commits](https://github.com/NuGet/NuGet.Client/commits) --- updated-dependencies: - dependency-name: NuGet.CommandLine dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .nuget/packages.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.nuget/packages.config b/.nuget/packages.config index 87d34f8af..ac480de76 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,6 +1,6 @@ - + - +