Package ro.redeul.google.go.annotator

Source Code of ro.redeul.google.go.annotator.GoAnnotator

package ro.redeul.google.go.annotator;

import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import ro.redeul.google.go.GoBundle;
import ro.redeul.google.go.highlight.GoSyntaxHighlighter;
import ro.redeul.google.go.lang.psi.GoFile;
import ro.redeul.google.go.lang.psi.GoPsiElement;
import ro.redeul.google.go.lang.psi.declarations.GoConstDeclaration;
import ro.redeul.google.go.lang.psi.declarations.GoVarDeclaration;
import ro.redeul.google.go.lang.psi.declarations.GoVarDeclarations;
import ro.redeul.google.go.lang.psi.expressions.GoExpr;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteral;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralIdentifier;
import ro.redeul.google.go.lang.psi.expressions.primary.GoBuiltinCallOrConversionExpression;
import ro.redeul.google.go.lang.psi.expressions.primary.GoCallOrConvExpression;
import ro.redeul.google.go.lang.psi.expressions.primary.GoLiteralExpression;
import ro.redeul.google.go.lang.psi.statements.GoDeferStatement;
import ro.redeul.google.go.lang.psi.statements.GoGoStatement;
import ro.redeul.google.go.lang.psi.statements.GoIfStatement;
import ro.redeul.google.go.lang.psi.statements.GoShortVarDeclaration;
import ro.redeul.google.go.lang.psi.toplevel.*;
import ro.redeul.google.go.lang.psi.types.GoPsiTypeName;
import ro.redeul.google.go.lang.psi.types.struct.GoTypeStructField;
import ro.redeul.google.go.lang.psi.utils.GoPsiUtils;
import ro.redeul.google.go.lang.psi.visitors.GoRecursiveElementVisitor;

import static com.intellij.patterns.PlatformPatterns.psiElement;
import static ro.redeul.google.go.inspection.InspectionUtil.getProblemRange;
import static ro.redeul.google.go.lang.psi.patterns.GoElementPatterns.GLOBAL_VAR_DECL;
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.isFunctionOrMethodCall;
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.resolveSafely;

/**
* Author: Toader Mihai Claudiu <mtoader@gmail.com>
* <p/>
* Date: Aug 30, 2010
* Time: 8:30:33 PM
*/
public class GoAnnotator extends GoRecursiveElementVisitor
    implements Annotator {

    private AnnotationHolder annotationHolder;

    public GoAnnotator() {

    }

    public void annotate(@NotNull PsiElement element,
                         @NotNull AnnotationHolder holder) {
        if (element instanceof GoPsiElement) {
            GoPsiElement goPsiElement = (GoPsiElement) element;

            try {
                annotationHolder = holder;

                goPsiElement.accept(this);
            } finally {
                annotationHolder = null;
            }
        }
    }

    private Annotation toAnnotation(ProblemDescriptor pd) {
        TextRange problemRange = getProblemRange(pd);
        String desc = pd.getDescriptionTemplate();

        Annotation annotation;

        switch (pd.getHighlightType()) {
            case GENERIC_ERROR_OR_WARNING:
            case ERROR:
            case GENERIC_ERROR:
            case LIKE_UNKNOWN_SYMBOL:
                annotation = annotationHolder.createErrorAnnotation(
                    problemRange, desc);
                break;

            case LIKE_DEPRECATED:
            case LIKE_UNUSED_SYMBOL: {
                annotation =
                    annotationHolder.createWeakWarningAnnotation(problemRange,
                                                                 desc);
                break;
            }

            case INFORMATION:
                annotation =
                    annotationHolder.createInfoAnnotation(problemRange, desc);
                break;

            case WEAK_WARNING:
            default:
                annotation =
                    annotationHolder.createWarningAnnotation(problemRange,
                                                             desc);
        }

        if (annotation != null) {
            annotation.setHighlightType(pd.getHighlightType());
        }

        return annotation;
    }

    @Override
    public void visitLiteralBool(GoLiteral<Boolean> literal) {
        Annotation ann = annotationHolder.createInfoAnnotation(literal, null);
        ann.setTextAttributes(GoSyntaxHighlighter.KEYWORD);
    }

    @Override
    public void visitIfStatement(GoIfStatement statement) {
        super.visitIfStatement(statement);

        if (statement.getExpression() == null) {
            PsiElement element = statement.getFirstChild();
            if (element == null) {
                element = statement;
            }
            annotationHolder.createErrorAnnotation(element,
                                                   GoBundle.message(
                                                       "error.missing.condition.in.if.statement"));
        }
    }

    @Override
    public void visitCallOrConvExpression(GoCallOrConvExpression expression) {
        if (expression.getTypeArgument() == null) {
            PsiElement definition = resolveSafely(
                expression.getBaseExpression(), PsiElement.class);

            if (psiElement(GoTypeSpec.class).accepts(definition)) {
                annotationHolder.createInfoAnnotation(
                    expression.getBaseExpression(), null)
                                .setTextAttributes(
                                    GoSyntaxHighlighter.TYPE_NAME);
                return;
            }
        }

        for (GoExpr argumentExpression : expression.getArguments()) {
            argumentExpression.accept(this);
        }
    }

    @Override
    public void visitBuiltinCallExpression(GoBuiltinCallOrConversionExpression expression) {
        PsiElement definition = resolveSafely(expression.getBaseExpression(),
                                              PsiElement.class);

        if (definition == null || psiElement(GoLiteralIdentifier.class).accepts(
            definition)) {
            annotationHolder.createInfoAnnotation(expression.getBaseExpression(), null)
                            .setTextAttributes(GoSyntaxHighlighter.KEYWORD);
        }

        if (psiElement(GoTypeSpec.class).accepts(definition)) {
            annotationHolder.createInfoAnnotation(
                expression.getBaseExpression(), null)
                            .setTextAttributes(GoSyntaxHighlighter.TYPE_NAME);
        }

        for (GoExpr argumentExpression : expression.getArguments()) {
            argumentExpression.accept(this);
        }
    }

    @Override
    public void visitLiteralExpression(GoLiteralExpression expression) {
        super.visitLiteralExpression(expression);

        if (expression.getLiteral().getType() == GoLiteral.Type.Identifier) {
            GoLiteralIdentifier identifier = (GoLiteralIdentifier) expression.getLiteral();
            processLiteralIdentifier(identifier);
        }
    }

    void processLiteralIdentifier(GoLiteralIdentifier identifier) {
        if (identifier.isBlank()) {
            return;
        }

        // make iota a keyword
        if (identifier.isIota() || identifier.getText().matches(
            "nil|true|false")) {
            annotationHolder.createInfoAnnotation(identifier, null)
                            .setTextAttributes(GoSyntaxHighlighter.KEYWORD);
            return;
        }

        if (psiElement(GoLiteralIdentifier.class)
            .withParent(
                psiElement(GoLiteralExpression.class)
                    .withParent(
                        psiElement(GoCallOrConvExpression.class)))
            .accepts(identifier))
            return;

        PsiElement definition = resolveSafely(identifier, PsiElement.class);

        if (definition == null)
            return;

        Annotation annotation =
            annotationHolder.createInfoAnnotation(identifier, null);

        if (psiElement().withParent(GoConstDeclaration.class)
            .accepts(definition)) {
            annotation.setTextAttributes(GoSyntaxHighlighter.CONST);
            return;
        }

        if (GLOBAL_VAR_DECL.accepts(definition)) {
            annotation.setTextAttributes(GoSyntaxHighlighter.GLOBAL_VARIABLE);
            return;
        }

        if (psiElement(GoTypeSpec.class).accepts(definition)) {
            annotation.setTextAttributes(GoSyntaxHighlighter.TYPE_NAME);
            return;
        }

        annotation.setTextAttributes(GoSyntaxHighlighter.VARIABLE);
    }

    @Override
    public void visitTypeName(GoPsiTypeName typeName) {
        Annotation ann = annotationHolder.createInfoAnnotation(typeName, null);
        ann.setTextAttributes(GoSyntaxHighlighter.TYPE_NAME);
    }

    @Override
    public void visitTypeNameDeclaration(GoTypeNameDeclaration declaration) {
        Annotation ann = annotationHolder.createInfoAnnotation(declaration,
                                                               null);
        ann.setTextAttributes(GoSyntaxHighlighter.TYPE_NAME);
    }

    @Override
    public void visitMethodDeclaration(GoMethodDeclaration declaration) {
        super.visitMethodDeclaration(declaration);

        PsiElement nameIdentifier = declaration.getNameIdentifier();
        if (nameIdentifier != null) {
            Annotation ann = annotationHolder.createInfoAnnotation(
                nameIdentifier, null);
            ann.setTextAttributes(GoSyntaxHighlighter.METHOD_DECLARATION);
        }
    }

    @Override
    public void visitFunctionDeclaration(GoFunctionDeclaration declaration) {
        super.visitFunctionDeclaration(declaration);

        PsiElement nameIdentifier = declaration.getNameIdentifier();
        if (nameIdentifier != null) {
            Annotation ann = annotationHolder.createInfoAnnotation(
                nameIdentifier, null);
            ann.setTextAttributes(GoSyntaxHighlighter.METHOD_DECLARATION);
        }
    }

    @Override
    public void visitConstDeclaration(GoConstDeclaration declaration) {
        super.visitConstDeclaration(declaration);

        for (GoLiteralIdentifier identifier : declaration.getIdentifiers()) {
            annotationHolder
                .createInfoAnnotation(identifier, null)
                .setTextAttributes(GoSyntaxHighlighter.CONST);
        }
    }

    @Override
    public void visitFunctionParameter(GoFunctionParameter parameter) {
        super.visitFunctionParameter(parameter);

        for (GoLiteralIdentifier identifier : parameter.getIdentifiers()) {
            annotationHolder
                .createInfoAnnotation(identifier, null)
                .setTextAttributes(GoSyntaxHighlighter.VARIABLE);
        }
    }

    @Override
    public void visitTypeStructField(GoTypeStructField field) {
        super.visitTypeStructField(field);

        for (GoLiteralIdentifier identifier : field.getIdentifiers()) {
            annotationHolder
                .createInfoAnnotation(identifier, null)
                .setTextAttributes(GoSyntaxHighlighter.VARIABLE);
        }
    }

    @Override
    public void visitShortVarDeclaration(GoShortVarDeclaration declaration) {
        visitVarDeclaration(declaration);
    }

    @Override
    public void visitVarDeclaration(GoVarDeclaration declaration) {
        super.visitVarDeclaration(declaration);
        TextAttributesKey type = GoSyntaxHighlighter.VARIABLE;

        if (psiElement(GoVarDeclarations.class)
            .withParent(psiElement(GoFile.class))
            .accepts(declaration.getParent())) {
            type = GoSyntaxHighlighter.GLOBAL_VARIABLE;
        }

        for (GoLiteralIdentifier identifier : declaration.getIdentifiers()) {
            annotationHolder
                .createInfoAnnotation(identifier, null)
                .setTextAttributes(type);
        }
    }

    @Override
    public void visitGoStatement(GoGoStatement statement) {
        super.visitGoStatement(statement);

        if (!isFunctionOrMethodCall(statement.getExpression())) {
            PsiElement lastChild = GoPsiUtils.getPrevSiblingIfItsWhiteSpaceOrComment(
                statement.getLastChild());
            if (lastChild == null) {
                lastChild = statement;
            }

            annotationHolder.createErrorAnnotation(lastChild,
                                                   "Argument to go must be function call");
        }
    }

    @Override
    public void visitDeferStatement(GoDeferStatement statement) {
        super.visitDeferStatement(statement);

        if (!isFunctionOrMethodCall(statement.getExpression())) {
            PsiElement lastChild = GoPsiUtils.getPrevSiblingIfItsWhiteSpaceOrComment(
                statement.getLastChild());
            if (lastChild == null) {
                lastChild = statement;
            }

            annotationHolder.createErrorAnnotation(lastChild,
                                                   "Argument to defer must be function call");
        }
    }
}
TOP

Related Classes of ro.redeul.google.go.annotator.GoAnnotator

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.