private boolean isSynthetic(CompilationUnitTree cut, Tree leaf) { JCTree tree = (JCTree) leaf; if (tree.pos == (-1)) return true; if (leaf.getKind() == Tree.Kind.METHOD) { //check for synthetic constructor: return (((JCMethodDecl)leaf).mods.flags & Flags.GENERATEDCONSTR) != 0L; } //check for synthetic superconstructor call: if (leaf.getKind() == Tree.Kind.EXPRESSION_STATEMENT) { ExpressionStatementTree est = (ExpressionStatementTree) leaf; if (est.getExpression().getKind() == Tree.Kind.METHOD_INVOCATION) { MethodInvocationTree mit = (MethodInvocationTree) est.getExpression(); if (mit.getMethodSelect().getKind() == Tree.Kind.IDENTIFIER) { IdentifierTree it = (IdentifierTree) mit.getMethodSelect(); if ("super".equals(it.getName().toString())) { return sp.getEndPosition(cut, leaf) == (-1); } } } } return false; }
/**Find span of the {@link MethodTree#getName()} identifier in the source. * Returns starting and ending offset of the name in the source code that was parsed * (ie. {@link CompilationInfo.getText()}, which may differ from the positions in the source * document if it has been already altered. * * @param method method which name should be searched for * @return the span of the name, or null if cannot be found * @since 0.25 */ public int[] findNameSpan(MethodTree method) { if (isSynthetic(info.getCompilationUnit(), method)) { return null; } JCMethodDecl jcm = (JCMethodDecl) method; String name; if (jcm.name == jcm.name.table.names.init) { TreePath path = info.getTrees().getPath(info.getCompilationUnit(), jcm); if (path == null) { return null; } Element em = info.getTrees().getElement(path); Element clazz; if (em == null || (clazz = em.getEnclosingElement()) == null || !clazz.getKind().isClass()) { return null; } name = clazz.getSimpleName().toString(); } else { name = method.getName().toString(); } return findNameSpan(name, method); }
@Override public void visitMethodDef(JCMethodDecl tree) { cancelService.abortIfCanceled(); JCBlock body = tree.body; try { super.visitMethodDef(tree); } finally { //reinstall body: tree.body = body; } if (trees instanceof NBJavacTrees && !env.enclClass.defs.contains(tree)) { TreePath path = trees.getPath(env.toplevel, env.enclClass); if (path != null) { ((NBJavacTrees)trees).addPathForElement(tree.sym, new TreePath(path, tree)); } } }
private int methodParamIndex(List<JCTree> path, JCTree param) { List<JCTree> curr = path; while (curr.head.getTag() != Tag.METHODDEF && curr.head.getTag() != Tag.LAMBDA) { curr = curr.tail; } if (curr.head.getTag() == Tag.METHODDEF) { JCMethodDecl method = (JCMethodDecl)curr.head; return method.params.indexOf(param); } else if (curr.head.getTag() == Tag.LAMBDA) { JCLambda lambda = (JCLambda)curr.head; return lambda.params.indexOf(param); } else { Assert.error("methodParamIndex expected to find method or lambda for param: " + param); return -1; } }
/** * methods: remove method bodies, make methods native */ @Override public void visitMethodDef(JCMethodDecl tree) { tree.mods = translate(tree.mods); tree.restype = translate(tree.restype); tree.typarams = translateTypeParams(tree.typarams); tree.params = translateVarDefs(tree.params); tree.thrown = translate(tree.thrown); if (tree.body != null) { if ((currClassMods & Flags.INTERFACE) != 0) { tree.mods.flags &= ~(Flags.DEFAULT | Flags.STATIC); } else { tree.mods.flags |= Flags.NATIVE; } tree.body = null; } result = tree; }
@Override public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { List<JCTree> result = super.translateTopLevelClass(env, cdef, make); Map<Symbol, JCMethodDecl> declarations = new HashMap<>(); Set<Symbol> toDump = new TreeSet<>(symbolComparator); new TreeScanner() { @Override public void visitMethodDef(JCMethodDecl tree) { if (tree.name.toString().startsWith("dump")) { toDump.add(tree.sym); } declarations.put(tree.sym, tree); super.visitMethodDef(tree); } }.scan(result); for (Symbol d : toDump) { dump(d, declarations, new HashSet<>()); } return result; }
/** {@inheritDoc} */ @Override protected JavacNode buildTree(JCTree node, Kind kind) { switch (kind) { case COMPILATION_UNIT: return buildCompilationUnit((JCCompilationUnit) node); case TYPE: return buildType((JCClassDecl) node); case FIELD: return buildField((JCVariableDecl) node); case INITIALIZER: return buildInitializer((JCBlock) node); case METHOD: return buildMethod((JCMethodDecl) node); case ARGUMENT: return buildLocalVar((JCVariableDecl) node, kind); case LOCAL: return buildLocalVar((JCVariableDecl) node, kind); case STATEMENT: return buildStatementOrExpression(node); case ANNOTATION: return buildAnnotation((JCAnnotation) node, false); default: throw new AssertionError("Did not expect: " + kind); } }
private JavacNode buildType(JCClassDecl type) { if (setAndGetAsHandled(type)) return null; List<JavacNode> childNodes = new ArrayList<JavacNode>(); for (JCAnnotation annotation : type.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, false)); for (JCTree def : type.defs) { /* A def can be: * JCClassDecl for inner types * JCMethodDecl for constructors and methods * JCVariableDecl for fields * JCBlock for (static) initializers */ if (def instanceof JCMethodDecl) addIfNotNull(childNodes, buildMethod((JCMethodDecl)def)); else if (def instanceof JCClassDecl) addIfNotNull(childNodes, buildType((JCClassDecl)def)); else if (def instanceof JCVariableDecl) addIfNotNull(childNodes, buildField((JCVariableDecl)def)); else if (def instanceof JCBlock) addIfNotNull(childNodes, buildInitializer((JCBlock)def)); } return putInMap(new JavacNode(this, type, childNodes, Kind.TYPE)); }
/** * Checks if there is a (non-default) constructor. In case of multiple constructors (overloading), only * the first constructor decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. * * @param node Any node that represents the Type (JCClassDecl) to look in, or any child node thereof. */ public static MemberExistsResult constructorExists(JavacNode node) { node = upToTypeNode(node); if (node != null && node.get() instanceof JCClassDecl) { top: for (JCTree def : ((JCClassDecl)node.get()).defs) { if (def instanceof JCMethodDecl) { JCMethodDecl md = (JCMethodDecl) def; if (md.name.contentEquals("<init>")) { if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) continue; List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); if (annotations != null) for (JCAnnotation anno : annotations) { if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) continue top; } return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } } } } return MemberExistsResult.NOT_EXISTS; }
@Override public void handle(AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.SNEAKY_THROWS_FLAG_USAGE, "@SneakyThrows"); deleteAnnotationIfNeccessary(annotationNode, SneakyThrows.class); Collection<String> exceptionNames = annotation.getRawExpressions("value"); if (exceptionNames.isEmpty()) { exceptionNames = Collections.singleton("java.lang.Throwable"); } java.util.List<String> exceptions = new ArrayList<String>(); for (String exception : exceptionNames) { if (exception.endsWith(".class")) exception = exception.substring(0, exception.length() - 6); exceptions.add(exception); } JavacNode owner = annotationNode.up(); switch (owner.getKind()) { case METHOD: handleMethod(annotationNode, (JCMethodDecl)owner.get(), exceptions); break; default: annotationNode.addError("@SneakyThrows is legal only on methods and constructors."); break; } }
private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); for (BuilderFieldData bfd : builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, type, source, statements); } } statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, false)))); JCBlock body = maker.Block(0, statements.toList()); return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(maker, CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); /* * if (shouldReturnThis) { methodType = cloneSelfType(field); } if (methodType == null) { //WARNING: Do not use field.getSymbolTable().voidType - that field has gone through non-backwards compatible API changes within javac1.6. methodType = treeMaker.Type(Javac.createVoidType(treeMaker, CTC_VOID)); shouldReturnThis = false; } */ }
public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); for (JCTypeParameter typeParam : typeParams) { typeArgs.append(maker.Ident(typeParam.name)); } JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.<JCExpression>nil(), null); JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); int modifiers = Flags.PUBLIC; if (isStatic) modifiers |= Flags.STATIC; return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(maker, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); }
public JCMethodDecl createCanEqual(JavacNode typeNode, JCTree source, List<JCAnnotation> onParam) { /* protected boolean canEqual(final java.lang.Object other) { * return other instanceof Outer.Inner.MyType; * } */ JavacTreeMaker maker = typeNode.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.PROTECTED, List.<JCAnnotation>nil()); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); Name canEqualName = typeNode.toName("canEqual"); JCExpression objectType = genJavaLangTypeRef(typeNode, "Object"); Name otherName = typeNode.toName("other"); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null)); JCBlock body = maker.Block(0, List.<JCStatement>of( maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode))))); return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); }
private void generateClearMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) { JCModifiers mods = maker.Modifiers(Flags.PUBLIC); List<JCTypeParameter> typeParams = List.nil(); List<JCExpression> thrown = List.nil(); List<JCVariableDecl> params = List.nil(); List<JCExpression> jceBlank = List.nil(); JCExpression thisDotKeyField = chainDots(builderType, "this", data.getPluralName() + "$key"); JCExpression thisDotKeyFieldDotClear = chainDots(builderType, "this", data.getPluralName() + "$key", "clear"); JCExpression thisDotValueFieldDotClear = chainDots(builderType, "this", data.getPluralName() + "$value", "clear"); JCStatement clearKeyCall = maker.Exec(maker.Apply(jceBlank, thisDotKeyFieldDotClear, jceBlank)); JCStatement clearValueCall = maker.Exec(maker.Apply(jceBlank, thisDotValueFieldDotClear, jceBlank)); JCExpression cond = maker.Binary(CTC_NOT_EQUAL, thisDotKeyField, maker.Literal(CTC_BOT, null)); JCBlock clearCalls = maker.Block(0, List.of(clearKeyCall, clearValueCall)); JCStatement ifSetCallClear = maker.If(cond, clearCalls, null); List<JCStatement> statements = returnStatement != null ? List.of(ifSetCallClear, returnStatement) : List.of(ifSetCallClear); JCBlock body = maker.Block(0, statements); Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, params, thrown, body, null); injectMethod(builderType, method); }
private void generateClearMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) { JCModifiers mods = maker.Modifiers(Flags.PUBLIC); List<JCTypeParameter> typeParams = List.nil(); List<JCExpression> thrown = List.nil(); List<JCVariableDecl> params = List.nil(); List<JCExpression> jceBlank = List.nil(); JCExpression thisDotField = maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()); JCExpression thisDotFieldDotClear = maker.Select(maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()), builderType.toName("clear")); JCStatement clearCall = maker.Exec(maker.Apply(jceBlank, thisDotFieldDotClear, jceBlank)); JCExpression cond = maker.Binary(CTC_NOT_EQUAL, thisDotField, maker.Literal(CTC_BOT, null)); JCStatement ifSetCallClear = maker.If(cond, clearCall, null); List<JCStatement> statements = returnStatement != null ? List.of(ifSetCallClear, returnStatement) : List.of(ifSetCallClear); JCBlock body = maker.Block(0, statements); Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, params, thrown, body, null); injectMethod(builderType, method); }
void generateSingularMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { List<JCTypeParameter> typeParams = List.nil(); List<JCExpression> thrown = List.nil(); JCModifiers mods = maker.Modifiers(Flags.PUBLIC); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, false, source)); JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), "add"); JCExpression invokeAdd = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotAdd, List.<JCExpression>of(maker.Ident(data.getSingularName()))); statements.append(maker.Exec(invokeAdd)); if (returnStatement != null) statements.append(returnStatement); JCBlock body = maker.Block(0, statements.toList()); Name name = data.getSingularName(); long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName("add", name.toString())); JCExpression paramType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getSingularName(), paramType, null); JCMethodDecl method = maker.MethodDef(mods, name, returnType, typeParams, List.of(param), thrown, body, null); injectMethod(builderType, method); }
void generatePluralMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { List<JCTypeParameter> typeParams = List.nil(); List<JCExpression> thrown = List.nil(); JCModifiers mods = maker.Modifiers(Flags.PUBLIC); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, false, source)); JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), "addAll"); JCExpression invokeAdd = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotAdd, List.<JCExpression>of(maker.Ident(data.getPluralName()))); statements.append(maker.Exec(invokeAdd)); if (returnStatement != null) statements.append(returnStatement); JCBlock body = maker.Block(0, statements.toList()); Name name = data.getPluralName(); long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName("addAll", name.toString())); JCExpression paramType = chainDots(builderType, "java", "util", "Collection"); paramType = addTypeArgs(1, true, builderType, paramType, data.getTypeArgs(), source); JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getPluralName(), paramType, null); JCMethodDecl method = maker.MethodDef(mods, name, returnType, typeParams, List.of(param), thrown, body, null); injectMethod(builderType, method); }
public JCMethodDecl createCanEqual(JavacNode typeNode, JCTree source, List<JCAnnotation> onParam) { /* public boolean canEqual(final java.lang.Object other) { * return other instanceof Outer.Inner.MyType; * } */ JavacTreeMaker maker = typeNode.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.PROTECTED, List.<JCAnnotation>nil()); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); Name canEqualName = typeNode.toName("canEqual"); JCExpression objectType = genJavaLangTypeRef(typeNode, "Object"); Name otherName = typeNode.toName("other"); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null)); JCBlock body = maker.Block(0, List.<JCStatement>of( maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode))))); return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); }
@Override public Pair<ASTRecord, Integer> visitMethod(MethodTree node, Insertion ins) { dbug.debug("TypePositionFinder.visitMethod%n"); super.visitMethod(node, ins); JCMethodDecl jcnode = (JCMethodDecl) node; JCVariableDecl jcvar = (JCVariableDecl) node.getReceiverParameter(); if (jcvar != null) { return pathAndPos(jcvar); } int pos = Position.NOPOS; ASTRecord astPath = astRecord(jcnode) .extend(Tree.Kind.METHOD, ASTPath.PARAMETER, -1); if (node.getParameters().isEmpty()) { // no parameters; find first (uncommented) '(' after method name pos = findMethodName(jcnode); if (pos >= 0) { pos = getFirstInstanceAfter('(', pos); } if (++pos <= 0) { throw new RuntimeException("Couldn't find param opening paren for: " + jcnode); } } else { pos = ((JCTree) node.getParameters().get(0)).getStartPosition(); } return Pair.of(astPath, pos); }
@Override public boolean visitAnnotationMethodDeclaration(AnnotationMethodDeclaration node) { JCMethodDecl methodDef = treeMaker.MethodDef( (JCModifiers)toTree(node.astModifiers()), toName(node.astMethodName()), toExpression(node.astReturnTypeReference()), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, toExpression(node.astDefaultValue()) ); int start = node.astMethodName().getPosition().getStart(); int end = node.getPosition().getEnd(); return set(node, setPos(start, end, methodDef)); }
@Override public boolean visitMethodDeclaration(MethodDeclaration node) { JCMethodDecl methodDef = treeMaker.MethodDef( (JCModifiers)toTree(node.astModifiers()), toName(node.astMethodName()), toExpression(node.astReturnTypeReference()), toList(JCTypeParameter.class, node.astTypeVariables()), toList(JCVariableDecl.class, node.astParameters()), toList(JCExpression.class, node.astThrownTypeReferences()), (JCBlock)toTree(node.astBody()), null ); for (JCVariableDecl decl : methodDef.params) { decl.mods.flags |= Flags.PARAMETER; } int start = node.astMethodName().getPosition().getStart(); int end = node.getPosition().getEnd(); return set(node, setPos(start, end, methodDef)); }
@Override public boolean visitConstructorDeclaration(ConstructorDeclaration node) { JCMethodDecl constrDef = treeMaker.MethodDef( (JCModifiers)toTree(node.astModifiers()), table.init, null, toList(JCTypeParameter.class, node.astTypeVariables()), toList(JCVariableDecl.class, node.astParameters()), toList(JCExpression.class, node.astThrownTypeReferences()), (JCBlock)toTree(node.astBody()), null ); for (JCVariableDecl decl : constrDef.params) { decl.mods.flags |= Flags.PARAMETER; } int start = node.astTypeName().getPosition().getStart(); int end = node.getPosition().getEnd(); return set(node, setPos(start, end, constrDef)); }
/** Finds a declaration with the given name and type that is in scope at the current location. */ public static Symbol findIdent(String name, VisitorState state, KindSelector kind) { ClassType enclosingClass = ASTHelpers.getType(state.findEnclosing(ClassTree.class)); if (enclosingClass == null || enclosingClass.tsym == null) { return null; } Env<AttrContext> env = Enter.instance(state.context).getClassEnv(enclosingClass.tsym); MethodTree enclosingMethod = state.findEnclosing(MethodTree.class); if (enclosingMethod != null) { env = MemberEnter.instance(state.context).getMethodEnv((JCMethodDecl) enclosingMethod, env); } try { Method method = Resolve.class.getDeclaredMethod("findIdent", Env.class, Name.class, KindSelector.class); method.setAccessible(true); Symbol result = (Symbol) method.invoke(Resolve.instance(state.context), env, state.getName(name), kind); return result.exists() ? result : null; } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } }
private List<Fix> fixesFromMethodParameters(VisitorState state, final ExpressionTree argument) { // find a method parameter of the same type and similar name and suggest it // as the new argument assert (argument.getKind() == IDENTIFIER || argument.getKind() == MEMBER_SELECT); FluentIterable<JCVariableDecl> collectionParams = FluentIterable.from( ASTHelpers.findEnclosingNode(state.getPath(), JCMethodDecl.class).getParameters()) .filter(isCollectionVariable(state)); Multimap<Integer, JCVariableDecl> potentialReplacements = partitionByEditDistance(simpleNameOfIdentifierOrMemberAccess(argument), collectionParams); return buildValidReplacements( potentialReplacements, new Function<JCVariableDecl, Fix>() { @Override public Fix apply(JCVariableDecl var) { return SuggestedFix.replace(argument, var.sym.toString()); } }); }