diff options
Diffstat (limited to 'src/core/lombok')
-rw-r--r-- | src/core/lombok/ConfigurationKeys.java | 2 | ||||
-rw-r--r-- | src/core/lombok/core/PostCompiler.java | 10 | ||||
-rw-r--r-- | src/core/lombok/core/handlers/HandlerUtil.java | 64 | ||||
-rw-r--r-- | src/core/lombok/eclipse/EclipseAST.java | 2 | ||||
-rw-r--r-- | src/core/lombok/eclipse/EclipseAugments.java | 2 | ||||
-rw-r--r-- | src/core/lombok/eclipse/TransformEclipseAST.java | 36 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 167 | ||||
-rwxr-xr-x | src/core/lombok/eclipse/handlers/HandleBuilder.java | 30 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java | 8 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleGetter.java | 1 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleLog.java | 16 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSetter.java | 1 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 1 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleWith.java | 1 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleWithBy.java | 1 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 115 |
16 files changed, 350 insertions, 107 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 60b98a94..01a4b576 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -140,7 +140,7 @@ public class ConfigurationKeys { * NB: GWT projects, and probably android projects, should explicitly set this key to {@code true} for the entire project. * * <br> - * <em>BREAKING CHANGE</em>: Starting with lombok v1.16.20, defaults to {@code false} instead of {@code true}, as {@code @ConstructorProperties} requires extra modules in JDK9. + * <em>BREAKING CHANGE</em>: Starting with lombok v1.16.20, defaults to {@code true} instead of {@code false}, as {@code @ConstructorProperties} requires extra modules in JDK9. * * @see ConfigurationKeys#ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES * @deprecated Since version 2.0, use {@link #ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES} instead. diff --git a/src/core/lombok/core/PostCompiler.java b/src/core/lombok/core/PostCompiler.java index e17f806e..72f4b3a2 100644 --- a/src/core/lombok/core/PostCompiler.java +++ b/src/core/lombok/core/PostCompiler.java @@ -72,10 +72,12 @@ public final class PostCompiler { // no need to call super byte[] original = toByteArray(); byte[] copy = null; - try { - copy = applyTransformations(original, fileName, diagnostics); - } catch (Exception e) { - diagnostics.addWarning(String.format("Error during the transformation of '%s'; no post-compilation has been applied", fileName)); + if (original.length > 0) { + try { + copy = applyTransformations(original, fileName, diagnostics); + } catch (Exception e) { + diagnostics.addWarning(String.format("Error during the transformation of '%s'; no post-compilation has been applied", fileName)); + } } if (copy == null) { diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 1c4437d7..92a9a142 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.AllArgsConstructor; @@ -756,4 +757,67 @@ public class HandlerUtil { if (PRIMITIVE_WRAPPER_TYPE_NAME_PATTERN.matcher(typeName).matches()) return 800; return 0; } + + private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITH(?:ER)?)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + private static final Pattern LINE_BREAK_FINDER = Pattern.compile("(\\r?\\n)?"); + + public static String stripLinesWithTagFromJavadoc(String javadoc, String regexpFragment) { + Pattern p = Pattern.compile("^\\s*\\**\\s*" + regexpFragment + "\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(javadoc); + return m.replaceAll(""); + } + + public static String stripSectionsFromJavadoc(String javadoc) { + Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); + if (!sectionMatcher.find()) return javadoc; + + return javadoc.substring(0, sectionMatcher.start()); + } + + public static String getJavadocSection(String javadoc, String sectionNameSpec) { + String[] sectionNames = sectionNameSpec.split("\\|"); + Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); + Matcher lineBreakMatcher = LINE_BREAK_FINDER.matcher(javadoc); + int sectionStart = -1; + int sectionEnd = -1; + while (sectionMatcher.find()) { + boolean found = false; + for (String sectionName : sectionNames) if (sectionMatcher.group(1).equalsIgnoreCase(sectionName)) { + found = true; + break; + } + if (found) { + lineBreakMatcher.find(sectionMatcher.end()); + sectionStart = lineBreakMatcher.end(); + } else if (sectionStart != -1) { + sectionEnd = sectionMatcher.start(); + } + } + + if (sectionStart != -1) { + if (sectionEnd != -1) return javadoc.substring(sectionStart, sectionEnd); + return javadoc.substring(sectionStart); + } + + return null; + } + + private static final Pattern FIND_RETURN = Pattern.compile("^\\s*\\**\\s*@returns?\\s+.*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + + public static String addReturnsThisIfNeeded(String in) { + if (FIND_RETURN.matcher(in).find()) return in; + + return addJavadocLine(in, "@return {@code this}."); + } + + public static String addReturnsUpdatedSelfIfNeeded(String in) { + if (FIND_RETURN.matcher(in).find()) return in; + + return addJavadocLine(in, "@return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed)."); + } + + public static String addJavadocLine(String in, String line) { + if (in.endsWith("\n")) return in + line + "\n"; + return in + "\n" + line; + } } diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index b45ac72d..d53856af 100644 --- a/src/core/lombok/eclipse/EclipseAST.java +++ b/src/core/lombok/eclipse/EclipseAST.java @@ -350,7 +350,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { if (!changed) clearChanged(); } - private static boolean isComplete(CompilationUnitDeclaration unit) { + public static boolean isComplete(CompilationUnitDeclaration unit) { return (unit.bits & ASTNode.HasAllMethodBodies) != 0; } diff --git a/src/core/lombok/eclipse/EclipseAugments.java b/src/core/lombok/eclipse/EclipseAugments.java index 4ecb99eb..783e25c9 100644 --- a/src/core/lombok/eclipse/EclipseAugments.java +++ b/src/core/lombok/eclipse/EclipseAugments.java @@ -21,6 +21,7 @@ */ package lombok.eclipse; +import java.util.Map; import java.util.List; import java.util.concurrent.ConcurrentMap; @@ -41,5 +42,6 @@ public final class EclipseAugments { public static final FieldAugment<ASTNode, Boolean> ASTNode_handled = FieldAugment.augment(ASTNode.class, boolean.class, "lombok$handled"); public static final FieldAugment<ASTNode, ASTNode> ASTNode_generatedBy = FieldAugment.augment(ASTNode.class, ASTNode.class, "$generatedBy"); public static final FieldAugment<Annotation, Boolean> Annotation_applied = FieldAugment.augment(Annotation.class, boolean.class, "lombok$applied"); + public static final FieldAugment<CompilationUnit, Map<String, String>> CompilationUnit_javadoc = FieldAugment.augment(CompilationUnit.class, Map.class, "$javadoc"); public static final FieldAugment<CompilationUnit, ConcurrentMap<String, List<SourceMethod>>> CompilationUnit_delegateMethods = FieldAugment.augment(CompilationUnit.class, ConcurrentMap.class, "$delegateMethods"); } diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java index 6fcde937..59a0709e 100644 --- a/src/core/lombok/eclipse/TransformEclipseAST.java +++ b/src/core/lombok/eclipse/TransformEclipseAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2019 The Project Lombok Authors. + * Copyright (C) 2009-2020 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,6 +24,9 @@ package lombok.eclipse; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; import lombok.ConfigurationKeys; import lombok.core.LombokConfiguration; @@ -63,6 +66,7 @@ public class TransformEclipseAST { public static boolean disableLombok = false; private static final HistogramTracker lombokTracker; + private static Map<CompilationUnitDeclaration, State> transformationStates = Collections.synchronizedMap(new WeakHashMap<CompilationUnitDeclaration, State>()); static { String v = System.getProperty("lombok.histogram"); @@ -130,6 +134,30 @@ public class TransformEclipseAST { } /** + * Check if lombok already handled the given AST. This method will return + * <code>true</code> once for diet mode and once for full mode. + * + * The reason for this is that Eclipse invokes the transform method multiple + * times during compilation and it is enough to transform it once and not + * repeat the whole thing over and over again. + * + * @param ast The AST node belonging to the compilation unit (java speak for a single source file). + * @return <code>true</code> if this AST was already handled by lombok. + */ + public static boolean alreadyTransformed(CompilationUnitDeclaration ast) { + State state = transformationStates.get(ast); + + if (state == State.FULL) return true; + if (state == State.DIET) { + if (!EclipseAST.isComplete(ast)) return true; + transformationStates.put(ast, State.FULL); + } else { + transformationStates.put(ast, State.DIET); + } + return false; + } + + /** * This method is called immediately after Eclipse finishes building a CompilationUnitDeclaration, which is * the top-level AST node when Eclipse parses a source file. The signature is 'magic' - you should not * change it! @@ -144,6 +172,7 @@ public class TransformEclipseAST { if (disableLombok) return; if (Symbols.hasSymbol("lombok.disable")) return; + if (alreadyTransformed(ast)) return; // Do NOT abort if (ast.bits & ASTNode.HasAllMethodBodies) != 0 - that doesn't work. @@ -243,4 +272,9 @@ public class TransformEclipseAST { nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority)); } } + + private static enum State { + DIET, + FULL + } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 6bfcf16e..d85c2ee8 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -39,6 +39,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; @@ -94,6 +96,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; @@ -103,6 +106,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; +import org.eclipse.jdt.internal.core.CompilationUnit; import lombok.AccessLevel; import lombok.ConfigurationKeys; @@ -2470,18 +2474,7 @@ public class EclipseHandlerUtil { } public static NameReference createNameReference(String name, Annotation source) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - - char[][] nameTokens = fromQualifiedName(name); - long[] pos = new long[nameTokens.length]; - Arrays.fill(pos, p); - - QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); - nameReference.statementEnd = pE; - - setGeneratedBy(nameReference, source); - return nameReference; + return generateQualifiedNameRef(source, fromQualifiedName(name)); } private static long[] copy(long[] array) { @@ -2635,4 +2628,154 @@ public class EclipseHandlerUtil { setGeneratedBy(ref, source); return ref; } + + public static TypeReference createTypeReference(String typeName, ASTNode source) { + return generateQualifiedTypeRef(source, fromQualifiedName(typeName)); + } + + public static String getDocComment(CompilationUnitDeclaration cud, ASTNode node) { + ICompilationUnit compilationUnit = cud.compilationResult.compilationUnit; + if (node instanceof FieldDeclaration) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) node; + char[] rawContent = CharOperation.subarray(compilationUnit.getContents(), fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd); + String rawContentString = new String(rawContent); + int startIndex = rawContentString.indexOf("/**"); + int endIndex = rawContentString.indexOf("*/"); + if (startIndex != -1 && endIndex != -1) { + /* Remove all leading asterisks */ + return rawContentString.substring(startIndex + 3, endIndex).replaceAll("(?m)^\\s*\\* ?", "").trim(); + } + } + return null; + } + + public static void setDocComment(CompilationUnitDeclaration cud, EclipseNode eclipseNode, String doc) { + setDocComment(cud, (TypeDeclaration) upToTypeNode(eclipseNode).get(), eclipseNode.get(), doc); + } + + public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { + if (cud.compilationResult.compilationUnit instanceof CompilationUnit) { + CompilationUnit compilationUnit = (CompilationUnit) cud.compilationResult.compilationUnit; + Map<String, String> docs = CompilationUnit_javadoc.setIfAbsent(compilationUnit, new HashMap<String, String>()); + + if (node instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; + String signature = getSignature(type, methodDeclaration); + /* Add javadoc start marker, add leading asterisks to each line, add javadoc end marker */ + docs.put(signature, String.format("/**%n%s%n */", doc.replaceAll("(?m)^", " * "))); + } + } + } + + public static String getSignature(TypeDeclaration type, AbstractMethodDeclaration methodDeclaration) { + StringBuilder sb = new StringBuilder(); + sb.append(type.name); + sb.append("."); + sb.append(methodDeclaration.selector); + sb.append("("); + Argument[] arguments = methodDeclaration.arguments; + if (arguments != null) { + for (Argument argument : arguments) { + String signature = Signature.createTypeSignature(argument.type.getLastToken(), false); + sb.append(signature); + } + } + sb.append(")"); + return sb.toString(); + } + + public static enum CopyJavadoc { + VERBATIM { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return getDocComment(cu, node.get()); + } + }, + GETTER { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + final ASTNode n = node.get(); + String javadoc = getDocComment(cu, n); + // step 1: Check if there is a 'GETTER' section. If yes, that becomes the new method's javadoc. + String out = getJavadocSection(javadoc, "GETTER"); + final boolean sectionBased = out != null; + if (!sectionBased) { + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@param(?:eter)?\\s+.*"); + } + return out; + } + }, + SETTER { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return applySetter(cu, node, "SETTER"); + } + }, + WITH { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return addReturnsUpdatedSelfIfNeeded(applySetter(cu, node, "WITH|WITHER")); + } + }, + WITH_BY { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return applySetter(cu, node, "WITHBY|WITH_BY"); + } + }; + + public abstract String apply(final CompilationUnitDeclaration cu, final EclipseNode node); + + private static String applySetter(final CompilationUnitDeclaration cu, EclipseNode node, String sectionName) { + final ASTNode n = node.get(); + String javadoc = getDocComment(cu, n); + // step 1: Check if there is a 'SETTER' section. If yes, that becomes the new method's javadoc. + String out = getJavadocSection(javadoc, sectionName); + final boolean sectionBased = out != null; + if (!sectionBased) { + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@returns?\\s+.*"); + } + return shouldReturnThis(node) ? addReturnsThisIfNeeded(out) : out; + } + } + + /** + * Copies javadoc on one node to the other. + * + * This one is a shortcut for {@link EclipseHandlerUtil#copyJavadoc(EclipseNode, ASTNode, TypeDeclaration, CopyJavadoc, boolean)} + * if source and target node are in the same type. + */ + public static void copyJavadoc(EclipseNode from, ASTNode to, CopyJavadoc copyMode) { + copyJavadoc(from, to, (TypeDeclaration) upToTypeNode(from).get(), copyMode, false); + } + + /** + * Copies javadoc on one node to the other. + * + * This one is a shortcut for {@link EclipseHandlerUtil#copyJavadoc(EclipseNode, ASTNode, TypeDeclaration, CopyJavadoc, boolean)} + * if source and target node are in the same type. + */ + public static void copyJavadoc(EclipseNode from, ASTNode to, CopyJavadoc copyMode, boolean forceAddReturn) { + copyJavadoc(from, to, (TypeDeclaration) upToTypeNode(from).get(), copyMode, forceAddReturn); + } + + public static void copyJavadoc(EclipseNode from, ASTNode to, TypeDeclaration type, CopyJavadoc copyMode) { + copyJavadoc(from, to, type, copyMode, false); + } + + /** + * Copies javadoc on one node to the other. + * + * in 'GETTER' copyMode, first a 'GETTER' segment is searched for. If it exists, that will become the javadoc for the 'to' node, and this section is + * stripped out of the 'from' node. If no 'GETTER' segment is found, then the entire javadoc is taken minus any {@code @param} lines and other sections. + * any {@code @return} lines are stripped from 'from'. + * + * in 'SETTER' mode, stripping works similarly to 'GETTER' mode, except {@code param} are copied and stripped from the original and {@code @return} are skipped. + */ + public static void copyJavadoc(EclipseNode from, ASTNode to, TypeDeclaration type, CopyJavadoc copyMode, boolean forceAddReturn) { + if (copyMode == null) copyMode = CopyJavadoc.VERBATIM; + try { + CompilationUnitDeclaration cud = ((CompilationUnitDeclaration) from.top().get()); + String newJavadoc = copyMode.apply(cud, from); + if (newJavadoc != null) { + if (forceAddReturn) newJavadoc = addReturnsThisIfNeeded(newJavadoc); + setDocComment(cud, type, to, newJavadoc); + } + } catch (Exception ignore) {} + } } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 801fe7e7..9e6c28e8 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -21,8 +21,8 @@ */ package lombok.eclipse.handlers; -import static lombok.eclipse.Eclipse.*; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; @@ -30,6 +30,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -84,14 +86,16 @@ import lombok.ConfigurationKeys; import lombok.Singular; import lombok.ToString; import lombok.core.AST.Kind; -import lombok.core.handlers.HandlerUtil; -import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.core.configuration.CheckerFrameworkVersion; +import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.HandlerUtil.FieldAccess; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.CopyJavadoc; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; @@ -965,9 +969,29 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { typeReference.annotations[0] = new Annotation[] {ann}; setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); } + if (sourceNode.up().getKind() == Kind.METHOD) { + copyJavadocFromParam(originalFieldNode.up(), setter, td, paramName.toString()); + } else { + copyJavadoc(originalFieldNode, setter, td, CopyJavadoc.SETTER, true); + } injectMethod(builderType, setter); } + private void copyJavadocFromParam(EclipseNode from, MethodDeclaration to, TypeDeclaration type, String param) { + try { + CompilationUnitDeclaration cud = (CompilationUnitDeclaration) from.top().get(); + String methodComment = getDocComment(cud, from.get()); + if (methodComment == null) return; + + Pattern pattern = Pattern.compile("@param " + param + " (\\S|\\s)+?(?=^ ?@)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(methodComment); + if (matcher.find()) { + String newJavadoc = addReturnsThisIfNeeded(matcher.group()); + setDocComment(cud, type, to, newJavadoc); + } + } catch (Exception ignore) {} + } + public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source, AccessLevel access) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index 9343011f..cee3912c 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -171,10 +171,10 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName injectMethod(fieldsType, constructor); } + Clinit cli = null; if (genClinit) { - Clinit cli = new Clinit(parent.compilationResult); + cli = new Clinit(parent.compilationResult); injectMethod(fieldsType, cli); - cli.traverse(generatedByVisitor, ((TypeDeclaration) fieldsType.get()).scope); } for (EclipseNode fieldNode : fields) { @@ -202,5 +202,9 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName injectField(fieldsType, constantField); constantField.traverse(generatedByVisitor, ((TypeDeclaration) fieldsType.get()).initializerScope); } + + if (genClinit) { + cli.traverse(generatedByVisitor, ((TypeDeclaration) fieldsType.get()).scope); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 9cd1e2a1..4d7d84ce 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -296,6 +296,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { } method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.GETTER); return method; } diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index a0e431e5..8297426d 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -22,11 +22,9 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; -import static lombok.eclipse.Eclipse.fromQualifiedName; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; -import java.util.Arrays; import java.util.List; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -35,7 +33,6 @@ import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; -import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -156,19 +153,6 @@ public class HandleLog { return fieldDecl; } - public static TypeReference createTypeReference(String typeName, Annotation source) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long) pS << 32 | pE; - - char[][] typeNameTokens = fromQualifiedName(typeName); - long[] pos = new long[typeNameTokens.length]; - Arrays.fill(pos, p); - - TypeReference typeReference = new QualifiedTypeReference(typeNameTokens, pos); - setGeneratedBy(typeReference, source); - return typeReference; - } - private static final Expression[] createFactoryParameters(ClassLiteralAccess loggingType, Annotation source, List<LogFactoryParameter> parameters, Expression loggerTopic) { Expression[] expressions = new Expression[parameters.size()]; int pS = source.sourceStart, pE = source.sourceEnd; diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index cb2ca3bf..83c6eef2 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -263,6 +263,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (returnType != null && returnStatement != null) createRelevantNonNullAnnotation(sourceNode, method); method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.SETTER, returnStatement != null); return method; } } diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index b1e7c419..79b7e816 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -741,6 +741,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } out.statements = body.isEmpty() ? null : body.toArray(new Statement[0]); + out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } diff --git a/src/core/lombok/eclipse/handlers/HandleWith.java b/src/core/lombok/eclipse/handlers/HandleWith.java index 83357710..dce193d8 100644 --- a/src/core/lombok/eclipse/handlers/HandleWith.java +++ b/src/core/lombok/eclipse/handlers/HandleWith.java @@ -290,6 +290,7 @@ public class HandleWith extends EclipseAnnotationHandler<With> { EclipseHandlerUtil.createRelevantNonNullAnnotation(fieldNode, method); method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.WITH); return method; } } diff --git a/src/core/lombok/eclipse/handlers/HandleWithBy.java b/src/core/lombok/eclipse/handlers/HandleWithBy.java index 5f229aaf..f56004f6 100644 --- a/src/core/lombok/eclipse/handlers/HandleWithBy.java +++ b/src/core/lombok/eclipse/handlers/HandleWithBy.java @@ -373,6 +373,7 @@ public class HandleWithBy extends EclipseAnnotationHandler<WithBy> { createRelevantNonNullAnnotation(fieldNode, method); method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.WITH_BY); return method; } } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index e0af0e52..2379d0a0 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -35,11 +35,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.lang.model.element.Element; +import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Scope; @@ -1127,7 +1127,25 @@ public class JavacHandlerUtil { } } } - + + static class JCAnnotationReflect { + private static Field ATTRIBUTE; + + static { + try { + ATTRIBUTE = Permit.getField(JCAnnotation.class, "attribute"); + } catch (Exception ignore) {} + } + + static Attribute.Compound getAttribute(JCAnnotation jcAnnotation) { + try { + return (Attribute.Compound) ATTRIBUTE.get(jcAnnotation); + } catch (Exception e) { + return null; + } + } + } + // jdk9 support, types have changed, names stay the same static class ClassSymbolMembersField { private static final Field membersField; @@ -1178,8 +1196,10 @@ public class JavacHandlerUtil { * Also takes care of updating the JavacAST. */ public static void injectMethod(JavacNode typeNode, JCMethodDecl method, List<Type> paramTypes, Type returnType) { + Context context = typeNode.getContext(); + Symtab symtab = Symtab.instance(context); JCClassDecl type = (JCClassDecl) typeNode.get(); - + if (method.getName().contentEquals("<init>")) { //Scan for default constructor, and remove it. int idx = 0; @@ -1196,7 +1216,7 @@ public class JavacHandlerUtil { idx++; } } - + addSuppressWarningsAll(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); addGenerated(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); type.defs = type.defs.append(method); @@ -1204,18 +1224,38 @@ public class JavacHandlerUtil { List<Symbol.VarSymbol> params = null; if (method.getParameters() != null && !method.getParameters().isEmpty()) { ListBuffer<Symbol.VarSymbol> newParams = new ListBuffer<Symbol.VarSymbol>(); - for (JCTree.JCVariableDecl param : method.getParameters()) { - if (param.sym != null) newParams.append(param.sym); + for (int i = 0; i < method.getParameters().size(); i++) { + JCTree.JCVariableDecl param = method.getParameters().get(i); + if (param.sym == null) { + Type paramType = paramTypes == null ? param.getType().type : paramTypes.get(i); + VarSymbol varSymbol = new VarSymbol(param.mods.flags, param.name, paramType, symtab.noSymbol); + List<JCAnnotation> annotations = param.getModifiers().getAnnotations(); + if (annotations != null && !annotations.isEmpty()) { + ListBuffer<Attribute.Compound> newAnnotations = new ListBuffer<Attribute.Compound>(); + for (JCAnnotation jcAnnotation : annotations) { + Attribute.Compound attribute = JCAnnotationReflect.getAttribute(jcAnnotation); + if (attribute != null) { + newAnnotations.append(attribute); + } + } + if (annotations.length() == newAnnotations.length()) { + varSymbol.appendAttributes(newAnnotations.toList()); + } + } + newParams.append(varSymbol); + } else { + newParams.append(param.sym); + } } params = newParams.toList(); if (params.length() != method.getParameters().length()) params = null; } fixMethodMirror(typeNode.getContext(), typeNode.getElement(), method.getModifiers().flags, method.getName(), paramTypes, params, returnType); - + typeNode.add(method, Kind.METHOD); } - + private static void fixMethodMirror(Context context, Element typeMirror, long access, Name methodName, List<Type> paramTypes, List<Symbol.VarSymbol> params, Type returnType) { if (typeMirror == null || paramTypes == null || returnType == null) return; ClassSymbol cs = (ClassSymbol) typeMirror; @@ -1963,47 +2003,6 @@ public class JavacHandlerUtil { return (JCExpression) in; } - private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITH(?:ER)?)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - - public static String stripLinesWithTagFromJavadoc(String javadoc, String regexpFragment) { - Pattern p = Pattern.compile("^\\s*\\**\\s*" + regexpFragment + "\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - Matcher m = p.matcher(javadoc); - return m.replaceAll(""); - } - - public static String stripSectionsFromJavadoc(String javadoc) { - Matcher m = SECTION_FINDER.matcher(javadoc); - if (!m.find()) return javadoc; - - return javadoc.substring(0, m.start()); - } - - public static String getJavadocSection(String javadoc, String sectionNameSpec) { - String[] sectionNames = sectionNameSpec.split("\\|"); - Matcher m = SECTION_FINDER.matcher(javadoc); - int sectionStart = -1; - int sectionEnd = -1; - while (m.find()) { - boolean found = false; - for (String sectionName : sectionNames) if (m.group(1).equalsIgnoreCase(sectionName)) { - found = true; - break; - } - if (found) { - sectionStart = m.end() + 1; - } else if (sectionStart != -1) { - sectionEnd = m.start(); - } - } - - if (sectionStart != -1) { - if (sectionEnd != -1) return javadoc.substring(sectionStart, sectionEnd); - return javadoc.substring(sectionStart); - } - - return null; - } - public static enum CopyJavadoc { VERBATIM { @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { @@ -2100,24 +2099,6 @@ public class JavacHandlerUtil { } catch (Exception ignore) {} } - private static final Pattern FIND_RETURN = Pattern.compile("^\\s*\\**\\s*@returns?\\s+.*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - static String addReturnsThisIfNeeded(String in) { - if (FIND_RETURN.matcher(in).find()) return in; - - return addJavadocLine(in, "@return {@code this}."); - } - - static String addReturnsUpdatedSelfIfNeeded(String in) { - if (FIND_RETURN.matcher(in).find()) return in; - - return addJavadocLine(in, "@return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed)."); - } - - static String addJavadocLine(String in, String line) { - if (in.endsWith("\n")) return in + line + "\n"; - return in + "\n" + line; - } - public static boolean isDirectDescendantOfObject(JavacNode typeNode) { if (!(typeNode.get() instanceof JCClassDecl)) throw new IllegalArgumentException("not a type node"); JCTree extending = Javac.getExtendsClause((JCClassDecl) typeNode.get()); |