aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok')
-rw-r--r--src/core/lombok/ConfigurationKeys.java2
-rw-r--r--src/core/lombok/core/PostCompiler.java10
-rw-r--r--src/core/lombok/core/handlers/HandlerUtil.java64
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java2
-rw-r--r--src/core/lombok/eclipse/EclipseAugments.java2
-rw-r--r--src/core/lombok/eclipse/TransformEclipseAST.java36
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java167
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleBuilder.java30
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java8
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java1
-rw-r--r--src/core/lombok/eclipse/handlers/HandleLog.java16
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java1
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSuperBuilder.java1
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWith.java1
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWithBy.java1
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java115
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());