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

org.jetbrains.jet.lang.diagnostics.PositioningStrategies Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2013 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jetbrains.jet.lang.diagnostics;


import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class PositioningStrategies {

    public static final PositioningStrategy DEFAULT = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull PsiElement element) {
            if (element instanceof JetObjectLiteralExpression) {
                JetObjectDeclaration objectDeclaration = ((JetObjectLiteralExpression) element).getObjectDeclaration();
                PsiElement objectKeyword = objectDeclaration.getObjectKeyword();
                JetDelegationSpecifierList delegationSpecifierList = objectDeclaration.getDelegationSpecifierList();
                if (delegationSpecifierList == null) {
                    return markElement(objectKeyword);
                }
                return markRange(objectKeyword.getTextRange().union(delegationSpecifierList.getTextRange()));
            }
            return super.mark(element);
        }
    };

    public static final PositioningStrategy DECLARATION_RETURN_TYPE = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetDeclaration declaration) {
            return markElement(getElementToMark(declaration));
        }

        @Override
        public boolean isValid(@NotNull JetDeclaration declaration) {
            return !hasSyntaxErrors(getElementToMark(declaration));
        }

        private PsiElement getElementToMark(@NotNull JetDeclaration declaration) {
            JetTypeReference returnTypeRef = null;
            PsiElement nameIdentifierOrPlaceholder = null;
            if (declaration instanceof JetNamedFunction) {
                JetFunction function = (JetNamedFunction) declaration;
                returnTypeRef = function.getReturnTypeRef();
                nameIdentifierOrPlaceholder = function.getNameIdentifier();
            }
            else if (declaration instanceof JetProperty) {
                JetProperty property = (JetProperty) declaration;
                returnTypeRef = property.getTypeRef();
                nameIdentifierOrPlaceholder = property.getNameIdentifier();
            }
            else if (declaration instanceof JetPropertyAccessor) {
                JetPropertyAccessor accessor = (JetPropertyAccessor) declaration;
                returnTypeRef = accessor.getReturnTypeReference();
                nameIdentifierOrPlaceholder = accessor.getNamePlaceholder();
            }

            if (returnTypeRef != null) return returnTypeRef;
            if (nameIdentifierOrPlaceholder != null) return nameIdentifierOrPlaceholder;
            return declaration;
        }
    };

    public static final PositioningStrategy NAME_IDENTIFIER = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull PsiNameIdentifierOwner element) {
            PsiElement nameIdentifier = element.getNameIdentifier();
            if (nameIdentifier != null) {
                return markElement(nameIdentifier);
            }
            if (element instanceof JetObjectDeclaration) {
                PsiElement objectKeyword = ((JetObjectDeclaration) element).getObjectKeyword();
                PsiElement parent = element.getParent();
                if (parent instanceof JetClassObject) {
                    PsiElement classKeyword = ((JetClassObject) parent).getClassKeywordNode();
                    PsiElement start = classKeyword == null ? objectKeyword : classKeyword;
                    return markRange(new TextRange(start.getTextRange().getStartOffset(), objectKeyword.getTextRange().getEndOffset()));
                }
                return markElement(objectKeyword);
            }
            return markElement(element);
        }
    };

    public static final PositioningStrategy NAMED_ELEMENT = new DeclarationHeader() {
        @Override
        public boolean isValid(@NotNull PsiNameIdentifierOwner element) {
            return (element.getNameIdentifier() != null || element instanceof JetObjectDeclaration) && super.isValid(element);
        }
    };

    private static class DeclarationHeader extends PositioningStrategy {
        @NotNull
        @Override
        public List mark(@NotNull T element) {
            if (element instanceof JetNamedFunction) {
                JetNamedFunction function = (JetNamedFunction)element;
                PsiElement endOfSignatureElement;
                JetParameterList valueParameterList = function.getValueParameterList();
                JetElement returnTypeRef = function.getReturnTypeRef();
                PsiElement nameIdentifier = function.getNameIdentifier();
                if (returnTypeRef != null) {
                    endOfSignatureElement = returnTypeRef;
                }
                else if (valueParameterList != null) {
                    endOfSignatureElement = valueParameterList;
                }
                else if (nameIdentifier != null) {
                    endOfSignatureElement = nameIdentifier;
                }
                else {
                    endOfSignatureElement = function;
                }
                return markRange(new TextRange(
                        function.getTextRange().getStartOffset(), endOfSignatureElement.getTextRange().getEndOffset()));
            }
            else if (element instanceof JetProperty) {
                JetProperty property = (JetProperty) element;
                PsiElement endOfSignatureElement;
                JetTypeReference propertyTypeRef = property.getTypeRef();
                PsiElement nameIdentifier = property.getNameIdentifier();
                if (propertyTypeRef != null) {
                    endOfSignatureElement = propertyTypeRef;
                }
                else if (nameIdentifier != null) {
                    endOfSignatureElement = nameIdentifier;
                }
                else {
                    endOfSignatureElement = property;
                }
                return markRange(new TextRange(
                        property.getTextRange().getStartOffset(), endOfSignatureElement.getTextRange().getEndOffset()));
            }
            else if (element instanceof JetPropertyAccessor) {
                JetPropertyAccessor accessor = (JetPropertyAccessor) element;
                PsiElement endOfSignatureElement = accessor.getReturnTypeReference();
                if (endOfSignatureElement == null) {
                    ASTNode rpar = accessor.getRightParenthesis();
                    endOfSignatureElement = rpar == null ? null : rpar.getPsi();
                }
                if (endOfSignatureElement == null) {
                    endOfSignatureElement = accessor.getNamePlaceholder();
                }
                return markRange(new TextRange(
                        accessor.getTextRange().getStartOffset(), endOfSignatureElement.getTextRange().getEndOffset()));
            }
            else if (element instanceof JetClass) {
                PsiElement nameAsDeclaration = ((JetClass) element).getNameIdentifier();
                if (nameAsDeclaration == null) {
                    return markElement(element);
                }
                PsiElement primaryConstructorParameterList = ((JetClass) element).getPrimaryConstructorParameterList();
                if (primaryConstructorParameterList == null) {
                    return markRange(nameAsDeclaration.getTextRange());
                }
                return markRange(new TextRange(
                        nameAsDeclaration.getTextRange().getStartOffset(), primaryConstructorParameterList.getTextRange().getEndOffset()));
            }
            else if (element instanceof JetObjectDeclaration) {
                return NAME_IDENTIFIER.mark((JetObjectDeclaration) element);
            }
            return super.mark(element);
        }
    }

    public static final PositioningStrategy DECLARATION = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetDeclaration element) {
            if (element instanceof PsiNameIdentifierOwner) {
                return NAMED_ELEMENT.mark((PsiNameIdentifierOwner) element);
            }
            return super.mark(element);
        }

        @Override
        public boolean isValid(@NotNull JetDeclaration element) {
            if (element instanceof PsiNameIdentifierOwner) {
                return NAMED_ELEMENT.isValid((PsiNameIdentifierOwner) element);
            }
            return super.isValid(element);
        }
    };

    public static final PositioningStrategy DECLARATION_OR_DEFAULT = new DeclarationHeader() {
        @NotNull
        @Override
        public List mark(@NotNull PsiElement element) {
            if (element instanceof JetDeclaration) {
                return super.mark((JetDeclaration) element);
            }
            return DEFAULT.mark(element);
        }

        @Override
        public boolean isValid(@NotNull PsiElement element) {
            if (element instanceof JetDeclaration) {
                return DECLARATION.isValid((JetDeclaration) element);
            }
            return DEFAULT.isValid(element);
        }
    };

    public static final PositioningStrategy ABSTRACT_MODIFIER = modifierSetPosition(JetTokens.ABSTRACT_KEYWORD);

    public static final PositioningStrategy OVERRIDE_MODIFIER = modifierSetPosition(JetTokens.OVERRIDE_KEYWORD);

    public static final PositioningStrategy FINAL_MODIFIER = modifierSetPosition(JetTokens.FINAL_KEYWORD);

    public static final PositioningStrategy VARIANCE_MODIFIER = modifierSetPosition(JetTokens.IN_KEYWORD,
                                                                                                          JetTokens.OUT_KEYWORD);
    public static final PositioningStrategy FOR_REDECLARATION = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull PsiElement element) {
            if (element instanceof JetNamedDeclaration) {
                PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
                if (nameIdentifier != null) {
                    return markElement(nameIdentifier);
                }
            }
            else if (element instanceof JetFile) {
                JetFile file = (JetFile) element;
                PsiElement nameIdentifier = file.getPackageDirective().getNameIdentifier();
                if (nameIdentifier != null) {
                    return markElement(nameIdentifier);
                }
            }
            return markElement(element);
        }
    };
    public static final PositioningStrategy FOR_UNRESOLVED_REFERENCE =
            new PositioningStrategy() {
                @NotNull
                @Override
                public List mark(@NotNull JetReferenceExpression element) {
                    if (element instanceof JetArrayAccessExpression) {
                        List ranges = ((JetArrayAccessExpression) element).getBracketRanges();
                        if (!ranges.isEmpty()) {
                            return ranges;
                        }
                    }
                    return Collections.singletonList(element.getTextRange());
                }
            };

    public static PositioningStrategy modifierSetPosition(final JetKeywordToken... tokens) {
        return new PositioningStrategy() {
            @NotNull
            @Override
            public List mark(@NotNull JetModifierListOwner modifierListOwner) {
                JetModifierList modifierList = modifierListOwner.getModifierList();
                assert modifierList != null : "No modifier list, but modifier has been found by the analyzer";

                for (JetKeywordToken token : tokens) {
                    ASTNode node = modifierList.getModifierNode(token);
                    if (node != null) {
                        return markNode(node);
                    }
                }
                throw new IllegalStateException("None of the modifiers is found: " + Arrays.asList(tokens));
            }
        };
    }

    public static final PositioningStrategy ARRAY_ACCESS = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetArrayAccessExpression element) {
            return markElement(element.getIndicesNode());
        }
    };

    public static final PositioningStrategy VISIBILITY_MODIFIER = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetModifierListOwner element) {
            List visibilityTokens = Lists.newArrayList(
                    JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PUBLIC_KEYWORD, JetTokens.INTERNAL_KEYWORD);
            List result = Lists.newArrayList();
            for (JetModifierKeywordToken token : visibilityTokens) {
                if (element.hasModifier(token)) {
                    //noinspection ConstantConditions
                    result.add(element.getModifierList().getModifierNode(token).getTextRange());
                }
            }

            if (!result.isEmpty()) return result;

            // Try to resolve situation when there's no visibility modifiers written before element

            if (element instanceof PsiNameIdentifierOwner) {
                PsiElement nameIdentifier = ((PsiNameIdentifierOwner) element).getNameIdentifier();
                if (nameIdentifier != null) {
                    return ImmutableList.of(nameIdentifier.getTextRange());
                }
            }

            if (element instanceof JetObjectDeclaration) {
                return ImmutableList.of(((JetObjectDeclaration) element).getObjectKeyword().getTextRange());
            }

            if (element instanceof JetPropertyAccessor) {
                return ImmutableList.of(((JetPropertyAccessor) element).getNamePlaceholder().getTextRange());
            }

            if (element instanceof JetClassInitializer) {
                return ImmutableList.of(element.getTextRange());
            }

            if (element instanceof JetClassObject) {
                JetObjectDeclaration objectDeclaration = ((JetClassObject) element).getObjectDeclaration();
                return ImmutableList.of(objectDeclaration.getObjectKeyword().getTextRange());
            }

            throw new IllegalArgumentException(
                    String.format("Can't find text range for element '%s' with the text '%s'",
                                  element.getClass().getCanonicalName(), element.getText()));
        }
    };

    public static final PositioningStrategy VARIANCE_IN_PROJECTION = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetTypeProjection element) {
            return markNode(element.getProjectionNode());
        }
    };

    public static final PositioningStrategy PARAMETER_DEFAULT_VALUE = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetParameter element) {
            return markNode(element.getDefaultValue().getNode());
        }
    };

    public static final PositioningStrategy CALL_ELEMENT = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull PsiElement callElement) {
            if (callElement instanceof JetCallElement) {
                JetExpression calleeExpression = ((JetCallElement) callElement).getCalleeExpression();
                if (calleeExpression != null) {
                    return markElement(calleeExpression);
                }
            }
            return markElement(callElement);
        }
    };

    public static final PositioningStrategy DECLARATION_WITH_BODY = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetDeclarationWithBody element) {
            JetExpression bodyExpression = element.getBodyExpression();
            if ((bodyExpression instanceof JetBlockExpression)) {
                TextRange lastBracketRange = ((JetBlockExpression) bodyExpression).getLastBracketRange();
                if (lastBracketRange != null) {
                    return markRange(lastBracketRange);
                }
            }
            return markElement(element);
        }

        @Override
        public boolean isValid(@NotNull JetDeclarationWithBody element) {
            if (!super.isValid(element)) return false;

            JetExpression bodyExpression = element.getBodyExpression();
            if (!(bodyExpression instanceof JetBlockExpression)) return false;
            if (((JetBlockExpression) bodyExpression).getLastBracketRange() == null) return false;
            return true;
        }
    };

    public static final PositioningStrategy VAL_OR_VAR_NODE = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetProperty property) {
            return markNode(property.getValOrVarNode());
        }
    };

    public static final PositioningStrategy ELSE_ENTRY = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetWhenEntry entry) {
            PsiElement elseKeywordElement = entry.getElseKeywordElement();
            assert elseKeywordElement != null;
            return markElement(elseKeywordElement);
        }
    };

    public static final PositioningStrategy WHEN_EXPRESSION = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetWhenExpression element) {
            return markElement(element.getWhenKeywordElement());
        }
    };

    public static final PositioningStrategy WHEN_CONDITION_IN_RANGE =
            new PositioningStrategy() {
                @NotNull
                @Override
                public List mark(@NotNull JetWhenConditionInRange condition) {
                    return markElement(condition.getOperationReference());
                }
            };

    public static final PositioningStrategy NULLABLE_TYPE = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetNullableType element) {
            return markNode(element.getQuestionMarkNode());
        }
    };

    public static final PositioningStrategy CALL_EXPRESSION = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull PsiElement element) {
            if (element instanceof JetCallExpression) {
                JetCallExpression callExpression = (JetCallExpression) element;
                PsiElement endElement;
                JetTypeArgumentList typeArgumentList = callExpression.getTypeArgumentList();
                JetExpression calleeExpression = callExpression.getCalleeExpression();
                if (typeArgumentList != null) {
                    endElement = typeArgumentList;
                }
                else if (calleeExpression != null) {
                    endElement = calleeExpression;
                }
                else {
                    endElement = element;
                }
                return markRange(new TextRange(element.getTextRange().getStartOffset(), endElement.getTextRange().getEndOffset()));
            }
            return super.mark(element);
        }
    };

    public static final PositioningStrategy VALUE_ARGUMENTS = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetElement element) {
            if (element instanceof JetValueArgumentList) {
                PsiElement rightParenthesis = ((JetValueArgumentList) element).getRightParenthesis();
                if (rightParenthesis != null) {
                    return markElement(rightParenthesis);
                }

            }
            return super.mark(element);
        }
    };

    public static final PositioningStrategy FUNCTION_LITERAL_PARAMETERS = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetFunctionLiteral functionLiteral) {
            JetParameterList valueParameterList = functionLiteral.getValueParameterList();
            if (valueParameterList != null) {
                return markElement(valueParameterList);
            }
            return markNode(functionLiteral.getOpenBraceNode());
        }
    };

    public static final PositioningStrategy CUT_CHAR_QUOTES = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetElement element) {
            if (element instanceof JetConstantExpression) {
                if (element.getNode().getElementType() == JetNodeTypes.CHARACTER_CONSTANT) {
                    TextRange elementTextRange = element.getTextRange();
                    return Collections.singletonList(
                            TextRange.create(elementTextRange.getStartOffset() + 1, elementTextRange.getEndOffset() - 1));
                }
            }
            return super.mark(element);
        }
    };

    public static final PositioningStrategy LONG_LITERAL_SUFFIX = new PositioningStrategy() {
        @NotNull
        @Override
        public List mark(@NotNull JetElement element) {
            if (element instanceof JetConstantExpression) {
                if (element.getNode().getElementType() == JetNodeTypes.INTEGER_CONSTANT) {
                    int endOffset = element.getTextRange().getEndOffset();
                    return Collections.singletonList(TextRange.create(endOffset - 1, endOffset));
                }
            }
            return super.mark(element);
        }
    };

    public static PositioningStrategy markTextRangesFromDiagnostic(
            @NotNull final Function1> getTextRanges
    ) {
        return new PositioningStrategy() {
            @NotNull
            @Override
            public List markDiagnostic(@NotNull ParametrizedDiagnostic diagnostic) {
                return getTextRanges.invoke(diagnostic);
            }
        };
    }

    private PositioningStrategies() {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy