diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | build.xml | 98 | ||||
-rw-r--r-- | buildScripts/ivy.xml | 24 | ||||
-rw-r--r-- | doc/changelog.markdown | 1 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleSneakyThrows.java | 21 | ||||
-rw-r--r-- | src/utils/lombok/javac/Javac.java | 35 | ||||
-rw-r--r-- | website/features/Data.html | 2 | ||||
-rw-r--r-- | website/features/Value.html | 2 |
8 files changed, 163 insertions, 21 deletions
@@ -17,3 +17,4 @@ /.idea *.markdown.html /junit*.properties +/eclipse.location @@ -255,7 +255,15 @@ the common tasks and can be called on to run the main aspects of all the sub-scr </ivy:intellijgen> </target> - <target name="eclipse" depends="deps, contrib" description="Creates eclipse project files and downloads all dependencies. Open this directory as project in eclipse after running this target."> + <target name="-skipEclipseDeps"> + <property name="eclipse.build.configname" value="buildWithoutEclipse" /> + </target> + + <target name="-addEclipseDeps"> + <property name="eclipse.build.configname" value="build" /> + </target> + + <target name="eclipse" depends="-addEclipseDeps, deps, contrib" description="Creates eclipse project files and downloads all dependencies. Open this directory as project in eclipse after running this target. This will NOT let you start a debug session for eclipse; use target 'eclipseForDebugging' instead to do that."> <ivy:eclipsegen source="1.6"> <srcdir dir="src/core" /> <srcdir dir="src/utils" /> @@ -267,20 +275,104 @@ the common tasks and can be called on to run the main aspects of all the sub-scr <srcdir dir="test/transform/src" /> <srcdir dir="test/core/src" /> <srcdir dir="test/bytecode/src" /> - <conf name="build" sources="contrib" /> + <conf name="${eclipse.build.configname}" sources="contrib" /> <conf name="test" sources="contrib" /> <settings> <url url="http://projectlombok.org/downloads/lombok.eclipse.settings" /> </settings> <apt location="lib/build/projectlombok.org-spi.jar" /> </ivy:eclipsegen> - + </target> + + <target name="ensureEcjDebugDeps" depends="config-ivy"> + <ivy:resolve file="buildScripts/ivy.xml" refresh="true" conf="buildWithoutEclipse" /> + <ivy:retrieve /> + </target> + + <target name="loadEclipseLocation"> + <loadfile property="eclipse.location" srcFile="eclipse.location" encoding="UTF-8" quiet="true" /> + </target> + + <target name="setupEclipseLocation" depends="loadEclipseLocation" unless="eclipse.location"> + <echo>To add your eclipse installation's own plugins as dependencies, the build script needs to know where your eclipse is installed. Please enter this now (it's saved for future executions of this task). For example: + + /Applications/eclipse + C:\Program Files\eclipse +</echo> + <input message="Path to eclipse: " addproperty="eclipse.location" /> + <available property="eclipse.found" file="${eclipse.location}/plugins" /> + <fail unless="eclipse.found">Eclipse can't be found in this location; I expect that directory to contain a subdirectory called 'plugins'.</fail> + <echo file="eclipse.location" message="${eclipse.location}" /> + </target> + + <target name="eclipseForDebugging" depends="-skipEclipseDeps, ensureEcjDebugDeps, eclipse, setupEclipseLocation" description="Creates eclipse project files and downloads all dependencies, but borrows all eclipse dependencies (and more) from your existing eclipse installation. This is very useful if you wish to start a debugging eclipse from inside eclipse, and then breakpoint eclipse code itself. Because the deps are inherited, line numbers will line up and such."> <copy file="buildScripts/eclipse-debug-target.template" tofile="LombokizedEclipse.launch" preservelastmodified="true" overwrite="true"> </copy> + + <!-- These are dependencies --> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.core.runtime" /></antcall> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.equinox.common" /></antcall> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.osgi" /></antcall> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.jdt.core" /></antcall> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.jdt.ui" /></antcall> + + <!-- These are merely useful --> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.text" /></antcall> + <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.ltk.core.refactoring" /></antcall> + </target> + + <target name="-augmentClasspath"> + <pathconvert property="augment.bin" setonempty="false" pathsep=" :: "> + <fileset dir="${eclipse.location}/plugins" includes="${pluginName}_*" /> + </pathconvert> + + <pathconvert property="augment.src" setonempty="false" pathsep=" :: "> + <fileset dir="${eclipse.location}/plugins" includes="${pluginName}.source_*" /> + </pathconvert> + + <condition property="noSourceAvailable"> + <and> + <isset property="augment.bin" /> + <not><isset property="augment.src" /></not> + </and> + </condition> + + <condition property="multiples"> + <or> + <contains string="${augment.bin}" substring=" :: " /> + <contains string="${augment.src}" substring=" :: " /> + </or> + </condition> + + <fail if="noSourceAvailable"> + You do not have sources for ${augment.bin}. I expect the sources to be in the same directory, but starting with '${prefix}.source_'. + </fail> + + <fail unless="augment.bin"> + You do not have the eclipse plugin '${pluginName}'. I expected it to be in your eclipse plugins directory (followed by an underscore and a version number). + </fail> + + <fail if="multiples"> + You have multiple versions of the same plugin. You should probably delete everything except the one your eclipse actually uses. + + Binaries: ${augment.bin} + + Sources: ${augment.src} + </fail> + + <condition property="intentionallyBreakTheRegexp" value="" else="thisWontBeInClasspathFile"> + <isset property="augment.bin" /> + </condition> + + <replaceregexp file=".classpath" flags="is" encoding="UTF-8"> + <regexp pattern="^(.*?)(.)${intentionallyBreakTheRegexp}(<classpathentry kind=.lib. path=)(.*)$" /> + <substitution expression="\1\2<classpathentry kind="lib" path="${augment.bin}" sourcepath="${augment.src}"/>\${line.separator}\2\3\4" /> + </replaceregexp> + <echo>Added to project classpath from your eclipse installation: ${pluginName}.</echo> </target> <target name="-test-compile" depends="ensureTestDeps, compile" unless="skipTests"> diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index bd9fb1a1..bcf5ecd1 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -3,7 +3,9 @@ <configurations> <conf name="eclipseBuild" /> <conf name="netbeansBuild" /> - <conf name="build" extends="eclipseBuild, netbeansBuild, javac6" /> + <conf name="buildBase" extends="netbeansBuild, javac6" /> + <conf name="build" extends="buildBase, eclipseBuild" /> + <conf name="buildWithoutEclipse" extends="buildBase" /> <conf name="runtime" /> <conf name="test" extends="runtime" /> <conf name="contrib" /> @@ -12,8 +14,8 @@ <conf name="javac7" /> </configurations> <dependencies> - <dependency org="org.projectlombok" name="lombok.patcher" rev="0.7" conf="build->default; runtime->default" /> - <dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="build->runtime; runtime" /> + <dependency org="org.projectlombok" name="lombok.patcher" rev="0.7" conf="buildBase->default; runtime->default" /> + <dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="buildBase->runtime; runtime" /> <dependency org="junit" name="junit" rev="4.8.2" conf="test->default; contrib->sources" /> <dependency org="log4j" name="log4j" rev="1.2.16" conf="test->default; contrib->sources" /> @@ -21,15 +23,15 @@ <dependency org="commons-logging" name="commons-logging" rev="1.1.1" conf="test->default; contrib->sources"/> <dependency org="org.slf4j" name="slf4j-api" rev="1.6.1" conf="test->default; contrib->sources"/> <dependency org="org.slf4j" name="slf4j-ext" rev="1.6.1" conf="test->default; contrib->sources"/> - <dependency org="com.googlecode.jarjar" name="jarjar" rev="1.1" conf="build->default" /> + <dependency org="com.googlecode.jarjar" name="jarjar" rev="1.1" conf="buildBase->default" /> - <dependency org="org.apache.ant" name="ant" rev="1.8.1" conf="build->default; contrib->sources" /> - <dependency org="projectlombok.org" name="spi" rev="0.2.7" conf="build" /> - <dependency org="projectlombok.org" name="ant-googlecode" rev="0.0.2" conf="build" /> - <dependency org="com.jcraft" name="jsch" rev="0.1.42" conf="build->default" /> - <dependency org="projectlombok.org" name="jsch-ant-fixed" rev="0.1.42" conf="build" /> - <dependency org="projectlombok.org" name="markdownj" rev="1.02b4" conf="build" /> - <dependency org="de.java2html" name="java2html" rev="5.0" conf="build->default" /> + <dependency org="org.apache.ant" name="ant" rev="1.8.1" conf="buildBase->default; contrib->sources" /> + <dependency org="projectlombok.org" name="spi" rev="0.2.7" conf="buildBase->build" /> + <dependency org="projectlombok.org" name="ant-googlecode" rev="0.0.2" conf="buildBase->build" /> + <dependency org="com.jcraft" name="jsch" rev="0.1.42" conf="buildBase->default" /> + <dependency org="projectlombok.org" name="jsch-ant-fixed" rev="0.1.42" conf="buildBase->build" /> + <dependency org="projectlombok.org" name="markdownj" rev="1.02b4" conf="buildBase->build" /> + <dependency org="de.java2html" name="java2html" rev="5.0" conf="buildBase->default" /> <dependency org="net.java.openjdk.custom" name="javac6" rev="1.6.0.18" conf="javac6->runtime; contrib->sources" /> <dependency org="net.java.openjdk.custom" name="javac7" rev="1.7.0" conf="javac7->runtime; contrib->sources" /> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index b5506fa9..400fe096 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,6 +2,7 @@ Lombok Changelog ---------------- ### v1.12.5 "Edgy Guinea Pig" +* BUGFIX: {Netbeans} @SneakyThrows would lead to unused import and break refactorings [Issue #471](https://code.google.com/p/projectlombok/issues/detail?id=471). * BUGFIX: Eclipse Organize Imports would generate error: AST must not be null [Issue #631](https://code.google.com/p/projectlombok/issues/detail?id=631). * BUGFIX: Copying javadoc to getters / setters / withers would copy non-relevant sections too. [Issue #585](https://code.google.com/p/projectlombok/issues/detail?id=585). * DETAIL: {Delombok} Inside enum bodies the delombok formatter didn't respect the emptyLines directive [Issue #629](https://code.google.com/p/projectlombok/issues/detail?id=629). diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java index 0b444801..aa0c3c7e 100644 --- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java @@ -40,12 +40,15 @@ 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.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCTry; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; +import lombok.javac.Javac; /** * Handles the {@code lombok.SneakyThrows} annotation for javac. @@ -120,15 +123,25 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { Context context = node.getContext(); JCBlock tryBlock = setGeneratedBy(maker.Block(0, contents), source, context); - JCExpression varType = chainDots(node, exception.split("\\.")); - JCVariableDecl catchParam = maker.VarDef(maker.Modifiers(Flags.FINAL), node.toName("$ex"), varType, null); + JCVariableDecl catchParam = maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER), node.toName("$ex"), varType, null); JCExpression lombokLombokSneakyThrowNameRef = chainDots(node, "lombok", "Lombok", "sneakyThrow"); JCBlock catchBody = maker.Block(0, List.<JCStatement>of(maker.Throw(maker.Apply( List.<JCExpression>nil(), lombokLombokSneakyThrowNameRef, List.<JCExpression>of(maker.Ident(node.toName("$ex"))))))); - - return setGeneratedBy(maker.Try(tryBlock, List.of(recursiveSetGeneratedBy(maker.Catch(catchParam, catchBody), source, context)), null), source, context); + JCTry tryStatement = maker.Try(tryBlock, List.of(recursiveSetGeneratedBy(maker.Catch(catchParam, catchBody), source, context)), null); + if (JavacHandlerUtil.inNetbeansEditor(node)) { + //set span (start and end position) of the try statement and the main block + //this allows NetBeans to dive into the statement correctly: + JCCompilationUnit top = (JCCompilationUnit) node.top().get(); + int startPos = contents.head.pos; + int endPos = Javac.getEndPosition(contents.last().pos(), top); + tryBlock.pos = startPos; + tryStatement.pos = startPos; + Javac.storeEnd(tryBlock, endPos, top); + Javac.storeEnd(tryStatement, endPos, top); + } + return setGeneratedBy(tryStatement, source, context); } } diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index bdf5e7a0..e207c44a 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -177,7 +177,7 @@ public class Javac { public static final TreeTag CTC_PREINC = treeTag("PREINC"); public static final TreeTag CTC_PREDEC = treeTag("PREDEC"); - private static final Method getExtendsClause, getEndPosition; + private static final Method getExtendsClause, getEndPosition, storeEnd; static { getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class<?>[0]); @@ -185,10 +185,32 @@ public class Javac { if (getJavaCompilerVersion() < 8) { getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", java.util.Map.class); + storeEnd = getMethod(java.util.Map.class, "put", Object.class, Object.class); } else { getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", "com.sun.tools.javac.tree.EndPosTable"); + Method storeEndMethodTemp; + Class<?> endPosTable; + try { + endPosTable = Class.forName("com.sun.tools.javac.tree.EndPosTable"); + } catch (ClassNotFoundException ex) { + throw sneakyThrow(ex); + } + try { + storeEndMethodTemp = endPosTable.getMethod("storeEnd", JCTree.class, int.class); + } catch (NoSuchMethodException e) { + try { + endPosTable = Class.forName("com.sun.tools.javac.parser.JavacParser$AbstractEndPosTable"); + storeEndMethodTemp = endPosTable.getDeclaredMethod("storeEnd", JCTree.class, int.class); + } catch (NoSuchMethodException ex) { + throw sneakyThrow(ex); + } catch (ClassNotFoundException ex) { + throw sneakyThrow(ex); + } + } + storeEnd = storeEndMethodTemp; } getEndPosition.setAccessible(true); + storeEnd.setAccessible(true); } private static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) { @@ -250,6 +272,17 @@ public class Javac { } } + public static void storeEnd(JCTree tree, int pos, JCCompilationUnit top) { + try { + Object endPositions = JCCOMPILATIONUNIT_ENDPOSITIONS.get(top); + storeEnd.invoke(endPositions, tree, pos); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } + } + private static final Class<?> JC_VOID_TYPE, JC_NO_TYPE; static { diff --git a/website/features/Data.html b/website/features/Data.html index ad3aa892..4d6e5609 100644 --- a/website/features/Data.html +++ b/website/features/Data.html @@ -38,7 +38,7 @@ </p><p> If the class already contains a method with the same name as any method that would normally be generated, that method is not generated, and no warning or error is emitted. For example, if you already have a method with signature <code>void hashCode(int a, int b, int c)</code>, no <code>int hashCode()</code> - method will be generated, even though technically <code>int hashCode()</code> is an entirely different method. The same rule applies to the constructor, + method will be generated, even though technically <code>int hashCode()</code> is an entirely different method. The same rule applies to the constructor (any explicit constructor will prevent <code>@Data</code> from generating one), <code>toString</code>, <code>equals</code>, and all getters and setters. </p><p> <code>@Data</code> can handle generics parameters for fields just fine. In order to reduce the boilerplate when constructing objects for classes with diff --git a/website/features/Value.html b/website/features/Value.html index 6bbd6f2a..e5dc7d9e 100644 --- a/website/features/Value.html +++ b/website/features/Value.html @@ -27,7 +27,7 @@ <code>@Value</code> is the immutable variant of <a href="Data.html"><code>@Data</code></a>; all fields are made <code>private</code> and <code>final</code> by default, and setters are not generated. The class itself is also made <code>final</code> by default, because immutability is not something that can be forced onto a subclass. Like <code>@Data</code>, useful <code>toString()</code>, <code>equals()</code> and <code>hashCode()</code> methods are also generated, each field gets a getter method, and a constructor that covers every argument (except <code>final</code> fields that are initialized in the field declaration) is also generated. </p><p> - In practice, <code>@Value</code> is shorthand for: <code>final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter</code>. + In practice, <code>@Value</code> is shorthand for: <code>final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter</code>, except that explicitly including an implementation of any of the relevant methods simply means that part won't be generated and no warning will be emitted. For example, if you write your own <code>toString</code>, no error occurs, and lombok will not generate a <code>toString</code>. Also, <em>any</em> explicit constructor, no matter the arguments list, implies lombok will not generate a constructor. If you do want lombok to generate the all-args constructor, add <code>@AllArgsConstructor</code> to the class. </p><p> It is possible to override the final-by-default and private-by-default behaviour using either an explicit access level on a field, or by using the <code>@NonFinal</code> or <code>@PackagePrivate</code> annotations.<br /> It is possible to override any default behaviour for any of the 'parts' that make up <code>@Value</code> by explicitly using that annotation. |