From commits-return-26355-archive-asf-public=cust-asf.ponee.io@netbeans.apache.org Sat Dec 28 16:58:26 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id B0814180607 for ; Sat, 28 Dec 2019 17:58:25 +0100 (CET) Received: (qmail 2523 invoked by uid 500); 28 Dec 2019 16:58:25 -0000 Mailing-List: contact commits-help@netbeans.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Delivered-To: mailing list commits@netbeans.apache.org Received: (qmail 2513 invoked by uid 99); 28 Dec 2019 16:58:25 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 28 Dec 2019 16:58:25 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id DA8808D80D; Sat, 28 Dec 2019 16:58:24 +0000 (UTC) Date: Sat, 28 Dec 2019 16:58:24 +0000 To: "commits@netbeans.apache.org" Subject: [netbeans] branch master updated: If an annotation processor crashes, just log the error and continue, rather than crash the whole processing. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <157755230465.4815.5799906010998284849@gitbox.apache.org> From: jlahoda@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: netbeans X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 29a1ad932472111195fb9af4d086b523b1e8f257 X-Git-Newrev: 20cf9519f592e4341c32e00dda5f525c1da8c597 X-Git-Rev: 20cf9519f592e4341c32e00dda5f525c1da8c597 X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated This is an automated email from the ASF dual-hosted git repository. jlahoda pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git The following commit(s) were added to refs/heads/master by this push: new 20cf951 If an annotation processor crashes, just log the error and continue, rather than crash the whole processing. 20cf951 is described below commit 20cf9519f592e4341c32e00dda5f525c1da8c597 Author: Jan Lahoda AuthorDate: Sat Dec 28 17:58:08 2019 +0100 If an annotation processor crashes, just log the error and continue, rather than crash the whole processing. --- .../modules/java/source/indexing/APTUtils.java | 77 +++++- .../java/source/indexing/CrashingAPTest.java | 258 +++++++++++++++++++++ 2 files changed, 334 insertions(+), 1 deletion(-) diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java b/java/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java index 5da0008..35c7719 100644 --- a/java/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java +++ b/java/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java @@ -18,6 +18,8 @@ */ package org.netbeans.modules.java.source.indexing; +import com.sun.tools.javac.util.Abort; +import com.sun.tools.javac.util.ClientCodeException; import com.sun.tools.javac.util.Context; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -50,9 +52,18 @@ import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import javax.annotation.processing.Completion; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import javax.tools.Diagnostic; import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.annotations.common.NullAllowed; @@ -77,6 +88,7 @@ import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.RequestProcessor; import org.openide.util.BaseUtilities; +import org.openide.util.NbBundle.Messages; import org.openide.util.Pair; import org.openide.util.WeakListeners; import org.openide.util.lookup.Lookups; @@ -359,7 +371,7 @@ public class APTUtils implements ChangeListener, PropertyChangeListener { Class clazz = Class.forName(name, true, cl); Object instance = clazz.newInstance(); if (instance instanceof Processor) { - result.add((Processor) instance); + result.add(new ErrorToleratingProcessor((Processor) instance)); } } catch (ThreadDeath td) { throw td; @@ -929,4 +941,67 @@ public class APTUtils implements ChangeListener, PropertyChangeListener { } } } + + private static final class ErrorToleratingProcessor implements Processor { + + private final Processor delegate; + private ProcessingEnvironment processingEnv; + private boolean valid = true; + + public ErrorToleratingProcessor(Processor delegate) { + this.delegate = delegate; + } + + @Override + public Set getSupportedOptions() { + return delegate.getSupportedOptions(); + } + + @Override + public Set getSupportedAnnotationTypes() { + return delegate.getSupportedAnnotationTypes(); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return delegate.getSupportedSourceVersion(); + } + + @Override + public void init(ProcessingEnvironment processingEnv) { + delegate.init(processingEnv); + this.processingEnv = processingEnv; + } + + @Override + @Messages("ERR_ProcessorException=Annotation processor {0} failed with an exception: {1}") + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!valid) { + return false; + } + try { + return delegate.process(annotations, roundEnv); + } catch (ClientCodeException | ThreadDeath | Abort err) { + valid = false; + throw err; + } catch (Throwable t) { + valid = false; + Element el = roundEnv.getRootElements().isEmpty() ? null : roundEnv.getRootElements().iterator().next(); + StringBuilder exception = new StringBuilder(); + exception.append(t.getMessage()).append("\n"); + for (StackTraceElement ste : t.getStackTrace()) { + exception.append(ste).append("\n"); + } + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, Bundle.ERR_ProcessorException(delegate.getClass().getName(), exception.toString()), el); + return false; + } + } + + @Override + public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { + return delegate.getCompletions(element, annotation, member, userText); + } + + } + } diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/CrashingAPTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/CrashingAPTest.java new file mode 100644 index 0000000..39d7f3b --- /dev/null +++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/CrashingAPTest.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.java.source.indexing; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import junit.framework.*; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.TypeElement; +import javax.swing.event.ChangeListener; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.classpath.JavaClassPathConstants; +import org.netbeans.api.java.queries.AnnotationProcessingQuery; +import org.netbeans.api.java.queries.AnnotationProcessingQuery.Result; +import org.netbeans.api.java.queries.AnnotationProcessingQuery.Trigger; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.Task; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.java.source.TestUtil; +import org.netbeans.modules.java.source.usages.IndexUtil; +import org.netbeans.spi.java.classpath.ClassPathProvider; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation; +import org.netbeans.spi.java.queries.SourceLevelQueryImplementation; +import org.openide.filesystems.FileLock; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ProxyLookup; + +public class CrashingAPTest extends NbTestCase { + + private FileObject src; + private FileObject data; + + static { + CrashingAPTest.class.getClassLoader().setDefaultAssertionStatus(true); + System.setProperty("org.openide.util.Lookup", CrashingAPTest.Lkp.class.getName()); + Assert.assertEquals(CrashingAPTest.Lkp.class, Lookup.getDefault().getClass()); + } + + public static class Lkp extends ProxyLookup { + + private static Lkp DEFAULT; + + public Lkp () { + Assert.assertNull(DEFAULT); + DEFAULT = this; + ClassLoader l = Lkp.class.getClassLoader(); + this.setLookups( + new Lookup [] { + Lookups.metaInfServices(l), + Lookups.singleton(l), + Lookups.singleton(ClassPathProviderImpl.getDefault()), + Lookups.singleton(SourceLevelQueryImpl.getDefault()), + Lookups.singleton(new APQImpl()), + }); + } + + } + + + public CrashingAPTest(String testName) { + super(testName); + } + + protected void setUp() throws Exception { + clearWorkDir(); + File workDir = getWorkDir(); + File cacheFolder = new File (workDir, "cache"); //NOI18N + cacheFolder.mkdirs(); + IndexUtil.setCacheFolder(cacheFolder); + FileObject wd = FileUtil.toFileObject(this.getWorkDir()); + assertNotNull(wd); + this.src = wd.createFolder("src"); + this.data = src.createData("Test","java"); + FileLock lock = data.lock(); + try { + PrintWriter out = new PrintWriter ( new OutputStreamWriter (data.getOutputStream(lock))); + try { + out.println ("public class Test {}"); + } finally { + out.close (); + } + } finally { + lock.releaseLock(); + } + ClassPathProviderImpl.getDefault().setClassPaths(TestUtil.getBootClassPath(), + ClassPathSupport.createClassPath(new URL[0]), + ClassPathSupport.createClassPath(new FileObject[]{this.src}), + ClassPathSupport.createClassPath(System.getProperty("java.class.path"))); + } + + public void testElementHandle() throws Exception { + final JavaSource js = JavaSource.forFileObject(data); + assertNotNull(js); + + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws IOException { + parameter.toPhase(Phase.RESOLVED); + List messages = parameter.getDiagnostics() + .stream() + .map(d -> d.getMessage(null)) + .map(m -> firstLine(m)) + .collect(Collectors.toList()); + List expected = Arrays.asList(Bundle.ERR_ProcessorException("org.netbeans.modules.java.source.indexing.CrashingAPTest$TestAP", "Crash")); + assertEquals(expected, messages); + } + },true); + } + + private String firstLine(String m) { + int newLine = m.indexOf('\n'); + if (newLine == (-1)) return m; + return m.substring(0, newLine); + } + + private static class ClassPathProviderImpl implements ClassPathProvider { + + private static ClassPathProviderImpl instance; + + private ClassPath compile; + private ClassPath boot; + private ClassPath src; + private ClassPath processorPath; + + private ClassPathProviderImpl () { + + } + + public synchronized ClassPath findClassPath(FileObject file, String type) { + if (ClassPath.COMPILE.equals(type)) { + return compile; + } + else if (ClassPath.BOOT.equals(type)) { + return boot; + } + else if (ClassPath.SOURCE.equals(type)) { + return src; + } + else if (JavaClassPathConstants.PROCESSOR_PATH.equals(type)) { + return processorPath; + } + else { + return null; + } + } + + public synchronized void setClassPaths (ClassPath boot, ClassPath compile, ClassPath src, ClassPath processorPath) { + this.boot = boot; + this.compile = compile; + this.src = src; + this.processorPath = processorPath; + } + + public static synchronized ClassPathProviderImpl getDefault () { + if (instance == null) { + instance = new ClassPathProviderImpl (); + } + return instance; + } + } + + private static class SourceLevelQueryImpl implements SourceLevelQueryImplementation { + + private static SourceLevelQueryImpl instance; + + private SourceLevelQueryImpl() {} + + @Override + public String getSourceLevel(FileObject javaFile) { + return "8"; + } + + public static synchronized SourceLevelQueryImpl getDefault () { + if (instance == null) { + instance = new SourceLevelQueryImpl(); + } + return instance; + } + } + + private static class APQImpl implements AnnotationProcessingQueryImplementation { + + private final Result result = new Result() { + public @NonNull Set annotationProcessingEnabled() { + return EnumSet.allOf(Trigger.class); + } + + public @CheckForNull Iterable annotationProcessorsToRun() { + return Arrays.asList(TestAP.class.getName()); + } + + public @CheckForNull URL sourceOutputDirectory() { + return null; + } + + public @NonNull Map processorOptions() { + return Collections.emptyMap(); + } + + public void addChangeListener(@NonNull ChangeListener l) {} + + public void removeChangeListener(@NonNull ChangeListener l) {} + }; + @Override + public AnnotationProcessingQuery.Result getAnnotationProcessingOptions(FileObject file) { + return result; + } + + } + + @SupportedAnnotationTypes("*") + public static class TestAP extends AbstractProcessor { + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + throw new IllegalStateException("Crash"); + } + } + + static { + System.setProperty("SourcePath.no.source.filter", "true"); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org For additional commands, e-mail: commits-help@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists