All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.strobel.decompiler.languages.java.ast.JavaNameResolver Maven / Gradle / Ivy

There is a newer version: 2.5.0.Final
Show newest version
/*
 * JavaNameResolver.java
 *
 * Copyright (c) 2014 Mike Strobel
 *
 * This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
 * and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
 *
 * This source code is subject to terms and conditions of the Apache License, Version 2.0.
 * A copy of the license can be found in the License.html file at the root of this distribution.
 * By using this source code in any fashion, you are agreeing to be bound by the terms of the
 * Apache License, Version 2.0.
 *
 * You must not remove this notice, or any other, from this software.
 */

package com.strobel.decompiler.languages.java.ast;

import com.strobel.assembler.metadata.*;
import com.strobel.core.Predicates;
import com.strobel.core.ReadOnlyList;
import com.strobel.core.StringUtilities;
import com.strobel.core.VerifyArgument;
import com.strobel.decompiler.ast.Variable;
import com.strobel.decompiler.patterns.Pattern;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static com.strobel.core.CollectionUtilities.any;

public final class JavaNameResolver {
    public static NameResolveResult resolve(final String name, final AstNode node) {
        return new Result(
            NameResolveMode.EXPRESSION,
            resolveCore(node, name, NameResolveMode.EXPRESSION)
        );
    }

    public static NameResolveResult resolveAsType(final String name, final AstNode node) {
        return new Result(
            NameResolveMode.TYPE,
            resolveCore(node, name, NameResolveMode.TYPE)
        );
    }

    private static List resolveCore(
        final AstNode location,
        final String name,
        final NameResolveMode mode) {

        final Set results = FindDeclarationVisitor.resolveName(location, name, mode);

        if (results.isEmpty()) {
            return ReadOnlyList.emptyList();
        }

        return new ReadOnlyList<>(Object.class, results);
    }

    private final static class FindDeclarationVisitor implements IAstVisitor> {
        private final NameResolveMode _mode;
        private boolean _isStaticContext = false;

        FindDeclarationVisitor(final NameResolveMode mode, final boolean isStaticContext) {
            _mode = VerifyArgument.notNull(mode, "mode");
            _isStaticContext = isStaticContext;
        }

        static Set resolveName(final AstNode node, final String name, final NameResolveMode mode) {
            VerifyArgument.notNull(node, "node");
            VerifyArgument.notNull(name, "name");
            VerifyArgument.notNull(mode, "mode");

            AstNode n = node;
            Set results = null;

            while (n instanceof Expression) {
                n = n.getParent();
            }

            if (n == null || n.isNull()) {
                return Collections.emptySet();
            }

            TypeDeclaration lastTypeDeclaration = null;

            final FindDeclarationVisitor visitor = new FindDeclarationVisitor(mode, isStaticContext(node));

            while (n != null && !n.isNull()) {
                if (n instanceof CompilationUnit) {
                    final Set unitResults = n.acceptVisitor(visitor, name);

                    if (!unitResults.isEmpty()) {
                        if (results == null) {
                            return unitResults;
                        }

                        results.addAll(unitResults);
                    }
                }

                AstNode parent = n.getParent();

                if (n instanceof MethodDeclaration) {
                    final Set methodResults = n.acceptVisitor(visitor, name);

                    if (!methodResults.isEmpty()) {
                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }
                        results.addAll(methodResults);
                    }

                    final MethodDefinition method = n.getUserData(Keys.METHOD_DEFINITION);

                    if (method != null) {
                        visitor._isStaticContext = method.isStatic();
                    }
                }
                else if (n instanceof TypeDeclaration) {
                    final Set typeResults = n.acceptVisitor(visitor, name);

                    if (!typeResults.isEmpty()) {
                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }

                        results.addAll(typeResults);
                        return results;
                    }

                    if (parent instanceof TypeDeclaration) {
                        final TypeDefinition type = n.getUserData(Keys.TYPE_DEFINITION);

                        if (type != null) {
                            visitor._isStaticContext = type.isStatic();
                        }
                    }
                    else if (parent instanceof LocalTypeDeclarationStatement) {
                        n = ((LocalTypeDeclarationStatement) parent).getTypeDeclaration();
                        parent = n.getParent();
                    }

                    lastTypeDeclaration = (TypeDeclaration) n;
                }
                else if (n instanceof Statement) {
                    final Statement s = (Statement) n;
                    final Set statementResults = s.acceptVisitor(visitor, name);

                    if (!statementResults.isEmpty()) {
                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }

                        results.addAll(statementResults);

                        if (mode == NameResolveMode.EXPRESSION ||
                            mode == NameResolveMode.TYPE && any(results, Predicates.instanceOf(TypeReference.class))) {

                            return results;
                        }
                    }

                    final Statement previousStatement = ((Statement) n).getPreviousStatement();

                    if (previousStatement != null) {
                        n = previousStatement;
                        continue;
                    }
                }

                n = parent;
            }

            if (results != null) {
                return results;
            }

            if (lastTypeDeclaration != null) {
                return visitor.searchUpScope(
                    name,
                    lastTypeDeclaration.getUserData(Keys.TYPE_DEFINITION),
                    new LinkedHashSet(),
                    true
                );
            }

            return Collections.emptySet();
        }

        private Set searchUpScope(
            final String name,
            final TypeDefinition type,
            final Set visitedTypes,
            final boolean searchGenericParameters) {

            if (type == null || visitedTypes.contains(type.getInternalName())) {
                return Collections.emptySet();
            }

            Set results = null;

            if (_mode == NameResolveMode.EXPRESSION) {
                for (final FieldDefinition f : type.getDeclaredFields()) {
                    if (StringUtilities.equals(f.getName(), name) && (!_isStaticContext || f.isStatic())) {
                        return Collections.singleton(f);
                    }
                }
            }

            if (StringUtilities.equals(type.getSimpleName(), name)) {
                results = new LinkedHashSet<>();
                results.add(type);
            }

            if (searchGenericParameters) {
                for (final GenericParameter gp : type.getGenericParameters()) {
                    if (StringUtilities.equals(gp.getName(), name)) {
                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }
                        results.add(gp);
                    }
                }
            }

            for (final TypeDefinition declaredType : type.getDeclaredTypes()) {
                if (StringUtilities.equals(declaredType.getSimpleName(), name)) {
                    if (results == null) {
                        results = new LinkedHashSet<>();
                    }

                    results.add(declaredType);
                }
            }

            if (results != null && !results.isEmpty()) {
                return results;
            }

            final TypeReference baseType = type.getBaseType();

            if (baseType != null) {
                final TypeDefinition resolvedBaseType = baseType.resolve();

                if (resolvedBaseType != null) {
                    final Set baseTypeResults = searchUpScope(name, resolvedBaseType, visitedTypes, false);

                    if (baseTypeResults != null && !baseTypeResults.isEmpty()) {
                        if (results == null) {
                            results = baseTypeResults instanceof LinkedHashSet ? baseTypeResults
                                                                                  : new LinkedHashSet<>(baseTypeResults);
                        }
                        else {
                            results.addAll(baseTypeResults);
                        }
                    }
                }
            }

            for (final TypeReference ifType : MetadataHelper.getInterfaces(type)) {
                final TypeDefinition resultIfType = ifType.resolve();

                if (resultIfType != null) {
                    final Set ifTypeResults = searchUpScope(name, resultIfType, visitedTypes, false);

                    if (ifTypeResults != null && !ifTypeResults.isEmpty()) {
                        if (results == null) {
                            results = ifTypeResults instanceof LinkedHashSet ? ifTypeResults
                                                                                : new LinkedHashSet<>(ifTypeResults);
                        }
                        else {
                            results.addAll(ifTypeResults);
                        }
                    }
                }
            }

            final MethodReference declaringMethod = type.getDeclaringMethod();

            if (declaringMethod != null) {
                final TypeReference declaringType = declaringMethod.getDeclaringType();

                if (declaringType != null) {
                    final TypeDefinition resolvedType = declaringType.resolve();

                    if (resolvedType != null) {
                        final Set declaringTypeResults = searchUpScope(name, resolvedType, visitedTypes, true);

                        if (declaringTypeResults != null && !declaringTypeResults.isEmpty()) {
                            if (results == null) {
                                results = declaringTypeResults instanceof LinkedHashSet ? declaringTypeResults
                                                                                           : new LinkedHashSet<>(declaringTypeResults);
                            }
                            else {
                                results.addAll(declaringTypeResults);
                            }
                        }
                    }
                    else if (StringUtilities.equals(declaringType.getSimpleName(), name)) {
                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }
                        results.add(declaringType);
                    }
                }
            }

            final TypeReference declaringType = type.getDeclaringType();

            if (declaringType != null) {
                final TypeDefinition resolvedType = declaringType.resolve();

                if (resolvedType != null) {
                    final Set declaringTypeResults = searchUpScope(name, resolvedType, visitedTypes, true);

                    if (declaringTypeResults != null && !declaringTypeResults.isEmpty()) {
                        if (results == null) {
                            results = declaringTypeResults instanceof LinkedHashSet ? declaringTypeResults
                                                                                       : new LinkedHashSet<>(declaringTypeResults);
                        }
                        else {
                            results.addAll(declaringTypeResults);
                        }
                    }
                }
                else if (StringUtilities.equals(declaringType.getSimpleName(), name)) {
                    if (results == null) {
                        results = new LinkedHashSet<>();
                    }
                    results.add(declaringType);
                }
            }

            if (results != null) {
                return results;
            }

            return Collections.emptySet();
        }

        private static boolean isStaticContext(final AstNode node) {
            for (AstNode n = node;
                 n != null && !n.isNull();
                 n = n.getParent()) {

                if (n instanceof MethodDeclaration) {
                    final MethodDefinition method = n.getUserData(Keys.METHOD_DEFINITION);

                    if (method != null) {
                        return method.isStatic();
                    }
                }

                if (n instanceof TypeDeclaration) {
                    final TypeDefinition type = n.getUserData(Keys.TYPE_DEFINITION);

                    if (type != null) {
                        return type.isStatic();
                    }
                }
            }

            return false;
        }

        @Override
        public Set visitComment(final Comment node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitPatternPlaceholder(final AstNode node, final Pattern pattern, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitInvocationExpression(final InvocationExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitTypeReference(final TypeReferenceExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitJavaTokenNode(final JavaTokenNode node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitMemberReferenceExpression(final MemberReferenceExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitIdentifier(final Identifier node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitNullReferenceExpression(final NullReferenceExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitThisReferenceExpression(final ThisReferenceExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitSuperReferenceExpression(final SuperReferenceExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitClassOfExpression(final ClassOfExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitBlockStatement(final BlockStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitExpressionStatement(final ExpressionStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitBreakStatement(final BreakStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitContinueStatement(final ContinueStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitDoWhileStatement(final DoWhileStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitEmptyStatement(final EmptyStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitIfElseStatement(final IfElseStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitLabelStatement(final LabelStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitLabeledStatement(final LabeledStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitReturnStatement(final ReturnStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitSwitchStatement(final SwitchStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitSwitchSection(final SwitchSection node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitCaseLabel(final CaseLabel node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitThrowStatement(final ThrowStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitCatchClause(final CatchClause node, final String name) {
            if (_mode == NameResolveMode.EXPRESSION && StringUtilities.equals(node.getVariableName(), name)) {
                final Variable exceptionVariable = node.getUserData(Keys.VARIABLE);

                if (exceptionVariable != null) {
                    return Collections.singleton(exceptionVariable);
                }
            }
            return Collections.emptySet();
        }

        @Override
        public Set visitAnnotation(final Annotation node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitNewLine(final NewLineNode node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitVariableDeclaration(final VariableDeclarationStatement node, final String name) {
            if (_mode == NameResolveMode.EXPRESSION) {
                final VariableInitializer v = node.getVariable(name);

                if (v != null) {
                    final Variable variable = v.getUserData(Keys.VARIABLE);

                    if (variable != null) {
                        return Collections.singleton(variable);
                    }
                }
            }
            return Collections.emptySet();
        }

        @Override
        public Set visitVariableInitializer(final VariableInitializer node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitText(final TextNode node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitImportDeclaration(final ImportDeclaration node, final String name) {
            final TypeReference importedType = node.getUserData(Keys.TYPE_REFERENCE);

            if (importedType != null && StringUtilities.equals(importedType.getSimpleName(), name)) {
                return Collections.singleton(importedType);
            }

            return Collections.emptySet();
        }

        @Override
        public Set visitSimpleType(final SimpleType node, final String name) {
            if (StringUtilities.equals(node.getIdentifier(), name)) {
                return Collections.singleton(node.toTypeReference());
            }
            return Collections.emptySet();
        }

        @Override
        public Set visitMethodDeclaration(final MethodDeclaration node, final String name) {
            Set results = null;

            if (_mode == NameResolveMode.EXPRESSION) {
                for (final ParameterDeclaration p : node.getParameters()) {
                    if (StringUtilities.equals(p.getName(), name)) {
                        final ParameterDefinition pd = p.getUserData(Keys.PARAMETER_DEFINITION);

                        if (pd == null) {
                            continue;
                        }

                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }

                        results.add(pd);
                    }
                }
            }

            for (final TypeParameterDeclaration tp : node.getTypeParameters()) {
                final TypeDefinition gp = tp.getUserData(Keys.TYPE_DEFINITION);

                if (gp != null && StringUtilities.equals(gp.getName(), name)) {
                    if (results == null) {
                        results = new LinkedHashSet<>();
                    }
                    results.add(gp);
                }
            }

            if (results != null) {
                return results;
            }

            return Collections.emptySet();
        }

        @Override
        public Set visitInitializerBlock(final InstanceInitializer node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitConstructorDeclaration(final ConstructorDeclaration node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitTypeParameterDeclaration(final TypeParameterDeclaration node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitParameterDeclaration(final ParameterDeclaration node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitFieldDeclaration(final FieldDeclaration node, final String name) {
            if (_mode == NameResolveMode.EXPRESSION) {
                if (StringUtilities.equals(node.getName(), name)) {
                    final FieldDefinition f = node.getUserData(Keys.FIELD_DEFINITION);

                    if (f != null && (!_isStaticContext || f.isStatic())) {
                        return Collections.singleton(f);
                    }
                }
            }
            return Collections.emptySet();
        }

        @Override
        public Set visitTypeDeclaration(final TypeDeclaration node, final String name) {
            Set results = null;

            if (_mode == NameResolveMode.EXPRESSION) {
                for (final EntityDeclaration member : node.getMembers()) {
                    if (member instanceof FieldDeclaration) {
                        final Set fieldResults = member.acceptVisitor(this, name);

                        if (fieldResults.isEmpty()) {
                            continue;
                        }

                        return fieldResults;
                    }
                }
            }

            if (StringUtilities.equals(node.getName(), name)) {
                final TypeDefinition typeDefinition = node.getUserData(Keys.TYPE_DEFINITION);

                if (typeDefinition != null) {
                    results = new LinkedHashSet<>();
                    results.add(typeDefinition);
                }
            }

            for (final EntityDeclaration member : node.getMembers()) {
                if (member instanceof TypeDeclaration) {
                    final TypeDeclaration td = (TypeDeclaration) member;

                    if (StringUtilities.equals(td.getName(), name)) {
                        final TypeDefinition t = td.getUserData(Keys.TYPE_DEFINITION);

                        if (t == null) {
                            continue;
                        }

                        if (results == null) {
                            results = new LinkedHashSet<>();
                        }

                        results.add(t);
                    }
                }
            }

            if (_mode == NameResolveMode.TYPE && results != null && !results.isEmpty()) {
                return results;
            }

            for (final TypeParameterDeclaration tp : node.getTypeParameters()) {
                final TypeDefinition gp = tp.getUserData(Keys.TYPE_DEFINITION);

                if (gp != null && StringUtilities.equals(gp.getName(), name)) {
                    if (results == null) {
                        results = new LinkedHashSet<>();
                    }
                    results.add(gp);
                }
            }

            if (results != null && !results.isEmpty()) {
                return results;
            }

            return searchUpScope(
                name,
                node.getUserData(Keys.TYPE_DEFINITION),
                new LinkedHashSet(),
                true
            );
        }

        @Override
        public Set visitLocalTypeDeclarationStatement(final LocalTypeDeclarationStatement node, final String name) {
            final TypeDeclaration typeDeclaration = node.getTypeDeclaration();

            if (typeDeclaration.isNull()) {
                return Collections.emptySet();
            }

            if (StringUtilities.equals(typeDeclaration.getName(), name)) {
                final TypeDefinition type = typeDeclaration.getUserData(Keys.TYPE_DEFINITION);

                if (type != null) {
                    return Collections.singleton(type);
                }
            }

            return searchUpScope(
                name,
                typeDeclaration.getUserData(Keys.TYPE_DEFINITION),
                new LinkedHashSet(),
                true
            );
        }

        @Override
        public Set visitCompilationUnit(final CompilationUnit node, final String name) {
            Set results = null;

            for (final TypeDeclaration typeDeclaration : node.getTypes()) {
                final Set typeResults = typeDeclaration.acceptVisitor(this, name);

                if (typeResults.isEmpty()) {
                    continue;
                }

                if (results == null) {
                    results = new LinkedHashSet<>();
                }

                results.addAll(typeResults);
            }

            for (final ImportDeclaration typeImport : node.getImports()) {
                final Set importResults = typeImport.acceptVisitor(this, name);

                if (importResults.isEmpty()) {
                    continue;
                }

                if (results == null) {
                    results = new LinkedHashSet<>();
                }

                results.addAll(importResults);
            }

            if (results != null) {
                return results;
            }

            return Collections.emptySet();
        }

        @Override
        public Set visitPackageDeclaration(final PackageDeclaration node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitArraySpecifier(final ArraySpecifier node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitComposedType(final ComposedType node, final String name) {
            return node.getBaseType().acceptVisitor(this, name);
        }

        @Override
        public Set visitWhileStatement(final WhileStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitPrimitiveExpression(final PrimitiveExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitCastExpression(final CastExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitBinaryOperatorExpression(final BinaryOperatorExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitInstanceOfExpression(final InstanceOfExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitIndexerExpression(final IndexerExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitIdentifierExpression(final IdentifierExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitUnaryOperatorExpression(final UnaryOperatorExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitConditionalExpression(final ConditionalExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitArrayInitializerExpression(final ArrayInitializerExpression arrayInitializerExpression, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitObjectCreationExpression(final ObjectCreationExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitArrayCreationExpression(final ArrayCreationExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitAssignmentExpression(final AssignmentExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitForStatement(final ForStatement node, final String name) {
            if (_mode == NameResolveMode.EXPRESSION) {
                Set results = null;

                for (final Statement initializer : node.getInitializers()) {
                    final Set initializerResults = initializer.acceptVisitor(this, name);

                    if (node.getInitializers().isEmpty()) {
                        continue;
                    }

                    if (results == null) {
                        results = new LinkedHashSet<>();
                    }

                    results.addAll(initializerResults);
                }
            }

            return Collections.emptySet();
        }

        @Override
        public Set visitForEachStatement(final ForEachStatement node, final String name) {
            if (_mode == NameResolveMode.EXPRESSION) {
                if (StringUtilities.equals(node.getVariableName(), name)) {
                    final Variable v = node.getUserData(Keys.VARIABLE);

                    if (v != null) {
                        return Collections.singleton(v);
                    }
                }
            }

            return Collections.emptySet();
        }

        @Override
        public Set visitTryCatchStatement(final TryCatchStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitGotoStatement(final GotoStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitParenthesizedExpression(final ParenthesizedExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitSynchronizedStatement(final SynchronizedStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitAnonymousObjectCreationExpression(final AnonymousObjectCreationExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitWildcardType(final WildcardType node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitMethodGroupExpression(final MethodGroupExpression node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitEnumValueDeclaration(final EnumValueDeclaration node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitAssertStatement(final AssertStatement node, final String name) {
            return Collections.emptySet();
        }

        @Override
        public Set visitLambdaExpression(final LambdaExpression node, final String name) {
            if (_mode == NameResolveMode.EXPRESSION) {
                Set results = null;

                for (final ParameterDeclaration pd : node.getParameters()) {
                    if (StringUtilities.equals(pd.getName(), name)) {
                        final ParameterDefinition p = pd.getUserData(Keys.PARAMETER_DEFINITION);

                        if (p != null) {
                            if (results == null) {
                                results = new LinkedHashSet<>();
                            }
                            results.add(p);
                        }
                    }
                }

                if (results != null) {
                    return results;
                }
            }

            return Collections.emptySet();
        }
    }

    private final static class Result extends NameResolveResult {
        private final NameResolveMode _mode;
        private final List _candidates;

        Result(final NameResolveMode mode, final List candidates) {
            _mode = mode;
            _candidates = candidates;
        }

        @Override
        public final List getCandidates() {
            return _candidates;
        }

        @Override
        public final NameResolveMode getMode() {
            return _mode;
        }
    }
}