Bug 498925: NullPointerException in Config.delegateGetMethodBodies
- assumed fix in 2 parts
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
index 7de8fdf..2863b92 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
@@ -433,6 +433,8 @@
this.totalUnits);
//{ObjectTeams: record 'place' for external invocation of getMethodBodies:
parsedUnit.place = this.totalUnits;
+ if (parsedUnit.scope != null)
+ parsedUnit.scope.parser = this.parser;
// SH}
this.unitsToProcess[this.totalUnits++] = parsedUnit;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
index f965ff6..c6e2a02 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -96,6 +96,8 @@
private ArrayList<Invocation> inferredInvocations;
//{ObjectTeams: when used as a baseimport scope, remember the original scope during this current lookup
public Scope originalScope;
+ // store parser for on-demand Dependencies.setup() lateron:
+ public Parser parser;
// SH}
public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
@@ -902,7 +904,7 @@
boolean createdConfig = false;
if (!Config.hasLookupEnvironment()) {
createdConfig = true;
- Dependencies.setup(this, null, environment(), false, true);
+ Dependencies.setup(this, this.parser, environment(), false, true);
}
try {
//SH}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index bc58cff..503776a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -3736,7 +3736,7 @@
boolean createdConfig = false;
if (!Config.hasLookupEnvironment()) {
createdConfig = true;
- Dependencies.setup(this, null, environment(), false, true);
+ Dependencies.setup(this, compilationUnitScope().parser, environment(), false, true);
}
try {
// SH}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Config.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Config.java
index 046d47b..93b2dc4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Config.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Config.java
@@ -20,7 +20,9 @@
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.compiler.control;
+import java.lang.ref.WeakReference;
import java.util.Stack;
+import java.util.WeakHashMap;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -62,7 +64,7 @@
}
}
- Object client;
+ WeakReference<Object> client;
Parser parser;
Parser plainParser; // alternate parser when client is a MatchLocator
LookupEnvironment lookupEnvironment;
@@ -116,6 +118,8 @@
// (entries are removed explicitly using release)
private static final ThreadLocal<Stack<Config>> _configs = new ThreadLocal<Stack<Config>>();
+ static final WeakHashMap<Object, Config> configsByClient = new WeakHashMap<>();
+
public static void addConfig(Config config)
{
synchronized (_configs) {
@@ -134,6 +138,8 @@
configStack.push(config);
}
+ if (config.client != null && config.client.get() != null)
+ configsByClient.put(config.client.get(), config);
}
/**
@@ -157,7 +163,7 @@
_configs.set(configStack);
Config config = new Config();
- config.client = client;
+ config.client = new WeakReference<>(client);
configStack.push(config);
return null; // no old config
} else {
@@ -167,6 +173,7 @@
clone.castRequired = existing.castRequired;
clone.loweringRequired = existing.loweringRequired;
clone.loweringPossible = existing.loweringPossible;
+ clone.client = new WeakReference<>(null);
existing.castRequired = null;
existing.loweringRequired = false;
existing.loweringPossible = false;
@@ -209,7 +216,8 @@
{
Config config = configStack.pop(); // remove Config
assert(config != null);
- if (config.client != client && config.client != null) // bad balance of addConfig and removeConfig calls
+ Object theClient = config.client.get();
+ if (theClient != client && theClient != null) // bad balance of addConfig and removeConfig calls
{
assert(false);
configStack.push(config); // be defensive, put it back
@@ -395,12 +403,13 @@
public static void delegateGetMethodBodies(CompilationUnitDeclaration unit) {
Config config = getConfig();
Parser parser = config.parser();
- if (config.client instanceof ITypeRequestor) {
+ Object theClient = config.client.get();
+ if (theClient instanceof ITypeRequestor) {
// MatchLocator.getMethodBodies and MatchLocatorParser.getMethodBodies
// both contribute to locating matches. Unit parser on behalf of
// Dependencies should however be parsed using a plain Parser:
if (config.plainParser == null)
- config.plainParser = ((ITypeRequestor)config.client).getPlainParser();
+ config.plainParser = ((ITypeRequestor)theClient).getPlainParser();
if (config.plainParser != null)
parser = config.plainParser;
}
@@ -433,14 +442,16 @@
*/
public static boolean clientIsCompiler() {
Config config = getConfig();
- return (config != null && config.client instanceof Compiler);
+ return (config != null && config.client.get() instanceof Compiler);
}
public static boolean clientIsBatchCompiler() {
Config config = safeGetConfig();
- return ( config != null
- && config.client instanceof Compiler
- && ((Compiler)config.client).isBatchCompiler);
+ if (config == null)
+ return false;
+ Object client = config.client.get();
+ return ( client instanceof Compiler
+ && ((Compiler)client).isBatchCompiler);
}
/**
@@ -474,4 +485,9 @@
exception.printStackTrace(System.err);
}
+ public boolean clientHasExactClass(Class<?> clazz) {
+ Object theClient = this.client.get();
+ return theClient != null && theClient.getClass() == clazz;
+ }
+
}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java
index f5fa74b..94e13ab 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java
@@ -20,8 +20,10 @@
package org.eclipse.objectteams.otdt.internal.core.compiler.control;
+import java.lang.ref.WeakReference;
import java.util.Iterator;
+import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
@@ -127,8 +129,11 @@
boolean bundledCompleteTypeBindings,
boolean strictDiet)
{
- Config config = new Config();
- config.client = client;
+ Config config = Config.configsByClient.get(client);
+ if (config != null && (config.parser != null || parser == null))
+ return config;
+ config = new Config();
+ config.client = new WeakReference<>(client);
config.parser = parser;
config.lookupEnvironment = lookupEnvironment;
config.verifyMethods = verifyMethods;
@@ -1108,7 +1113,7 @@
for (int j = 0; j < unit.types.length; j++) {
if (unit.types[j].isRole()) {
if (unit.types.length != 1) {
- if (Config.getConfig().client.getClass() == Compiler.class) // exact match.
+ if (Config.getConfig().clientHasExactClass(Compiler.class))
{
environment.problemReporter.roleFileMustDeclareOneType(unit);
return;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
index c83304e..6cf13a0 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
@@ -818,7 +818,7 @@
BlockScope blockScope = (BlockScope) this.astNodesToBlockScope.get(expression);
if (blockScope != null) {
//{ObjectTeams: calling into the compiler needs dependencies configured:
- Dependencies.setup(this, null, lookupEnvironment(), false, false, false, true, true, false);
+ Dependencies.setup(this, blockScope.compilationUnitScope().parser, lookupEnvironment(), false, false, false, true, true, false);
try {
// orig:
return this.getTypeBinding(thisReference.resolveType(blockScope));
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
index a869e24..2b4efd1 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
@@ -41,6 +41,7 @@
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.JavaElement;
@@ -133,18 +134,36 @@
}
if (refType != null) {
//{ObjectTeams: calling getAnnotations() requires Dependencies control:
- Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, true); // TODO(SH): parser, flags?
+ setupDependencies();
try {
// orig:
return this.annotations = resolveAnnotationBindings(refType.getAnnotations(), false);
// :giro
} finally {
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
// SH}
}
return this.annotations = AnnotationBinding.NoAnnotations;
}
+
+//{ObjectTeams: utilities for methods needing configured Dependencies:
+ void setupDependencies() {
+ setupDependencies(true, true, true, true, false, true);
+ }
+
+ Config setupDependencies(boolean verifyMethods,
+ boolean analyzeCode,
+ boolean generateCode,
+ boolean buildFieldsAndMethods,
+ boolean bundledCompleteTypeBindings,
+ boolean strictDiet) {
+ Parser parser = (this.resolver.scope() != null) ? this.resolver.scope().parser : null;
+ return Dependencies.setup(this.resolver, parser, this.resolver.lookupEnvironment(),
+ verifyMethods, analyzeCode, generateCode, buildFieldsAndMethods, bundledCompleteTypeBindings, strictDiet);
+ }
+// SH}
+
private IAnnotationBinding[] resolveAnnotationBindings(org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations, boolean isTypeUse) {
int length = internalAnnotations == null ? 0 : internalAnnotations.length;
if (length != 0) {
@@ -284,7 +303,7 @@
try {
if (isClass() || isInterface() || isEnum()) {
//{ObjectTeams: calling methods() requires Dependencies control:
- Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, true); // TODO(SH): parser, flags?
+ setupDependencies();
usesDependencies = true;
// SH}
ReferenceBinding referenceBinding = (ReferenceBinding) this.binding;
@@ -325,7 +344,7 @@
//{ObjectTeams: cleanup:
finally {
if (usesDependencies)
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
// SH}
return this.fields = NO_VARIABLE_BINDINGS;
@@ -347,7 +366,7 @@
try {
if (isClass() || isInterface() || isEnum()) {
//{ObjectTeams: calling methods() requires Dependencies control:
- Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, true); // TODO(SH): parser, flags?
+ setupDependencies();
usesDependencies = true;
// SH}
ReferenceBinding referenceBinding = (ReferenceBinding) this.binding;
@@ -391,7 +410,7 @@
//{ObjectTeams: cleanup:
finally {
if (usesDependencies)
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
// SH}
return this.methods = NO_METHOD_BINDINGS;
@@ -569,7 +588,7 @@
//{ObjectTeams: protect with minimally configured Dependencies:
Config cfg = null;
if (!Dependencies.isSetup())
- cfg = Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, false, false, true, false, true);
+ cfg = setupDependencies(true, false, false, true, false, true);
try {
// orig:
MethodBinding sam = this.binding.getSingleAbstractMethod(scope, true);
@@ -579,7 +598,7 @@
// :giro
} finally {
if (cfg != null)
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
// SH}
}
@@ -604,7 +623,7 @@
// see Bug 352605 - Eclipse is reporting "Could not retrieve superclass" every few minutes
Config cfg = null;
if (!Dependencies.isSetup())
- cfg = Dependencies.setup(this, null, this.resolver.lookupEnvironment(), false, false, false, false, false, true);
+ cfg = setupDependencies(false, false, false, false, false, true);
try {
// - continued at bottom of method - SH}
try {
@@ -671,7 +690,7 @@
//{ObjectTeams: conclude try-finally from above
} finally {
if (cfg != null)
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
// SH}
}
@@ -1038,14 +1057,14 @@
// see Bug 352605 - Eclipse is reporting "Could not retrieve superclass" every few minutes
Config cfg = null;
if (!Dependencies.isSetup())
- cfg = Dependencies.setup(this, null, this.resolver.lookupEnvironment(), false, false, false, false, false, true);
+ cfg = setupDependencies(false, false, false, false, false, true);
try {
// orig:
superclass = ((ReferenceBinding)this.binding).superclass();
// :giro
} finally {
if (cfg != null)
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
// SH}
} catch (RuntimeException e) {
@@ -1480,7 +1499,7 @@
ReferenceBinding roleBinding = (ReferenceBinding) this.binding;
Config cfg = null;
if (!Dependencies.isSetup())
- cfg = Dependencies.setup(this, null, this.resolver.lookupEnvironment(), false, false, false, false, false, true);
+ cfg = setupDependencies(false, false, false, false, false, true);
try {
ReferenceBinding baseclass = roleBinding.baseclass();
if (baseclass == null) {
@@ -1489,7 +1508,7 @@
return this.resolver.getTypeBinding(baseclass);
} finally {
if (cfg != null)
- Dependencies.release(this);
+ Dependencies.release(this.resolver);
}
}
// ira+SH}