@Override public Description matchClass(ClassTree classTree, VisitorState state) { TypeSymbol symbol = ASTHelpers.getSymbol(classTree); if (symbol.getKind() != ElementKind.CLASS) { return Description.NO_MATCH; } MethodTree equals = null; for (Tree member : classTree.getMembers()) { if (!(member instanceof MethodTree)) { continue; } MethodTree methodTree = (MethodTree) member; if (EQUALS_MATCHER.matches(methodTree, state)) { equals = methodTree; } } if (equals == null) { return Description.NO_MATCH; } MethodSymbol hashCodeSym = ASTHelpers.resolveExistingMethod( state, symbol, state.getName("hashCode"), ImmutableList.<Type>of(), ImmutableList.<Type>of()); if (hashCodeSym.owner.equals(state.getSymtab().objectType.tsym)) { return describeMatch(equals); } return Description.NO_MATCH; }
/** * Find the index of the current class member. * * @param wc * @param classTree * @param offset * @return */ static int findClassMemberIndex(WorkingCopy wc, ClassTree classTree, int offset) { int index = 0; SourcePositions sp = wc.getTrees().getSourcePositions(); GuardedDocument gdoc = null; try { Document doc = wc.getDocument(); if (doc != null && doc instanceof GuardedDocument) { gdoc = (GuardedDocument) doc; } } catch (IOException ioe) { } Tree lastMember = null; for (Tree tree : classTree.getMembers()) { if (offset <= sp.getStartPosition(wc.getCompilationUnit(), tree)) { if (gdoc == null) { break; } int pos = (int) (lastMember != null ? sp.getEndPosition(wc.getCompilationUnit(), lastMember) : sp.getStartPosition(wc.getCompilationUnit(), classTree)); pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos); if (pos <= sp.getStartPosition(wc.getCompilationUnit(), tree)) { break; } } index++; lastMember = tree; } return index; }
/** Returns true if a class overrides Object.equals */ private boolean overridesEquals(ClassTree node) { List<? extends Tree> members = node.getMembers(); for (Tree member : members) { if (member instanceof MethodTree) { MethodTree mTree = (MethodTree) member; ExecutableElement enclosing = TreeUtils.elementFromDeclaration(mTree); if (overrides(enclosing, Object.class, "equals")) { return true; } } } return false; }
/** * In the first enclosing class, find the top-level member that contains tree. TODO: should we * look whether these elements are enclosed within another class that is itself under * construction. * * <p>Are there any other type of top level objects? */ private Tree findTopLevelClassMemberForTree(TreePath path) { ClassTree enclosingClass = TreeUtils.enclosingClass(path); if (enclosingClass != null) { List<? extends Tree> classMembers = enclosingClass.getMembers(); TreePath searchPath = path; while (searchPath.getParentPath() != null && searchPath.getParentPath() != enclosingClass) { searchPath = searchPath.getParentPath(); if (classMembers.contains(searchPath.getLeaf())) { return searchPath.getLeaf(); } } } 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; }