diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/NameResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/NameResolver.java index 931e02d21d..e2704e20f3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/NameResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/NameResolver.java @@ -99,6 +99,11 @@ public interface NameResolver { } return null; } + + @Override + public String toString() { + return "Composite[" + resolvers + "]"; + } }; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainIteratorImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainIteratorImpl.java index e81b8175dc..fc234944b6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainIteratorImpl.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainIteratorImpl.java @@ -34,7 +34,7 @@ class ShadowChainIteratorImpl done(); return; } - assert !next.getResolver().resolveHere(name).isEmpty() : "Shadow iterator stopped on wrong node"; + assert !next.resolveHere(name).isEmpty() : "Shadow iterator stopped on wrong node"; setNext(next); } @@ -55,7 +55,7 @@ class ShadowChainIteratorImpl @Override public List getResults() { - return getCurrentValue().getResolver().resolveHere(name); + return getCurrentValue().resolveHere(name); } // inclusive of the parameter diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNode.java index 7eae4d4cf0..1fdaa64217 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNode.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.symbols.table.coreimpl; +import java.util.List; + import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.util.OptionalBool; @@ -36,6 +38,13 @@ public interface ShadowChainNode { */ NameResolver getResolver(); + /** + * Wraps {@link #getResolver()}{@code .resolveHere()}, may do + * additional stuff like caching. + */ + default List resolveHere(String simpleName) { + return getResolver().resolveHere(simpleName); + } /** * Returns whether this node knows the given symbol (without asking diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNodeBase.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNodeBase.java index 3d5c955c2f..c547c88611 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNodeBase.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/coreimpl/ShadowChainNodeBase.java @@ -81,19 +81,33 @@ class ShadowChainNodeBase implements ShadowChain, ShadowChainNode resolve(String name) { - List res = resolver.resolveHere(name); - handleResolverKnows(name, !res.isEmpty()); + List res = this.resolveHere(name); if (res.isEmpty()) { + // failed, continue return getParent().asChain().resolve(name); - } else if (!isShadowBarrier()) { - // A successful search ends on the first node that is a - // shadow barrier, inclusive - // A failed search continues regardless - return merger.apply(res, getParent().asChain().resolve(name)); + } else { + // successful search: fetch all non-shadowed names + // note: we can't call ShadowChain::resolve on the parent + // as it would ignore the shadow barriers if the parent + // does not know the name. + ShadowChainNode node = this; + while (!node.isShadowBarrier() && node.getParent() != null) { + // The search ends on the first node that is a + // shadow barrier, inclusive. + node = node.getParent(); + res = merger.apply(res, node.resolveHere(name)); + } } return res; } + @Override + public List resolveHere(String simpleName) { + List res = resolver.resolveHere(simpleName); + handleResolverKnows(simpleName, !res.isEmpty()); + return res; + } + protected void handleResolverKnows(String name, boolean resolverKnows) { // to be overridden } diff --git a/pmd-java/src/test/java/javasymbols/testdata/deep/StaticContainer.java b/pmd-java/src/test/java/javasymbols/testdata/deep/StaticContainer.java new file mode 100644 index 0000000000..28f2c69694 --- /dev/null +++ b/pmd-java/src/test/java/javasymbols/testdata/deep/StaticContainer.java @@ -0,0 +1,15 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package javasymbols.testdata.deep; + +public class StaticContainer { + + /** + * Shadows a java.lang member + */ + public static class Exception { + + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java index 2ce3b7e540..c942139e0d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.java; import java.io.PrintStream; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -12,6 +13,7 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; @@ -126,4 +128,41 @@ public class JavaParsingHelper extends BaseParsingHelper, T : RootNode protected abstract fun clone(params: Params): Self @JvmOverloads - fun withProcessing(boolean: Boolean = true): Self = - clone(params.copy(doProcess = boolean)) + fun withProcessing(doProcess: Boolean = true): Self = + clone(params.copy(doProcess = doProcess)) /** * Returns an instance of [Self] for which all parsing methods