Package com.google.errorprone.bugpatterns

Source Code of com.google.errorprone.bugpatterns.ClassCanBeStatic$ReferenceEnclosing

/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.errorprone.bugpatterns;

import static com.google.errorprone.BugPattern.Category.JDK;
import static com.google.errorprone.BugPattern.MaturityLevel.EXPERIMENTAL;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.hasIdentifier;
import static com.google.errorprone.matchers.Matchers.kindIs;
import static com.google.errorprone.matchers.Matchers.nestingKind;
import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.parentNode;
import static com.google.errorprone.matchers.MultiMatcher.MatchType.ANY;

import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.util.ASTHelpers;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Types;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;

/**
* @author alexloh@google.com (Alex Loh)
*/
@BugPattern(name = "ClassCanBeStatic",
    summary = "Inner class is non-static but does not reference enclosing class",
    explanation = "An inner class should be static unless it references members" +
        "of its enclosing class. An inner class that is made non-static unnecessarily" +
        "uses more memory and does not make the intent of the class clear.",
    category = JDK, maturity = EXPERIMENTAL, severity = ERROR)
public class ClassCanBeStatic extends BugChecker implements ClassTreeMatcher {

  /**
   * Matches any class definitions that fit the following:
   * <ol>
   * <li> Is non-static
   * <li> Is an inner class (ie has an enclosing class)
   * <li> Enclosing class is non-nested or static
   * <li> Has no references to variables defined in enclosing class
   * </ol>
   */
  private static Matcher<ClassTree> classTreeMatcher = new Matcher<ClassTree>() {
      @Override
      public boolean matches(ClassTree classTree, VisitorState state) {
        return allOf(
          not(Matchers.<ClassTree>hasModifier(Modifier.STATIC)),
          kindIs(Kind.CLASS),
          nestingKind(NestingKind.MEMBER),
          parentNode(kindIs(Kind.CLASS)),
          anyOf(
              parentNode(nestingKind(NestingKind.TOP_LEVEL)),
              parentNode(Matchers.<ClassTree>hasModifier(Modifier.STATIC))),
          not(hasIdentifier(ANY, referenceEnclosing(classTree, state.getTypes())))
        ).matches(classTree, state);
      }
    };

  private static Matcher<IdentifierTree> referenceEnclosing(ClassTree classTree, Types types) {
    return new ReferenceEnclosing(classTree, types);
  }

  /**
   * Matches an identifier that is declared outside of given classTree
   */
  private static class ReferenceEnclosing implements Matcher<IdentifierTree> {

    private final ClassSymbol currentClass;
    private final Types types;

    public ReferenceEnclosing(ClassTree classTree, Types types) {
      currentClass = (ClassSymbol) ASTHelpers.getSymbol(classTree);
      this.types = types;
    }

    @Override
    public boolean matches(IdentifierTree node, VisitorState state) {
      Symbol sym = ASTHelpers.getSymbol(node);
      return !sym.isLocal() && !sym.isMemberOf(currentClass, types);
    }
  }

  @Override
  public Description matchClass(ClassTree tree, VisitorState state) {
    if (!classTreeMatcher.matches(tree, state)) {
      return Description.NO_MATCH;
    }

    // figure out where to insert the static modifier
    // if there is other modifier, prepend 'static ' in front of class
    // else insert 'static ' AFTER public/private/protected and BEFORE final
    Fix fix;

    ModifiersTree mods = tree.getModifiers();
    if (mods.getFlags().isEmpty()) {
      fix = SuggestedFix.prefixWith(tree, "static ");
    } else {
      // Note that the use of .toString() here effectively destroys any special
      // formatting, eg if the modifiers previously had multiple spaces or a
      // comment between them, after this fix they will all have exactly one
      // space between each modifier.
      String newmods = mods.toString();
      int ind = newmods.indexOf("final");
      if (ind < 0) {
        // append if 'final' not found
        newmods += "static";
        fix = SuggestedFix.replace(mods, newmods);
      } else {
        // insert at ind, just before 'final'
        newmods = newmods.substring(0, ind) + "static "
                + newmods.substring(ind, newmods.length() - 1);
        fix = SuggestedFix.replace(mods, newmods);
      }
    }

    return describeMatch(tree, fix);
  }
}
TOP

Related Classes of com.google.errorprone.bugpatterns.ClassCanBeStatic$ReferenceEnclosing

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.