// // Gendarme.Rules.Smells.AvoidCodeDuplicatedInSameClassRule class // // Authors: // Néstor Salceda // // (C) 2007 Néstor Salceda // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using Mono.Cecil; using Gendarme.Framework; using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Smells { /// /// This rule checks for duplicated code in the same class. /// /// /// Bad example: /// /// public class MyClass { /// private IList myList; /// /// public MyClass () { /// myList = new ArrayList (); /// myList.Add ("Foo"); /// myList.Add ("Bar"); /// myList.Add ("Baz"); /// } /// /// public void MakeStuff () { /// foreach (string value in myList) { /// Console.WriteLine (value); /// } /// myList.Add ("FooReplied"); /// } /// /// public void MakeMoreStuff () { /// foreach (string value in myList) { /// Console.WriteLine (value); /// } /// myList.Remove ("FooReplied"); /// } /// } /// /// /// /// Good example: /// /// public class MyClass { /// private IList myList; /// /// public MyClass () { /// myList = new ArrayList (); /// myList.Add ("Foo"); /// myList.Add ("Bar"); /// myList.Add ("Baz"); /// } /// /// private void PrintValuesInList () { /// foreach (string value in myList) { /// Console.WriteLine (value); /// } /// } /// /// public void MakeStuff () { /// PrintValuesInList (); /// myList.Add ("FooReplied"); /// } /// /// public void MakeMoreStuff () { /// PrintValuesInList (); /// myList.Remove ("FooReplied"); /// } /// } /// /// [Problem ("There is similar code in various methods in the same class. Your code will be better if you can unify them.")] [Solution ("You should apply the Extract Method refactoring and have a single implementation of the code.")] public class AvoidCodeDuplicatedInSameClassRule : Rule, ITypeRule { private CodeDuplicatedLocator locator; public AvoidCodeDuplicatedInSameClassRule () { locator = new CodeDuplicatedLocator (this); } public RuleResult CheckType (TypeDefinition type) { // don't analyze cases where no methods (or body) are available if (type.IsEnum || type.IsInterface || !type.HasMethods) return RuleResult.DoesNotApply; // ignore code generated by compiler/tools, since they can generate some amount of duplicated code if (type.IsGeneratedCode ()) return RuleResult.DoesNotApply; locator.Clear (); foreach (MethodDefinition current in type.AllMethods ()) { locator.CompareMethodAgainstTypeMethods (current, type); locator.CheckedMethods.AddIfNew (current.Name); } return Runner.CurrentRuleResult; } } }