@Override
 public void visitNode(Tree tree) {
   if (hasSemantic()) {
     TypeParameters typeParameters;
     String messageEnd;
     if (tree.is(Tree.Kind.METHOD)) {
       typeParameters = ((MethodTree) tree).typeParameters();
       messageEnd = "method.";
     } else {
       typeParameters = ((ClassTree) tree).typeParameters();
       messageEnd = "class.";
       if (tree.is(Tree.Kind.INTERFACE)) {
         messageEnd = "interface.";
       }
     }
     for (TypeParameterTree typeParameter : typeParameters) {
       Symbol symbol = getSemanticModel().getSymbol(typeParameter);
       if (symbol.usages().isEmpty()) {
         String message =
             new StringBuilder(typeParameter.identifier().name())
                 .append(" is not used in the ")
                 .append(messageEnd)
                 .toString();
         addIssue(typeParameter, message);
       }
     }
   }
 }
 public void checkIfUnused(VariableTree tree) {
   if (tree.modifiers().annotations().isEmpty()) {
     Symbol symbol = tree.symbol();
     String name = symbol.name();
     if (symbol.isPrivate()
         && !"serialVersionUID".equals(name)
         && symbol.usages().size() == assignments.get(symbol).size()) {
       addIssue(tree, "Remove this unused \"" + name + "\" private field.");
     }
   }
 }
 @Override
 public void visitCatch(CatchTree tree) {
   if (!isExcludedType(tree.parameter().type())) {
     Symbol exception = tree.parameter().symbol();
     validUsagesStack.addFirst(exception.usages());
     super.visitCatch(tree);
     Collection<IdentifierTree> usages = validUsagesStack.pop();
     if (usages.isEmpty()) {
       context.reportIssue(this, tree.parameter(), "Either log or rethrow this exception.");
     }
   }
 }