/**
* Copyright (c) 2010, 2013 Darmstadt University of Technology.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marcel Bruch - initial API and implementation.
*/
package org.eclipse.recommenders.completion.rcp;
import static com.google.common.base.Objects.firstNonNull;
import static java.util.concurrent.TimeUnit.*;
import static org.apache.commons.lang3.StringUtils.substring;
import static org.eclipse.jdt.core.compiler.CharOperation.NO_CHAR_CHAR;
import static org.eclipse.recommenders.completion.rcp.CompletionContextKey.*;
import static org.eclipse.recommenders.internal.completion.rcp.l10n.LogMessages.*;
import static org.eclipse.recommenders.jdt.JavaElementsFinder.resolveType;
import static org.eclipse.recommenders.rcp.utils.JdtUtils.findFirstDeclaration;
import static org.eclipse.recommenders.utils.Checks.cast;
import static org.eclipse.recommenders.utils.Logs.log;
import static org.eclipse.recommenders.utils.Reflections.getDeclaredField;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang3.mutable.MutableObject;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.CompletionContext;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.IPackageBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.internal.codeassist.InternalCompletionContext;
import org.eclipse.jdt.internal.codeassist.InternalExtendedCompletionContext;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnLocalName;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnMemberAccess;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnQualifiedAllocationExpression;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnQualifiedNameReference;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.ui.text.javadoc.HTMLTagCompletionProposalComputer;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.recommenders.completion.rcp.processable.ProposalCollectingCompletionRequestor;
import org.eclipse.recommenders.internal.completion.rcp.l10n.LogMessages;
import org.eclipse.recommenders.internal.completion.rcp.l10n.Messages;
import org.eclipse.recommenders.jdt.AstBindings;
import org.eclipse.recommenders.rcp.utils.ASTNodeUtils;
import org.eclipse.recommenders.rcp.utils.JdtUtils;
import org.eclipse.recommenders.utils.Logs;
import org.eclipse.recommenders.utils.names.IPackageName;
import org.eclipse.recommenders.utils.names.ITypeName;
import org.eclipse.recommenders.utils.rcp.TimeDelimitedProgressMonitor;
import org.eclipse.swt.widgets.Shell;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@SuppressWarnings({ "restriction", "rawtypes" })
public final class CompletionContextFunctions {
private static final long COMPLETION_TIME_OUT = SECONDS.toMillis(5);
private CompletionContextFunctions() {
// Not meant to be instantiated
}
public static Map<CompletionContextKey, ICompletionContextFunction> defaultFunctions() {
Map<CompletionContextKey, ICompletionContextFunction> res = new HashMap<CompletionContextKey, ICompletionContextFunction>();
res.put(COMPLETION_PREFIX, new CompletionPrefixContextFunction());
res.put(IS_COMPLETION_ON_TYPE, new CompletionOnTypeContextFunction());
res.put(ENCLOSING_ELEMENT, new EnclosingElementContextFunction());
res.put(ENCLOSING_TYPE, new EnclosingTypeContextFunction());
res.put(ENCLOSING_METHOD, new EnclosingMethodContextFunction());
res.put(ENCLOSING_AST_METHOD, new EnclosingAstMethodContextFunction());
res.put(ENCLOSING_METHOD_FIRST_DECLARATION, new EnclosingMethodFirstDeclarationContextFunction());
res.put(EXPECTED_TYPE, new ExpectedTypeContextFunction());
res.put(EXPECTED_TYPENAMES, new ExpectedTypeNamesContextFunction());
res.put(INTERNAL_COMPLETIONCONTEXT, new InternalCompletionContextFunction());
res.put(JAVA_PROPOSALS, new InternalCompletionContextFunction());
res.put(LOOKUP_ENVIRONMENT, new LookupEnvironmentContextFunction());
res.put(RECEIVER_TYPEBINDING, new ReceiverTypeBindingContextFunction());
res.put(RECEIVER_NAME, new ReceiverNameContextFunction());
res.put(VISIBLE_METHODS, new VisibleMethodsContextFunction());
res.put(VISIBLE_FIELDS, new VisibleFieldsContextFunction());
res.put(VISIBLE_LOCALS, new VisibleLocalsContextFunction());
res.put(SESSION_ID, new SessionIdFunction());
res.put(IMPORTED_PACKAGES, new ImportedPackagesFunction());
return res;
}
public static class EnclosingElementContextFunction implements ICompletionContextFunction<IJavaElement> {
@Override
public IJavaElement compute(IRecommendersCompletionContext context, CompletionContextKey<IJavaElement> key) {
IJavaElement res = null;
try {
InternalCompletionContext core = context.get(INTERNAL_COMPLETIONCONTEXT, null);
if (core != null && core.isExtended()) {
res = core.getEnclosingElement();
}
} catch (Exception e) {
// IAE thrown by JDT if it fails to parse the signature.
// we silently ignore that and return nothing instead.
}
context.set(key, res);
return res;
}
}
public static class CompletionOnTypeContextFunction implements ICompletionContextFunction<Boolean> {
@Override
public Boolean compute(IRecommendersCompletionContext context, CompletionContextKey<Boolean> key) {
ASTNode node = context.getCompletionNode().orNull();
boolean res = false;
if (node instanceof CompletionOnQualifiedNameReference) {
Binding binding = ((CompletionOnQualifiedNameReference) node).binding;
res = binding != null && Binding.TYPE == binding.kind();
}
context.set(key, res);
return res;
}
}
public static class EnclosingMethodContextFunction implements ICompletionContextFunction<IMethod> {
@Override
public IMethod compute(IRecommendersCompletionContext context, CompletionContextKey<IMethod> key) {
IJavaElement enclosing = context.get(ENCLOSING_ELEMENT, null);
IMethod res = (IMethod) (enclosing instanceof IMethod ? enclosing : null);
context.set(key, res);
return res;
}
}
public static class EnclosingMethodFirstDeclarationContextFunction implements ICompletionContextFunction<IMethod> {
@Override
public IMethod compute(IRecommendersCompletionContext context, CompletionContextKey<IMethod> key) {
IMethod root = null;
IMethod enclosing = context.get(ENCLOSING_METHOD, null);
if (enclosing != null) {
root = findFirstDeclaration(enclosing);
}
context.set(key, root);
return root;
}
}
public static class EnclosingTypeContextFunction implements ICompletionContextFunction<IType> {
@Override
public IType compute(IRecommendersCompletionContext context, CompletionContextKey<IType> key) {
IJavaElement enclosing = context.get(ENCLOSING_ELEMENT, null);
IType res = null;
if (enclosing instanceof IType) {
res = (IType) enclosing;
} else if (enclosing instanceof IField) {
res = ((IField) enclosing).getDeclaringType();
} else {
// res = null
}
context.set(key, res);
return res;
}
}
public static class ExpectedTypeContextFunction implements ICompletionContextFunction<IType> {
@Override
public IType compute(IRecommendersCompletionContext context, CompletionContextKey<IType> key) {
JavaContentAssistInvocationContext ctx = context.get(JAVA_CONTENTASSIST_CONTEXT, null);
IType res = ctx == null ? null : ctx.getExpectedType();
context.set(key, res);
return res;
}
}
public static class ExpectedTypeNamesContextFunction implements ICompletionContextFunction<Set<ITypeName>> {
@Override
public Set<ITypeName> compute(IRecommendersCompletionContext context,
CompletionContextKey<Set<ITypeName>> key) {
ASTNode completion = context.getCompletionNode().orNull();
InternalCompletionContext core = context.get(INTERNAL_COMPLETIONCONTEXT, null);
char[][] signatures;
if (isArgumentCompletion(completion) && context.getPrefix().isEmpty()) {
ICompilationUnit cu = context.getCompilationUnit();
int offset = context.getInvocationOffset();
signatures = simulateCompletionWithFakePrefix(cu, offset);
} else {
signatures = core.getExpectedTypesSignatures();
}
Set<ITypeName> res = Sets.newHashSet();
for (char[] signature : Objects.firstNonNull(signatures, NO_CHAR_CHAR)) {
IJavaElement enclosing = context.getEnclosingElement().orNull();
ITypeName resolved = resolveType(signature, enclosing).orNull();
if (resolved != null) {
res.add(resolved);
}
}
context.set(key, res);
return res;
}
private boolean isArgumentCompletion(ASTNode completion) {
return completion instanceof MessageSend || completion instanceof CompletionOnQualifiedAllocationExpression;
}
private char[][] simulateCompletionWithFakePrefix(ICompilationUnit cu, int offset) {
final MutableObject<char[][]> res = new MutableObject<char[][]>(null);
ICompilationUnit wc = null;
String fakePrefix = "___x"; //$NON-NLS-1$
try {
wc = cu.getWorkingCopy(new NullProgressMonitor());
IBuffer buffer = wc.getBuffer();
String contents = buffer.getContents();
String newContents = substring(contents, 0, offset) + fakePrefix
+ substring(contents, offset, contents.length());
buffer.setContents(newContents);
wc.codeComplete(offset + 1, new CompletionRequestor(true) {
@Override
public boolean isExtendedContextRequired() {
return true;
}
@Override
public void acceptContext(CompletionContext context) {
res.setValue(context.getExpectedTypesSignatures());
super.acceptContext(context);
}
@Override
public void accept(CompletionProposal proposal) {
}
});
} catch (JavaModelException e) {
log(ERROR_EXCEPTION_DURING_CODE_COMPLETION_AT_OFFSET, e, cu.getElementName(), offset);
} finally {
discardWorkingCopy(wc);
}
return res.getValue();
}
private void discardWorkingCopy(ICompilationUnit wc) {
try {
if (wc != null) {
wc.discardWorkingCopy();
}
} catch (JavaModelException x) {
log(ERROR_EXCEPTION_DURING_CODE_COMPLETION, x);
}
}
}
public static class ReceiverTypeBindingContextFunction implements ICompletionContextFunction<TypeBinding> {
@Override
public TypeBinding compute(IRecommendersCompletionContext context, CompletionContextKey<TypeBinding> key) {
final ASTNode n = context.getCompletionNode().orNull();
if (n == null) {
return null;
}
TypeBinding receiver = null;
if (n instanceof CompletionOnLocalName) {
// final CompletionOnLocalName c = cast(n);
// name = c.realName;
} else if (n instanceof CompletionOnSingleNameReference) {
final CompletionOnSingleNameReference c = cast(n);
receiver = c.resolvedType;
} else if (n instanceof CompletionOnQualifiedNameReference) {
final CompletionOnQualifiedNameReference c = cast(n);
switch (c.binding.kind()) {
case Binding.VARIABLE:
case Binding.FIELD:
case Binding.LOCAL:
final VariableBinding varBinding = (VariableBinding) c.binding;
receiver = varBinding.type;
break;
case Binding.TYPE:
case Binding.GENERIC_TYPE:
// e.g. Class.|<ctrl-space>
receiver = (TypeBinding) c.binding;
break;
default:
}
} else if (n instanceof CompletionOnMemberAccess) {
final CompletionOnMemberAccess c = cast(n);
receiver = c.actualReceiverType;
}
context.set(key, receiver);
return receiver;
}
}
public static class ReceiverNameContextFunction implements ICompletionContextFunction<String> {
@Override
public String compute(IRecommendersCompletionContext context, CompletionContextKey<String> key) {
final ASTNode n = context.getCompletionNode().orNull();
if (n == null) {
return ""; //$NON-NLS-1$
}
char[] name = null;
if (n instanceof CompletionOnQualifiedNameReference) {
final CompletionOnQualifiedNameReference c = cast(n);
switch (c.binding.kind()) {
case Binding.VARIABLE:
case Binding.FIELD:
case Binding.LOCAL:
final VariableBinding b = (VariableBinding) c.binding;
name = b.name;
break;
}
} else if (n instanceof CompletionOnLocalName) {
final CompletionOnLocalName c = cast(n);
name = c.realName;
} else if (n instanceof CompletionOnSingleNameReference) {
// final CompletionOnSingleNameReference c = cast(n);
// TODO is that correct?
// name = c.token;
name = CharOperation.NO_CHAR;
} else if (n instanceof CompletionOnMemberAccess) {
final CompletionOnMemberAccess c = cast(n);
if (c.receiver instanceof ThisReference) {
name = "this".toCharArray(); //$NON-NLS-1$
} else if (c.receiver instanceof MessageSend) {
// some anonymous type/method return value that has no
// name...
// e.g.:
// PlatformUI.getWorkbench()|^Space --> receiver is
// anonymous
// --> name = null
name = null;
} else if (c.fieldBinding() != null) {
// does this happen? When?
name = c.fieldBinding().name;
} else if (c.localVariableBinding() != null) {
// does this happen? when?
name = c.localVariableBinding().name;
}
}
String res = new String(firstNonNull(name, CharOperation.NO_CHAR));
res = res.replace(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$
context.set(key, res);
return res;
}
}
public static class InternalCompletionContextFunction implements ICompletionContextFunction<Object> {
private final HTMLTagCompletionProposalComputer htmlTagProposalComputer = new HTMLTagCompletionProposalComputer();
@Override
public Object compute(IRecommendersCompletionContext context, CompletionContextKey<Object> key) {
JavaContentAssistInvocationContext coreContext = context.getJavaContext();
int offset = context.getInvocationOffset();
if (offset == -1) {
return null;
}
ICompilationUnit cu = context.getCompilationUnit();
ProposalCollectingCompletionRequestor collector = new ProposalCollectingCompletionRequestor(coreContext);
try {
cu.codeComplete(offset, collector, new TimeDelimitedProgressMonitor(COMPLETION_TIME_OUT, MILLISECONDS));
} catch (JavaModelException e) {
if (e.isDoesNotExist() && !cu.getJavaProject().isOnClasspath(cu)) {
// See
// org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposalComputer#internalComputeCompletionProposals.
ITextViewer viewer = context.getJavaContext().getViewer();
Shell shell = viewer.getTextWidget().getShell();
MessageDialog.openInformation(shell, Messages.DIALOG_TITLE_CANNOT_PERFORM_OPERATION,
Messages.DIALOG_MESSAGE_NOT_ON_CLASSPATH);
} else {
log(ERROR_EXCEPTION_DURING_CODE_COMPLETION, e);
}
} catch (Exception e) {
log(ERROR_EXCEPTION_DURING_CODE_COMPLETION, e);
}
InternalCompletionContext internal = collector.getCoreContext();
context.set(INTERNAL_COMPLETIONCONTEXT, internal);
Map<IJavaCompletionProposal, CompletionProposal> proposals = collector.getProposals();
proposals.putAll(HtmlTagProposals.computeHtmlTagProposals(htmlTagProposalComputer, coreContext));
context.set(JAVA_PROPOSALS, proposals);
if (INTERNAL_COMPLETIONCONTEXT.equals(key)) {
return internal;
} else {
return proposals;
}
}
}
public static class CompletionPrefixContextFunction implements ICompletionContextFunction<String> {
@Override
public String compute(IRecommendersCompletionContext context, CompletionContextKey<String> key) {
InternalCompletionContext ctx = context.get(INTERNAL_COMPLETIONCONTEXT, null);
char[] prefix = CharOperation.NO_CHAR;
if (ctx != null) {
prefix = firstNonNull(ctx.getToken(), CharOperation.NO_CHAR);
}
String res = new String(prefix);
context.set(key, res);
return res;
}
}
public static class VisibleMethodsContextFunction implements ICompletionContextFunction<List<IMethod>> {
@Override
public List<IMethod> compute(IRecommendersCompletionContext context, CompletionContextKey<List<IMethod>> key) {
InternalCompletionContext ctx = context.get(INTERNAL_COMPLETIONCONTEXT, null);
if (ctx == null || !ctx.isExtended()) {
return Collections.emptyList();
}
final ObjectVector v = ctx.getVisibleMethods();
final List<IMethod> res = Lists.newArrayListWithCapacity(v.size);
for (int i = v.size(); i-- > 0;) {
final MethodBinding b = cast(v.elementAt(i));
final Optional<IMethod> f = JdtUtils.createUnresolvedMethod(b);
if (f.isPresent()) {
res.add(f.get());
}
}
context.set(key, res);
return res;
}
}
public static class VisibleFieldsContextFunction implements ICompletionContextFunction<List<IField>> {
@Override
public List<IField> compute(IRecommendersCompletionContext context, CompletionContextKey<List<IField>> key) {
InternalCompletionContext ctx = context.get(INTERNAL_COMPLETIONCONTEXT, null);
if (ctx == null || !ctx.isExtended()) {
return Collections.emptyList();
}
final ObjectVector v = ctx.getVisibleFields();
final List<IField> res = Lists.newArrayListWithCapacity(v.size);
for (int i = v.size(); i-- > 0;) {
final FieldBinding b = cast(v.elementAt(i));
final Optional<IField> f = JdtUtils.createUnresolvedField(b);
if (f.isPresent()) {
res.add(f.get());
}
}
context.set(key, res);
return res;
}
}
public static class VisibleLocalsContextFunction implements ICompletionContextFunction<List<ILocalVariable>> {
@Override
public List<ILocalVariable> compute(IRecommendersCompletionContext context,
CompletionContextKey<List<ILocalVariable>> key) {
InternalCompletionContext ctx = context.get(INTERNAL_COMPLETIONCONTEXT, null);
if (ctx == null || !ctx.isExtended()) {
return Collections.emptyList();
}
final ObjectVector v = ctx.getVisibleLocalVariables();
final List<ILocalVariable> res = Lists.newArrayListWithCapacity(v.size);
for (int i = v.size(); i-- > 0;) {
final LocalVariableBinding b = cast(v.elementAt(i));
final JavaElement parent = (JavaElement) context.getEnclosingElement().get();
final ILocalVariable f = JdtUtils.createUnresolvedLocaVariable(b, parent);
res.add(f);
}
context.set(key, res);
return res;
}
}
public static class EnclosingAstMethodContextFunction implements ICompletionContextFunction<MethodDeclaration> {
@Override
public MethodDeclaration compute(IRecommendersCompletionContext context,
CompletionContextKey<MethodDeclaration> key) {
MethodDeclaration astMethod = null;
IMethod jdtMethod = context.getEnclosingMethod().orNull();
if (jdtMethod != null) {
Optional<CompilationUnit> ast = context.getAST();
if (ast.isPresent()) {
astMethod = ASTNodeUtils.find(ast.get(), jdtMethod).orNull();
} else {
return null;
}
}
context.set(key, astMethod);
return astMethod;
}
}
public static class LookupEnvironmentContextFunction implements ICompletionContextFunction<LookupEnvironment> {
private static Class<InternalCompletionContext> internalCompletionContextClass;
private static Class<InternalExtendedCompletionContext> internalExtendedCompletionContextClass;
static {
try {
internalCompletionContextClass = InternalCompletionContext.class;
} catch (LinkageError e) {
Logs.log(LogMessages.WARNING_LINKAGE_ERROR, e);
}
try {
internalExtendedCompletionContextClass = InternalExtendedCompletionContext.class;
} catch (LinkageError e) {
Logs.log(LogMessages.WARNING_LINKAGE_ERROR, e);
}
}
private static final Field EXTENDED_CONTEXT = getDeclaredField(true, internalCompletionContextClass,
"extendedContext").orNull(); //$NON-NLS-1$
private static final Field LOOKUP_ENVIRONMENT = getDeclaredField(true, internalExtendedCompletionContextClass,
"lookupEnvironment").orNull(); //$NON-NLS-1$
@Override
public LookupEnvironment compute(IRecommendersCompletionContext context,
CompletionContextKey<LookupEnvironment> key) {
if (EXTENDED_CONTEXT == null || LOOKUP_ENVIRONMENT == null) {
return null;
}
try {
InternalCompletionContext ctx = context.get(CompletionContextKey.INTERNAL_COMPLETIONCONTEXT, null);
if (ctx == null) {
return null;
}
InternalExtendedCompletionContext extCtx = cast(EXTENDED_CONTEXT.get(ctx));
if (extCtx == null) {
return null;
}
LookupEnvironment env = cast(LOOKUP_ENVIRONMENT.get(extCtx));
context.set(key, env);
return env;
} catch (Exception e) {
Logs.log(LogMessages.ERROR_EXCEPTION_WHILE_COMPUTING_LOOKUP_ENVIRONMENT, e);
return null;
}
}
}
public static class SessionIdFunction implements ICompletionContextFunction<UUID> {
@Override
public UUID compute(IRecommendersCompletionContext context, CompletionContextKey<UUID> key) {
UUID res = UUID.randomUUID();
context.set(key, res);
return res;
}
}
public static class ImportedPackagesFunction implements ICompletionContextFunction<Set<IPackageName>> {
@Override
@SuppressWarnings("unchecked")
public Set<IPackageName> compute(IRecommendersCompletionContext context,
CompletionContextKey<Set<IPackageName>> key) {
Optional<CompilationUnit> ast = context.getAST();
Set<IPackageName> res = Sets.newHashSet();
List<ImportDeclaration> imports = null;
if (ast.isPresent()) {
imports = ast.get().imports();
} else {
return res;
}
for (ImportDeclaration decl : imports) {
IBinding b = decl.resolveBinding();
if (b == null) {
continue;
}
switch (b.getKind()) {
case IBinding.TYPE: {
ITypeName type = AstBindings.toTypeName((ITypeBinding) b).orNull();
if (type != null) {
res.add(type.getPackage());
}
break;
}
case IBinding.PACKAGE: {
IPackageName pkg = AstBindings.toPackageName((IPackageBinding) b).orNull();
if (pkg != null) {
res.add(pkg);
}
break;
}
case IBinding.METHOD: {
ITypeName type = AstBindings.toTypeName(((IMethodBinding) b).getDeclaringClass()).orNull();
if (type != null) {
res.add(type.getPackage());
}
break;
}
case IBinding.VARIABLE: {
ITypeName type = AstBindings.toTypeName(((IVariableBinding) b).getDeclaringClass()).orNull();
if (type != null) {
res.add(type.getPackage());
}
break;
}
}
}
context.set(key, res);
return res;
}
}
}