private static List<? extends TypeMirror> computeParametrizedType(
      Set<ElementKind> types,
      CompilationInfo info,
      TreePath parent,
      Tree error,
      int offset,
      TypeMirror[] typeParameterBound,
      int[] numTypeParameters) {
    ParameterizedTypeTree ptt = (ParameterizedTypeTree) parent.getLeaf();

    if (ptt.getType() == error) {
      Tree gpt = parent.getParentPath().getLeaf();
      if (TreeUtilities.CLASS_TREE_KINDS.contains(gpt.getKind())
          && ((ClassTree) gpt).getExtendsClause() == ptt) {
        types.add(ElementKind.CLASS);
      } else if (TreeUtilities.CLASS_TREE_KINDS.contains(gpt.getKind())
          && ((ClassTree) gpt).getImplementsClause().contains(ptt)) {
        types.add(ElementKind.INTERFACE);
      } else {
        types.add(ElementKind.CLASS);
        types.add(ElementKind.INTERFACE);
      }

      if (numTypeParameters != null) {
        numTypeParameters[0] = ptt.getTypeArguments().size();
      }
      return null;
    }

    TypeMirror resolved = info.getTrees().getTypeMirror(parent);
    DeclaredType resolvedDT = null;

    if (resolved != null && resolved.getKind() == TypeKind.DECLARED) {
      resolvedDT = (DeclaredType) resolved;
    }

    int index = 0;

    for (Tree t : ptt.getTypeArguments()) {
      if (t == error) {
        if (resolvedDT != null && typeParameterBound != null) {
          List<? extends TypeMirror> typeArguments =
              ((DeclaredType) resolvedDT.asElement().asType()).getTypeArguments();

          if (typeArguments.size() > index) {
            typeParameterBound[0] = ((TypeVariable) typeArguments.get(index)).getUpperBound();
          }
        }

        types.add(ElementKind.CLASS); // XXX: class/interface/enum/annotation?
        return null;
      }

      index++;
    }

    return null;
  }
  @Override
  public AnnotatedTypeMirror getAnnotatedType(Tree tree) {
    if (tree.getKind() == Tree.Kind.POSTFIX_DECREMENT
        || tree.getKind() == Tree.Kind.POSTFIX_INCREMENT) {

      return getPostFixAnno((UnaryTree) tree, super.getAnnotatedType(tree));

    } else {
      return super.getAnnotatedType(tree);
    }
  }
 public StringConcatenateNode(Tree tree, Node left, Node right) {
   super(InternalUtils.typeOf(tree));
   assert tree.getKind() == Kind.PLUS;
   this.tree = tree;
   this.left = left;
   this.right = right;
 }
  @Override
  public AnnotatedDeclaredType getSelfType(Tree tree) {
    AnnotatedDeclaredType selfType = super.getSelfType(tree);

    TreePath path = getPath(tree);
    Tree topLevelMember = findTopLevelClassMemberForTree(path);
    if (topLevelMember != null) {
      if (topLevelMember.getKind() != Kind.METHOD
          || TreeUtils.isConstructor((MethodTree) topLevelMember)) {

        setSelfTypeInInitializationCode(tree, selfType, path);
      }
    }

    return selfType;
  }
 @Override
 public boolean isValidUse(AnnotatedPrimitiveType type, Tree tree) {
   if (tree.getKind() != Tree.Kind.TYPE_CAST && !type.hasAnnotation(NONNULL)) {
     // TODO: casts are sometimes inferred as @Nullable.
     // Find a way to correctly handle that case.
     return false;
   }
   return super.isValidUse(type, tree);
 }
  private static List<? extends TypeMirror> computeNewClass(
      Set<ElementKind> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
    NewClassTree nct = (NewClassTree) parent.getLeaf();
    boolean errorInRealArguments = false;

    for (Tree param : nct.getArguments()) {
      errorInRealArguments |= param == error;
    }

    if (errorInRealArguments) {
      TypeMirror[] proposedType = new TypeMirror[1];
      int[] proposedIndex = new int[1];
      ExecutableElement ee =
          org.netbeans.modules.editor.java.Utilities.fuzzyResolveMethodInvocation(
              info, parent, proposedType, proposedIndex);

      if (ee == null) { // cannot be resolved
        return null;
      }

      types.add(ElementKind.PARAMETER);
      types.add(ElementKind.LOCAL_VARIABLE);
      types.add(ElementKind.FIELD);

      return Collections.singletonList(proposedType[0]);
    }

    Tree id = nct.getIdentifier();

    if (id.getKind() == Kind.PARAMETERIZED_TYPE) {
      id = ((ParameterizedTypeTree) id).getType();
    }

    if (id == error) {
      return resolveType(
          EnumSet.noneOf(ElementKind.class), info, parent.getParentPath(), nct, offset, null, null);
    }

    return null;
  }
 /** Are all fields committed-only? */
 protected boolean areAllFieldsCommittedOnly(ClassTree classTree) {
   if (!useFbc) {
     // In the rawness type system, no fields can store not fully
     // initialized objects.
     return true;
   }
   for (Tree member : classTree.getMembers()) {
     if (!member.getKind().equals(Tree.Kind.VARIABLE)) {
       continue;
     }
     VariableTree var = (VariableTree) member;
     VariableElement varElt = TreeUtils.elementFromDeclaration(var);
     // var is not committed-only
     if (getDeclAnnotation(varElt, NotOnlyInitialized.class) != null) {
       // var is not static -- need a check of initializer blocks,
       // not of constructor which is where this is used
       if (!varElt.getModifiers().contains(Modifier.STATIC)) {
         return false;
       }
     }
   }
   return true;
 }
  @Override
  public boolean isValidUse(
      AnnotatedDeclaredType declarationType, AnnotatedDeclaredType useType, Tree tree) {
    // At most a single qualifier on a type, ignoring a possible PolyAll
    // annotation.
    boolean foundInit = false;
    boolean foundNonNull = false;
    Set<Class<? extends Annotation>> initQuals = atypeFactory.getInitializationAnnotations();
    Set<Class<? extends Annotation>> nonNullQuals = atypeFactory.getNullnessAnnotations();

    for (AnnotationMirror anno : useType.getAnnotations()) {
      if (QualifierPolymorphism.isPolyAll(anno)) {
        // ok.
      } else if (containsSameIgnoringValues(initQuals, anno)) {
        if (foundInit) {
          return false;
        }
        foundInit = true;
      } else if (containsSameIgnoringValues(nonNullQuals, anno)) {
        if (foundNonNull) {
          return false;
        }
        foundNonNull = true;
      }
    }

    if (tree.getKind() == Tree.Kind.VARIABLE) {
      Element vs = InternalUtils.symbol(tree);
      switch (vs.getKind()) {
        case EXCEPTION_PARAMETER:
          if (useType.hasAnnotation(NULLABLE)) {
            // Exception parameters cannot use Nullable
            // annotations. They default to NonNull.
            return false;
          }
          break;
        default:
          // nothing to do
          break;
      }
    }

    // The super implementation checks that useType is a subtype
    // of declarationType. However, declarationType by default
    // is NonNull, which would then forbid Nullable uses.
    // Therefore, don't perform this check.
    return true;
  }
  @Override
  protected void commonAssignmentCheck(
      Tree varTree, ExpressionTree valueExp, /*@CompilerMessageKey*/ String errorKey) {

    // allow MonotonicNonNull to be initialized to null at declaration
    if (varTree.getKind() == Tree.Kind.VARIABLE) {
      Element elem = TreeUtils.elementFromDeclaration((VariableTree) varTree);
      if (atypeFactory.fromElement(elem).hasEffectiveAnnotation(MONOTONIC_NONNULL)
          && !checker.getLintOption(
              AbstractNullnessChecker.LINT_NOINITFORMONOTONICNONNULL,
              AbstractNullnessChecker.LINT_DEFAULT_NOINITFORMONOTONICNONNULL)) {
        return;
      }
    }
    super.commonAssignmentCheck(varTree, valueExp, errorKey);
  }
  @Override
  public boolean isAssignable(AnnotatedTypeMirror varType, Tree varTree) {
    if (varTree.getKind() == Tree.Kind.VARIABLE || varType.hasAnnotation(ASSIGNABLE)) return true;

    Element varElement = InternalUtils.symbol(varTree);
    if (varElement == null || !varElement.getKind().isField() || ElementUtils.isStatic(varElement))
      return true;

    ExpressionTree expTree = (ExpressionTree) varTree;
    AnnotatedTypeMirror receiver = factory.getReceiver(expTree);

    boolean isAssignable =
        receiver.hasAnnotation(MUTABLE)
            || (receiver.hasAnnotation(ASSIGNS_FIELDS) && TreeUtils.isSelfAccess(expTree));

    return isAssignable;
  }
 @Override
 public AnnotatedTypeMirror getAnnotatedType(Tree tree) {
   AnnotatedTypeMirror type = super.getAnnotatedType(tree);
   if (tree instanceof ExpressionTree) tree = TreeUtils.skipParens((ExpressionTree) tree);
   Element elt = InternalUtils.symbol(tree);
   if (!checker.isChecking() /*&& !checker.isDefaultAnyType(type)*/
       && type.isAnnotated()
       && !type.getKind().isPrimitive()
       && type.getKind() != TypeKind.NULL
       && (elt == null || !ElementUtils.isStatic(elt))) {
     // We don't want annotations on the following trees
     Kind kind = tree.getKind();
     if (kind == Kind.METHOD_INVOCATION
         || kind == Kind.ARRAY_ACCESS
         || kind == Kind.MEMBER_SELECT
         || kind == Kind.CONDITIONAL_EXPRESSION) {
       type = type.getCopy(false);
     }
   }
   return type;
 }
Exemple #12
0
 static Tree skipParens(Tree tree) {
   return tree.accept(SKIP_PARENS, null);
 }
  private Pair<ParameterizedTypeTree, AnnotatedDeclaredType> extractParameterizedTypeTree(
      Tree tree, AnnotatedDeclaredType type) {
    ParameterizedTypeTree typeargtree = null;

    switch (tree.getKind()) {
      case VARIABLE:
        Tree lt = ((VariableTree) tree).getType();
        if (lt instanceof ParameterizedTypeTree) {
          typeargtree = (ParameterizedTypeTree) lt;
        } else {
          // System.out.println("Found a: " + lt);
        }
        break;
      case PARAMETERIZED_TYPE:
        typeargtree = (ParameterizedTypeTree) tree;
        break;
      case NEW_CLASS:
        NewClassTree nct = (NewClassTree) tree;
        ExpressionTree nctid = nct.getIdentifier();
        if (nctid.getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
          typeargtree = (ParameterizedTypeTree) nctid;
          /*
           * This is quite tricky... for anonymous class instantiations,
           * the type at this point has no type arguments. By doing the
           * following, we get the type arguments again.
           */
          type = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(typeargtree);
        }
        break;
      case ANNOTATED_TYPE:
        AnnotatedTypeTree tr = (AnnotatedTypeTree) tree;
        ExpressionTree undtr = tr.getUnderlyingType();
        if (undtr instanceof ParameterizedTypeTree) {
          typeargtree = (ParameterizedTypeTree) undtr;
        } else if (undtr instanceof IdentifierTree) {
          // @Something D -> Nothing to do
        } else {
          // TODO: add more test cases to ensure that nested types are
          // handled correctly,
          // e.g. @Nullable() List<@Nullable Object>[][]
          Pair<ParameterizedTypeTree, AnnotatedDeclaredType> p =
              extractParameterizedTypeTree(undtr, type);
          typeargtree = p.first;
          type = p.second;
        }
        break;
      case IDENTIFIER:
      case ARRAY_TYPE:
      case NEW_ARRAY:
      case MEMBER_SELECT:
      case UNBOUNDED_WILDCARD:
      case EXTENDS_WILDCARD:
      case SUPER_WILDCARD:
      case TYPE_PARAMETER:
        // Nothing to do.
        // System.out.println("Found a: " + (tree instanceof
        // ParameterizedTypeTree));
        break;
      default:
        // the parameterized type is the result of some expression tree.
        // No need to do anything further.
        break;
        // System.err.printf("TypeValidator.visitDeclared unhandled tree: %s of kind %s\n",
        //                 tree, tree.getKind());
    }

    return Pair.of(typeargtree, type);
  }
  /**
   * Pattern matches to prevent false positives of the form {@code (a == b || a.compareTo(b) == 0)}.
   * Returns true iff the given node fits this pattern.
   *
   * @param node
   * @return true iff the node fits the pattern (a == b || a.compareTo(b) == 0)
   */
  private boolean suppressEarlyCompareTo(final BinaryTree node) {
    // Only handle == binary trees
    if (node.getKind() != Tree.Kind.EQUAL_TO) return false;

    Tree left = node.getLeftOperand();
    Tree right = node.getRightOperand();

    // Only valid if we're comparing identifiers.
    if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER)) {
      return false;
    }

    final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
    final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);

    // looking for ((a == b || a.compareTo(b) == 0)
    Heuristics.Matcher matcher =
        new Heuristics.Matcher() {

          @Override
          public Boolean visitBinary(BinaryTree tree, Void p) {
            if (tree.getKind() == Tree.Kind.EQUAL_TO) { // a.compareTo(b) == 0
              ExpressionTree leftTree =
                  tree.getLeftOperand(); // looking for a.compareTo(b) or b.compareTo(a)
              ExpressionTree rightTree = tree.getRightOperand(); // looking for 0

              if (rightTree.getKind() != Tree.Kind.INT_LITERAL) {
                return false;
              }
              LiteralTree rightLiteral = (LiteralTree) rightTree;
              if (!rightLiteral.getValue().equals(0)) {
                return false;
              }

              return visit(leftTree, p);
            } else {
              // a == b || a.compareTo(b) == 0
              ExpressionTree leftTree = tree.getLeftOperand(); // looking for a==b
              ExpressionTree rightTree =
                  tree.getRightOperand(); // looking for a.compareTo(b) == 0 or b.compareTo(a) == 0
              if (leftTree != node) {
                return false;
              }
              if (rightTree.getKind() != Tree.Kind.EQUAL_TO) {
                return false;
              }
              return visit(rightTree, p);
            }
          }

          @Override
          public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) {
            if (!isInvocationOfCompareTo(tree)) {
              return false;
            }

            List<? extends ExpressionTree> args = tree.getArguments();
            if (args.size() != 1) {
              return false;
            }
            ExpressionTree arg = args.get(0);
            if (arg.getKind() != Tree.Kind.IDENTIFIER) {
              return false;
            }
            Element argElt = TreeUtils.elementFromUse(arg);

            ExpressionTree exp = tree.getMethodSelect();
            if (exp.getKind() != Tree.Kind.MEMBER_SELECT) {
              return false;
            }
            MemberSelectTree member = (MemberSelectTree) exp;
            if (member.getExpression().getKind() != Tree.Kind.IDENTIFIER) {
              return false;
            }

            Element refElt = TreeUtils.elementFromUse(member.getExpression());

            if (!((refElt.equals(lhs) && argElt.equals(rhs))
                || ((refElt.equals(rhs) && argElt.equals(lhs))))) {
              return false;
            }
            return true;
          }
        };

    boolean okay =
        Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.CONDITIONAL_OR, matcher))
            .match(getCurrentPath());
    return okay;
  }
  // TODO: handle != comparisons too!
  private boolean suppressInsideComparison(final BinaryTree node) {
    // Only handle == binary trees
    if (node.getKind() != Tree.Kind.EQUAL_TO) return false;

    Tree left = node.getLeftOperand();
    Tree right = node.getRightOperand();

    // Only valid if we're comparing identifiers.
    if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER))
      return false;

    // If we're not directly in an if statement in a method (ignoring
    // parens and blocks), terminate.
    // TODO: only if it's the first statement in the block
    if (!Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) return false;

    ExecutableElement enclosing = TreeUtils.elementFromDeclaration(visitorState.getMethodTree());
    assert enclosing != null;

    final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
    final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);

    // Matcher to check for if statement that returns zero
    Heuristics.Matcher matcher =
        new Heuristics.Matcher() {

          @Override
          public Boolean visitIf(IfTree tree, Void p) {
            return visit(tree.getThenStatement(), p);
          }

          @Override
          public Boolean visitBlock(BlockTree tree, Void p) {
            if (tree.getStatements().size() > 0) return visit(tree.getStatements().get(0), p);
            return false;
          }

          @Override
          public Boolean visitReturn(ReturnTree tree, Void p) {
            ExpressionTree expr = tree.getExpression();
            return (expr != null
                && expr.getKind() == Tree.Kind.INT_LITERAL
                && ((LiteralTree) expr).getValue().equals(0));
          }
        };

    // Determine whether or not the "then" statement of the if has a single
    // "return 0" statement (for the Comparator.compare heuristic).
    if (overrides(enclosing, Comparator.class, "compare")) {
      final boolean returnsZero =
          Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcher))
              .match(getCurrentPath());

      if (!returnsZero) return false;

      assert enclosing.getParameters().size() == 2;
      Element p1 = enclosing.getParameters().get(0);
      Element p2 = enclosing.getParameters().get(1);
      return (p1.equals(lhs) && p2.equals(rhs)) || (p2.equals(lhs) && p1.equals(rhs));

    } else if (overrides(enclosing, Object.class, "equals")) {
      assert enclosing.getParameters().size() == 1;
      Element param = enclosing.getParameters().get(0);
      Element thisElt = getThis(trees.getScope(getCurrentPath()));
      assert thisElt != null;
      return (thisElt.equals(lhs) && param.equals(rhs))
          || (param.equals(lhs) && thisElt.equals(rhs));

    } else if (overrides(enclosing, Comparable.class, "compareTo")) {

      final boolean returnsZero =
          Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcher))
              .match(getCurrentPath());

      if (!returnsZero) {
        return false;
      }

      assert enclosing.getParameters().size() == 1;
      Element param = enclosing.getParameters().get(0);
      Element thisElt = getThis(trees.getScope(getCurrentPath()));
      assert thisElt != null;
      return (thisElt.equals(lhs) && param.equals(rhs))
          || (param.equals(lhs) && thisElt.equals(rhs));
    }
    return false;
  }
 @Override
 public boolean matches(Tree tree, VisitorState state) {
   FirstMatchingScanner scanner = new FirstMatchingScanner(state);
   Boolean matchFound = tree.accept(scanner, false);
   return matchFound != null && matchFound;
 }