Package ro.redeul.google.go.util

Source Code of ro.redeul.google.go.util.GoTypeInspectUtil

package ro.redeul.google.go.util;

import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.psi.PsiElement;
import ro.redeul.google.go.GoBundle;
import ro.redeul.google.go.inspection.InspectionResult;
import ro.redeul.google.go.inspection.fix.CastTypeFix;
import ro.redeul.google.go.lang.parser.GoElementTypes;
import ro.redeul.google.go.lang.psi.GoPsiElement;
import ro.redeul.google.go.lang.psi.declarations.GoConstDeclaration;
import ro.redeul.google.go.lang.psi.expressions.GoExpr;
import ro.redeul.google.go.lang.psi.expressions.GoUnaryExpression;
import ro.redeul.google.go.lang.psi.expressions.binary.GoBinaryExpression;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteral;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralFloat;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralIdentifier;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralInteger;
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.expressions.primary.GoParenthesisedExpression;
import ro.redeul.google.go.lang.psi.statements.GoReturnStatement;
import ro.redeul.google.go.lang.psi.toplevel.GoFunctionDeclaration;
import ro.redeul.google.go.lang.psi.toplevel.GoFunctionParameter;
import ro.redeul.google.go.lang.psi.types.*;
import ro.redeul.google.go.lang.psi.typing.GoType;
import ro.redeul.google.go.lang.psi.typing.GoTypeSlice;
import ro.redeul.google.go.lang.psi.typing.GoTypes;
import ro.redeul.google.go.lang.psi.utils.GoExpressionUtils;
import ro.redeul.google.go.lang.psi.utils.GoPsiUtils;

import static ro.redeul.google.go.lang.psi.utils.GoTypeUtils.resolveToFinalType;

public class GoTypeInspectUtil {


    public static boolean checkIsInterface(GoPsiType psiType) {
        if (psiType instanceof GoPsiTypeInterface)
            return true;
        if (psiType instanceof GoPsiTypeName)
            return psiType.getName().equals("error") && ((GoPsiTypeName) psiType).isPrimitive();
        if (psiType instanceof GoPsiTypeSlice)
            return checkIsInterface(((GoPsiTypeSlice) psiType).getElementType());
        if (psiType instanceof GoPsiTypePointer)
            return checkIsInterface(((GoPsiTypePointer) psiType).getTargetType());
        if (psiType instanceof GoPsiTypeArray)
            return checkIsInterface(((GoPsiTypeArray) psiType).getElementType());
        if (psiType instanceof GoPsiTypeChannel)
            return checkIsInterface(((GoPsiTypeChannel) psiType).getElementType());
        return false;
    }

    public static boolean checkParametersExp(GoPsiType psiType, GoExpr expr) {
        GoType type = GoTypes.fromPsi(psiType);

        GoPsiType resolved = resolveToFinalType(psiType);
        if (resolved instanceof GoPsiTypeInterface)
            return true;

        PsiElement firstChildOfExp = expr.getFirstChild();
        if (checkIsInterface(resolved)) {
            return true;
        }
        if (resolved == null) {
            return false;
        }


        GoType[] goTypes = expr.getType();
        if (goTypes.length != 0 && goTypes[0] != null) {
            return GoUtil.areTypesAssignable(GoTypes.getInstance(expr.getProject()).fromPsiType(psiType), goTypes[0]);
        }

        //Fix issue #520 with nil
        if (IsNil(expr)) {
            if (resolved instanceof GoPsiTypeName) {
                GoPsiTypeName typeName = (GoPsiTypeName) resolved;
                if (typeName.isPrimitive() && typeName.getName() != null && typeName.getName().equals("error")) {
                    return true;
                }
            }
            return resolved instanceof GoPsiTypeInterface ||
                    resolved instanceof GoPsiTypeFunction ||
                    resolved instanceof GoPsiTypePointer ||
                    resolved instanceof GoPsiTypeSlice ||
                    resolved instanceof GoPsiTypeMap ||
                    resolved instanceof GoPsiTypeChannel;
        } else if (expr.isConstantExpression()) {
                  }

        goTypes = expr.getType();
        if (goTypes.length != 0 && goTypes[0] != null) {
            return GoUtil.CompareTypes(psiType, goTypes[0], expr);
        }

        if (psiType instanceof GoPsiTypeFunction)
            return GoUtil.CompareTypes(psiType, null, expr);

        if (firstChildOfExp instanceof GoLiteralIdentifier) {
            GoPsiElement goPsiElement = GoUtil.ResolveTypeOfVarDecl((GoPsiElement) firstChildOfExp);
            if (goPsiElement instanceof GoPsiType)
                return GoUtil.CompareTypes(psiType, goPsiElement);
        }
        if (expr instanceof GoCallOrConvExpression && firstChildOfExp instanceof GoPsiTypeParenthesized) {
            return GoUtil.CompareTypes(psiType, ((GoPsiTypeParenthesized) firstChildOfExp).getInnerType(), expr);
        }
        psiType = resolved;
        if (psiType == null) {
            return false;
        }

        String typeText = psiType.getText();
        if (expr instanceof GoLiteralExpression) {
            GoLiteral.Type type1 = ((GoLiteralExpression) expr).getLiteral().getType();
            return type1 == GoLiteral.Type.Identifier || type1.name().toLowerCase().equals(typeText);
        }

        return true;

    }

    public static boolean IsNil(PsiElement psiElement) {
        if (psiElement instanceof GoParenthesisedExpression)
            return IsNil(((GoParenthesisedExpression) psiElement).getInnerExpression());
        if (psiElement instanceof GoLiteralExpression)
            psiElement = ((GoLiteralExpression) psiElement).getLiteral();
        return psiElement instanceof GoLiteralIdentifier && ((GoLiteralIdentifier) psiElement).getName().equals("nil");
    }

    public static boolean checkValidLiteralFloatExpr(GoExpr expr) {
        if (expr instanceof GoLiteralExpression) {
            GoLiteral literal = ((GoLiteralExpression) expr).getLiteral();
            if (literal instanceof GoLiteralIdentifier) {
                //Never will be null
                PsiElement goPsiElement = GoUtil.ResolveReferece(literal).getParent();
                if (goPsiElement instanceof GoConstDeclaration) {
                    for (GoExpr goExpr : ((GoConstDeclaration) goPsiElement).getExpressions()) {
                        if (!checkValidLiteralFloatExpr(goExpr))
                            return false;
                    }
                }
                return true;
            }
            if (literal instanceof GoLiteralExpression)
                return checkValidLiteralIntExpr((GoExpr) literal);
            return literal instanceof GoLiteralFloat || literal instanceof GoLiteralInteger || literal.getNode().getElementType() == GoElementTypes.LITERAL_CHAR;
        }
        if (expr instanceof GoBinaryExpression) {
            if (!checkValidLiteralFloatExpr(((GoBinaryExpression) expr).getLeftOperand()))
                return false;
            return checkValidLiteralFloatExpr(((GoBinaryExpression) expr).getRightOperand());
        }
        if (expr instanceof GoUnaryExpression)
            return checkValidLiteralFloatExpr(((GoUnaryExpression) expr).getExpression());
        return false;
    }

    public static boolean checkValidLiteralIntExpr(GoExpr expr) {
        if (expr instanceof GoLiteralExpression) {
            GoLiteral literal = ((GoLiteralExpression) expr).getLiteral();
            if (literal instanceof GoLiteralIdentifier) {
                //Never will be null
                PsiElement goPsiElement = GoUtil.ResolveReferece(literal).getParent();
                if (goPsiElement instanceof GoConstDeclaration) {
                    for (GoExpr goExpr : ((GoConstDeclaration) goPsiElement).getExpressions()) {
                        if (!checkValidLiteralIntExpr(goExpr))
                            return false;
                    }
                }
                return true;
            }
            if (literal instanceof GoLiteralExpression)
                return checkValidLiteralIntExpr((GoExpr) literal);
            if (literal instanceof GoLiteralInteger || literal.getNode().getElementType() == GoElementTypes.LITERAL_CHAR)
                return true;
            return literal instanceof GoLiteralFloat && literal.getText().matches("^[0-9]*\\.0*$");
        }
        if (expr instanceof GoBinaryExpression) {
            if (!checkValidLiteralIntExpr(((GoBinaryExpression) expr).getLeftOperand()))
                return false;
            return checkValidLiteralIntExpr(((GoBinaryExpression) expr).getRightOperand());
        }
        if (expr instanceof GoUnaryExpression)
            return checkValidLiteralIntExpr(((GoUnaryExpression) expr).getExpression());
        if (expr instanceof GoParenthesisedExpression)
            return checkValidLiteralIntExpr(((GoParenthesisedExpression) expr).getInnerExpression());
        return false;
    }

    public static void checkFunctionTypeArguments(GoCallOrConvExpression call, InspectionResult result) {
        GoFunctionDeclaration goFunctionDeclaration = GoExpressionUtils.resolveToFunctionDeclaration(call);
        GoExpr[] goExprs = call.getArguments();
        int index = 0;

        if (goFunctionDeclaration == null)
            return;

        if (call instanceof GoBuiltinCallOrConversionExpression) {
            GoPsiType[] builtinTypes = ((GoBuiltinCallOrConversionExpression) call).getArgumentsType();
            if (builtinTypes.length > 0 && goExprs.length == builtinTypes.length) {
                for (; index < goExprs.length; index++) {
                    GoExpr goExpr = goExprs[index];
                    GoPsiType type = builtinTypes[index];
                    if (!checkParametersExp(type, goExpr)){
                        result.addProblem(
                                goExpr,
                                GoBundle.message("warning.functioncall.type.mismatch", type.getText()),
                                ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new CastTypeFix(goExpr, GoTypes.fromPsi(type)));
                        return;
                    }
                }
            }
            return;
        }

        for (GoFunctionParameter functionParameter : goFunctionDeclaration.getParameters()) {
            if (index >= goExprs.length)
                return;
            GoPsiType type = functionParameter.getType();
            String typeName = type != null ? type.getText() : "";
            if (functionParameter.isVariadic()) {
                if (call.isCallWithVariadicParameter()){
                    GoExpr goExpr = goExprs[index];
                    GoType[] types = goExpr.getType();
                    if (types.length!=1){
                        result.addProblem(
                                goExpr,
                                GoBundle.message("warning.functioncall.type.mismatch", "[]"+typeName),
                                ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                        return;
                    }
                    GoType exprType = types[0].underlyingType();
                    if (!(exprType instanceof GoTypeSlice)){
                        result.addProblem(
                                goExpr,
                                GoBundle.message("warning.functioncall.type.mismatch", "[]"+typeName),
                                ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                        return;
                    }

                    //TODO test with assignable
                    if (!((GoTypeSlice) exprType).getElementType().isIdentical(GoTypes.fromPsi(type)) ) {
                        result.addProblem(
                                goExpr,
                                GoBundle.message("warning.functioncall.type.mismatch", "[]"+typeName),
                                ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                        return;
                    }
                }else {
                    for (; index < goExprs.length; index++) {
                        GoExpr goExpr = goExprs[index];
                        if (!checkParametersExp(functionParameter.getType(), goExpr)) {
                            result.addProblem(
                                    goExpr,
                                    GoBundle.message("warning.functioncall.type.mismatch", typeName),
                                    ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new CastTypeFix(goExpr, GoTypes.fromPsi(type)));
                            return;
                        }
                    }
                }
            } else {
                GoLiteralIdentifier[] identifiers = functionParameter.getIdentifiers();
                if (identifiers.length < 2) {
                    GoExpr goExpr = goExprs[index];
                    if (!checkParametersExp(functionParameter.getType(), goExpr)) {
                        result.addProblem(
                                goExpr,
                                GoBundle.message("warning.functioncall.type.mismatch", typeName),
                                ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new CastTypeFix(goExpr, GoTypes.fromPsi(type)));
                        return;
                    }
                    index++;
                } else {
                    for (GoLiteralIdentifier goLiteralIdentifier : identifiers) {
                        GoExpr goExpr = goExprs[index];
                        if (!checkParametersExp(functionParameter.getType(), goExpr)) {
                            result.addProblem(
                                    goExpr,
                                    GoBundle.message("warning.functioncall.type.mismatch", typeName),
                                    ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new CastTypeFix(goExpr, GoTypes.fromPsi(type)));
                            return;
                        }
                        index++;
                    }
                }
            }
        }
    }

    public static boolean checkFunctionTypeReturns(GoReturnStatement statement, InspectionResult result) {
        int index = 0;

        GoFunctionDeclaration containingFunction = GoPsiUtils.findParentOfType(statement, GoFunctionDeclaration.class);
        if (containingFunction == null)
            return true;

        GoType[] returnTypes = containingFunction.getReturnTypes();

        GoType[] valueTypes = GoType.EMPTY_ARRAY;

        GoExpr[] expressions = statement.getExpressions();
        if (expressions.length == 1 && expressions[0] instanceof GoCallOrConvExpression) {
            GoFunctionDeclaration calledFunction = GoExpressionUtils.resolveToFunctionDeclaration(expressions[0]);
            if ( calledFunction != null )
                valueTypes = calledFunction.getReturnTypes();
        }

        if ( valueTypes.length != returnTypes.length )
            result.addProblem(
                    statement,
                    "Not Enough");

        //                for (GoType returnType : calledFunction.getReturnTypes()) {
//                    if (!returnType.isAssignableFrom(returnTypes[index])) {
//                        result.addProblem(
//                                expressions[0],
//                                GoBundle.message("warn.function.return.call.types.mismatch"),
//                                new ChangeReturnsParametersFix(statement));
//                        return false;
//                    }
//
//                    index++;
//                }
//            return true;

        return false;

//        for (GoFunctionParameter functionParameter : results) {
//            if (index >= expressions.length)
//                return false;
//            GoPsiType type = functionParameter.getType();
//            GoLiteralIdentifier[] identifiers = functionParameter.getIdentifiers();
//            String typeName = type != null ? type.getText() : "";
//            if (identifiers.length < 2) {
//                GoExpr goExpr = expressions[index];
//                if (!checkParametersExp(functionParameter.getType(), goExpr)) {
//                    result.addProblem(
//                            goExpr,
//                            GoBundle.message("warning.functioncall.type.mismatch", typeName),
//                            new CastTypeFix(goExpr, GoTypes.fromPsi(type)),
//                            new ChangeReturnsParametersFix(statement));
//                    return false;
//                }
//                index++;
//            } else {
//                for (GoLiteralIdentifier goLiteralIdentifier : identifiers) {
//                    GoExpr goExpr = expressions[index];
//                    if (!checkParametersExp(functionParameter.getType(), goExpr)) {
//                        result.addProblem(
//                                goExpr,
//                                GoBundle.message("warning.functioncall.type.mismatch", typeName),
//                                new CastTypeFix(goExpr, GoTypes.fromPsi(type)),
//                                new ChangeReturnsParametersFix(statement));
//
//                        return false;
//                    }
//                    index++;
//                }
//            }
//
//        }
//        return true;
    }
}
TOP

Related Classes of ro.redeul.google.go.util.GoTypeInspectUtil

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.