8224177: Harden annotation processing framework to irregular behavior from processors

Reviewed-by: jjg
This commit is contained in:
Joe Darcy 2019-05-23 18:47:24 -07:00
parent 64d0470860
commit 4dd6b687ef
9 changed files with 405 additions and 19 deletions

View File

@ -686,11 +686,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
static class ProcessorState {
public Processor processor;
public boolean contributed;
private ArrayList<Pattern> supportedAnnotationPatterns;
private ArrayList<String> supportedOptionNames;
private Set<String> supportedAnnotationStrings; // Used for warning generation
private Set<Pattern> supportedAnnotationPatterns;
private Set<String> supportedOptionNames;
ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh,
boolean allowModules, ProcessingEnvironment env) {
boolean allowModules, ProcessingEnvironment env, boolean lint) {
processor = p;
contributed = false;
@ -700,18 +701,46 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
checkSourceVersionCompatibility(source, log);
supportedAnnotationPatterns = new ArrayList<>();
for (String importString : processor.getSupportedAnnotationTypes()) {
supportedAnnotationPatterns.add(importStringToPattern(allowModules,
importString,
processor,
log));
// Check for direct duplicates in the strings of
// supported annotation types. Do not check for
// duplicates that would result after stripping of
// module prefixes.
supportedAnnotationStrings = new LinkedHashSet<>();
supportedAnnotationPatterns = new LinkedHashSet<>();
for (String annotationPattern : processor.getSupportedAnnotationTypes()) {
boolean patternAdded = supportedAnnotationStrings.add(annotationPattern);
supportedAnnotationPatterns.
add(importStringToPattern(allowModules, annotationPattern,
processor, log, lint));
if (lint && !patternAdded) {
log.warning(Warnings.ProcDuplicateSupportedAnnotation(annotationPattern,
p.getClass().getName()));
}
}
supportedOptionNames = new ArrayList<>();
// If a processor supports "*", that matches
// everything and other entries are redundant. With
// more work, it could be checked that the supported
// annotation types were otherwise non-overlapping
// with each other in other cases, for example "foo.*"
// and "foo.bar.*".
if (lint &&
supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) &&
supportedAnnotationPatterns.size() > 1) {
log.warning(Warnings.ProcRedundantTypesWithWildcard(p.getClass().getName()));
}
supportedOptionNames = new LinkedHashSet<>();
for (String optionName : processor.getSupportedOptions() ) {
if (checkOptionName(optionName, log))
supportedOptionNames.add(optionName);
if (checkOptionName(optionName, log)) {
boolean optionAdded = supportedOptionNames.add(optionName);
if (lint && !optionAdded) {
log.warning(Warnings.ProcDuplicateOptionName(optionName,
p.getClass().getName()));
}
}
}
} catch (ClientCodeException e) {
@ -797,7 +826,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
log, source, dcfh,
Feature.MODULES.allowedInSource(source),
JavacProcessingEnvironment.this);
JavacProcessingEnvironment.this,
lint);
psi.procStateList.add(ps);
return ps;
} else
@ -1705,7 +1735,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
* regex matching that string. If the string is not a valid
* import-style string, return a regex that won't match anything.
*/
private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log) {
private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, boolean lint) {
String module;
String pkg;
int slash = s.indexOf('/');
@ -1716,17 +1746,28 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
module = allowModules ? ".*/" : "";
pkg = s;
} else {
module = Pattern.quote(s.substring(0, slash + 1));
String moduleName = s.substring(0, slash);
if (!SourceVersion.isIdentifier(moduleName)) {
return warnAndNoMatches(s, p, log, lint);
}
module = Pattern.quote(moduleName + "/");
// And warn if module is specified if modules aren't supported, conditional on -Xlint:proc?
pkg = s.substring(slash + 1);
}
if (MatchingUtils.isValidImportString(pkg)) {
return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg));
} else {
log.warning(Warnings.ProcMalformedSupportedString(s, p.getClass().getName()));
return noMatches; // won't match any valid identifier
return warnAndNoMatches(s, p, log, lint);
}
}
private static Pattern warnAndNoMatches(String s, Processor p, Log log, boolean lint) {
if (lint) {
log.warning(Warnings.ProcMalformedSupportedString(s, p.getClass().getName()));
}
return noMatches; // won't match any valid identifier
}
/**
* For internal use only. This method may be removed without warning.
*/

View File

@ -1911,6 +1911,18 @@ compiler.warn.proc.annotations.without.processors=\
compiler.warn.proc.processor.incompatible.source.version=\
Supported source version ''{0}'' from annotation processor ''{1}'' less than -source ''{2}''
# 0: string, 1: string
compiler.warn.proc.duplicate.option.name=\
Duplicate supported option ''{0}'' returned by annotation processor ''{1}''
# 0: string, 1: string
compiler.warn.proc.duplicate.supported.annotation=\
Duplicate supported annotation type ''{0}'' returned by annotation processor ''{1}''
# 0: string
compiler.warn.proc.redundant.types.with.wildcard=\
Annotation processor ''{0}'' redundantly supports both ''*'' and other annotation types
compiler.warn.proc.proc-only.requested.no.procs=\
Annotation processing without compilation requested but no processors were found.

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.warn.proc.duplicate.option.name
// key: compiler.warn.proc.duplicate.supported.annotation
// options: -processor AnnoProc -Xlint:processing
class DuplicateSupportedInfoFromProc { }

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
public class AnnoProc extends AbstractProcessor {
public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv) {
return true;
}
@Override
public Set<String> getSupportedOptions() {
IdentityHashMap<String, Integer> temp = new IdentityHashMap<>();
temp.put(new String("foo"), 1);
temp.put(new String("foo"), 2);
// Return a set with two copies of the option name "foo".
return temp.keySet();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
IdentityHashMap<String, Integer> temp = new IdentityHashMap<>();
temp.put(new String("java.lang.SupressWarnings"), 1);
temp.put(new String("java.lang.SupressWarnings"), 2);
// Return a set with two copies of the annotation type name.
return temp.keySet();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,6 +22,6 @@
*/
// key: compiler.warn.proc.malformed.supported.string
// options: -processor AnnoProc
// options: -processor AnnoProc -Xlint:processing
class MalformedSupported { }

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.warn.proc.redundant.types.with.wildcard
// options: -processor AnnoProc -Xlint:processing
class RedundantTypesWithWildcardProc { }

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes({"java.lang.SuppressWarnings", "*"})
public class AnnoProc extends AbstractProcessor {
public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv) {
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8224177
* @summary Test warnings from the annotation processing runtime about malformed supported information from processors.
* @compile TestRepeatedItemsRuntime.java
* @compile/ref=gold_sv_none.out -XDrawDiagnostics -processor TestRepeatedItemsRuntime -proc:only TestRepeatedItemsRuntime.java
* @compile/ref=auric_current.out -XDrawDiagnostics -processor TestRepeatedItemsRuntime -proc:only -Xlint:processing TestRepeatedItemsRuntime.java
*/
import java.lang.annotation.*;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
/**
* A warning should be issued by the logic in
* javax.annotation.processing.AbstractProcessor for the repeated
* information. The "Foo" option warnings occur regardless of source
* level. The number of times the Baz annotation type is repeated
* depends on whether or not the source level supports modules.
*/
@Quux
public class TestRepeatedItemsRuntime extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override
public Set<String>getSupportedOptions() {
IdentityHashMap<String, Integer> temp = new IdentityHashMap<>();
// Use String constructor for identity map.
temp.put(new String("foo"), 1);
temp.put(new String("foo"), 2);
var returnValue = temp.keySet();
assert returnValue.size() == 2;
return returnValue;
}
/**
* Partial implementation of the Set interface with identity
* semantics and predictable iteration order.
*
* The javax.annotation.processing.Processor protocol relies on
* the iterator.
*/
private static class ArrayBackedSet implements Set<String> {
private static String[] data = {"Quux",
"Quux",
"&&&/foo.Bar",
"foo.Bar",
"foo.Bar",
"quux/Quux",
"*"};
public ArrayBackedSet() {}
// Return an iterator of known iteration order so the set warning messages will be predictable.
@Override
public Iterator<String> iterator() {
return Arrays.asList(data).iterator();
}
@Override
public boolean add(String e) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends String> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object o){
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public int hashCode() {
int hash = 0;
for (String s : data) {
hash += s.hashCode();
}
return hash;
}
@Override
public boolean isEmpty() {
return data.length > 0;
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return data.length;
}
@Override
public Object[] toArray() {
return data.clone();
}
@Override
public <T> T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
}
@Override
public Set<String>getSupportedAnnotationTypes() {
return new ArrayBackedSet();
}
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnvironment) {
return true;
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Quux {
}

View File

@ -0,0 +1,6 @@
- compiler.warn.proc.duplicate.supported.annotation: Quux, TestRepeatedItemsRuntime
- compiler.warn.proc.malformed.supported.string: &&&/foo.Bar, TestRepeatedItemsRuntime
- compiler.warn.proc.duplicate.supported.annotation: foo.Bar, TestRepeatedItemsRuntime
- compiler.warn.proc.redundant.types.with.wildcard: TestRepeatedItemsRuntime
- compiler.warn.proc.duplicate.option.name: foo, TestRepeatedItemsRuntime
5 warnings