@ -134,6 +134,15 @@ final class ClassStub implements JClassSymbol, AsmStub, AnnotationOwner {
|
||||
: HashTreePSet.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canReenter() {
|
||||
// We might call the parsing logic again in the same thread,
|
||||
// e.g. in order to determine "annotAttributes", getDeclaredMethods() is called, which
|
||||
// calls ensureParsed().
|
||||
// Note: Other threads can't reenter, since our thread own the ParseLock monitor.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean postCondition() {
|
||||
return signature != null && enclosingInfo != null;
|
||||
|
@ -163,7 +163,7 @@ abstract class GenericSigBase<T extends JTypeParameterOwnerSymbol & AsmStub> {
|
||||
|
||||
@Override
|
||||
protected boolean postCondition() {
|
||||
return (superItfs != null && superType != null || signature == null) && typeParameters != null;
|
||||
return superItfs != null && (superType != null || signature == null) && typeParameters != null;
|
||||
}
|
||||
|
||||
void setSuperInterfaces(List<JClassType> supers) {
|
||||
|
@ -32,14 +32,22 @@ abstract class ParseLock {
|
||||
try {
|
||||
boolean success = doParse();
|
||||
status = success ? ParseStatus.FULL : ParseStatus.FAILED;
|
||||
this.status = status;
|
||||
finishParse(!success);
|
||||
} catch (Throwable t) {
|
||||
status = ParseStatus.FAILED;
|
||||
this.status = status;
|
||||
LOG.error(t.toString(), t);
|
||||
finishParse(true);
|
||||
}
|
||||
|
||||
// the status must be updated as last statement, so that
|
||||
// other threads see the status FULL or FAILED only after finishParse()
|
||||
// returns. Otherwise, some fields might not have been initialized.
|
||||
//
|
||||
// Note: the current thread might reenter the parsing logic through
|
||||
// finishParse() -> ... -> ensureParsed(). In that case the status is still BEING_PARSED,
|
||||
// and we don't call finishParse() again. See below for canReenter()
|
||||
this.status = status;
|
||||
|
||||
assert status.isFinished : "Inconsistent status " + status;
|
||||
assert postCondition() : "Post condition not satisfied after parsing sig " + this;
|
||||
} else if (status == ParseStatus.BEING_PARSED && !canReenter()) {
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symbols.internal.asm;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pcollections.PSet;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeSystem;
|
||||
|
||||
class ClassStubTest {
|
||||
// while parsing the annotation type, ClassStub's parseLock.ensureParsed()
|
||||
// is called multiple times, reentering the parselock while the status is
|
||||
// still BEING_PARSED.
|
||||
@Test
|
||||
void loadAndParseAnnotation() {
|
||||
// class stub - annotation type
|
||||
TypeSystem typeSystem = TypeSystem.usingClassLoaderClasspath(JavaParsingHelper.class.getClassLoader());
|
||||
JClassSymbol classSymbol = typeSystem.getClassSymbol("java.lang.Deprecated");
|
||||
PSet<String> annotationAttributeNames = classSymbol.getAnnotationAttributeNames();
|
||||
assertFalse(annotationAttributeNames.isEmpty());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user