Package ro.redeul.google.go.lang.psi.resolve.references

Source Code of ro.redeul.google.go.lang.psi.resolve.references.LabelReference

package ro.redeul.google.go.lang.psi.resolve.references;

import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.resolve.ResolveCache;
import org.jetbrains.annotations.NotNull;
import ro.redeul.google.go.lang.psi.GoPsiElement;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralFunction;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralIdentifier;
import ro.redeul.google.go.lang.psi.resolve.ResolvingCache;
import ro.redeul.google.go.lang.psi.statements.GoLabeledStatement;
import ro.redeul.google.go.lang.psi.toplevel.GoFunctionDeclaration;
import ro.redeul.google.go.lang.psi.visitors.GoRecursiveElementVisitor;

import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;

import static com.intellij.patterns.PlatformPatterns.psiElement;
import static com.intellij.patterns.StandardPatterns.or;
import static ro.redeul.google.go.lang.parser.GoElementTypes.*;
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.findParentOfType;

public class LabelReference
    extends Reference.Single<GoLiteralIdentifier, LabelSolver, LabelReference> {

    @SuppressWarnings("unchecked")
    public static final ElementPattern<GoLiteralIdentifier> MATCHER =
            psiElement(GoLiteralIdentifier.class)
                    .withParent(
                            or(
                                    psiElement(GOTO_STATEMENT),
                                    psiElement(BREAK_STATEMENT),
                                    psiElement(CONTINUE_STATEMENT)
                            )
                    );

    private static final ResolveCache.AbstractResolver<LabelReference, ResolvingCache.Result> RESOLVER =
            new ResolveCache.AbstractResolver<LabelReference, ResolvingCache.Result>() {
                @Override
                public ResolvingCache.Result resolve(@NotNull LabelReference labelReference, boolean incompleteCode) {
                    GoLiteralIdentifier e = labelReference.getElement();
                    GoFunctionDeclaration function = findParentOfType(e,
                            GoFunctionDeclaration.class);
                    final String name = e.getName();
                    if (function == null || name == null || name.isEmpty()) {
                        return null;
                    }

                    final AtomicReference<PsiElement> declaration = new AtomicReference<PsiElement>();

                    new GoRecursiveElementVisitor() {
                        @Override
                        public void visitElement(GoPsiElement element) {
                            if (declaration.get() == null) {
                                super.visitElement(element);
                            }
                        }

                        @Override
                        public void visitLabeledStatement(GoLabeledStatement statement) {
                            super.visitLabeledStatement(statement);

                            GoLiteralIdentifier label = statement.getLabel();
                            if (label != null && name.equals(label.getText())) {
                                declaration.set(label);
                            }
                        }

                        @Override
                        public void visitFunctionLiteral(GoLiteralFunction literal) {
                        }
                    }.visitElement(function);

                    return ResolvingCache.Result.fromElement(declaration.get());
                }
            };

    public LabelReference(@NotNull GoLiteralIdentifier element) {
        super(element, RESOLVER);
    }

    @Override
    protected LabelReference self() {
        return this;
    }

    @NotNull
    @Override
    public String getCanonicalText() {
        return getElement().getCanonicalName();
    }

    @Override
    public boolean isReferenceTo(PsiElement element) {
        if (!(element instanceof GoLiteralIdentifier)) {
            return false;
        }

        PsiElement parent = element.getParent();
        if (!(parent instanceof GoLabeledStatement)) {
            return false;
        }

        GoLiteralIdentifier label = ((GoLabeledStatement) parent).getLabel();
        String name = getElement().getName();
        if (label == null || name == null || name.isEmpty() || !name.equals(
                label.getName())) {
            return false;
        }

        PsiElement resolve = resolve();
        return resolve != null && resolve.getTextOffset() == element.getTextOffset();
    }

    @NotNull
    @Override
    public Object[] getVariants() {
        GoFunctionDeclaration function = findParentOfType(getElement(),
                GoFunctionDeclaration.class);
        if (function == null) {
            return new Object[0];
        }

        final TreeSet<String> labels = new TreeSet<String>();
        new GoRecursiveElementVisitor() {
            @Override
            public void visitLabeledStatement(GoLabeledStatement statement) {
                super.visitLabeledStatement(statement);

                GoLiteralIdentifier label = statement.getLabel();
                if (label != null) {
                    labels.add(label.getName());
                }
            }

            @Override
            public void visitFunctionLiteral(GoLiteralFunction literal) {
                // don't check function literal
            }
        }.visitElement(function);
        return labels.toArray();
    }

    @Override
    public boolean isSoft() {
        return false;
    }
}
TOP

Related Classes of ro.redeul.google.go.lang.psi.resolve.references.LabelReference

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.