Coverage Report - com.puppycrawl.tools.checkstyle.gui.ParseTreeTablePresentation
 
Classes in this File Line Coverage Branch Coverage Complexity
ParseTreeTablePresentation
100%
96/96
100%
46/46
2.722
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle.gui;
 21  
 
 22  
 import java.util.HashMap;
 23  
 import java.util.Map;
 24  
 
 25  
 import antlr.ASTFactory;
 26  
 import antlr.collections.AST;
 27  
 import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser;
 28  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 29  
 import com.puppycrawl.tools.checkstyle.api.DetailNode;
 30  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 31  
 import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode;
 32  
 import com.puppycrawl.tools.checkstyle.utils.JavadocUtils;
 33  
 import com.puppycrawl.tools.checkstyle.utils.TokenUtils;
 34  
 
 35  
 /**
 36  
  * The model that backs the parse tree in the GUI.
 37  
  *
 38  
  * @author Lars K├╝hne
 39  
  */
 40  
 public class ParseTreeTablePresentation {
 41  
 
 42  
     /** Exception message. */
 43  
     private static final String UNKNOWN_COLUMN_MSG = "Unknown column";
 44  
 
 45  
     /** Column names. */
 46  3
     private static final String[] COLUMN_NAMES = {
 47  
         "Tree",
 48  
         "Type",
 49  
         "Line",
 50  
         "Column",
 51  
         "Text",
 52  
     };
 53  
 
 54  
     /**
 55  
      * The root node of the tree table model.
 56  
      */
 57  
     private final Object root;
 58  
 
 59  
     /** Cache to store already parsed Javadoc comments. Used for optimisation purposes. */
 60  31
     private final Map<DetailAST, DetailNode> blockCommentToJavadocTree = new HashMap<>();
 61  
 
 62  
     /** Parsing mode. */
 63  
     private ParseMode parseMode;
 64  
 
 65  
     /**
 66  
      * Constructor initialise root node.
 67  
      * @param parseTree DetailAST parse tree.
 68  
      */
 69  31
     public ParseTreeTablePresentation(DetailAST parseTree) {
 70  31
         root = createArtificialTreeRoot();
 71  31
         setParseTree(parseTree);
 72  31
     }
 73  
 
 74  
     /**
 75  
      * Set parse tree.
 76  
      * @param parseTree DetailAST parse tree.
 77  
      */
 78  
     protected final void setParseTree(DetailAST parseTree) {
 79  54
         ((AST) root).setFirstChild(parseTree);
 80  54
     }
 81  
 
 82  
     /**
 83  
      * Set parse mode.
 84  
      * @param mode ParseMode enum
 85  
      */
 86  
     protected void setParseMode(ParseMode mode) {
 87  19
         parseMode = mode;
 88  19
     }
 89  
 
 90  
     /**
 91  
      * Returns number of available columns.
 92  
      * @return the number of available columns.
 93  
      */
 94  
     public int getColumnCount() {
 95  4
         return COLUMN_NAMES.length;
 96  
     }
 97  
 
 98  
     /**
 99  
      * Returns name for specified column number.
 100  
      * @param column the column number
 101  
      * @return the name for column number {@code column}.
 102  
      */
 103  
     public String getColumnName(int column) {
 104  5
         return COLUMN_NAMES[column];
 105  
     }
 106  
 
 107  
     /**
 108  
      * Returns type of specified column number.
 109  
      * @param column the column number
 110  
      * @return the type for column number {@code column}.
 111  
      */
 112  
     // -@cs[ForbidWildcardAsReturnType] We need to satisfy javax.swing.table.AbstractTableModel
 113  
     // public Class<?> getColumnClass(int columnIndex) {...}
 114  
     public Class<?> getColumnClass(int column) {
 115  
         final Class<?> columnClass;
 116  
 
 117  6
         switch (column) {
 118  
             case 0:
 119  1
                 columnClass = ParseTreeTableModel.class;
 120  1
                 break;
 121  
             case 1:
 122  1
                 columnClass = String.class;
 123  1
                 break;
 124  
             case 2:
 125  1
                 columnClass = Integer.class;
 126  1
                 break;
 127  
             case 3:
 128  1
                 columnClass = Integer.class;
 129  1
                 break;
 130  
             case 4:
 131  1
                 columnClass = String.class;
 132  1
                 break;
 133  
             default:
 134  1
                 throw new IllegalStateException(UNKNOWN_COLUMN_MSG);
 135  
         }
 136  5
         return columnClass;
 137  
     }
 138  
 
 139  
     /**
 140  
      * Returns the value to be displayed for node at column number.
 141  
      * @param node the node
 142  
      * @param column the column number
 143  
      * @return the value to be displayed for node {@code node}, at column number {@code column}.
 144  
      */
 145  
     public Object getValueAt(Object node, int column) {
 146  
         final Object result;
 147  
 
 148  12
         if (node instanceof DetailNode) {
 149  6
             result = getValueAtDetailNode((DetailNode) node, column);
 150  
         }
 151  
         else {
 152  6
             result = getValueAtDetailAST((DetailAST) node, column);
 153  
         }
 154  
 
 155  10
         return result;
 156  
     }
 157  
 
 158  
     /**
 159  
      * Returns the child of parent at index.
 160  
      * @param parent the node to get a child from.
 161  
      * @param index the index of a child.
 162  
      * @return the child of parent at index.
 163  
      */
 164  
     public Object getChild(Object parent, int index) {
 165  
         final Object result;
 166  
 
 167  31
         if (parent instanceof DetailNode) {
 168  1
             result = ((DetailNode) parent).getChildren()[index];
 169  
         }
 170  
         else {
 171  30
             result = getChildAtDetailAst((DetailAST) parent, index);
 172  
         }
 173  
 
 174  31
         return result;
 175  
     }
 176  
 
 177  
     /**
 178  
      * Returns the number of children of parent.
 179  
      * @param parent the node to count children for.
 180  
      * @return the number of children of the node parent.
 181  
      */
 182  
     public int getChildCount(Object parent) {
 183  
         final int result;
 184  
 
 185  31
         if (parent instanceof DetailNode) {
 186  2
             result = ((DetailNode) parent).getChildren().length;
 187  
         }
 188  
         else {
 189  29
             if (parseMode == ParseMode.JAVA_WITH_JAVADOC_AND_COMMENTS
 190  4
                     && ((AST) parent).getType() == TokenTypes.COMMENT_CONTENT
 191  2
                     && JavadocUtils.isJavadocComment(((DetailAST) parent).getParent())) {
 192  
                 //getChildCount return 0 on COMMENT_CONTENT,
 193  
                 //but we need to attach javadoc tree, that is separate tree
 194  1
                 result = 1;
 195  
             }
 196  
             else {
 197  28
                 result = ((DetailAST) parent).getChildCount();
 198  
             }
 199  
         }
 200  
 
 201  31
         return result;
 202  
     }
 203  
 
 204  
     /**
 205  
      * Returns value of root.
 206  
      * @return the root.
 207  
      */
 208  
     public Object getRoot() {
 209  29
         return root;
 210  
     }
 211  
 
 212  
     /**
 213  
      * Whether the node is a leaf.
 214  
      * @param node the node to check.
 215  
      * @return true if the node is a leaf.
 216  
      */
 217  
     public boolean isLeaf(Object node) {
 218  2
         return getChildCount(node) == 0;
 219  
     }
 220  
 
 221  
     /**
 222  
      * Return the index of child in parent.  If either {@code parent}
 223  
      * or {@code child} is {@code null}, returns -1.
 224  
      * If either {@code parent} or {@code child} don't
 225  
      * belong to this tree model, returns -1.
 226  
      *
 227  
      * @param parent a node in the tree, obtained from this data source.
 228  
      * @param child the node we are interested in.
 229  
      * @return the index of the child in the parent, or -1 if either
 230  
      *     {@code child} or {@code parent} are {@code null}
 231  
      *     or don't belong to this tree model.
 232  
      */
 233  
     public int getIndexOfChild(Object parent, Object child) {
 234  6
         int index = -1;
 235  21
         for (int i = 0; i < getChildCount(parent); i++) {
 236  20
             if (getChild(parent, i).equals(child)) {
 237  5
                 index = i;
 238  5
                 break;
 239  
             }
 240  
         }
 241  6
         return index;
 242  
     }
 243  
 
 244  
     /**
 245  
      * Indicates whether the the value for node {@code node}, at column number {@code column} is
 246  
      * editable.
 247  
      * @param column the column number
 248  
      * @return true if editable
 249  
      */
 250  
     public boolean isCellEditable(int column) {
 251  1
         return false;
 252  
     }
 253  
 
 254  
     /**
 255  
      * Creates artificial tree root.
 256  
      * @return artificial tree root.
 257  
      */
 258  
     private static DetailAST createArtificialTreeRoot() {
 259  31
         final ASTFactory factory = new ASTFactory();
 260  31
         factory.setASTNodeClass(DetailAST.class.getName());
 261  31
         return (DetailAST) factory.create(TokenTypes.EOF, "ROOT");
 262  
     }
 263  
 
 264  
     /**
 265  
      * Gets child of DetailAST node at specified index.
 266  
      * @param parent DetailAST node
 267  
      * @param index child index
 268  
      * @return child DetailsAST or DetailNode if child is Javadoc node
 269  
      *         and parseMode is JAVA_WITH_JAVADOC_AND_COMMENTS.
 270  
      */
 271  
     private Object getChildAtDetailAst(DetailAST parent, int index) {
 272  
         final Object result;
 273  30
         if (parseMode == ParseMode.JAVA_WITH_JAVADOC_AND_COMMENTS
 274  9
                 && parent.getType() == TokenTypes.COMMENT_CONTENT
 275  8
                 && JavadocUtils.isJavadocComment(parent.getParent())) {
 276  7
             result = getJavadocTree(parent.getParent());
 277  
         }
 278  
         else {
 279  23
             int currentIndex = 0;
 280  23
             DetailAST child = parent.getFirstChild();
 281  55
             while (currentIndex < index) {
 282  32
                 child = child.getNextSibling();
 283  32
                 currentIndex++;
 284  
             }
 285  23
             result = child;
 286  
         }
 287  
 
 288  30
         return result;
 289  
     }
 290  
 
 291  
     /**
 292  
      * Gets a value for DetailNode object.
 293  
      * @param node DetailNode(Javadoc) node.
 294  
      * @param column column index.
 295  
      * @return value at specified column.
 296  
      */
 297  
     private static Object getValueAtDetailNode(DetailNode node, int column) {
 298  
         final Object value;
 299  
 
 300  6
         switch (column) {
 301  
             case 0:
 302  
                 // first column is tree model. no value needed
 303  1
                 value = null;
 304  1
                 break;
 305  
             case 1:
 306  1
                 value = JavadocUtils.getTokenName(node.getType());
 307  1
                 break;
 308  
             case 2:
 309  1
                 value = node.getLineNumber();
 310  1
                 break;
 311  
             case 3:
 312  1
                 value = node.getColumnNumber();
 313  1
                 break;
 314  
             case 4:
 315  1
                 value = node.getText();
 316  1
                 break;
 317  
             default:
 318  1
                 throw new IllegalStateException(UNKNOWN_COLUMN_MSG);
 319  
         }
 320  5
         return value;
 321  
     }
 322  
 
 323  
     /**
 324  
      * Gets a value for DetailAST object.
 325  
      * @param ast DetailAST node.
 326  
      * @param column column index.
 327  
      * @return value at specified column.
 328  
      */
 329  
     private static Object getValueAtDetailAST(DetailAST ast, int column) {
 330  
         final Object value;
 331  
 
 332  6
         switch (column) {
 333  
             case 0:
 334  
                 // first column is tree model. no value needed
 335  1
                 value = null;
 336  1
                 break;
 337  
             case 1:
 338  1
                 value = TokenUtils.getTokenName(ast.getType());
 339  1
                 break;
 340  
             case 2:
 341  1
                 value = ast.getLineNo();
 342  1
                 break;
 343  
             case 3:
 344  1
                 value = ast.getColumnNo();
 345  1
                 break;
 346  
             case 4:
 347  1
                 value = ast.getText();
 348  1
                 break;
 349  
             default:
 350  1
                 throw new IllegalStateException(UNKNOWN_COLUMN_MSG);
 351  
         }
 352  5
         return value;
 353  
     }
 354  
 
 355  
     /**
 356  
      * Gets Javadoc (DetailNode) tree of specified block comments.
 357  
      * @param blockComment Javadoc comment as a block comment
 358  
      * @return DetailNode tree
 359  
      */
 360  
     private DetailNode getJavadocTree(DetailAST blockComment) {
 361  7
         DetailNode javadocTree = blockCommentToJavadocTree.get(blockComment);
 362  7
         if (javadocTree == null) {
 363  6
             javadocTree = new JavadocDetailNodeParser().parseJavadocAsDetailNode(blockComment)
 364  6
                     .getTree();
 365  6
             blockCommentToJavadocTree.put(blockComment, javadocTree);
 366  
         }
 367  7
         return javadocTree;
 368  
     }
 369  
 }