org.jetbrains.jet.lang.diagnostics.PositioningStrategies Maven / Gradle / Ivy
/*
* 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() {
}
}