diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index dd646e57..9411b9ba 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2022 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -2972,4 +2972,41 @@ public class EclipseHandlerUtil { setDocComment(cud, type, to, newJavadoc); } catch (Exception ignore) {} } + + /** + * Returns the method node containing the given annotation, or {@code null} if the given annotation node is not on a method or argument. + */ + public static EclipseNode getAnnotatedMethod(EclipseNode node) { + if (node == null || node.getKind() != Kind.ANNOTATION) return null; + + EclipseNode result = node.up(); + if (result.getKind() == Kind.ARGUMENT) { + result = node.up(); + } + if (result.getKind() != Kind.METHOD) { + result = null; + } + return result; + } + + /** + * Returns {@code true} if the given method node body was parsed. + */ + public static boolean hasParsedBody(EclipseNode method) { + if (method == null || method.getKind() != Kind.METHOD) return false; + + boolean isCompleteParse = method.getAst().isCompleteParse(); + if (isCompleteParse) return true; + + AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration) method.get(); + if (methodDecl.statements != null) return true; + + // If the method is part of a field initializer it was parsed + EclipseNode parent = method.up(); + while (parent != null) { + if (parent.getKind() == Kind.FIELD) return true; + parent = parent.up(); + } + return false; + } } diff --git a/src/core/lombok/eclipse/handlers/HandleLocked.java b/src/core/lombok/eclipse/handlers/HandleLocked.java index 240a6498..ab733c97 100644 --- a/src/core/lombok/eclipse/handlers/HandleLocked.java +++ b/src/core/lombok/eclipse/handlers/HandleLocked.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 The Project Lombok Authors. + * Copyright (C) 2021-2024 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,15 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.EcjAugments.ASTNode_handled; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import lombok.Locked; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.Locked; import lombok.spi.Provides; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; /** * Handles the {@code lombok.Locked} annotation for eclipse. @@ -52,5 +56,11 @@ public class HandleLocked extends EclipseAnnotationHandler { @Override public void preHandle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { String annotationValue = annotation.getInstance().value(); HandleLockedUtil.preHandle(annotationValue, LOCK_TYPE_CLASS, LOCK_IMPL_CLASS, annotationNode); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleLockedRead.java b/src/core/lombok/eclipse/handlers/HandleLockedRead.java index a293467a..33f2583b 100644 --- a/src/core/lombok/eclipse/handlers/HandleLockedRead.java +++ b/src/core/lombok/eclipse/handlers/HandleLockedRead.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 The Project Lombok Authors. + * Copyright (C) 2021-2024 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,15 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.EcjAugments.ASTNode_handled; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import lombok.Locked; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.Locked; import lombok.spi.Provides; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; /** * Handles the {@code lombok.Locked.Read} annotation for eclipse. @@ -53,5 +57,11 @@ public class HandleLockedRead extends EclipseAnnotationHandler { @Override public void preHandle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { String annotationValue = annotation.getInstance().value(); HandleLockedUtil.preHandle(annotationValue, LOCK_TYPE_CLASS, LOCK_IMPL_CLASS, annotationNode); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleLockedWrite.java b/src/core/lombok/eclipse/handlers/HandleLockedWrite.java index 6192c76b..548b4d4a 100644 --- a/src/core/lombok/eclipse/handlers/HandleLockedWrite.java +++ b/src/core/lombok/eclipse/handlers/HandleLockedWrite.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 The Project Lombok Authors. + * Copyright (C) 2021-2024 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,15 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.EcjAugments.ASTNode_handled; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import lombok.Locked; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.Locked; import lombok.spi.Provides; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; /** * Handles the {@code lombok.Locked.Write} annotation for eclipse. @@ -53,5 +57,11 @@ public class HandleLockedWrite extends EclipseAnnotationHandler { @Override public void preHandle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { String annotationValue = annotation.getInstance().value(); HandleLockedUtil.preHandle(annotationValue, LOCK_TYPE_CLASS, LOCK_IMPL_CLASS, annotationNode); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java index 5f0ca3fb..74d9df6f 100644 --- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -22,6 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.EcjAugments.ASTNode_handled; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; @@ -29,15 +30,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import lombok.ConfigurationKeys; -import lombok.SneakyThrows; -import lombok.core.AnnotationValues; -import lombok.core.HandlerPriority; -import lombok.eclipse.DeferUntilPostDiet; -import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseNode; -import lombok.spi.Provides; - import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -58,6 +50,15 @@ import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import lombok.ConfigurationKeys; +import lombok.SneakyThrows; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.eclipse.DeferUntilPostDiet; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; + /** * Handles the {@code lombok.HandleSneakyThrows} annotation for eclipse. */ @@ -76,6 +77,15 @@ public class HandleSneakyThrows extends EclipseAnnotationHandler { } } + @Override + public void preHandle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, ast, annotationNode); + ASTNode_handled.set(ast, true); + } + } + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.SNEAKY_THROWS_FLAG_USAGE, "@SneakyThrows"); diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index dbe363d9..c5fbcf4f 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -22,6 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.EcjAugments.ASTNode_handled; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; @@ -70,6 +71,12 @@ public class HandleSynchronized extends EclipseAnnotationHandler { if (method.isAbstract()) return; createLockField(annotation, annotationNode, new boolean[] {method.isStatic()}, false); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } public char[] createLockField(AnnotationValues annotation, EclipseNode annotationNode, boolean[] isStatic, boolean reportErrors) { diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index 51ec41c5..0cb379ff 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -29,14 +29,12 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; -import java.io.StringWriter; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import org.junit.Assert; @@ -83,28 +81,38 @@ public abstract class AbstractRunTests { return new FileTester() { @Override public void runTest() throws Throwable { if (directiveFailure_ != null) throw directiveFailure_; - LinkedHashSet messages = new LinkedHashSet(); - StringWriter writer = new StringWriter(); - LombokConfiguration.overrideConfigurationResolverFactory(new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(URI sourceLocation) { return sourceDirectives_.getConfiguration(); } }); + TestParameters testParameters = new TestParameters(); + testParameters.setEncoding(sourceDirectives_.getSpecifiedEncoding()); + testParameters.setFormatPreferences(sourceDirectives_.getFormatPreferences()); + testParameters.setMinVersion(sourceDirectives_.minVersion()); + testParameters.setVerifyDiet(sourceDirectives_.isVerifyDiet()); boolean checkPositions = !(params instanceof TestLombokFilesIdempotent || params instanceof TestSourceFiles) && !sourceDirectives_.isSkipCompareContent(); + testParameters.setCheckPositions(checkPositions); + String javaVersionString = System.getProperty("compiler.compliance.level"); + if (javaVersionString != null) { + long version = Long.parseLong(javaVersionString); + testParameters.setSourceVersion(version); + testParameters.setTargetVersion(version); + } - boolean changed = transformCode(messages, writer, file, sourceDirectives_.getSpecifiedEncoding(), sourceDirectives_.getFormatPreferences(), sourceDirectives_.minVersion(), checkPositions); + TransformationResult result = transformCode(file, testParameters); + boolean changed = result.isChanged(); boolean forceUnchanged = sourceDirectives_.forceUnchanged() || sourceDirectives_.isSkipCompareContent(); - if (params.expectChanges() && !forceUnchanged && !changed) messages.add(new CompilerMessage(-1, -1, true, "not flagged modified")); - if (!params.expectChanges() && changed) messages.add(new CompilerMessage(-1, -1, true, "unexpected modification")); + if (params.expectChanges() && !forceUnchanged && !changed) result.addMessage(new CompilerMessage(-1, -1, true, "not flagged modified")); + if (!params.expectChanges() && changed) result.addMessage(new CompilerMessage(-1, -1, true, "unexpected modification")); - compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent()); + compare(file.getName(), expected, result, params.printErrors(), sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent()); } }; } - protected abstract boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences, int minVersion, boolean checkPositions) throws Throwable; + protected abstract TransformationResult transformCode(File file, TestParameters parameters) throws Throwable; protected String readFile(File file) throws IOException { BufferedReader reader; @@ -154,7 +162,10 @@ public abstract class AbstractRunTests { } } - private void compare(String name, LombokTestSource expected, String actualFile, LinkedHashSet actualMessages, boolean printErrors, boolean skipCompareContent) throws Throwable { + private void compare(String name, LombokTestSource expected, TransformationResult result, boolean printErrors, boolean skipCompareContent) throws Throwable { + String actualFile = result.getOutput(); + LinkedHashSet actualMessages = result.getMessages(); + if (!skipCompareContent) try { compareContent(name, expected.getContent(), actualFile); } catch (Throwable e) { diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index 27ffc31a..92bc53ea 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2019 The Project Lombok Authors. + * Copyright (C) 2014-2024 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 @@ -58,6 +58,7 @@ public class LombokTestSource { private final boolean skipCompareContent; private final boolean skipIdempotent; private final boolean unchanged; + private final boolean verifyDiet; private final int versionLowerLimit, versionUpperLimit; private final ConfigurationResolver configuration; private final String specifiedEncoding; @@ -113,6 +114,10 @@ public class LombokTestSource { return skipIdempotent; } + public boolean isVerifyDiet() { + return verifyDiet; + } + public String getSpecifiedEncoding() { return specifiedEncoding; } @@ -162,6 +167,7 @@ public class LombokTestSource { private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?contents?\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern SKIP_IDEMPOTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?idempotent\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern ISSUE_REF_PATTERN = Pattern.compile("^\\s*issue #?\\d+(:?\\s+.*)?$", Pattern.CASE_INSENSITIVE); + private static final Pattern VERIFY_DIET_PATTERN = Pattern.compile("^\\s*eclipse:\\s*verify[- ]?diet\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private LombokTestSource(File file, String content, List messages, List directives) { this.file = file; @@ -175,6 +181,7 @@ public class LombokTestSource { boolean skipCompareContent = false; boolean skipIdempotent = false; boolean unchanged = false; + boolean verifyDiet = false; String encoding = null; Map formats = new HashMap(); String[] platformLimit = null; @@ -204,6 +211,10 @@ public class LombokTestSource { if (ISSUE_REF_PATTERN.matcher(directive).matches()) { continue; } + if (VERIFY_DIET_PATTERN.matcher(directive).matches()) { + verifyDiet = true; + continue; + } if (lc.startsWith("platform ")) { String platformDesc = lc.substring("platform ".length()); @@ -257,6 +268,7 @@ public class LombokTestSource { this.skipCompareContent = skipCompareContent; this.skipIdempotent = skipIdempotent; this.unchanged = unchanged; + this.verifyDiet = verifyDiet; this.platforms = platformLimit == null ? null : Arrays.asList(platformLimit); ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() { diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index adfb1fce..918a0de4 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -66,24 +66,24 @@ import com.sun.tools.javac.tree.TreeScanner; import lombok.delombok.Delombok; import lombok.javac.CapturingDiagnosticListener; -import lombok.javac.CapturingDiagnosticListener.CompilerMessage; import lombok.javac.Javac; public class RunTestsViaDelombok extends AbstractRunTests { private Delombok delombok = new Delombok(); @Override - public boolean transformCode(Collection messages, StringWriter result, final File file, String encoding, Map formatPreferences, int version, boolean checkPositions) throws Throwable { + public TransformationResult transformCode(final File file, TestParameters parameters) throws Throwable { + TransformationResult result = new TransformationResult(); delombok.setVerbose(true); ChangedChecker cc = new ChangedChecker(); delombok.setFeedback(cc.feedback); delombok.setForceProcess(true); - delombok.setCharset(encoding == null ? "UTF-8" : encoding); - delombok.setFormatPreferences(formatPreferences); + delombok.setCharset(parameters.getEncoding() == null ? "UTF-8" : parameters.getEncoding()); + delombok.setFormatPreferences(parameters.getFormatPreferences()); - delombok.setDiagnosticsListener(new CapturingDiagnosticListener(file, messages)); + delombok.setDiagnosticsListener(new CapturingDiagnosticListener(file, result.getMessages())); - if (checkPositions) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(version)); + if (parameters.isCheckPositions()) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(parameters.getMinVersion())); delombok.addAdditionalAnnotationProcessor(new ValidateTypesProcessor()); delombok.addAdditionalAnnotationProcessor(new ValidateNoDuplicateTreeNodeProcessor()); @@ -91,12 +91,15 @@ public class RunTestsViaDelombok extends AbstractRunTests { delombok.setSourcepath(file.getAbsoluteFile().getParent()); String bcp = System.getProperty("delombok.bootclasspath"); if (bcp != null) delombok.setBootclasspath(bcp); - delombok.setWriter(result); + StringWriter sw = new StringWriter(); + delombok.setWriter(sw); Locale originalLocale = Locale.getDefault(); try { Locale.setDefault(Locale.ENGLISH); delombok.delombok(); - return cc.isChanged(); + result.setOutput(sw.toString()); + result.setChanged(cc.isChanged()); + return result; } finally { Locale.setDefault(originalLocale); } diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index d46a890f..57174947 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2021 The Project Lombok Authors. + * Copyright (C) 2010-2024 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 @@ -22,9 +22,7 @@ package lombok; import java.io.File; -import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -32,9 +30,6 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import lombok.eclipse.Eclipse; -import lombok.javac.CapturingDiagnosticListener.CompilerMessage; - import org.eclipse.core.internal.registry.ExtensionRegistry; import org.eclipse.core.internal.runtime.Activator; import org.eclipse.core.internal.runtime.PlatformActivator; @@ -61,18 +56,19 @@ import org.eclipse.jdt.internal.core.JavaModelManager; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import lombok.eclipse.Eclipse; +import lombok.javac.CapturingDiagnosticListener.CompilerMessage; + public class RunTestsViaEcj extends AbstractRunTests { - protected CompilerOptions ecjCompilerOptions() { + protected CompilerOptions ecjCompilerOptions(TestParameters parameters) { CompilerOptions options = new CompilerOptions(); Map warnings = new HashMap(); - String javaVersionString = System.getProperty("compiler.compliance.level"); long ecjCompilerVersionConstant = Eclipse.getLatestEcjCompilerVersionConstant(); long ecjCompilerVersion = Eclipse.getEcjCompilerVersion(); - if (javaVersionString != null) { - long javaVersion = Long.parseLong(javaVersionString); - ecjCompilerVersionConstant = (javaVersion + 44) << 16; - ecjCompilerVersion = javaVersion; + if (parameters.getSourceVersion() != null) { + ecjCompilerVersionConstant = (parameters.getSourceVersion() + 44) << 16; + ecjCompilerVersion = parameters.getSourceVersion(); } else { // Preview features are only allowed if the maximum compiler version is equal to the source version warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled"); @@ -127,7 +123,8 @@ public class RunTestsViaEcj extends AbstractRunTests { } @Override - public boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences, int minVersion, boolean checkPositions) throws Throwable { + public TransformationResult transformCode(File file, TestParameters parameters) throws Throwable { + TransformationResult result = new TransformationResult(); final AtomicReference compilationResult_ = new AtomicReference(); final AtomicReference compilationUnit_ = new AtomicReference(); ICompilerRequestor bitbucketRequestor = new ICompilerRequestor() { @@ -143,12 +140,18 @@ public class RunTestsViaEcj extends AbstractRunTests { sourceUnit = getSourceUnit(file, source); } catch (Throwable t) { t.printStackTrace(); - return false; + result.setChanged(false); + return result; } - Compiler ecjCompiler = new Compiler(createFileSystem(file, minVersion), ecjErrorHandlingPolicy(), ecjCompilerOptions(), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { + Compiler ecjCompiler = new Compiler(createFileSystem(file), ecjErrorHandlingPolicy(), ecjCompilerOptions(parameters), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { @Override protected synchronized void addCompilationUnit(ICompilationUnit inUnit, CompilationUnitDeclaration parsedUnit) { - if (inUnit == sourceUnit) compilationUnit_.set(parsedUnit); + if (inUnit == sourceUnit) { + compilationUnit_.set(parsedUnit); + if (parameters.isVerifyDiet()) { + result.setOutput(parsedUnit.toString()); + } + } super.addCompilationUnit(inUnit, parsedUnit); } }; @@ -161,24 +164,28 @@ public class RunTestsViaEcj extends AbstractRunTests { CategorizedProblem[] problems = compilationResult.getAllProblems(); if (problems != null) for (CategorizedProblem p : problems) { - messages.add(new CompilerMessage(p.getSourceLineNumber(), p.getSourceStart(), p.isError(), p.getMessage())); + result.addMessage(new CompilerMessage(p.getSourceLineNumber(), p.getSourceStart(), p.isError(), p.getMessage())); } CompilationUnitDeclaration cud = compilationUnit_.get(); - if (cud == null) result.append("---- No CompilationUnit provided by ecj ----"); - else { - String output = cud.toString(); - // starting somewhere around ecj16, the print code is a bit too cavalier with printing modifiers. - output = output.replace("non-sealed @val", "@val"); - result.append(output); + if (cud == null) { + result.setOutput("---- No CompilationUnit provided by ecj ----"); + } else { + if (!parameters.isVerifyDiet()) { + String output = cud.toString(); + // starting somewhere around ecj16, the print code is a bit too cavalier with printing modifiers. + output = output.replace("non-sealed @val", "@val"); + result.setOutput(output); + } + + if (eclipseAvailable()) { + EclipseDomConversion.toDomAst(cud, sourceArray); + } } - if (eclipseAvailable()) { - EclipseDomConversion.toDomAst(cud, sourceArray); - } - - return true; + result.setChanged(true); + return result; } @SuppressWarnings("unused") @@ -238,7 +245,7 @@ public class RunTestsViaEcj extends AbstractRunTests { } } - private FileSystem createFileSystem(File file, int minVersion) { + private FileSystem createFileSystem(File file) { List classpath = new ArrayList(); if (new File("bin/main").exists()) classpath.add("bin/main"); classpath.add("dist/lombok.jar"); diff --git a/test/core/src/lombok/TestParameters.java b/test/core/src/lombok/TestParameters.java new file mode 100644 index 00000000..dba7b990 --- /dev/null +++ b/test/core/src/lombok/TestParameters.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2024 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok; + +import java.util.Map; + +public class TestParameters { + private Long sourceVersion; + private Long targetVersion; + + // Javac only + private Integer minVersion; + private String encoding; + private Map formatPreferences; + private boolean checkPositions; + + // Eclipse/Ecj only + private boolean verifyDiet; + + public Long getSourceVersion() { + return sourceVersion; + } + + public void setSourceVersion(Long sourceVersion) { + this.sourceVersion = sourceVersion; + } + + public Long getTargetVersion() { + return targetVersion; + } + + public void setTargetVersion(Long targetVersion) { + this.targetVersion = targetVersion; + } + + public Integer getMinVersion() { + return minVersion; + } + + public void setMinVersion(Integer minVersion) { + this.minVersion = minVersion; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public Map getFormatPreferences() { + return formatPreferences; + } + + public void setFormatPreferences(Map formatPreferences) { + this.formatPreferences = formatPreferences; + } + + public boolean isCheckPositions() { + return checkPositions; + } + + public void setCheckPositions(boolean checkPositions) { + this.checkPositions = checkPositions; + } + + public boolean isVerifyDiet() { + return verifyDiet; + } + + public void setVerifyDiet(boolean verifyDiet) { + this.verifyDiet = verifyDiet; + } +} diff --git a/test/core/src/lombok/TransformationResult.java b/test/core/src/lombok/TransformationResult.java new file mode 100644 index 00000000..b0d45e44 --- /dev/null +++ b/test/core/src/lombok/TransformationResult.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok; + +import java.util.LinkedHashSet; + +import lombok.javac.CapturingDiagnosticListener.CompilerMessage; + +public class TransformationResult { + private boolean changed; + private boolean success; + private LinkedHashSet messages = new LinkedHashSet(); + private String output; + + public void addMessage(CompilerMessage message) { + getMessages().add(message); + } + + public void setOutput(String output) { + this.output = output; + } + + public String getOutput() { + return output; + } + + public boolean isChanged() { + return changed; + } + + public void setChanged(boolean changed) { + this.changed = changed; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public LinkedHashSet getMessages() { + return messages; + } +} diff --git a/test/transform/resource/after-delombok/LockedInInitializer.java b/test/transform/resource/after-delombok/LockedInInitializer.java new file mode 100644 index 00000000..a4b687fc --- /dev/null +++ b/test/transform/resource/after-delombok/LockedInInitializer.java @@ -0,0 +1,41 @@ +public class LockedInInitializer { + public static final Runnable LOCKED = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.util.concurrent.locks.Lock $lock = new java.util.concurrent.locks.ReentrantLock(); + @Override + public void run() { + this.$lock.lock(); + try { + System.out.println("test"); + } finally { + this.$lock.unlock(); + } + } + }; + public static final Runnable LOCKED_READ = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + @Override + public void run() { + this.$lock.readLock().lock(); + try { + System.out.println("test"); + } finally { + this.$lock.readLock().unlock(); + } + } + }; + public static final Runnable LOCKED_WRITE = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + @Override + public void run() { + this.$lock.writeLock().lock(); + try { + System.out.println("test"); + } finally { + this.$lock.writeLock().unlock(); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/SneakyThrowsInInitializer.java b/test/transform/resource/after-delombok/SneakyThrowsInInitializer.java new file mode 100644 index 00000000..b47dadc4 --- /dev/null +++ b/test/transform/resource/after-delombok/SneakyThrowsInInitializer.java @@ -0,0 +1,12 @@ +public class SneakyThrowsInInitializer { + public static final Runnable R = new Runnable() { + @Override + public void run() { + try { + System.out.println("test"); + } catch (final java.lang.Throwable $ex) { + throw lombok.Lombok.sneakyThrow($ex); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/SynchronizedInInitializer.java b/test/transform/resource/after-delombok/SynchronizedInInitializer.java new file mode 100644 index 00000000..c63f4e74 --- /dev/null +++ b/test/transform/resource/after-delombok/SynchronizedInInitializer.java @@ -0,0 +1,12 @@ +public class SynchronizedInInitializer { + public static final Runnable SYNCHRONIZED = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; + @Override + public void run() { + synchronized (this.$lock) { + System.out.println("test"); + } + } + }; +} diff --git a/test/transform/resource/after-ecj/LockedInInitializer.java b/test/transform/resource/after-ecj/LockedInInitializer.java new file mode 100644 index 00000000..aea88d0d --- /dev/null +++ b/test/transform/resource/after-ecj/LockedInInitializer.java @@ -0,0 +1,49 @@ +import lombok.Locked; +public class LockedInInitializer { + public static final Runnable LOCKED = new Runnable() { + private final java.util.concurrent.locks.Lock $lock = new java.util.concurrent.locks.ReentrantLock(); + public @Override @Locked void run() { + this.$lock.lock(); + try + { + System.out.println("test"); + } + finally + { + this.$lock.unlock(); + } + } + }; + public static final Runnable LOCKED_READ = new Runnable() { + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + public @Override @Locked.Read void run() { + this.$lock.readLock().lock(); + try + { + System.out.println("test"); + } + finally + { + this.$lock.readLock().unlock(); + } + } + }; + public static final Runnable LOCKED_WRITE = new Runnable() { + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + public @Override @Locked.Write void run() { + this.$lock.writeLock().lock(); + try + { + System.out.println("test"); + } + finally + { + this.$lock.writeLock().unlock(); + } + } + }; + () { + } + public LockedInInitializer() { + } +} diff --git a/test/transform/resource/after-ecj/SneakyThrowsInInitializer.java b/test/transform/resource/after-ecj/SneakyThrowsInInitializer.java new file mode 100644 index 00000000..2e981b02 --- /dev/null +++ b/test/transform/resource/after-ecj/SneakyThrowsInInitializer.java @@ -0,0 +1,19 @@ +import lombok.SneakyThrows; +public class SneakyThrowsInInitializer { + public static final Runnable R = new Runnable() { + public @Override @SneakyThrows void run() { + try + { + System.out.println("test"); + } + catch (final java.lang.Throwable $ex) + { + throw lombok.Lombok.sneakyThrow($ex); + } + } + }; + () { + } + public SneakyThrowsInInitializer() { + } +} diff --git a/test/transform/resource/after-ecj/SynchronizedInInitializer.java b/test/transform/resource/after-ecj/SynchronizedInInitializer.java new file mode 100644 index 00000000..dad6ff8d --- /dev/null +++ b/test/transform/resource/after-ecj/SynchronizedInInitializer.java @@ -0,0 +1,16 @@ +import lombok.Synchronized; +public class SynchronizedInInitializer { + public static final Runnable SYNCHRONIZED = new Runnable() { + private final java.lang.Object $lock = new java.lang.Object[0]; + public @Override @Synchronized void run() { + synchronized (this.$lock) + { + System.out.println("test"); + } + } + }; + () { + } + public SynchronizedInInitializer() { + } +} diff --git a/test/transform/resource/before/LockedInInitializer.java b/test/transform/resource/before/LockedInInitializer.java new file mode 100644 index 00000000..f4df0247 --- /dev/null +++ b/test/transform/resource/before/LockedInInitializer.java @@ -0,0 +1,26 @@ +//eclipse: verify diet +import lombok.Locked; + +public class LockedInInitializer { + public static final Runnable LOCKED = new Runnable() { + @Override + @Locked + public void run() { + System.out.println("test"); + } + }; + public static final Runnable LOCKED_READ = new Runnable() { + @Override + @Locked.Read + public void run() { + System.out.println("test"); + } + }; + public static final Runnable LOCKED_WRITE = new Runnable() { + @Override + @Locked.Write + public void run() { + System.out.println("test"); + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/SneakyThrowsInInitializer.java b/test/transform/resource/before/SneakyThrowsInInitializer.java new file mode 100644 index 00000000..87f77309 --- /dev/null +++ b/test/transform/resource/before/SneakyThrowsInInitializer.java @@ -0,0 +1,15 @@ +//eclipse: verify diet +import lombok.SneakyThrows; + +public class SneakyThrowsInInitializer { + + public static final Runnable R = new Runnable() { + + @Override + @SneakyThrows + public void run() { + System.out.println("test"); + + } + }; +} diff --git a/test/transform/resource/before/SynchronizedInInitializer.java b/test/transform/resource/before/SynchronizedInInitializer.java new file mode 100644 index 00000000..4d295d9e --- /dev/null +++ b/test/transform/resource/before/SynchronizedInInitializer.java @@ -0,0 +1,12 @@ +//eclipse: verify diet +import lombok.Synchronized; + +public class SynchronizedInInitializer { + public static final Runnable SYNCHRONIZED = new Runnable() { + @Override + @Synchronized + public void run() { + System.out.println("test"); + } + }; +} \ No newline at end of file