Coverage Report - org.argouml.uml.cognitive.critics.CrOperNameConflict
 
Classes in this File Line Coverage Branch Coverage Complexity
CrOperNameConflict
18%
11/58
0%
0/48
7.6
 
 1  
 /* $Id: CrOperNameConflict.java 17849 2010-01-12 19:50:34Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    maurelio1234
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2007 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.uml.cognitive.critics;
 40  
 
 41  
 import java.util.ArrayList;
 42  
 import java.util.Collection;
 43  
 import java.util.HashSet;
 44  
 import java.util.Iterator;
 45  
 import java.util.Set;
 46  
 
 47  
 import javax.swing.Icon;
 48  
 
 49  
 import org.argouml.cognitive.Critic;
 50  
 import org.argouml.cognitive.Designer;
 51  
 import org.argouml.model.Model;
 52  
 import org.argouml.uml.cognitive.UMLDecision;
 53  
 
 54  
 /**
 55  
  * A critic to detect when a class has operations with two matching
 56  
  * signatures.<p>
 57  
  *
 58  
  * Takes each operation in turn and compares its signature with all
 59  
  * earlier operations. This version corrects and earlier bug, which
 60  
  * checked for matching names as well as types in the parameter
 61  
  * list.<p>
 62  
  *
 63  
  * <em>Warning</em>. The algorithm in is quadratic in the number of
 64  
  * operations. It could be computationally demanding on a design where
 65  
  * classes have a lot of operations. See the {@link #predicate2}
 66  
  * method for possible solutions.<p>
 67  
  *
 68  
  * See the ArgoUML User Manual: Change Names or Signatures in &lt;artifact&gt;
 69  
  *
 70  
  * @author jrobbins@ics.uci.edu
 71  
  */
 72  
 
 73  
 public class CrOperNameConflict extends CrUML {
 74  
 
 75  
     /**
 76  
      * Constructor for the critic.<p>
 77  
      *
 78  
      * Sets up the resource name, which will allow headline and
 79  
      * description to found for the current locale. Provides design
 80  
      * issue categories (METHODS, NAMING), sets a knowledge type
 81  
      * (SYNTAX) and adds triggers for metaclasses "behaviouralFeature"
 82  
      * and feature_name".<p>
 83  
      */
 84  177040759
     public CrOperNameConflict() {
 85  177040759
         setupHeadAndDesc();
 86  177040759
         addSupportedDecision(UMLDecision.METHODS);
 87  177040759
         addSupportedDecision(UMLDecision.NAMING);
 88  
 
 89  177040759
         setKnowledgeTypes(Critic.KT_SYNTAX);
 90  
 
 91  
         // These may not actually make any difference at present (the code
 92  
         // behind addTrigger needs more work).
 93  
 
 94  177040759
         addTrigger("behavioralFeature");
 95  177040759
         addTrigger("feature_name");
 96  177040759
     }
 97  
 
 98  
 
 99  
     /**
 100  
      * The trigger for the critic.<p>
 101  
      *
 102  
      * Finds all the operations for the given classifier. Takes each
 103  
      * operation in turn and compares its signature with all earlier
 104  
      * operations. This version corrects an earlier bug, which checked
 105  
      * for matching names as well as types in the parameter list.<p>
 106  
      *
 107  
      * <em>Note</em>. The signature ignores any return parameters in
 108  
      * looking for a match. This is in line with Java/C++.<p>
 109  
      *
 110  
      * We do not need to worry about signature clashes that are
 111  
      * inherited (overloading). This is something encouraged in many
 112  
      * OO environments to facilitate polymorphism.<p>
 113  
      *
 114  
      * This algorithm is quadratic in the number of operations. If
 115  
      * this became a problem, we would have to consider sorting the
 116  
      * operations list and comparing only adjacent pairs
 117  
      * (potentially O(n log n) performance).<p>
 118  
      *
 119  
      * @param  dm    the {@link Object} to be checked against the critic.
 120  
      *
 121  
      * @param  dsgr  the {@link Designer} creating the model. Not used,
 122  
      *               this is for future development of ArgoUML.
 123  
      *
 124  
      * @return       {@link #PROBLEM_FOUND PROBLEM_FOUND} if the critic is
 125  
      *               triggered, otherwise {@link #NO_PROBLEM NO_PROBLEM}.
 126  
      */
 127  
     @Override
 128  
     public boolean predicate2(Object dm, Designer dsgr) {
 129  
 
 130  
         // Only do this for classifiers
 131  
 
 132  0
         if (!(Model.getFacade().isAClassifier(dm))) {
 133  0
             return NO_PROBLEM;
 134  
         }
 135  
 
 136  
         // Get all the features (giving up if there are none). Then loop
 137  
         // through finding all operations. Each time we find one, we compare
 138  
         // its signature with all previous (held in collection operSeen), and then
 139  
         // if it doesn't match add it to the collection.
 140  
 
 141  0
         Collection operSeen = new ArrayList();
 142  0
         for (Object op : Model.getFacade().getOperations(dm)) {
 143  
 
 144  
             // Compare against all earlier operations. If there's a match we've
 145  
             // found the problem
 146  0
             for (Object o : operSeen) {
 147  0
                 if (signaturesMatch(op, o)) {
 148  0
                     return PROBLEM_FOUND;
 149  
                 }
 150  
             }
 151  
 
 152  
             // Add to the collection and round to look at the next one
 153  
 
 154  0
             operSeen.add(op);
 155  
         }
 156  
 
 157  
         // If we drop out here, there was no match and we have no problem
 158  
 
 159  0
         return NO_PROBLEM;
 160  
     }
 161  
 
 162  
 
 163  
     /**
 164  
      * Return the icon to be used for the clarifier for this critic.<p>
 165  
      *
 166  
      * A clarifier is the graphical highlight used to show the
 167  
      * presence of a critique. For example wavy colored underlines
 168  
      * beneath operations.<p>
 169  
      *
 170  
      * In this case it will be a wavy line under the second of the
 171  
      * clashing operations.<p>
 172  
      *
 173  
      * @return       The {@link javax.swing.Icon Icon} to use.
 174  
      */
 175  
     @Override
 176  
     public Icon getClarifier() {
 177  0
         return ClOperationCompartment.getTheInstance();
 178  
     }
 179  
 
 180  
 
 181  
     /**
 182  
      * Sees if the signatures of two Operations are the same.<p>
 183  
      *
 184  
      * Checks for matching operation name, and list of parameter
 185  
      * types. The order of the parameters is significant.
 186  
      *
 187  
      * This version also checks for the parameter kind, since
 188  
      * otherwise, "op(int a)" and "op():int" appear to have the same
 189  
      * signature. Purists would probably suggest that the kind should
 190  
      * match exactly. However we only differentiate the return
 191  
      * parameter(s). It is unlikely that any practical OO language
 192  
      * would be able to distinguish instantiation of in from out from
 193  
      * inout parameters.<p>
 194  
      *
 195  
      * We ignore return parameters completely. This is in line with
 196  
      * Java/C++ which regard <code>int x(int, int)</code> and
 197  
      * <code>double x(int, int)</code> as having the same
 198  
      * signature.<p>
 199  
      *
 200  
      * If you need to modify this method, take care, since there are
 201  
      * numerous "telegraph pole" problems involved in working through
 202  
      * pairs of mixed lists.<p>
 203  
      *
 204  
      * @param op1 the first operation whose signature is being compared.
 205  
      * @param op2 the second operation whose signature is being compared.
 206  
      *
 207  
      * @return    <code>true</code> if the signatures match, <code>false</code>
 208  
      *            otherwise.
 209  
      */
 210  
     private boolean signaturesMatch(Object op1, Object op2) {
 211  
 
 212  
         // Check that the names match.
 213  
 
 214  0
         String name1 = Model.getFacade().getName(op1);
 215  0
         if (name1 == null) {
 216  0
             return false;
 217  
         }
 218  
 
 219  0
         String name2 = Model.getFacade().getName(op2);
 220  0
         if (name2 == null) {
 221  0
             return false;
 222  
         }
 223  
 
 224  0
         if (!name1.equals(name2)) {
 225  0
             return false;
 226  
         }
 227  
 
 228  
         // Check that the parameter lists match.
 229  
 
 230  0
         Iterator params1 = Model.getFacade().getParameters(op1).iterator();
 231  0
         Iterator params2 = Model.getFacade().getParameters(op2).iterator();
 232  
 
 233  
         while (params1.hasNext()
 234  0
                && params2.hasNext()) {
 235  
 
 236  
             // Get the next non-return parameter. Null if non left.
 237  0
             Object p1 = null;
 238  0
             while (p1 == null && params1.hasNext()) {
 239  0
                 p1 = params1.next();
 240  0
                 if (Model.getFacade().isReturn(p1))
 241  0
                     p1 = null;
 242  
             }
 243  
 
 244  0
             Object p2 = null;
 245  0
             while (p2 == null && params1.hasNext()) {
 246  0
                 p2 = params1.next();
 247  0
                 if (Model.getFacade().isReturn(p2))
 248  0
                     p2 = null;
 249  
             }
 250  
 
 251  0
             if (p1 == null && p2 == null)
 252  0
                 return true;        // Both lists have the same length
 253  
 
 254  
             // Different lengths:
 255  0
             if (p1 == null || p2 == null) {
 256  0
                 return false;
 257  
             }
 258  
 
 259  
             // Compare the type of the parameters. If any of the types is
 260  
             // null, then we have a match.
 261  0
             Object p1type = Model.getFacade().getType(p1);
 262  0
             if (p1type == null) {
 263  0
                 continue;
 264  
             }
 265  
 
 266  0
             Object p2type = Model.getFacade().getType(p2);
 267  0
             if (p2type == null) {
 268  0
                 continue;
 269  
             }
 270  
 
 271  0
             if (!p1type.equals(p2type)) {
 272  0
                 return false;
 273  
             }
 274  
 
 275  
             // This pair of params where the same. Lets check the next pair.
 276  0
         }
 277  
 
 278  0
         if (!params1.hasNext() && !params2.hasNext()) {
 279  
             // Both lists have the same length.
 280  0
             return true;
 281  
         }
 282  
 
 283  0
         return false;
 284  
     }
 285  
 
 286  
     /*
 287  
      * @see org.argouml.uml.cognitive.critics.CrUML#getCriticizedDesignMaterials()
 288  
      */
 289  
     public Set<Object> getCriticizedDesignMaterials() {
 290  177040759
         Set<Object> ret = new HashSet<Object>();
 291  177040759
         ret.add(Model.getMetaTypes().getClassifier());
 292  177040759
         return ret;
 293  
     }
 294  
     
 295  
 }