/** * 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; }
@Override public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) { if (tree.getTypeDecls().size() <= 1) { // package-info.java files have zero top-level declarations, everything // else should have exactly one. return Description.NO_MATCH; } if (tree.getPackageName() == null) { // Real code doesn't use the default package. return Description.NO_MATCH; } List<String> names = new ArrayList<>(); for (Tree member : tree.getTypeDecls()) { if (member instanceof ClassTree) { ClassTree classMember = (ClassTree) member; switch (classMember.getKind()) { case CLASS: case INTERFACE: case ANNOTATION_TYPE: case ENUM: SuppressWarnings suppression = ASTHelpers.getAnnotation(classMember, SuppressWarnings.class); if (suppression != null && !Collections.disjoint(Arrays.asList(suppression.value()), allNames())) { // If any top-level classes have @SuppressWarnings("TopLevel"), ignore // this compilation unit. We can't rely on the normal suppression // mechanism because the only enclosing element is the package declaration, // and @SuppressWarnings can't be applied to packages. return Description.NO_MATCH; } names.add(classMember.getSimpleName().toString()); break; default: break; } } } if (names.size() <= 1) { // this can happen with multiple type declarations if some of them are // empty (e.g. ";" at the top level counts as an empty type decl) return Description.NO_MATCH; } String message = String.format( "Expected at most one top-level class declaration, instead found: %s", Joiner.on(", ").join(names)); return buildDescription(tree.getPackageName()).setMessage(message).build(); }
@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; }
private static List<? extends TypeMirror> computeClass( Set<ElementKind> types, CompilationInfo info, TreePath parent, Tree error, int offset) { ClassTree ct = (ClassTree) parent.getLeaf(); if (ct.getExtendsClause() == error) { types.add(ElementKind.CLASS); return null; } for (Tree t : ct.getImplementsClause()) { if (t == error) { types.add(ElementKind.INTERFACE); return null; } } // XXX: annotation types... return null; }
private State checkClass(ClassTree classTree) { if (anonymousMode) { anonymousInnerCount++; if (anonymousInnerCount == anonymousInnerNumber) { return advanceDepth(); } } else { if (classTree.getSimpleName().contentEquals(actualName)) { return advanceDepth(); } } return State.DEAD_END; }
/** 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; }
/* * Method to implement the @UsesObjectEquals functionality. * If a class is marked @UsesObjectEquals, it must: * * -not override .equals(Object) * -be a subclass of Object or another class marked @UsesObjectEquals * * If a class is not marked @UsesObjectEquals, it must: * * -not have a superclass marked @UsesObjectEquals * * * @see org.checkerframework.common.basetype.BaseTypeVisitor#visitClass(com.sun.source.tree.ClassTree, java.lang.Object) */ @Override public Void visitClass(ClassTree node, Void p) { // Looking for an @UsesObjectEquals class declaration TypeElement elt = TreeUtils.elementFromDeclaration(node); UsesObjectEquals annotation = elt.getAnnotation(UsesObjectEquals.class); Tree superClass = node.getExtendsClause(); Element elmt = null; if (superClass != null && (superClass instanceof IdentifierTree || superClass instanceof MemberSelectTree)) { elmt = TreeUtils.elementFromUse((ExpressionTree) superClass); } // if it's there, check to make sure does not override equals // and supertype is Object or @UsesObjectEquals if (annotation != null) { // check methods to ensure no .equals if (overridesEquals(node)) { checker.report(Result.failure("overrides.equals"), node); } if (!(superClass == null || (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null))) { checker.report(Result.failure("superclass.unmarked"), node); } } else { // the class is not marked @UsesObjectEquals -> make sure its superclass isn't either. // this is impossible after design change making @UsesObjectEquals inherited? // check left in case of future design change back to non-inherited. if (superClass != null && (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null)) { checker.report(Result.failure("superclass.marked"), node); } } return super.visitClass(node, p); }
/** 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 ChangeInfo implement() throws Exception { JavaSource js = JavaSource.forFileObject(sourceCode); js.runModificationTask( new Task<WorkingCopy>() { @Override public void run(WorkingCopy parameter) throws Exception { parameter.toPhase(Phase.RESOLVED); TypeElement suppressWarningsAnnotation = null; for (String ann : SUPPRESS_WARNINGS_ANNOTATIONS) { if ((suppressWarningsAnnotation = parameter.getElements().getTypeElement(ann)) != null) break; } if (suppressWarningsAnnotation == null) { NotifyDescriptor nd = new NotifyDescriptor.Message( "Cannot find SuppressWarnings annotation with Retention.CLASS, please add some on the classpath", NotifyDescriptor.WARNING_MESSAGE); DialogDisplayer.getDefault().notifyLater(nd); return; } int realPos; if (pos != (-1)) { realPos = pos; } else { realPos = (int) parameter.getCompilationUnit().getLineMap().getPosition(line, 0); } TreePath tp = parameter.getTreeUtilities().pathFor(realPos); while (tp != null && !ANNOTATABLE.contains(tp.getLeaf().getKind())) { tp = tp.getParentPath(); } if (tp == null) return; ModifiersTree mods; Tree leaf = tp.getLeaf(); switch (leaf.getKind()) { case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: mods = ((ClassTree) leaf).getModifiers(); break; case METHOD: mods = ((MethodTree) leaf).getModifiers(); break; case VARIABLE: mods = ((MethodTree) leaf).getModifiers(); break; default: throw new IllegalStateException(leaf.getKind().name()); } parameter.rewrite( mods, GeneratorUtilities.get(parameter) .appendToAnnotationValue( mods, suppressWarningsAnnotation, "value", parameter.getTreeMaker().Literal(bugId))); } }) .commit(); return null; }
public void run(WorkingCopy workingCopy) throws Exception { try { workingCopy.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); CompilationUnitTree cut = workingCopy.getCompilationUnit(); ClassTree classTree = (ClassTree) cut.getTypeDecls().get(0); TreeMaker make = workingCopy.getTreeMaker(); // Import org.glassfish.openesb.pojose.api.annotation.POJO // org.glassfish.openesb.pojose.api.annotation.Operation CompilationUnitTree copy = make.addCompUnitImport( cut, make.Import(make.Identifier(GeneratorUtil.PROVIDER_QUAL_CLASS_ANNOTATION), false)); // workingCopy.rewrite(cut, copy); // cut = workingCopy.getCompilationUnit(); // classTree = (ClassTree) cut.getTypeDecls().get(0); CompilationUnitTree copy1 = make.addCompUnitImport( copy, make.Import( make.Identifier(GeneratorUtil.POJO_QUAL_OPERATION_ANNOTATION_CLASS), false)); copy = make.addCompUnitImport( copy1, make.Import(make.Identifier(GeneratorUtil.CTX_QUAL_CLASS_ANNOTATION), false)); copy1 = make.addCompUnitImport( copy, make.Import(make.Identifier(GeneratorUtil.RSRC_QUAL_CLASS_ANNOTATION), false)); workingCopy.rewrite(cut, copy1); cut = workingCopy.getCompilationUnit(); classTree = (ClassTree) cut.getTypeDecls().get(0); // ADD POJO CLASS TYPE ANNOTATION /* Document dox = workingCopy.getDocument(); Element[] arrayOfElements = dox.getRootElements(); for ( Element el : arrayOfElements) { displayElements(el,0); }*/ List<ExpressionTree> argumentValueList = new ArrayList<ExpressionTree>(); if (annotationArguments != null) { Set<Map.Entry<String, Object>> annArgValSet = annotationArguments.entrySet(); for (Map.Entry<String, Object> mapenty : annArgValSet) { argumentValueList.add( GeneratorUtil.createAnnotationArgument(make, mapenty.getKey(), mapenty.getValue())); } } AnnotationTree pojoAnnTypeTree = GeneratorUtil.createAnnotation( make, workingCopy, GeneratorUtil.PROVIDER_CLASS_ANNOTATION, argumentValueList); ModifiersTree oldTree = classTree.getModifiers(); ModifiersTree newTree = make.Modifiers(oldTree, Collections.singletonList(pojoAnnTypeTree)); workingCopy.rewrite(oldTree, newTree); cut = workingCopy.getCompilationUnit(); classTree = (ClassTree) cut.getTypeDecls().get(0); ModifiersTree modifiers = handleModifiersAndAnnotations(make, workingCopy, GeneratorUtil.RSRC_ANNOTATION, null); VariableTree variableTree = GeneratorUtil.createField( make, workingCopy, modifiers, GeneratorUtil .POJO_CTX_VARIABLE, // TODO: Check if this variable is not used by this class. GeneratorUtil.CTX_ANNOTATION, // NOI18N null); ClassTree newClassTree1 = make.addClassMember(classTree, variableTree); // workingCopy.rewrite(classTree, newClassTree1); // CompilationUnitTree modClassTree = make.addCompUnitTypeDecl(cut, pojoAnnTypeTree); // workingCopy.rewrite(cut, modClassTree); cut = workingCopy.getCompilationUnit(); classTree = newClassTree1; // (ClassTree) cut.getTypeDecls().get(0); // ADD POJO OPERATION. boolean bOperationReturnsVoid = methodReturnType == null || methodReturnType.equals(GeneratorUtil.GENERATE_VOID); argumentValueList = new ArrayList<ExpressionTree>(); if (!bOperationReturnsVoid && this.operationArguments != null) { Set<Map.Entry<String, Object>> annArgValSet = operationArguments.entrySet(); for (Map.Entry<String, Object> mapenty : annArgValSet) { argumentValueList.add( GeneratorUtil.createAnnotationArgument(make, mapenty.getKey(), mapenty.getValue())); } } AnnotationTree anTree = GeneratorUtil.createAnnotation(make, workingCopy, annotationType, argumentValueList); Tree returnType = null; boolean bReturnVoid = false; if (bOperationReturnsVoid) { returnType = make.PrimitiveType(TypeKind.VOID); // return type bReturnVoid = true; } else { returnType = GeneratorUtil.createType(make, workingCopy, methodReturnType); } List<TypeParameterTree> listOfInputTypes = new ArrayList<TypeParameterTree>(); List<VariableTree> listOfInputVariables = new ArrayList<VariableTree>(); // ModifiersTree modTree = make.Modifiers(Collections.singleton(Modifier.PUBLIC)); ModifiersTree parMods = make.Modifiers(Collections.EMPTY_SET, Collections.EMPTY_LIST); int ix = 0; String inputVariableName = null; String inputVariableType = null; VariableTree inputIdentifier = null; for (String argumentType : methodArgumentType) { if (!argumentType.equals("")) { // listOfInputTypes.add( make.TypeParameter(argumentType, null)); inputVariableName = GeneratorUtil.POJO_VARIABLE_NAME_PREFIX + (ix++); inputVariableType = argumentType; inputIdentifier = GeneratorUtil.createField( make, workingCopy, parMods /** modTree* */ , inputVariableName, argumentType, null); listOfInputVariables.add(inputIdentifier); } } BlockTree blockTree = null; if (bReturnVoid) { blockTree = make.Block(Collections.EMPTY_LIST, false); } else { // List<ExpressionTree> returnExpList = // Collections.singletonList((ExpressionTree)make.Identifier("null")); if (inputVariableType != null && this.methodReturnType != null && methodReturnType.equals(inputVariableType)) { ReturnTree retTree = make.Return(make.Identifier(inputVariableName)); blockTree = make.Block(Collections.singletonList(retTree), false); } else { ReturnTree retTree = make.Return(make.Identifier("null")); blockTree = make.Block(Collections.singletonList(retTree), false); } } MethodTree newMethod = make.Method( make.Modifiers( Collections.singleton(Modifier.PUBLIC), // modifiers Collections.singletonList(anTree)), // modifiers and annotations methodName, // name returnType, // return type Collections.EMPTY_LIST, // listOfInputTypes, // type parameters for parameters listOfInputVariables, // parameters Collections.EMPTY_LIST, blockTree, // empty statement block null // default value - not applicable here, used by annotations ); ClassTree oldClassTree = (ClassTree) cut.getTypeDecls().get(0); ClassTree newClassTree = make.addClassMember(classTree, newMethod); workingCopy.rewrite(oldClassTree, newClassTree); } catch (Exception e) { myException = e; throw e; } }
@Override public String toString() { return String.format( "method %s (%s) / class %s (%s)", (mt != null ? mt.getName() : "null"), mrt, (ct != null ? ct.getSimpleName() : "null"), act); }