aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilippe Charles <charphi@users.noreply.github.com>2018-08-22 09:54:00 +0200
committerGitHub <noreply@github.com>2018-08-22 09:54:00 +0200
commit3ffac6642456e2c7d32952c62df8a565e2d4728b (patch)
treeb0a28ac208dcb8af9add494c4caffe4f11bb287b /src
parent35c7c6bda2e71da2e6e06cec5b0fb012c348f694 (diff)
parent769185e123dfd4a073161eafb58ce50bb79d6201 (diff)
downloadlombok-3ffac6642456e2c7d32952c62df8a565e2d4728b.tar.gz
lombok-3ffac6642456e2c7d32952c62df8a565e2d4728b.tar.bz2
lombok-3ffac6642456e2c7d32952c62df8a565e2d4728b.zip
Merge branch 'master' into master
Diffstat (limited to 'src')
-rw-r--r--src/core/lombok/ConfigurationKeys.java20
-rw-r--r--src/core/lombok/bytecode/ClassFileMetaData.java11
-rw-r--r--src/core/lombok/core/AST.java12
-rw-r--r--src/core/lombok/core/AnnotationProcessor.java30
-rw-r--r--src/core/lombok/core/LombokConfiguration.java15
-rw-r--r--src/core/lombok/core/LombokInternalAliasing.java6
-rw-r--r--src/core/lombok/core/LombokNode.java38
-rw-r--r--src/core/lombok/core/Version.java2
-rw-r--r--src/core/lombok/core/configuration/ConfigurationApp.java7
-rw-r--r--src/core/lombok/core/configuration/ConfigurationKey.java12
-rw-r--r--src/core/lombok/core/configuration/ConfigurationResolverFactory.java6
-rw-r--r--src/core/lombok/core/configuration/StringConfigurationSource.java1
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java12
-rw-r--r--src/core/lombok/eclipse/EclipseASTAdapter.java7
-rw-r--r--src/core/lombok/eclipse/EclipseASTVisitor.java111
-rw-r--r--src/core/lombok/eclipse/EclipseNode.java10
-rw-r--r--src/core/lombok/eclipse/HandlerLibrary.java24
-rw-r--r--src/core/lombok/eclipse/TransformEclipseAST.java32
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java26
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java36
-rw-r--r--src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java26
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java144
-rw-r--r--src/core/lombok/experimental/FieldNameConstants.java28
-rw-r--r--src/core/lombok/javac/JavacAST.java7
-rw-r--r--src/core/lombok/javac/JavacASTVisitor.java14
-rw-r--r--src/core/lombok/javac/JavacNode.java9
-rw-r--r--src/core/lombok/javac/JavacTransformer.java11
-rw-r--r--src/core/lombok/javac/apt/LombokProcessor.java21
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java30
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldDefaults.java2
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldNameConstants.java129
-rw-r--r--src/core9/module-info.java2
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java1
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchVal.java16
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java84
-rw-r--r--src/eclipseAgent/lombok/launch/PatchFixesHider.java2
-rw-r--r--src/launch/lombok/launch/Agent.java2
-rw-r--r--src/launch/lombok/launch/AnnotationProcessor.java2
-rw-r--r--src/launch/lombok/launch/Main.java12
-rw-r--r--src/launch/lombok/launch/ShadowClassLoader.java37
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java24
41 files changed, 680 insertions, 341 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index f5134bbd..184ded27 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2017 The Project Lombok Authors.
+ * Copyright (C) 2013-2018 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
@@ -39,6 +39,13 @@ public class ConfigurationKeys {
// ----- global -----
/**
+ * lombok configuration: {@code dangerousconfig.lombok.disable} = {@code true} | {@code false}.
+ *
+ * If {@code true}, lombok is disabled entirely.
+ */
+ public static final ConfigurationKey<Boolean> LOMBOK_DISABLE = new ConfigurationKey<Boolean>("dangerousconfig.lombok.disable", "Disables lombok transformers. It does not flag any lombok mentions (so, @Cleanup silently does nothing), and does not disable patched operations in eclipse either. Don't use this unless you know what you're doing. (default: false).", true) {};
+
+ /**
* lombok configuration: {@code lombok.addGeneratedAnnotation} = {@code true} | {@code false}.
*
* If {@code true}, lombok generates {@code @javax.annotation.Generated("lombok")} on all fields, methods, and types that are generated, unless {@code lombok.addJavaxGeneratedAnnotation} is set.
@@ -522,18 +529,11 @@ public class ConfigurationKeys {
public static final ConfigurationKey<FlagUsageType> FIELD_NAME_CONSTANTS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.fieldNameConstants.flagUsage", "Emit a warning or error if @FieldNameConstants is used.") {};
/**
- * lombok configuration: {@code lombok.fieldNameConstants.prefix} = &lt;String: aJavaIdentifierPrefix&gt; (Default: {@code PREFIX_}).
+ * lombok configuration: {@code lombok.fieldNameConstants.innerTypeName} = &lt;String: AValidJavaTypeName&gt; (Default: {@code Fields}).
*
* The names of the constants generated by {@code @FieldNameConstants} will be prefixed with this value.
*/
- public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_PREFIX = new ConfigurationKey<String>("lombok.fieldNameConstants.prefix", "names of constants generated by @FieldNameConstants will be prefixed with this value. (default: 'PREFIX_').") {};
-
- /**
- * lombok configuration: {@code lombok.fieldNameConstants.suffix} = &lt;String: aJavaIdentifierPrefix&gt; (Default: nothing).
- *
- * The names of the constants generated by {@code @FieldNameConstants} will be suffixed with this value.
- */
- public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_SUFFIX = new ConfigurationKey<String>("lombok.fieldNameConstants.suffix", "names of constants generated by @FieldNameConstants will be suffixed with this value. (default: nothing).") {};
+ public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_INNER_TYPE_NAME = new ConfigurationKey<String>("lombok.fieldNameConstants.innerTypeName", "The default name of the inner type generated by @FieldNameConstants. (default: 'Fields').") {};
// ----- Wither -----
diff --git a/src/core/lombok/bytecode/ClassFileMetaData.java b/src/core/lombok/bytecode/ClassFileMetaData.java
index 0dc6a6c8..826eed83 100644
--- a/src/core/lombok/bytecode/ClassFileMetaData.java
+++ b/src/core/lombok/bytecode/ClassFileMetaData.java
@@ -116,23 +116,24 @@ public class ClassFileMetaData {
int end = pos + size;
// the resulting string might be smaller
- StringBuilder result = new StringBuilder(size);
+ char[] result = new char[size];
+ int length = 0;
while (pos < end) {
int first = (byteCode[pos++] & 0xFF);
if (first < 0x80) {
- result.append((char)first);
+ result[length++] = (char)first;
} else if ((first & 0xE0) == 0xC0) {
int x = (first & 0x1F) << 6;
int y = (byteCode[pos++] & 0x3F);
- result.append((char)(x | y));
+ result[length++] = (char)(x | y);
} else {
int x = (first & 0x0F) << 12;
int y = (byteCode[pos++] & 0x3F) << 6;
int z = (byteCode[pos++] & 0x3F);
- result.append((char)(x | y | z));
+ result[length++] = (char)(x | y | z);
}
}
- return result.toString();
+ return new String(result, 0, length);
}
/**
diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java
index 1142018f..fe7a4330 100644
--- a/src/core/lombok/core/AST.java
+++ b/src/core/lombok/core/AST.java
@@ -216,19 +216,19 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
}
}
- private static final ConcurrentMap<Class<?>, Collection<FieldAccess>> fieldsOfASTClasses = new ConcurrentHashMap<Class<?>, Collection<FieldAccess>>();
+ private static final ConcurrentMap<Class<?>, FieldAccess[]> fieldsOfASTClasses = new ConcurrentHashMap<Class<?>, FieldAccess[]>();
/** Returns FieldAccess objects for the stated class. Each field that contains objects of the kind returned by
* {@link #getStatementTypes()}, either directly or inside of an array or java.util.collection (or array-of-arrays,
* or collection-of-collections, et cetera), is returned.
*/
- protected Collection<FieldAccess> fieldsOf(Class<?> c) {
- Collection<FieldAccess> fields = fieldsOfASTClasses.get(c);
+ protected FieldAccess[] fieldsOf(Class<?> c) {
+ FieldAccess[] fields = fieldsOfASTClasses.get(c);
if (fields != null) return fields;
- fields = new ArrayList<FieldAccess>();
- getFields(c, fields);
- fieldsOfASTClasses.putIfAbsent(c, fields);
+ List<FieldAccess> fieldList = new ArrayList<FieldAccess>();
+ getFields(c, fieldList);
+ fieldsOfASTClasses.putIfAbsent(c, fieldList.toArray(new FieldAccess[fieldList.size()]));
return fieldsOfASTClasses.get(c);
}
diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java
index 04448ecb..293bfef6 100644
--- a/src/core/lombok/core/AnnotationProcessor.java
+++ b/src/core/lombok/core/AnnotationProcessor.java
@@ -49,7 +49,7 @@ import lombok.patcher.ClassRootFinder;
@SupportedAnnotationTypes("*")
public class AnnotationProcessor extends AbstractProcessor {
-
+
private static String trace(Throwable t) {
StringWriter w = new StringWriter();
t.printStackTrace(new PrintWriter(w, true));
@@ -65,42 +65,35 @@ public class AnnotationProcessor extends AbstractProcessor {
private final List<ProcessorDescriptor> registered = Arrays.asList(new JavacDescriptor(), new EcjDescriptor());
private final List<ProcessorDescriptor> active = new ArrayList<ProcessorDescriptor>();
private final List<String> delayedWarnings = new ArrayList<String>();
-
+
/**
* This method is a simplified version of {@link lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment}
* It simply returns the processing environment, but in case of gradle incremental compilation,
* the delegate ProcessingEnvironment of the gradle wrapper is returned.
*/
public static ProcessingEnvironment getJavacProcessingEnvironment(ProcessingEnvironment procEnv, List<String> delayedWarnings) {
- ProcessingEnvironment javacProcEnv = tryRecursivelyObtainJavacProcessingEnvironment(procEnv);
-
- if (javacProcEnv == null) {
- delayedWarnings.add("Can't get the delegate of the gradle IncrementalProcessingEnvironment.");
- }
-
- return javacProcEnv;
+ return tryRecursivelyObtainJavacProcessingEnvironment(procEnv);
}
-
+
private static ProcessingEnvironment tryRecursivelyObtainJavacProcessingEnvironment(ProcessingEnvironment procEnv) {
if (procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) {
return procEnv;
}
-
+
for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) {
try {
Field field = procEnvClass.getDeclaredField("delegate");
field.setAccessible(true);
Object delegate = field.get(procEnv);
-
+
return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate);
} catch (final Exception e) {
// no valid delegate, try superclass
}
}
-
+
return null;
}
-
static class JavacDescriptor extends ProcessorDescriptor {
private Processor processor;
@@ -110,10 +103,13 @@ public class AnnotationProcessor extends AbstractProcessor {
}
@Override boolean want(ProcessingEnvironment procEnv, List<String> delayedWarnings) {
+ // do not run on ECJ as it may print warnings
+ if (procEnv.getClass().getName().startsWith("org.eclipse.jdt.")) return false;
+
ProcessingEnvironment javacProcEnv = getJavacProcessingEnvironment(procEnv, delayedWarnings);
-
+
if (javacProcEnv == null) return false;
-
+
try {
ClassLoader classLoader = findAndPatchClassLoader(javacProcEnv);
processor = (Processor) Class.forName("lombok.javac.apt.LombokProcessor", false, classLoader).newInstance();
@@ -209,7 +205,7 @@ public class AnnotationProcessor extends AbstractProcessor {
for (TypeElement elem : annotations) {
zeroElems = false;
Name n = elem.getQualifiedName();
- if (n.length() > 7 && n.subSequence(0, 7).toString().equals("lombok.")) continue;
+ if (n.toString().startsWith("lombok.")) continue;
onlyLombok = false;
}
diff --git a/src/core/lombok/core/LombokConfiguration.java b/src/core/lombok/core/LombokConfiguration.java
index eb7b3d75..4a79c797 100644
--- a/src/core/lombok/core/LombokConfiguration.java
+++ b/src/core/lombok/core/LombokConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 The Project Lombok Authors.
+ * Copyright (C) 2013-2018 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
@@ -21,6 +21,7 @@
*/
package lombok.core;
+import java.net.URI;
import java.util.Collections;
import lombok.core.configuration.BubblingConfigurationResolver;
@@ -44,7 +45,7 @@ public class LombokConfiguration {
static {
if (System.getProperty("lombok.disableConfig") != null) {
configurationResolverFactory = new ConfigurationResolverFactory() {
- @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) {
+ @Override public ConfigurationResolver createResolver(URI sourceLocation) {
return NULL_RESOLVER;
}
};
@@ -63,13 +64,17 @@ public class LombokConfiguration {
}
static <T> T read(ConfigurationKey<T> key, AST<?, ?, ?> ast) {
- return configurationResolverFactory.createResolver(ast).resolve(key);
+ return configurationResolverFactory.createResolver(ast.getAbsoluteFileLocation()).resolve(key);
+ }
+
+ public static <T> T read(ConfigurationKey<T> key, URI sourceLocation) {
+ return configurationResolverFactory.createResolver(sourceLocation).resolve(key);
}
private static ConfigurationResolverFactory createFileSystemBubblingResolverFactory() {
return new ConfigurationResolverFactory() {
- @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) {
- return new BubblingConfigurationResolver(cache.sourcesForJavaFile(ast.getAbsoluteFileLocation(), ConfigurationProblemReporter.CONSOLE));
+ @Override public ConfigurationResolver createResolver(URI sourceLocation) {
+ return new BubblingConfigurationResolver(cache.sourcesForJavaFile(sourceLocation, ConfigurationProblemReporter.CONSOLE));
}
};
}
diff --git a/src/core/lombok/core/LombokInternalAliasing.java b/src/core/lombok/core/LombokInternalAliasing.java
index 3dc1bfa2..c1089580 100644
--- a/src/core/lombok/core/LombokInternalAliasing.java
+++ b/src/core/lombok/core/LombokInternalAliasing.java
@@ -36,10 +36,8 @@ public class LombokInternalAliasing {
*/
public static String processAliases(String in) {
if (in == null) return null;
- for (Map.Entry<String, String> e : ALIASES.entrySet()) {
- if (in.equals(e.getKey())) return e.getValue();
- }
- return in;
+ String ret = ALIASES.get(in);
+ return ret == null ? in : ret;
}
static {
diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java
index d6708956..5a0842bc 100644
--- a/src/core/lombok/core/LombokNode.java
+++ b/src/core/lombok/core/LombokNode.java
@@ -40,7 +40,6 @@ import lombok.core.AST.Kind;
* For example, JCTree for javac, and ASTNode for Eclipse.
*/
public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> implements DiagnosticsReceiver {
- protected final A ast;
protected final Kind kind;
protected final N node;
protected LombokImmutableList<L> children;
@@ -59,8 +58,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @param kind The kind of node represented by this object.
*/
@SuppressWarnings("unchecked")
- protected LombokNode(A ast, N node, List<L> children, Kind kind) {
- this.ast = ast;
+ protected LombokNode(N node, List<L> children, Kind kind) {
this.kind = kind;
this.node = node;
this.children = children != null ? LombokImmutableList.copyOf(children) : LombokImmutableList.<L>of();
@@ -72,9 +70,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
this.isStructurallySignificant = calculateIsStructurallySignificant(null);
}
- public A getAst() {
- return ast;
- }
+ public abstract A getAst();
/** {@inheritDoc} */
@Override public String toString() {
@@ -88,7 +84,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#getPackageDeclaration()
*/
public String getPackageDeclaration() {
- return ast.getPackageDeclaration();
+ return getAst().getPackageDeclaration();
}
/**
@@ -97,7 +93,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#getImportList()
*/
public ImportList getImportList() {
- return ast.getImportList();
+ return getAst().getImportList();
}
/**
@@ -111,7 +107,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#get(Object)
*/
public L getNodeFor(N obj) {
- return ast.get(obj);
+ return getAst().get(obj);
}
/**
@@ -187,7 +183,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#getLatestJavaSpecSupported()
*/
public int getLatestJavaSpecSupported() {
- return ast.getLatestJavaSpecSupported();
+ return getAst().getLatestJavaSpecSupported();
}
/**
@@ -196,7 +192,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#getSourceVersion()
*/
public int getSourceVersion() {
- return ast.getSourceVersion();
+ return getAst().getSourceVersion();
}
/**
@@ -205,7 +201,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#top()
*/
public L top() {
- return ast.top();
+ return getAst().top();
}
/**
@@ -214,7 +210,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* @see AST#getFileName()
*/
public String getFileName() {
- return ast.getFileName();
+ return getAst().getFileName();
}
/**
@@ -224,8 +220,8 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
*/
@SuppressWarnings({"unchecked"})
public L add(N newChild, Kind newChildKind) {
- ast.setChanged();
- L n = ast.buildTree(newChild, newChildKind);
+ getAst().setChanged();
+ L n = getAst().buildTree(newChild, newChildKind);
if (n == null) return null;
n.parent = (L) this;
children = children.append(n);
@@ -242,20 +238,20 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
Map<N, L> oldNodes = new IdentityHashMap<N, L>();
gatherAndRemoveChildren(oldNodes);
- L newNode = ast.buildTree(get(), kind);
+ L newNode = getAst().buildTree(get(), kind);
- ast.setChanged();
+ getAst().setChanged();
- ast.replaceNewWithExistingOld(oldNodes, newNode);
+ getAst().replaceNewWithExistingOld(oldNodes, newNode);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void gatherAndRemoveChildren(Map<N, L> map) {
for (LombokNode child : children) child.gatherAndRemoveChildren(map);
- ast.identityDetector.remove(get());
+ getAst().identityDetector.remove(get());
map.put(get(), (L) this);
children = LombokImmutableList.of();
- ast.getNodeMap().remove(get());
+ getAst().getNodeMap().remove(get());
}
/**
@@ -264,7 +260,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
* Does not change the underlying (javac/Eclipse) AST, only the wrapped view.
*/
public void removeChild(L child) {
- ast.setChanged();
+ getAst().setChanged();
children = children.removeElement(child);
}
diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java
index 70af48e0..4b119873 100644
--- a/src/core/lombok/core/Version.java
+++ b/src/core/lombok/core/Version.java
@@ -30,7 +30,7 @@ public class Version {
// ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries).
// Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example.
// Official builds always end in an even number. (Since 0.10.2).
- private static final String VERSION = "1.18.1";
+ private static final String VERSION = "1.18.3";
private static final String RELEASE_NAME = "Edgy Guinea Pig";
// private static final String RELEASE_NAME = "Envious Ferret";
diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java
index efe57e38..9cfec2e7 100644
--- a/src/core/lombok/core/configuration/ConfigurationApp.java
+++ b/src/core/lombok/core/configuration/ConfigurationApp.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Project Lombok Authors.
+ * Copyright (C) 2014-2018 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
@@ -118,7 +118,7 @@ public class ConfigurationApp extends LombokApp {
boolean verbose = args.verbose;
if (args.generate) {
- return generate(keys, verbose);
+ return generate(keys, verbose, !args.key.isEmpty());
}
return display(keys, verbose, args.paths, !args.key.isEmpty());
@@ -130,8 +130,9 @@ public class ConfigurationApp extends LombokApp {
return this;
}
- public int generate(Collection<ConfigurationKey<?>> keys, boolean verbose) {
+ public int generate(Collection<ConfigurationKey<?>> keys, boolean verbose, boolean explicit) {
for (ConfigurationKey<?> key : keys) {
+ if (!explicit && key.isHidden()) continue;
String keyName = key.getKeyName();
ConfigurationDataType type = key.getType();
String description = key.getDescription();
diff --git a/src/core/lombok/core/configuration/ConfigurationKey.java b/src/core/lombok/core/configuration/ConfigurationKey.java
index d46a70b0..18075190 100644
--- a/src/core/lombok/core/configuration/ConfigurationKey.java
+++ b/src/core/lombok/core/configuration/ConfigurationKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 The Project Lombok Authors.
+ * Copyright (C) 2013-2018 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
@@ -43,13 +43,19 @@ public abstract class ConfigurationKey<T> {
private final String keyName;
private final String description;
private final ConfigurationDataType type;
+ private final boolean hidden;
public ConfigurationKey(String keyName, String description) {
+ this(keyName, description, false);
+ }
+
+ public ConfigurationKey(String keyName, String description, boolean hidden) {
this.keyName = checkName(keyName);
@SuppressWarnings("unchecked")
ConfigurationDataType type = ConfigurationDataType.toDataType((Class<? extends ConfigurationKey<?>>)getClass());
this.type = type;
this.description = description;
+ this.hidden = hidden;
registerKey(keyName, this);
}
@@ -65,6 +71,10 @@ public abstract class ConfigurationKey<T> {
return type;
}
+ public final boolean isHidden() {
+ return hidden;
+ }
+
@Override public String toString() {
return keyName + " (" + type + "): " + description;
}
diff --git a/src/core/lombok/core/configuration/ConfigurationResolverFactory.java b/src/core/lombok/core/configuration/ConfigurationResolverFactory.java
index 83b58c2f..b640b271 100644
--- a/src/core/lombok/core/configuration/ConfigurationResolverFactory.java
+++ b/src/core/lombok/core/configuration/ConfigurationResolverFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Project Lombok Authors.
+ * Copyright (C) 2014-2018 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
@@ -21,8 +21,8 @@
*/
package lombok.core.configuration;
-import lombok.core.AST;
+import java.net.URI;
public interface ConfigurationResolverFactory {
- ConfigurationResolver createResolver(AST<?, ?, ?> ast);
+ ConfigurationResolver createResolver(URI sourceLocation);
}
diff --git a/src/core/lombok/core/configuration/StringConfigurationSource.java b/src/core/lombok/core/configuration/StringConfigurationSource.java
index dd2f0319..abf6eea0 100644
--- a/src/core/lombok/core/configuration/StringConfigurationSource.java
+++ b/src/core/lombok/core/configuration/StringConfigurationSource.java
@@ -67,7 +67,6 @@ public class StringConfigurationSource implements ConfigurationSource {
list.add(new ListModification(value, add));
}
});
-
return new StringConfigurationSource(values);
}
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index dc2c9843..7cd2e400 100644
--- a/src/core/lombok/eclipse/EclipseAST.java
+++ b/src/core/lombok/eclipse/EclipseAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 The Project Lombok Authors.
+ * Copyright (C) 2009-2018 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
@@ -73,16 +73,20 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
private static final URI NOT_CALCULATED_MARKER = URI.create("https://projectlombok.org/not/calculated");
private URI memoizedAbsoluteFileLocation = NOT_CALCULATED_MARKER;
+ public static URI getAbsoluteFileLocation(CompilationUnitDeclaration ast) {
+ return getAbsoluteFileLocation0(ast);
+ }
+
public URI getAbsoluteFileLocation() {
if (memoizedAbsoluteFileLocation != NOT_CALCULATED_MARKER) return memoizedAbsoluteFileLocation;
- memoizedAbsoluteFileLocation = getAbsoluteFileLocation0();
+ memoizedAbsoluteFileLocation = getAbsoluteFileLocation0(this.compilationUnitDeclaration);
return memoizedAbsoluteFileLocation;
}
/** This is the call, but we wrapped it to memoize this. */
- private URI getAbsoluteFileLocation0() {
- String fileName = getFileName();
+ private static URI getAbsoluteFileLocation0(CompilationUnitDeclaration ast) {
+ String fileName = toFileName(ast);
if (fileName != null && (fileName.startsWith("file:") || fileName.startsWith("sourcecontrol:"))) {
// Some exotic build systems get real fancy with filenames. Known culprits:
// The 'jazz' source control system _probably_ (not confirmed yet) uses sourcecontrol://jazz: urls.
diff --git a/src/core/lombok/eclipse/EclipseASTAdapter.java b/src/core/lombok/eclipse/EclipseASTAdapter.java
index 2a78c270..61807fff 100644
--- a/src/core/lombok/eclipse/EclipseASTAdapter.java
+++ b/src/core/lombok/eclipse/EclipseASTAdapter.java
@@ -36,6 +36,9 @@ import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
* has been implemented with an empty body. Override whichever methods you need.
*/
public abstract class EclipseASTAdapter implements EclipseASTVisitor {
+
+ private final boolean deferUntilPostDiet = getClass().isAnnotationPresent(DeferUntilPostDiet.class);
+
/** {@inheritDoc} */
public void visitCompilationUnit(EclipseNode top, CompilationUnitDeclaration unit) {}
@@ -98,4 +101,8 @@ public abstract class EclipseASTAdapter implements EclipseASTVisitor {
/** {@inheritDoc} */
public void endVisitStatement(EclipseNode statementNode, Statement statement) {}
+
+ public boolean isDeferUntilPostDiet() {
+ return deferUntilPostDiet ;
+ }
}
diff --git a/src/core/lombok/eclipse/EclipseASTVisitor.java b/src/core/lombok/eclipse/EclipseASTVisitor.java
index f5b49cbb..b2fd4b2f 100644
--- a/src/core/lombok/eclipse/EclipseASTVisitor.java
+++ b/src/core/lombok/eclipse/EclipseASTVisitor.java
@@ -26,7 +26,9 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.io.PrintStream;
import java.lang.reflect.Modifier;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.Block;
@@ -38,6 +40,7 @@ import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
/**
* Implement so you can ask any EclipseAST.Node to traverse depth-first through all children,
@@ -199,8 +202,82 @@ public interface EclipseASTVisitor {
print("</CUD>");
}
+ private String printFlags(int flags, ASTNode node) {
+ StringBuilder out = new StringBuilder();
+ if ((flags & ClassFileConstants.AccPublic) != 0) {
+ flags &= ~ClassFileConstants.AccPublic;
+ out.append("public ");
+ }
+ if ((flags & ClassFileConstants.AccPrivate) != 0) {
+ flags &= ~ClassFileConstants.AccPrivate;
+ out.append("private ");
+ }
+ if ((flags & ClassFileConstants.AccProtected) != 0) {
+ flags &= ~ClassFileConstants.AccProtected;
+ out.append("protected ");
+ }
+ if ((flags & ClassFileConstants.AccStatic) != 0) {
+ flags &= ~ClassFileConstants.AccStatic;
+ out.append("static ");
+ }
+ if ((flags & ClassFileConstants.AccFinal) != 0) {
+ flags &= ~ClassFileConstants.AccFinal;
+ out.append("final ");
+ }
+ if ((flags & ClassFileConstants.AccSynchronized) != 0) {
+ flags &= ~ClassFileConstants.AccSynchronized;
+ out.append("synchronized ");
+ }
+ if ((flags & ClassFileConstants.AccNative) != 0) {
+ flags &= ~ClassFileConstants.AccNative;
+ out.append("native ");
+ }
+ if ((flags & ClassFileConstants.AccInterface) != 0) {
+ flags &= ~ClassFileConstants.AccInterface;
+ out.append("interface ");
+ }
+ if ((flags & ClassFileConstants.AccAbstract) != 0) {
+ flags &= ~ClassFileConstants.AccAbstract;
+ out.append("abstract ");
+ }
+ if ((flags & ClassFileConstants.AccStrictfp) != 0) {
+ flags &= ~ClassFileConstants.AccStrictfp;
+ out.append("strictfp ");
+ }
+ if ((flags & ClassFileConstants.AccSynthetic) != 0) {
+ flags &= ~ClassFileConstants.AccSynthetic;
+ out.append("synthetic ");
+ }
+ if ((flags & ClassFileConstants.AccAnnotation) != 0) {
+ flags &= ~ClassFileConstants.AccAnnotation;
+ out.append("annotation ");
+ }
+ if ((flags & ClassFileConstants.AccEnum) != 0) {
+ flags &= ~ClassFileConstants.AccEnum;
+ out.append("enum ");
+ }
+
+ if ((flags & ClassFileConstants.AccVolatile) != 0) {
+ flags &= ~ClassFileConstants.AccVolatile;
+ if (node instanceof FieldDeclaration) out.append("volatile ");
+ else out.append("volatile/bridge ");
+ }
+ if ((flags & ClassFileConstants.AccTransient) != 0) {
+ flags &= ~ClassFileConstants.AccTransient;
+ if (node instanceof Argument) out.append("varargs ");
+ else if (node instanceof FieldDeclaration) out.append("transient ");
+ else out.append("transient/varargs ");
+ }
+
+ if (flags != 0) {
+ out.append(String.format(" 0x%08X ", flags));
+ }
+
+ return out.toString().trim();
+ }
+
public void visitType(EclipseNode node, TypeDeclaration type) {
- print("<TYPE %s%s%s>", str(type.name), isGenerated(type) ? " (GENERATED)" : "", position(node));
+ print("<TYPE %s%s%s> %s", str(type.name), isGenerated(type) ? " (GENERATED)" : "", position(node), printFlags(type.modifiers, type));
indent++;
if (printContent) {
print("%s", type);
@@ -239,8 +316,8 @@ public interface EclipseASTVisitor {
}
public void visitField(EclipseNode node, FieldDeclaration field) {
- print("<FIELD%s %s %s = %s%s>", isGenerated(field) ? " (GENERATED)" : "",
- str(field.type), str(field.name), field.initialization, position(node));
+ print("<FIELD%s %s %s = %s%s> %s", isGenerated(field) ? " (GENERATED)" : "",
+ str(field.type), str(field.name), field.initialization, position(node), printFlags(field.modifiers, field));
indent++;
if (printContent) {
if (field.initialization != null) print("%s", field.initialization);
@@ -260,9 +337,13 @@ public interface EclipseASTVisitor {
public void visitMethod(EclipseNode node, AbstractMethodDeclaration method) {
String type = method instanceof ConstructorDeclaration ? "CONSTRUCTOR" : "METHOD";
- print("<%s %s: %s%s%s>", type, str(method.selector), method.statements != null ? "filled" : "blank",
- isGenerated(method) ? " (GENERATED)" : "", position(node));
+ print("<%s %s: %s%s%s> %s", type, str(method.selector), method.statements != null ? ("filled(" + method.statements.length + ")") : "blank",
+ isGenerated(method) ? " (GENERATED)" : "", position(node), printFlags(method.modifiers, method));
indent++;
+ if (method instanceof ConstructorDeclaration) {
+ ConstructorDeclaration cd = (ConstructorDeclaration) method;
+ print("--> constructorCall: %s", cd.constructorCall == null ? "-NONE-" : cd.constructorCall);
+ }
if (printContent) {
if (method.statements != null) print("%s", method);
disablePrinting++;
@@ -281,7 +362,8 @@ public interface EclipseASTVisitor {
}
public void visitMethodArgument(EclipseNode node, Argument arg, AbstractMethodDeclaration method) {
- print("<METHODARG%s %s %s = %s%s>", isGenerated(arg) ? " (GENERATED)" : "", str(arg.type), str(arg.name), arg.initialization, position(node));
+ print("<METHODARG%s %s %s = %s%s> %s", isGenerated(arg) ? " (GENERATED)" : "",
+ str(arg.type), str(arg.name), arg.initialization, position(node), printFlags(arg.modifiers, arg));
indent++;
}
@@ -295,7 +377,8 @@ public interface EclipseASTVisitor {
}
public void visitLocal(EclipseNode node, LocalDeclaration local) {
- print("<LOCAL%s %s %s = %s%s>", isGenerated(local) ? " (GENERATED)" : "", str(local.type), str(local.name), local.initialization, position(node));
+ print("<LOCAL%s %s %s = %s%s> %s", isGenerated(local) ? " (GENERATED)" : "",
+ str(local.type), str(local.name), local.initialization, position(node), printFlags(local.modifiers, local));
indent++;
}
@@ -310,6 +393,14 @@ public interface EclipseASTVisitor {
public void visitStatement(EclipseNode node, Statement statement) {
print("<%s%s%s>", statement.getClass(), isGenerated(statement) ? " (GENERATED)" : "", position(node));
+ if (statement instanceof AllocationExpression) {
+ AllocationExpression alloc = (AllocationExpression) statement;
+ print(" --> arguments: %s", alloc.arguments == null ? "NULL" : alloc.arguments.length);
+ print(" --> genericTypeArguments: %s", alloc.genericTypeArguments == null ? "NULL" : alloc.genericTypeArguments.length);
+ print(" --> typeArguments: %s", alloc.typeArguments == null ? "NULL" : alloc.typeArguments.length);
+ print(" --> enumConstant: %s", alloc.enumConstant);
+ print(" --> inferredReturnType: %s", alloc.inferredReturnType);
+ }
indent++;
print("%s", statement);
}
@@ -325,5 +416,11 @@ public interface EclipseASTVisitor {
int end = node.get().sourceEnd();
return String.format(" [%d, %d]", start, end);
}
+
+ public boolean isDeferUntilPostDiet() {
+ return false;
+ }
}
+
+ boolean isDeferUntilPostDiet();
}
diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java
index 4db1d38d..1738c770 100644
--- a/src/core/lombok/eclipse/EclipseNode.java
+++ b/src/core/lombok/eclipse/EclipseNode.java
@@ -44,16 +44,22 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
* Eclipse specific version of the LombokNode class.
*/
public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode, ASTNode> {
+ private EclipseAST ast;
/** {@inheritDoc} */
EclipseNode(EclipseAST ast, ASTNode node, List<EclipseNode> children, Kind kind) {
- super(ast, node, children, kind);
+ super(node, children, kind);
+ this.ast = ast;
}
+ @Override
+ public EclipseAST getAst() {
+ return ast;
+ }
/**
* Visits this node and all child nodes depth-first, calling the provided visitor's visit methods.
*/
public void traverse(EclipseASTVisitor visitor) {
- if (!this.isCompleteParse() && visitor.getClass().isAnnotationPresent(DeferUntilPostDiet.class)) return;
+ if (visitor.isDeferUntilPostDiet() && !isCompleteParse()) return;
switch (getKind()) {
case COMPILATION_UNIT:
diff --git a/src/core/lombok/eclipse/HandlerLibrary.java b/src/core/lombok/eclipse/HandlerLibrary.java
index 07c6f97b..0e72fb38 100644
--- a/src/core/lombok/eclipse/HandlerLibrary.java
+++ b/src/core/lombok/eclipse/HandlerLibrary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2014 The Project Lombok Authors.
+ * Copyright (C) 2009-2018 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
@@ -212,21 +212,25 @@ public class HandlerLibrary {
* @param ast The Compilation Unit that contains the Annotation AST Node.
* @param annotationNode The Lombok AST Node representing the Annotation AST Node.
* @param annotation 'node.get()' - convenience parameter.
+ * @param priority current prioritiy
+ * @return the priority we want to run - MAX_VALUE means never
*/
- public void handleAnnotation(CompilationUnitDeclaration ast, EclipseNode annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation, long priority) {
+ public long handleAnnotation(CompilationUnitDeclaration ast, EclipseNode annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation, long priority) {
TypeResolver resolver = new TypeResolver(annotationNode.getImportList());
TypeReference rawType = annotation.type;
- if (rawType == null) return;
+ if (rawType == null) return Long.MAX_VALUE;
String fqn = resolver.typeRefToFullyQualifiedName(annotationNode, typeLibrary, toQualifiedName(annotation.type.getTypeName()));
- if (fqn == null) return;
+ if (fqn == null) return Long.MAX_VALUE;
AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
- if (container == null) return;
- if (priority != container.getPriority()) return;
+ if (container == null) return Long.MAX_VALUE;
+
+ if (priority < container.getPriority()) return container.getPriority(); // we want to run at this priority
+ if (priority > container.getPriority()) return Long.MAX_VALUE; // it's over- we do not want to run again
if (!annotationNode.isCompleteParse() && container.deferUntilPostDiet()) {
if (needsHandling(annotation)) container.preHandle(annotation, annotationNode);
- return;
+ return Long.MAX_VALUE;
}
try {
@@ -236,13 +240,16 @@ public class HandlerLibrary {
} catch (Throwable t) {
error(ast, String.format("Lombok annotation handler %s failed", container.handler.getClass()), t);
}
+ return Long.MAX_VALUE;
}
/**
* Will call all registered {@link EclipseASTVisitor} instances.
*/
- public void callASTVisitors(EclipseAST ast, long priority, boolean isCompleteParse) {
+ public long callASTVisitors(EclipseAST ast, long priority, boolean isCompleteParse) {
+ long nearestPriority = Long.MAX_VALUE;
for (VisitorContainer container : visitorHandlers) {
+ if (priority < container.getPriority()) nearestPriority = Math.min(container.getPriority(), nearestPriority);
if (!isCompleteParse && container.deferUntilPostDiet()) continue;
if (priority != container.getPriority()) continue;
try {
@@ -252,5 +259,6 @@ public class HandlerLibrary {
String.format("Lombok visitor handler %s failed", container.visitor.getClass()), t);
}
}
+ return nearestPriority;
}
}
diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java
index 683465c9..323fc171 100644
--- a/src/core/lombok/eclipse/TransformEclipseAST.java
+++ b/src/core/lombok/eclipse/TransformEclipseAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2018 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
@@ -25,6 +25,8 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Field;
+import lombok.ConfigurationKeys;
+import lombok.core.LombokConfiguration;
import lombok.core.debug.DebugSnapshotStore;
import lombok.core.debug.HistogramTracker;
import lombok.patcher.Symbols;
@@ -143,6 +145,8 @@ public class TransformEclipseAST {
// Do NOT abort if (ast.bits & ASTNode.HasAllMethodBodies) != 0 - that doesn't work.
+ if (Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, EclipseAST.getAbsoluteFileLocation(ast)))) return;
+
try {
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform entry");
long histoToken = lombokTracker == null ? 0L : lombokTracker.start();
@@ -182,42 +186,54 @@ public class TransformEclipseAST {
* then handles any PrintASTs.
*/
public void go() {
+ long nextPriority = Long.MIN_VALUE;
for (Long d : handlers.getPriorities()) {
- ast.traverse(new AnnotationVisitor(d));
- handlers.callASTVisitors(ast, d, ast.isCompleteParse());
+ if (nextPriority > d) continue;
+ AnnotationVisitor visitor = new AnnotationVisitor(d);
+ ast.traverse(visitor);
+ // if no visitor interested for this AST, nextPriority would be MAX_VALUE and we bail out immediatetly
+ nextPriority = visitor.getNextPriority();
+ nextPriority = Math.min(nextPriority, handlers.callASTVisitors(ast, d, ast.isCompleteParse()));
}
}
private static class AnnotationVisitor extends EclipseASTAdapter {
private final long priority;
+ // this is the next priority we continue to visit.
+ // Long.MAX_VALUE means never. Each visit method will potentially reduce the next priority
+ private long nextPriority = Long.MAX_VALUE;
public AnnotationVisitor(long priority) {
this.priority = priority;
}
+ public long getNextPriority() {
+ return nextPriority;
+ }
+
@Override public void visitAnnotationOnField(FieldDeclaration field, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, priority);
+ nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, priority);
+ nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnLocal(LocalDeclaration local, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, priority);
+ nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnMethod(AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, priority);
+ nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnType(TypeDeclaration type, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, priority);
+ nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
}
}
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 2dce285c..87df6d1b 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -24,6 +24,7 @@ package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.EclipseAugments.*;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.setGeneratedBy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -1862,4 +1863,29 @@ public class EclipseHandlerUtil {
String p = typeDecl.superclass.toString();
return p.equals("Object") || p.equals("java.lang.Object");
}
+
+ public static NameReference generateQualifiedNameRef(ASTNode source, char[]... varNames) {
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long)pS << 32 | pE;
+
+ NameReference ref;
+
+ if (varNames.length > 1) ref = new QualifiedNameReference(varNames, new long[varNames.length], pS, pE);
+ else ref = new SingleNameReference(varNames[0], p);
+ setGeneratedBy(ref, source);
+ return ref;
+ }
+
+ public static TypeReference generateQualifiedTypeRef(ASTNode source, char[]... varNames) {
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long)pS << 32 | pE;
+
+ TypeReference ref;
+
+ long[] poss = Eclipse.poss(source, varNames.length);
+ if (varNames.length > 1) ref = new QualifiedTypeReference(varNames, poss);
+ else ref = new SingleTypeReference(varNames[0], p);
+ setGeneratedBy(ref, source);
+ return ref;
+ }
}
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index e1b1af26..9a069c58 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -40,6 +40,7 @@ import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
@@ -47,6 +48,7 @@ import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
@@ -146,6 +148,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
+
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
Builder builderInstance = annotation.getInstance();
@@ -490,6 +494,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
}
+ private static final char[] EMPTY_LIST = "emptyList".toCharArray();
private MethodDeclaration generateToBuilderMethod(String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source) {
// return new ThingieBuilder<A, B>().setA(this.a).setB(this.b);
@@ -509,19 +514,34 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
for (BuilderFieldData bfd : builderFields) {
char[] setterName = fluent ? bfd.name : HandlerUtil.buildAccessorName("set", new String(bfd.name)).toCharArray();
MessageSend ms = new MessageSend();
+ Expression[] tgt = new Expression[bfd.singularData == null ? 1 : 2];
+
if (bfd.obtainVia == null || !bfd.obtainVia.field().isEmpty()) {
char[] fieldName = bfd.obtainVia == null ? bfd.rawName : bfd.obtainVia.field().toCharArray();
- FieldReference fr = new FieldReference(fieldName, 0);
- fr.receiver = new ThisReference(0, 0);
- ms.arguments = new Expression[] {fr};
+ for (int i = 0; i < tgt.length; i++) {
+ FieldReference fr = new FieldReference(fieldName, 0);
+ fr.receiver = new ThisReference(0, 0);
+ tgt[i] = fr;
+ }
} else {
String obtainName = bfd.obtainVia.method();
boolean obtainIsStatic = bfd.obtainVia.isStatic();
- MessageSend obtainExpr = new MessageSend();
- obtainExpr.receiver = obtainIsStatic ? new SingleNameReference(type.getName().toCharArray(), 0) : new ThisReference(0, 0);
- obtainExpr.selector = obtainName.toCharArray();
- if (obtainIsStatic) obtainExpr.arguments = new Expression[] {new ThisReference(0, 0)};
- ms.arguments = new Expression[] {obtainExpr};
+ for (int i = 0; i < tgt.length; i++) {
+ MessageSend obtainExpr = new MessageSend();
+ obtainExpr.receiver = obtainIsStatic ? new SingleNameReference(type.getName().toCharArray(), 0) : new ThisReference(0, 0);
+ obtainExpr.selector = obtainName.toCharArray();
+ if (obtainIsStatic) obtainExpr.arguments = new Expression[] {new ThisReference(0, 0)};
+ tgt[i] = obtainExpr;
+ }
+ }
+ if (bfd.singularData == null) {
+ ms.arguments = tgt;
+ } else {
+ Expression ifNull = new EqualExpression(tgt[0], new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
+ MessageSend emptyList = new MessageSend();
+ emptyList.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA, TypeConstants.UTIL, "Collections".toCharArray());
+ emptyList.selector = EMPTY_LIST;
+ ms.arguments = new Expression[] {new ConditionalExpression(ifNull, emptyList, tgt[1])};
}
ms.receiver = receiver;
ms.selector = setterName;
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index c99b9b5f..6945e5d9 100644
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -69,7 +69,6 @@ import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
@@ -819,29 +818,4 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
expr.sourceStart = pS; expr.sourceEnd = pE;
return expr;
}
-
- public NameReference generateQualifiedNameRef(ASTNode source, char[]... varNames) {
- int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long)pS << 32 | pE;
-
- NameReference ref;
-
- if (varNames.length > 1) ref = new QualifiedNameReference(varNames, new long[varNames.length], pS, pE);
- else ref = new SingleNameReference(varNames[0], p);
- setGeneratedBy(ref, source);
- return ref;
- }
-
- public TypeReference generateQualifiedTypeRef(ASTNode source, char[]... varNames) {
- int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long)pS << 32 | pE;
-
- TypeReference ref;
-
- long[] poss = Eclipse.poss(source, varNames.length);
- if (varNames.length > 1) ref = new QualifiedTypeReference(varNames, poss);
- else ref = new SingleTypeReference(varNames[0], p);
- setGeneratedBy(ref, source);
- return ref;
- }
}
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java
index c3a28f7f..15650490 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java
@@ -24,32 +24,37 @@ package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.handlers.HandlerUtil;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.experimental.FieldNameConstants;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.Clinit;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.mangosdk.spi.ProviderFor;
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldNameConstants> {
- public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, String prefix, String suffix) {
+ public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit) {
TypeDeclaration typeDecl = null;
if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
@@ -57,22 +62,29 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName
boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
if (typeDecl == null || notAClass) {
- errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field.");
+ errorNode.addError("@FieldNameConstants is only supported on a class or an enum.");
return;
}
+ List<EclipseNode> qualified = new ArrayList<EclipseNode>();
+
for (EclipseNode field : typeNode.down()) {
- if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix);
+ if (fieldQualifiesForFieldNameConstantsGeneration(field, onlyExplicit)) qualified.add(field);
+ }
+
+ if (qualified.isEmpty()) {
+ errorNode.addWarning("No fields qualify for @FieldNameConstants, therefore this annotation does nothing");
+ } else {
+ createInnerTypeFieldNameConstants(typeNode, errorNode.get(), level, qualified, asEnum, innerTypeName);
}
}
- private void generateFieldNameConstantsForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, String prefix, String suffix) {
- if (hasAnnotation(FieldNameConstants.class, fieldNode)) return;
- createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, pos, false);
- }
-
- private boolean fieldQualifiesForFieldNameConstantsGeneration(EclipseNode field) {
+ private boolean fieldQualifiesForFieldNameConstantsGeneration(EclipseNode field, boolean onlyExplicit) {
if (field.getKind() != Kind.FIELD) return false;
+ if (hasAnnotation(FieldNameConstants.Exclude.class, field)) return false;
+ if (hasAnnotation(FieldNameConstants.Include.class, field)) return true;
+ if (onlyExplicit) return false;
+
FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
return filterField(fieldDecl);
}
@@ -81,55 +93,75 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants");
EclipseNode node = annotationNode.up();
- FieldNameConstants annotatationInstance = annotation.getInstance();
- AccessLevel level = annotatationInstance.level();
- String prefix = annotatationInstance.prefix();
- String suffix = annotatationInstance.suffix();
- if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX);
- if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX);
- if (prefix == null) prefix = "FIELD_";
- if (suffix == null) suffix = "";
- if (node == null) return;
-
- switch (node.getKind()) {
- case FIELD:
- if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true);
- break;
- case TYPE:
- if (level == AccessLevel.NONE) {
- annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE.");
- return;
- }
- generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix);
- break;
- }
- }
-
- private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists) {
- for (EclipseNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, source, whineIfExists);
- }
-
- private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) {
- if (fieldNode.getKind() != Kind.FIELD) {
- errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field");
+ FieldNameConstants annotationInstance = annotation.getInstance();
+ AccessLevel level = annotationInstance.level();
+ boolean asEnum = annotationInstance.asEnum();
+ boolean usingLombokv1_18_2 = annotation.isExplicit("prefix") || annotation.isExplicit("suffix") || node.getKind() == Kind.FIELD;
+
+ if (usingLombokv1_18_2) {
+ annotationNode.addError("@FieldNameConstants has been redesigned in lombok v1.18.4; please upgrade your project dependency on lombok. See https://projectlombok.org/features/experimental/FieldNameConstants for more information.");
return;
}
- FieldDeclaration field = (FieldDeclaration) fieldNode.get();
- String fieldName = new String(field.name);
- String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix;
- if (constantName.equals(fieldName)) {
- fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field.");
+ if (level == AccessLevel.NONE) {
+ annotationNode.addWarning("AccessLevel.NONE is not compatible with @FieldNameConstants. If you don't want the inner type, simply remove FieldNameConstants.");
return;
}
- int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long) pS << 32 | pE;
- FieldDeclaration fieldConstant = new FieldDeclaration(constantName.toCharArray(), pS,pE);
- fieldConstant.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
- fieldConstant.modifiers = toEclipseModifier(level) | Modifier.STATIC | Modifier.FINAL;
- fieldConstant.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p,p,p});
- fieldConstant.initialization = new StringLiteral(field.name, pS, pE, 0);
- injectField(fieldNode.up(), fieldConstant);
+ String innerTypeName = annotationInstance.innerTypeName();
+ if (innerTypeName.isEmpty()) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME);
+ if (innerTypeName == null || innerTypeName.isEmpty()) innerTypeName = "Fields";
+
+ generateFieldNameConstantsForType(node, annotationNode, level, asEnum, innerTypeName, annotationInstance.onlyExplicitlyIncluded());
+ }
+
+ private void createInnerTypeFieldNameConstants(EclipseNode typeNode, ASTNode source, AccessLevel level, List<EclipseNode> fields, boolean asEnum, String innerTypeName) {
+ if (fields.isEmpty()) return;
+
+ TypeDeclaration parent = (TypeDeclaration) typeNode.get();
+ TypeDeclaration innerType = new TypeDeclaration(parent.compilationResult);
+ innerType.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ innerType.modifiers = toEclipseModifier(level) | (asEnum ? ClassFileConstants.AccEnum : ClassFileConstants.AccStatic | ClassFileConstants.AccFinal);
+ char[] name = innerTypeName.toCharArray();
+ innerType.name = name;
+ innerType.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
+ EclipseNode innerNode = injectType(typeNode, innerType);
+
+ ConstructorDeclaration constructor = new ConstructorDeclaration(parent.compilationResult);
+ constructor.selector = name;
+ constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
+ constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
+ constructor.modifiers = ClassFileConstants.AccPrivate;
+ ExplicitConstructorCall superCall = new ExplicitConstructorCall(0);
+ superCall.sourceStart = source.sourceStart;
+ superCall.sourceEnd = source.sourceEnd;
+ superCall.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ constructor.constructorCall = superCall;
+ if (!asEnum) constructor.statements = new Statement[0];
+
+ injectMethod(innerNode, constructor);
+
+ if (asEnum) injectMethod(innerNode, new Clinit(parent.compilationResult));
+
+ for (EclipseNode fieldNode : fields) {
+ FieldDeclaration field = (FieldDeclaration) fieldNode.get();
+ char[] fName = field.name;
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+ FieldDeclaration fieldConstant = new FieldDeclaration(fName, pS, pE);
+ fieldConstant.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ fieldConstant.modifiers = asEnum ? 0 : ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal;
+ fieldConstant.type = asEnum ? null : new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p});
+ if (asEnum) {
+ AllocationExpression ac = new AllocationExpression();
+ ac.enumConstant = fieldConstant;
+ ac.sourceStart = source.sourceStart;
+ ac.sourceEnd = source.sourceEnd;
+ fieldConstant.initialization = ac;
+ } else {
+ fieldConstant.initialization = new StringLiteral(field.name, pS, pE, 0);
+ }
+ injectField(innerNode, fieldConstant);
+ }
}
}
diff --git a/src/core/lombok/experimental/FieldNameConstants.java b/src/core/lombok/experimental/FieldNameConstants.java
index 31c2970c..d6886890 100644
--- a/src/core/lombok/experimental/FieldNameConstants.java
+++ b/src/core/lombok/experimental/FieldNameConstants.java
@@ -29,12 +29,32 @@ import java.lang.annotation.Target;
import lombok.AccessLevel;
/**
- * Generates String constants containing the field name for each field.
+ * Generates an inner type, containing String constants containing the field name for each field. Alternatively, generates an inner enum with enum values matching each field name.
*/
-@Target({ElementType.TYPE, ElementType.FIELD})
+@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface FieldNameConstants {
lombok.AccessLevel level() default AccessLevel.PUBLIC;
- String prefix() default " CONFIG DEFAULT ";
- String suffix() default " CONFIG DEFAULT ";
+ boolean asEnum() default false;
+ String innerTypeName() default "";
+
+ /**
+ * Only include fields and methods explicitly marked with {@code @FieldNameConstants.Include}.
+ * Normally, all (non-static) fields are included by default.
+ */
+ boolean onlyExplicitlyIncluded() default false;
+
+ /**
+ * If present, do not include this field in the generated fieldnames inner type.
+ */
+ @Target(ElementType.FIELD)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Exclude {}
+
+ /**
+ * If present, include this field in the generated fieldnames inner type (default).
+ */
+ @Target(ElementType.FIELD)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Include {}
}
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 4ca2c050..091612cc 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2017 The Project Lombok Authors.
+ * Copyright (C) 2009-2018 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
@@ -93,8 +93,11 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
}
@Override public URI getAbsoluteFileLocation() {
+ return getAbsoluteFileLocation((JCCompilationUnit) top().get());
+ }
+
+ public static URI getAbsoluteFileLocation(JCCompilationUnit cu) {
try {
- JCCompilationUnit cu = (JCCompilationUnit) top().get();
return cu.sourcefile.toUri();
} catch (Exception e) {
return null;
diff --git a/src/core/lombok/javac/JavacASTVisitor.java b/src/core/lombok/javac/JavacASTVisitor.java
index 565980f9..d4f8f731 100644
--- a/src/core/lombok/javac/JavacASTVisitor.java
+++ b/src/core/lombok/javac/JavacASTVisitor.java
@@ -149,8 +149,12 @@ public interface JavacASTVisitor {
print("</CUD>");
}
+ private String printFlags(long f) {
+ return Flags.toString(f);
+ }
+
@Override public void visitType(JavacNode node, JCClassDecl type) {
- print("<TYPE %s>", type.name);
+ print("<TYPE %s> %s", type.name, printFlags(type.mods.flags));
indent++;
if (printContent) {
print("%s", type);
@@ -185,7 +189,7 @@ public interface JavacASTVisitor {
}
@Override public void visitField(JavacNode node, JCVariableDecl field) {
- print("<FIELD %s %s>", field.vartype, field.name);
+ print("<FIELD %s %s> %s", field.vartype, field.name, printFlags(field.mods.flags));
indent++;
if (printContent) {
if (field.init != null) print("%s", field.init);
@@ -210,7 +214,7 @@ public interface JavacASTVisitor {
type = "DEFAULTCONSTRUCTOR";
} else type = "CONSTRUCTOR";
} else type = "METHOD";
- print("<%s %s> returns: %s", type, method.name, method.restype);
+ print("<%s %s> %s returns: %s", type, method.name, printFlags(method.mods.flags), method.restype);
indent++;
if (printContent) {
if (method.body == null) print("(ABSTRACT)");
@@ -230,7 +234,7 @@ public interface JavacASTVisitor {
}
@Override public void visitMethodArgument(JavacNode node, JCVariableDecl arg, JCMethodDecl method) {
- print("<METHODARG %s %s>", arg.vartype, arg.name);
+ print("<METHODARG %s %s> %s", arg.vartype, arg.name, printFlags(arg.mods.flags));
indent++;
}
@@ -244,7 +248,7 @@ public interface JavacASTVisitor {
}
@Override public void visitLocal(JavacNode node, JCVariableDecl local) {
- print("<LOCAL %s %s>", local.vartype, local.name);
+ print("<LOCAL %s %s> %s", local.vartype, local.name, printFlags(local.mods.flags));
indent++;
}
diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java
index 2bce6e3a..3963c892 100644
--- a/src/core/lombok/javac/JavacNode.java
+++ b/src/core/lombok/javac/JavacNode.java
@@ -50,11 +50,18 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
* Javac specific version of the LombokNode class.
*/
public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTree> {
+ private JavacAST ast;
/**
* Passes through to the parent constructor.
*/
public JavacNode(JavacAST ast, JCTree node, List<JavacNode> children, Kind kind) {
- super(ast, node, children, kind);
+ super(node, children, kind);
+ this.ast = ast;
+ }
+
+ @Override
+ public JavacAST getAst() {
+ return ast;
}
public Element getElement() {
diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java
index 54977a59..2e37b32b 100644
--- a/src/core/lombok/javac/JavacTransformer.java
+++ b/src/core/lombok/javac/JavacTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2017 The Project Lombok Authors.
+ * Copyright (C) 2009-2018 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
@@ -35,6 +35,9 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
+import lombok.ConfigurationKeys;
+import lombok.core.LombokConfiguration;
+
public class JavacTransformer {
private final HandlerLibrary handlers;
private final Messager messager;
@@ -65,7 +68,11 @@ public class JavacTransformer {
java.util.List<JavacAST> asts = new ArrayList<JavacAST>();
- for (JCCompilationUnit unit : compilationUnits) asts.add(new JavacAST(messager, context, unit));
+ for (JCCompilationUnit unit : compilationUnits) {
+ if (!Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, JavacAST.getAbsoluteFileLocation(unit)))) {
+ asts.add(new JavacAST(messager, context, unit));
+ }
+ }
for (JavacAST ast : asts) {
ast.traverse(new AnnotationVisitor(priority));
diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java
index 0e6880e4..247d0560 100644
--- a/src/core/lombok/javac/apt/LombokProcessor.java
+++ b/src/core/lombok/javac/apt/LombokProcessor.java
@@ -43,6 +43,7 @@ import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
+import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileManager;
@@ -166,13 +167,13 @@ public class LombokProcessor extends AbstractProcessor {
if (!(originalFiler instanceof InterceptingJavaFileManager)) {
final Messager messager = processingEnv.getMessager();
DiagnosticsReceiver receiver = new MessagerDiagnosticsReceiver(messager);
-
+
JavaFileManager newFilerManager = new InterceptingJavaFileManager(originalFiler, receiver);
ht.put(key, newFilerManager);
Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager");
filerFileManagerField.setAccessible(true);
filerFileManagerField.set(javacFiler, newFilerManager);
-
+
if (lombok.javac.Javac.getJavaCompilerVersion() > 8
&& !lombok.javac.handlers.JavacHandlerUtil.inNetbeansCompileOnSave(context)) {
replaceFileManagerJdk9(context, newFilerManager);
@@ -383,10 +384,7 @@ public class LombokProcessor extends AbstractProcessor {
private String getModuleNameFor(Element element) {
while (element != null) {
- if (element.getKind().name().equals("MODULE")) {
- String n = element.getSimpleName().toString().trim();
- return n.isEmpty() ? null : n;
- }
+ if (element.getKind().name().equals("MODULE")) return ModuleNameOracle.getModuleName(element);
Element n = element.getEnclosingElement();
if (n == element) return null;
element = n;
@@ -394,6 +392,15 @@ public class LombokProcessor extends AbstractProcessor {
return null;
}
+ // QualifiedNameable is a java7 thing, so to remain compatible with java6, shove this into an inner class to avoid the ClassNotFoundError.
+ private static class ModuleNameOracle {
+ static String getModuleName(Element element) {
+ if (!(element instanceof QualifiedNameable)) return null;
+ String name = ((QualifiedNameable) element).getQualifiedName().toString().trim();
+ return name.isEmpty() ? null : name;
+ }
+ }
+
private JCCompilationUnit toUnit(Element element) {
TreePath path = trees == null ? null : trees.getPath(element);
if (path == null) return null;
@@ -432,7 +439,7 @@ public class LombokProcessor extends AbstractProcessor {
}
/**
- * This class returns the given filer as a JavacFiler. In case the case that the filer is no
+ * This class returns the given filer as a JavacFiler. In case the filer is no
* JavacFiler (e.g. the Gradle IncrementalFiler), its "delegate" field is used to get the JavacFiler
* (directly or through a delegate field again)
*/
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index bb495fbc..edf6f2ae 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -99,6 +99,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
@Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
+
Builder builderInstance = annotation.getInstance();
// These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them.
@@ -490,18 +492,34 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
JCExpression invoke = call;
for (BuilderFieldData bfd : builderFields) {
Name setterName = fluent ? bfd.name : type.toName(HandlerUtil.buildAccessorName("set", bfd.name.toString()));
- JCExpression arg;
+ JCExpression[] tgt = new JCExpression[bfd.singularData == null ? 1 : 2];
if (bfd.obtainVia == null || !bfd.obtainVia.field().isEmpty()) {
- arg = maker.Select(maker.Ident(type.toName("this")), bfd.obtainVia == null ? bfd.rawName : type.toName(bfd.obtainVia.field()));
+ for (int i = 0; i < tgt.length; i++) {
+ tgt[i] = maker.Select(maker.Ident(type.toName("this")), bfd.obtainVia == null ? bfd.rawName : type.toName(bfd.obtainVia.field()));
+ }
} else {
if (bfd.obtainVia.isStatic()) {
- JCExpression c = maker.Select(maker.Ident(type.toName(type.getName())), type.toName(bfd.obtainVia.method()));
- arg = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>of(maker.Ident(type.toName("this"))));
+ for (int i = 0; i < tgt.length; i++) {
+ JCExpression c = maker.Select(maker.Ident(type.toName(type.getName())), type.toName(bfd.obtainVia.method()));
+ tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>of(maker.Ident(type.toName("this"))));
+ }
} else {
- JCExpression c = maker.Select(maker.Ident(type.toName("this")), type.toName(bfd.obtainVia.method()));
- arg = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>nil());
+ for (int i = 0; i < tgt.length; i++) {
+ JCExpression c = maker.Select(maker.Ident(type.toName("this")), type.toName(bfd.obtainVia.method()));
+ tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>nil());
+ }
}
}
+
+ JCExpression arg;
+ if (bfd.singularData == null) {
+ arg = tgt[0];
+ } else {
+ JCExpression eqNull = maker.Binary(CTC_EQUAL, tgt[0], maker.Literal(CTC_BOT, null));
+ JCExpression emptyList = maker.Apply(List.<JCExpression>nil(), chainDots(type, "java", "util", "Collections", "emptyList"), List.<JCExpression>nil());
+ arg = maker.Conditional(eqNull, emptyList, tgt[1]);
+ }
+
invoke = maker.Apply(List.<JCExpression>nil(), maker.Select(invoke, setterName), List.of(arg));
}
JCStatement statement = maker.Return(invoke);
diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
index 52f6c39c..aa381c0d 100644
--- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
@@ -44,7 +44,7 @@ import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
/**
- * Handles the {@code lombok.FieldDefaults} annotation for eclipse.
+ * Handles the {@code lombok.FieldDefaults} annotation for javac.
*/
@ProviderFor(JavacASTVisitor.class)
@HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier.
diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java
index 8ff136fc..5b120948 100644
--- a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java
+++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java
@@ -24,13 +24,11 @@ package lombok.javac.handlers;
import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage;
import static lombok.javac.handlers.JavacHandlerUtil.*;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
+import java.util.ArrayList;
import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
-import lombok.core.handlers.HandlerUtil;
import lombok.core.AnnotationValues;
import lombok.experimental.FieldNameConstants;
import lombok.javac.JavacAnnotationHandler;
@@ -40,16 +38,23 @@ import lombok.javac.JavacTreeMaker;
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
@ProviderFor(JavacAnnotationHandler.class)
public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameConstants> {
- public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, String prefix, String suffix) {
+ public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit) {
JCClassDecl typeDecl = null;
if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
@@ -57,22 +62,31 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo
boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
if (typeDecl == null || notAClass) {
- errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field.");
+ errorNode.addError("@FieldNameConstants is only supported on a class or an enum.");
return;
}
+ java.util.List<JavacNode> qualified = new ArrayList<JavacNode>();
+
for (JavacNode field : typeNode.down()) {
- if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix);
+ if (fieldQualifiesForFieldNameConstantsGeneration(field, onlyExplicit)) qualified.add(field);
+ }
+
+ if (qualified.isEmpty()) {
+ errorNode.addWarning("No fields qualify for @FieldNameConstants, therefore this annotation does nothing");
+ } else {
+ createInnerTypeFieldNameConstants(typeNode, errorNode.get(), level, qualified, asEnum, innerTypeName);
}
}
- private void generateFieldNameConstantsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, String prefix, String suffix) {
- if (hasAnnotation(FieldNameConstants.class, fieldNode)) return;
- createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, false);
- }
-
- private boolean fieldQualifiesForFieldNameConstantsGeneration(JavacNode field) {
+ private boolean fieldQualifiesForFieldNameConstantsGeneration(JavacNode field, boolean onlyExplicit) {
if (field.getKind() != Kind.FIELD) return false;
+ boolean exclAnn = JavacHandlerUtil.hasAnnotationAndDeleteIfNeccessary(FieldNameConstants.Exclude.class, field);
+ boolean inclAnn = JavacHandlerUtil.hasAnnotationAndDeleteIfNeccessary(FieldNameConstants.Include.class, field);
+ if (exclAnn) return false;
+ if (inclAnn) return true;
+ if (onlyExplicit) return false;
+
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
if (fieldDecl.name.toString().startsWith("$")) return false;
if ((fieldDecl.mods.flags & Flags.STATIC) != 0) return false;
@@ -82,56 +96,61 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo
public void handle(AnnotationValues<FieldNameConstants> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants");
- Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields();
deleteAnnotationIfNeccessary(annotationNode, FieldNameConstants.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode node = annotationNode.up();
- FieldNameConstants annotatationInstance = annotation.getInstance();
- AccessLevel level = annotatationInstance.level();
- String prefix = annotatationInstance.prefix();
- String suffix = annotatationInstance.suffix();
- if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX);
- if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX);
- if (prefix == null) prefix = "FIELD_";
- if (suffix == null) suffix = "";
- if (node == null) return;
- switch (node.getKind()) {
- case FIELD:
- if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, fields, annotationNode, annotationNode, true);
- break;
- case TYPE:
- if (level == AccessLevel.NONE) {
- annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE.");
- return;
- }
- generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix);
- break;
- }
- }
-
- private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection<JavacNode> fieldNodes, JavacNode annotationNode, JavacNode errorNode, boolean whineIfExists) {
- for (JavacNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, whineIfExists);
- }
-
- private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, JavacNode fieldNode, JavacNode source, boolean whineIfExists) {
- if (fieldNode.getKind() != Kind.FIELD) {
- source.addError("@FieldNameConstants is only supported on a class, an enum, or a field");
+ FieldNameConstants annotationInstance = annotation.getInstance();
+ AccessLevel level = annotationInstance.level();
+ boolean asEnum = annotationInstance.asEnum();
+ boolean usingLombokv1_18_2 = annotation.isExplicit("prefix") || annotation.isExplicit("suffix") || node.getKind() == Kind.FIELD;
+
+ if (usingLombokv1_18_2) {
+ annotationNode.addError("@FieldNameConstants has been redesigned in lombok v1.18.4; please upgrade your project dependency on lombok. See https://projectlombok.org/features/experimental/FieldNameConstants for more information.");
return;
}
- JCVariableDecl field = (JCVariableDecl) fieldNode.get();
- String fieldName = field.name.toString();
- String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix;
- if (constantName.equals(fieldName)) {
- fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field.");
+
+ if (level == AccessLevel.NONE) {
+ annotationNode.addWarning("AccessLevel.NONE is not compatible with @FieldNameConstants. If you don't want the inner type, simply remove @FieldNameConstants.");
return;
}
- JavacTreeMaker treeMaker = fieldNode.getTreeMaker();
- JCModifiers modifiers = treeMaker.Modifiers(toJavacModifier(level) | Modifier.STATIC | Modifier.FINAL);
- JCExpression returnType = chainDots(fieldNode, "java", "lang", "String");
- JCExpression init = treeMaker.Literal(fieldNode.getName());
- JCVariableDecl fieldConstant = treeMaker.VarDef(modifiers, fieldNode.toName(constantName), returnType, init);
- injectField(fieldNode.up(), fieldConstant);
+ String innerTypeName = annotationInstance.innerTypeName();
+ if (innerTypeName.isEmpty()) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME);
+ if (innerTypeName == null || innerTypeName.isEmpty()) innerTypeName = "Fields";
+
+ generateFieldNameConstantsForType(node, annotationNode, level, asEnum, innerTypeName, annotationInstance.onlyExplicitlyIncluded());
+ }
+
+ private void createInnerTypeFieldNameConstants(JavacNode typeNode, DiagnosticPosition pos, AccessLevel level, java.util.List<JavacNode> fields, boolean asEnum, String innerTypeName) {
+ if (fields.isEmpty()) return;
+
+ JavacTreeMaker maker = typeNode.getTreeMaker();
+ JCModifiers mods = maker.Modifiers(toJavacModifier(level) | (asEnum ? Flags.ENUM : Flags.STATIC | Flags.FINAL));
+
+ Name fieldsName = typeNode.toName(innerTypeName);
+ JCClassDecl innerType = maker.ClassDef(mods, fieldsName, List.<JCTypeParameter>nil(), null, List.<JCExpression>nil(), List.<JCTree>nil());
+ JavacNode innerNode = injectType(typeNode, innerType);
+
+ JCModifiers genConstrMods = maker.Modifiers(Flags.GENERATEDCONSTR | (asEnum ? 0L : Flags.PRIVATE));
+ JCBlock genConstrBody = maker.Block(0L, List.<JCStatement>of(maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("super")), List.<JCExpression>nil()))));
+ JCMethodDecl genConstr = maker.MethodDef(genConstrMods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), genConstrBody, null);
+
+ injectMethod(innerNode, genConstr);
+
+ for (JavacNode field : fields) {
+ JCModifiers enumValueMods = maker.Modifiers(Flags.PUBLIC | Flags.STATIC | Flags.FINAL | (asEnum ? Flags.ENUM : 0L));
+ JCExpression returnType;
+ JCExpression init;
+ if (asEnum) {
+ returnType = maker.Ident(fieldsName);
+ init = maker.NewClass(null, List.<JCExpression>nil(), maker.Ident(fieldsName), List.<JCExpression>nil(), null);
+ } else {
+ returnType = chainDots(field, "java", "lang", "String");
+ init = maker.Literal(field.getName());
+ }
+ JCVariableDecl enumField = maker.VarDef(enumValueMods, ((JCVariableDecl) field.get()).name, returnType, init);
+ injectField(innerNode, enumField);
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/core9/module-info.java b/src/core9/module-info.java
index f4d5815f..56e54270 100644
--- a/src/core9/module-info.java
+++ b/src/core9/module-info.java
@@ -23,6 +23,7 @@ module lombok {
requires java.compiler;
requires java.instrument;
requires jdk.unsupported;
+ requires static org.mapstruct.processor;
exports lombok;
exports lombok.experimental;
@@ -36,4 +37,3 @@ module lombok {
provides javax.annotation.processing.Processor with lombok.launch.AnnotationProcessorHider.AnnotationProcessor;
provides org.mapstruct.ap.spi.AstModifyingAnnotationProcessor with lombok.launch.AnnotationProcessorHider.AstModificationNotifier;
}
-
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java
index 52f63765..c0a2c6fe 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java
@@ -32,6 +32,7 @@ import lombok.core.Version;
public class PatchFixesShadowLoaded {
public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) {
if ("aboutText".equals(key)) {
+ if (origReturnValue.contains(" is installed. https://projectlombok.org")) return origReturnValue;
return origReturnValue + "\n\nLombok " + Version.getFullVersion() + " is installed. https://projectlombok.org/";
}
return origReturnValue;
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
index c2a362bd..fee104d3 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
@@ -210,16 +210,16 @@ public class PatchVal {
if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false;
boolean decomponent = false;
- boolean val = isVal(local, scope);
- boolean var = isVar(local, scope);
- if (!(val || var)) return false;
+ boolean val = isVal(local, scope);
+ boolean var = isVar(local, scope);
+ if (!(val || var)) return false;
StackTraceElement[] st = new Throwable().getStackTrace();
for (int i = 0; i < st.length - 2 && i < 10; i++) {
if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) {
boolean valInForStatement = val &&
- st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") &&
- st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement");
+ st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") &&
+ st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement");
if (valInForStatement) return false;
break;
}
@@ -269,7 +269,7 @@ public class PatchVal {
}
}
- if(val) local.modifiers |= ClassFileConstants.AccFinal;
+ if (val) local.modifiers |= ClassFileConstants.AccFinal;
local.annotations = addValAnnotation(local.annotations, local.type, scope);
local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(local.type, 3));
@@ -298,7 +298,7 @@ public class PatchVal {
if (val) forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal;
forEach.elementVariable.annotations = addValAnnotation(forEach.elementVariable.annotations, forEach.elementVariable.type, scope);
forEach.elementVariable.type = replacement != null ? replacement :
- new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3));
+ new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3));
return false;
}
@@ -326,7 +326,7 @@ public class PatchVal {
resolved = ((ArrayBinding) resolved).elementsType();
return resolved;
} else if (resolved instanceof ReferenceBinding) {
- ReferenceBinding iterableType = ((ReferenceBinding)resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false);
+ ReferenceBinding iterableType = ((ReferenceBinding) resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false);
TypeBinding[] arguments = null;
if (iterableType != null) switch (iterableType.kind()) {
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
index d59b6a2e..99447bae 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
@@ -47,9 +47,9 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.parser.Parser;
public class PatchValEclipse {
@@ -103,6 +103,10 @@ public class PatchValEclipse {
}
}
+ private static boolean couldBeVal(ImportReference[] imports, TypeReference type) {
+ return PatchVal.couldBe(imports, "lombok.val", type);
+ }
+
private static boolean couldBeVar(ImportReference[] imports, TypeReference type) {
return PatchVal.couldBe(imports, "lombok.experimental.var", type) || PatchVal.couldBe(imports, "lombok.var", type);
}
@@ -118,17 +122,18 @@ public class PatchValEclipse {
}
public static void addFinalAndValAnnotationToModifierList(Object converter, List<IExtendedModifier> modifiers, AST ast, LocalDeclaration in) {
- // First check that 'in' has the final flag on, and a @val / @lombok.val annotation.
- if ((in.modifiers & ClassFileConstants.AccFinal) == 0) return;
+ // First check that 'in' has the final flag on, and a @val / @lombok.val / @var / @lombok.var annotation.
if (in.annotations == null) return;
boolean found = false;
- Annotation valAnnotation = null;
-
+ Annotation valAnnotation = null, varAnnotation = null;
for (Annotation ann : in.annotations) {
if (couldBeVal(null, ann.type)) {
found = true;
valAnnotation = ann;
- break;
+ }
+ if (couldBeVar(null, ann.type)) {
+ found = true;
+ varAnnotation = ann;
}
}
@@ -139,10 +144,11 @@ public class PatchValEclipse {
if (modifiers == null) return; // This is null only if the project is 1.4 or less. Lombok doesn't work in that.
boolean finalIsPresent = false;
boolean valIsPresent = false;
+ boolean varIsPresent = false;
for (Object present : modifiers) {
if (present instanceof Modifier) {
- ModifierKeyword keyword = ((Modifier)present).getKeyword();
+ ModifierKeyword keyword = ((Modifier) present).getKeyword();
if (keyword == null) continue;
if (keyword.toFlagValue() == Modifier.FINAL) finalIsPresent = true;
}
@@ -151,20 +157,18 @@ public class PatchValEclipse {
Name typeName = ((org.eclipse.jdt.core.dom.Annotation) present).getTypeName();
if (typeName != null) {
String fullyQualifiedName = typeName.getFullyQualifiedName();
- if ("val".equals(fullyQualifiedName) || "lombok.val".equals(fullyQualifiedName)) {
- valIsPresent = true;
- }
+ if ("val".equals(fullyQualifiedName) || "lombok.val".equals(fullyQualifiedName)) valIsPresent = true;
+ if ("var".equals(fullyQualifiedName) || "lombok.var".equals(fullyQualifiedName) || "lombok.experimental.var".equals(fullyQualifiedName)) varIsPresent = true;
}
}
}
- if (!finalIsPresent) {
- modifiers.add(
- createModifier(ast, ModifierKeyword.FINAL_KEYWORD, valAnnotation.sourceStart, valAnnotation.sourceEnd));
+ if (!finalIsPresent && valAnnotation != null) {
+ modifiers.add(createModifier(ast, ModifierKeyword.FINAL_KEYWORD, valAnnotation.sourceStart, valAnnotation.sourceEnd));
}
- if (!valIsPresent) {
- MarkerAnnotation newAnnotation = createValAnnotation(ast, valAnnotation, valAnnotation.sourceStart, valAnnotation.sourceEnd);
+ if (!valIsPresent && valAnnotation != null) {
+ MarkerAnnotation newAnnotation = createValVarAnnotation(ast, valAnnotation, valAnnotation.sourceStart, valAnnotation.sourceEnd);
try {
Reflection.astConverterRecordNodes.invoke(converter, newAnnotation, valAnnotation);
Reflection.astConverterRecordNodes.invoke(converter, newAnnotation.getTypeName(), valAnnotation.type);
@@ -175,10 +179,19 @@ public class PatchValEclipse {
}
modifiers.add(newAnnotation);
}
- }
-
- private static boolean couldBeVal(ImportReference[] imports, TypeReference type) {
- return PatchVal.couldBe(imports, "lombok.val", type);
+
+ if (!varIsPresent && varAnnotation != null) {
+ MarkerAnnotation newAnnotation = createValVarAnnotation(ast, varAnnotation, varAnnotation.sourceStart, varAnnotation.sourceEnd);
+ try {
+ Reflection.astConverterRecordNodes.invoke(converter, newAnnotation, varAnnotation);
+ Reflection.astConverterRecordNodes.invoke(converter, newAnnotation.getTypeName(), varAnnotation.type);
+ } catch (IllegalAccessException e) {
+ throw Lombok.sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw Lombok.sneakyThrow(e.getCause());
+ }
+ modifiers.add(newAnnotation);
+ }
}
public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) {
@@ -200,7 +213,7 @@ public class PatchValEclipse {
return modifier;
}
- public static MarkerAnnotation createValAnnotation(AST ast, Annotation original, int start, int end) {
+ public static MarkerAnnotation createValVarAnnotation(AST ast, Annotation original, int start, int end) {
MarkerAnnotation out = null;
try {
out = Reflection.markerAnnotationConstructor.newInstance(ast);
@@ -212,13 +225,23 @@ public class PatchValEclipse {
throw Lombok.sneakyThrow(e);
}
+ char[][] tokens;
+ if (original.type instanceof SingleTypeReference) {
+ tokens = new char[1][];
+ tokens[0] = ((SingleTypeReference) original.type).token;
+ } else if (original.type instanceof QualifiedTypeReference) {
+ tokens = ((QualifiedTypeReference) original.type).tokens;
+ } else {
+ return null;
+ }
+
if (out != null) {
- SimpleName valName = ast.newSimpleName("val");
+ SimpleName valName = ast.newSimpleName(new String(tokens[tokens.length - 1]));
valName.setSourceRange(start, end - start + 1);
- if (original.type instanceof SingleTypeReference) {
+ if (tokens.length == 1) {
out.setTypeName(valName);
setIndex(valName, 1);
- } else {
+ } else if (tokens.length == 2) {
SimpleName lombokName = ast.newSimpleName("lombok");
lombokName.setSourceRange(start, end - start + 1);
setIndex(lombokName, 1);
@@ -227,6 +250,21 @@ public class PatchValEclipse {
setIndex(fullName, 1);
fullName.setSourceRange(start, end - start + 1);
out.setTypeName(fullName);
+ } else {
+ SimpleName lombokName = ast.newSimpleName("lombok");
+ lombokName.setSourceRange(start, end - start + 1);
+ SimpleName experimentalName = ast.newSimpleName("experimental");
+ lombokName.setSourceRange(start, end - start + 1);
+ setIndex(lombokName, 1);
+ setIndex(experimentalName, 2);
+ setIndex(valName, 3);
+ QualifiedName lombokExperimentalName = ast.newQualifiedName(lombokName, experimentalName);
+ lombokExperimentalName.setSourceRange(start, end - start + 1);
+ setIndex(lombokExperimentalName, 1);
+ QualifiedName fullName = ast.newQualifiedName(lombokExperimentalName, valName);
+ setIndex(fullName, 1);
+ fullName.setSourceRange(start, end - start + 1);
+ out.setTypeName(fullName);
}
out.setSourceRange(start, end - start + 1);
}
diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
index 317b06a4..3c70d81d 100644
--- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java
+++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
@@ -92,7 +92,7 @@ final class PatchFixesHider {
shadowLoader = Util.class.getClassLoader();
} catch (ClassNotFoundException e) {
// If we get here, it isn't, and we should use the shadowloader.
- shadowLoader = Main.createShadowClassLoader();
+ shadowLoader = Main.getShadowClassLoader();
}
}
diff --git a/src/launch/lombok/launch/Agent.java b/src/launch/lombok/launch/Agent.java
index 7989e51f..357a8e48 100644
--- a/src/launch/lombok/launch/Agent.java
+++ b/src/launch/lombok/launch/Agent.java
@@ -35,7 +35,7 @@ final class Agent {
}
private static void runLauncher(String agentArgs, Instrumentation instrumentation, boolean injected) throws Throwable {
- ClassLoader cl = Main.createShadowClassLoader();
+ ClassLoader cl = Main.getShadowClassLoader();
try {
Class<?> c = cl.loadClass("lombok.core.AgentLauncher");
Method m = c.getDeclaredMethod("runAgents", String.class, Instrumentation.class, boolean.class, Class.class);
diff --git a/src/launch/lombok/launch/AnnotationProcessor.java b/src/launch/lombok/launch/AnnotationProcessor.java
index c4f922b9..b03dec76 100644
--- a/src/launch/lombok/launch/AnnotationProcessor.java
+++ b/src/launch/lombok/launch/AnnotationProcessor.java
@@ -104,7 +104,7 @@ class AnnotationProcessorHider {
}
private static AbstractProcessor createWrappedInstance() {
- ClassLoader cl = Main.createShadowClassLoader();
+ ClassLoader cl = Main.getShadowClassLoader();
try {
Class<?> mc = cl.loadClass("lombok.core.AnnotationProcessor");
return (AbstractProcessor) mc.getDeclaredConstructor().newInstance();
diff --git a/src/launch/lombok/launch/Main.java b/src/launch/lombok/launch/Main.java
index b81b6268..82913f8e 100644
--- a/src/launch/lombok/launch/Main.java
+++ b/src/launch/lombok/launch/Main.java
@@ -25,12 +25,18 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
class Main {
- static ClassLoader createShadowClassLoader() {
- return new ShadowClassLoader(Main.class.getClassLoader(), "lombok", null, Arrays.<String>asList(), Arrays.asList("lombok.patcher.Symbols"));
+
+ private static ShadowClassLoader classLoader;
+
+ static synchronized ClassLoader getShadowClassLoader() {
+ if (classLoader == null) {
+ classLoader = new ShadowClassLoader(Main.class.getClassLoader(), "lombok", null, Arrays.<String>asList(), Arrays.asList("lombok.patcher.Symbols"));
+ }
+ return classLoader;
}
public static void main(String[] args) throws Throwable {
- ClassLoader cl = createShadowClassLoader();
+ ClassLoader cl = getShadowClassLoader();
Class<?> mc = cl.loadClass("lombok.core.Main");
try {
mc.getMethod("main", String[].class).invoke(null, new Object[] {args});
diff --git a/src/launch/lombok/launch/ShadowClassLoader.java b/src/launch/lombok/launch/ShadowClassLoader.java
index 36dd289c..5489f3ea 100644
--- a/src/launch/lombok/launch/ShadowClassLoader.java
+++ b/src/launch/lombok/launch/ShadowClassLoader.java
@@ -296,17 +296,18 @@ class ShadowClassLoader extends ClassLoader {
return null;
}
- private boolean partOfShadow(URL item, String name) {
- return inOwnBase(item, name) || isPartOfShadowSuffix(item, name, sclSuffix);
+ private boolean partOfShadow(String item, String name) {
+ return !name.startsWith("java/")
+ && !name.startsWith("sun/")
+ && (inOwnBase(item, name) || isPartOfShadowSuffix(item, name, sclSuffix));
}
/**
* Checks if the stated item is located inside the same classpath root as the jar that hosts ShadowClassLoader.class. {@code item} and {@code name} refer to the same thing.
*/
- private boolean inOwnBase(URL item, String name) {
+ private boolean inOwnBase(String item, String name) {
if (item == null) return false;
- String itemString = item.toString();
- return (itemString.length() == SELF_BASE_LENGTH + name.length()) && SELF_BASE.regionMatches(0, itemString, 0, SELF_BASE_LENGTH);
+ return (item.length() == SELF_BASE_LENGTH + name.length()) && SELF_BASE.regionMatches(0, item, 0, SELF_BASE_LENGTH);
}
private static boolean sclFileContainsSuffix(InputStream in, String suffix) throws IOException {
@@ -386,12 +387,11 @@ class ShadowClassLoader extends ClassLoader {
}
}
- private boolean isPartOfShadowSuffix(URL item, String name, String suffix) {
+ private boolean isPartOfShadowSuffix(String url, String name, String suffix) {
// Instead of throwing an exception or logging, weird, unexpected cases just return false.
// This is better than throwing an exception, because exceptions would make your build tools unusable.
// Such cases are marked with the comment: // *unexpected*
- if (item == null) return false;
- String url = item.toString();
+ if (url == null) return false;
if (url.startsWith("file:/")) {
url = urlDecode(url.substring(5));
if (url.length() <= name.length() || !url.endsWith(name) || url.charAt(url.length() - name.length() - 1) != '/') {
@@ -436,14 +436,14 @@ class ShadowClassLoader extends ClassLoader {
Enumeration<URL> sec = super.getResources(name);
while (sec.hasMoreElements()) {
URL item = sec.nextElement();
- if (!partOfShadow(item, name)) vector.add(item);
+ if (!partOfShadow(item.toString(), name)) vector.add(item);
}
if (altName != null) {
Enumeration<URL> tern = super.getResources(altName);
while (tern.hasMoreElements()) {
URL item = tern.nextElement();
- if (!partOfShadow(item, altName)) vector.add(item);
+ if (!partOfShadow(item.toString(), altName)) vector.add(item);
}
}
@@ -483,11 +483,11 @@ class ShadowClassLoader extends ClassLoader {
if (altName != null) {
URL res = super.getResource(altName);
- if (res != null && (!noSuper || partOfShadow(res, altName))) return res;
+ if (res != null && (!noSuper || partOfShadow(res.toString(), altName))) return res;
}
URL res = super.getResource(name);
- if (res != null && (!noSuper || partOfShadow(res, name))) return res;
+ if (res != null && (!noSuper || partOfShadow(res.toString(), name))) return res;
return null;
}
@@ -501,12 +501,12 @@ class ShadowClassLoader extends ClassLoader {
private URL getResourceSkippingSelf(String name) throws IOException {
URL candidate = super.getResource(name);
if (candidate == null) return null;
- if (!partOfShadow(candidate, name)) return candidate;
+ if (!partOfShadow(candidate.toString(), name)) return candidate;
Enumeration<URL> en = super.getResources(name);
while (en.hasMoreElements()) {
candidate = en.nextElement();
- if (!partOfShadow(candidate, name)) return candidate;
+ if (!partOfShadow(candidate.toString(), name)) return candidate;
}
return null;
@@ -526,9 +526,14 @@ class ShadowClassLoader extends ClassLoader {
String fileNameOfClass = name.replace(".", "/") + ".class";
URL res = getResource_(fileNameOfClass, true);
if (res == null) {
- if (!exclusionListMatch(fileNameOfClass)) return super.loadClass(name, resolve);
- throw new ClassNotFoundException(name);
+ if (!exclusionListMatch(fileNameOfClass)) try {
+ return super.loadClass(name, resolve);
+ } catch (ClassNotFoundException cnfe) {
+ res = getResource_("secondaryLoading.SCL." + sclSuffix + "/" + name.replace(".", "/") + ".SCL." + sclSuffix, true);
+ if (res == null) throw cnfe;
+ }
}
+ if (res == null) throw new ClassNotFoundException(name);
byte[] b;
int p = 0;
diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java
index 5ef33086..943a7a7a 100644
--- a/src/utils/lombok/eclipse/Eclipse.java
+++ b/src/utils/lombok/eclipse/Eclipse.java
@@ -56,6 +56,8 @@ public class Eclipse {
*/
public static final int ECLIPSE_DO_NOT_TOUCH_FLAG = ASTNode.Bit24;
+ private static final Pattern SPLIT_AT_DOT = Pattern.compile("\\.");
+
private Eclipse() {
//Prevent instantiation
}
@@ -65,19 +67,25 @@ public class Eclipse {
* but we need to deal with it. This turns [[java][lang][String]] into "java.lang.String".
*/
public static String toQualifiedName(char[][] typeName) {
- int len = typeName.length - 1;
+ int len = typeName.length - 1; // number of dots
+ if (len == 0) return new String(typeName[0]);
+
for (char[] c : typeName) len += c.length;
- StringBuilder sb = new StringBuilder(len);
- boolean first = true;
- for (char[] c : typeName) {
- sb.append(first ? "" : ".").append(c);
- first = false;
+ char[] ret = new char[len];
+ char[] part = typeName[0];
+ System.arraycopy(part, 0, ret, 0, part.length);
+ int pos = part.length;
+ for (int i = 1; i < typeName.length; i++) {
+ ret[pos++] = '.';
+ part = typeName[i];
+ System.arraycopy(part, 0, ret, pos, part.length);
+ pos += part.length;
}
- return sb.toString();
+ return new String(ret);
}
public static char[][] fromQualifiedName(String typeName) {
- String[] split = typeName.split("\\.");
+ String[] split = SPLIT_AT_DOT.split(typeName);
char[][] result = new char[split.length][];
for (int i = 0; i < split.length; i++) {
result[i] = split[i].toCharArray();