Package com.google.errorprone.bugpatterns

Source Code of com.google.errorprone.bugpatterns.GuiceAssistedParameters

/*
* Copyright 2013 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.GUICE;
import static com.google.errorprone.BugPattern.MaturityLevel.EXPERIMENTAL;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;

import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
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.AnnotationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Attribute.Compound;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;

import javax.lang.model.element.TypeElement;

/**
* @author sgoldfeder@google.com (Steven Goldfeder)
*/
@BugPattern(name = "GuiceAssistedParameters", summary =
    "A constructor cannot have two @Assisted parameters of the same type unless they are "
    + "disambiguated with named @Assisted annotations. ",
    explanation = "See http://google-guice.googlecode.com/git/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html",
    category = GUICE, severity = ERROR, maturity = EXPERIMENTAL)
public class GuiceAssistedParameters extends BugChecker implements VariableTreeMatcher {

  private static final String ASSISTED_ANNOTATION = "com.google.inject.assistedinject.Assisted";

  private Matcher<VariableTree> constructorAssistedParameterMatcher = new Matcher<VariableTree>() {
    @Override
    public boolean matches(VariableTree t, VisitorState state) {
      Symbol modified = ASTHelpers.getSymbol(state.getPath().getParentPath().getLeaf());
      return modified != null && modified.isConstructor()
          && Matchers.<VariableTree>hasAnnotation(ASSISTED_ANNOTATION).matches(t, state);
    }
  };

  @Override
  public final Description matchVariable(VariableTree variableTree, VisitorState state) {
    if (constructorAssistedParameterMatcher.matches(variableTree, state)) {
      Compound thisParamsAssisted = null;
      for (Compound c : ASTHelpers.getSymbol(variableTree).getAnnotationMirrors()) {
        if (((TypeElement) c.getAnnotationType().asElement()).getQualifiedName()
            .contentEquals(ASSISTED_ANNOTATION)) {
          thisParamsAssisted = c;
        }
      }
      MethodTree enclosingMethod = (MethodTree) state.getPath().getParentPath().getLeaf();
      // count the number of parameters of this type and value. One is expected since we
      // will be iterating through all parameters including the one we're matching.
      int numIdentical = 0;
      for (VariableTree parameter : enclosingMethod.getParameters()) {
        if (Matchers.<VariableTree>isSameType(variableTree).matches(parameter, state)) {
          Compound otherParamsAssisted = null;
          for (Compound c : ASTHelpers.getSymbol(parameter).getAnnotationMirrors()) {
            if (((TypeElement) c.getAnnotationType().asElement()).getQualifiedName()
                .contentEquals(ASSISTED_ANNOTATION)) {
              otherParamsAssisted = c;
            }
          }
          if (otherParamsAssisted != null) {
            if (thisParamsAssisted.getElementValues().isEmpty()
                && otherParamsAssisted.getElementValues().isEmpty()) {
              //both have unnamed @Assisted annotations
              numIdentical++;
            }
            //if value is specified, check that they are equal
            //also, there can only be one value which is why I didn't check for equality
            //in both directions
            for (MethodSymbol m : thisParamsAssisted.getElementValues().keySet())
              if (otherParamsAssisted.getElementValues().get(m).getValue()
                  .equals(thisParamsAssisted.getElementValues().get(m).getValue())) {
                numIdentical++;
              }
          }
          if (numIdentical > 1) {
            return describe(variableTree, state);
          }
        }
      }
    }
    return Description.NO_MATCH;
  }

  public Description describe(VariableTree variableTree, VisitorState state) {
    // find the @Assisted annotation to put the error on
    for (AnnotationTree annotation : variableTree.getModifiers().getAnnotations()) {
      if (ASTHelpers.getSymbol(annotation).equals(state.getSymbolFromString(ASSISTED_ANNOTATION))) {
        return describeMatch(annotation, SuggestedFix.delete(annotation));
      }
    }
    throw new IllegalStateException("Expected to find @Assisted on this parameter");
  }
}
TOP

Related Classes of com.google.errorprone.bugpatterns.GuiceAssistedParameters

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.