Added ability not to mark error if there is a syntax one in some cases

This commit is contained in:
Svetlana Isakova
2012-03-06 13:07:04 +04:00
parent 5b6805eede
commit 72c9eef31b
9 changed files with 62 additions and 95 deletions
@@ -44,8 +44,8 @@ public class CheckerTestUtil {
public static final Comparator<Diagnostic> DIAGNOSTIC_COMPARATOR = new Comparator<Diagnostic>() { public static final Comparator<Diagnostic> DIAGNOSTIC_COMPARATOR = new Comparator<Diagnostic>() {
@Override @Override
public int compare(Diagnostic o1, Diagnostic o2) { public int compare(Diagnostic o1, Diagnostic o2) {
List<TextRange> ranges1 = getTextRanges(o1); List<TextRange> ranges1 = o1.getTextRanges();
List<TextRange> ranges2 = getTextRanges(o2); List<TextRange> ranges2 = o2.getTextRanges();
if (ranges1.size() != ranges2.size()) return ranges1.size() - ranges2.size(); if (ranges1.size() != ranges2.size()) return ranges1.size() - ranges2.size();
for (int i = 0; i < ranges1.size(); i++) { for (int i = 0; i < ranges1.size(); i++) {
TextRange range1 = ranges1.get(i); TextRange range1 = ranges1.get(i);
@@ -160,7 +160,7 @@ public class CheckerTestUtil {
private static void unexpectedDiagnostics(List<Diagnostic> actual, DiagnosticDiffCallbacks callbacks) { private static void unexpectedDiagnostics(List<Diagnostic> actual, DiagnosticDiffCallbacks callbacks) {
for (Diagnostic diagnostic : actual) { for (Diagnostic diagnostic : actual) {
if (!diagnostic.getPsiFile().equals(callbacks.getFile())) continue; if (!diagnostic.getPsiFile().equals(callbacks.getFile())) continue;
List<TextRange> textRanges = getTextRanges(diagnostic); List<TextRange> textRanges = diagnostic.getTextRanges();
for (TextRange textRange : textRanges) { for (TextRange textRange : textRanges) {
callbacks.unexpectedDiagnostic(diagnostic.getFactory().getName(), textRange.getStartOffset(), textRange.getEndOffset()); callbacks.unexpectedDiagnostic(diagnostic.getFactory().getName(), textRange.getStartOffset(), textRange.getEndOffset());
} }
@@ -358,7 +358,10 @@ public class CheckerTestUtil {
List<DiagnosticDescriptor> diagnosticDescriptors = Lists.newArrayList(); List<DiagnosticDescriptor> diagnosticDescriptors = Lists.newArrayList();
DiagnosticDescriptor currentDiagnosticDescriptor = null; DiagnosticDescriptor currentDiagnosticDescriptor = null;
for (Diagnostic diagnostic : list) { for (Diagnostic diagnostic : list) {
TextRange textRange = getTextRanges(diagnostic).get(0); List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) continue;
TextRange textRange = textRanges.get(0);
if (currentDiagnosticDescriptor != null && currentDiagnosticDescriptor.equalRange(textRange)) { if (currentDiagnosticDescriptor != null && currentDiagnosticDescriptor.equalRange(textRange)) {
currentDiagnosticDescriptor.diagnostics.add(diagnostic); currentDiagnosticDescriptor.diagnostics.add(diagnostic);
} }
@@ -370,10 +373,6 @@ public class CheckerTestUtil {
return diagnosticDescriptors; return diagnosticDescriptors;
} }
private static List<TextRange> getTextRanges(Diagnostic currentDiagnostic) {
return currentDiagnostic.getTextRanges();
}
private static class DiagnosticDescriptor { private static class DiagnosticDescriptor {
private final int start; private final int start;
private final int end; private final int end;
@@ -26,6 +26,8 @@ import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
@@ -75,11 +77,13 @@ public class DiagnosticUtils {
return offsetToLineAndColumn(document, offset).toString() + pathSuffix; return offsetToLineAndColumn(document, offset).toString() + pathSuffix;
} }
@NotNull @Nullable
public static LineAndColumn getLineAndColumn(@NotNull Diagnostic diagnostic) { public static LineAndColumn getLineAndColumn(@NotNull Diagnostic diagnostic) {
PsiFile file = diagnostic.getPsiFile(); PsiFile file = diagnostic.getPsiFile();
Document document = file.getViewProvider().getDocument(); Document document = file.getViewProvider().getDocument();
TextRange firstRange = diagnostic.getTextRanges().iterator().next(); List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return null;
TextRange firstRange = textRanges.iterator().next();
return offsetToLineAndColumn(document, firstRange.getStartOffset()); return offsetToLineAndColumn(document, firstRange.getStartOffset());
} }
@@ -32,6 +32,7 @@ import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -116,7 +117,6 @@ public interface Errors {
DiagnosticFactory<JetExpression> MANY_FUNCTION_LITERAL_ARGUMENTS = DiagnosticFactory.create(ERROR, "Only one function literal is allowed outside a parenthesized argument list"); DiagnosticFactory<JetExpression> MANY_FUNCTION_LITERAL_ARGUMENTS = DiagnosticFactory.create(ERROR, "Only one function literal is allowed outside a parenthesized argument list");
DiagnosticFactory<PsiElement> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory.create(ERROR, "This property must either have a type annotation or be initialized"); DiagnosticFactory<PsiElement> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory.create(ERROR, "This property must either have a type annotation or be initialized");
DiagnosticFactory<JetElement> FUNCTION_WITH_NO_TYPE_NO_BODY = DiagnosticFactory.create(ERROR, "This function must either declare a return type or have a body element");
DiagnosticFactory<JetModifierListOwner> ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS = DiagnosticFactory.create(ERROR, "This property cannot be declared abstract", PositioningStrategies.POSITION_ABSTRACT_MODIFIER); DiagnosticFactory<JetModifierListOwner> ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS = DiagnosticFactory.create(ERROR, "This property cannot be declared abstract", PositioningStrategies.POSITION_ABSTRACT_MODIFIER);
DiagnosticFactory<JetProperty> ABSTRACT_PROPERTY_NOT_IN_CLASS = DiagnosticFactory.create(ERROR, "A property may be abstract only when defined in a class or trait", PositioningStrategies.POSITION_ABSTRACT_MODIFIER); DiagnosticFactory<JetProperty> ABSTRACT_PROPERTY_NOT_IN_CLASS = DiagnosticFactory.create(ERROR, "A property may be abstract only when defined in a class or trait", PositioningStrategies.POSITION_ABSTRACT_MODIFIER);
DiagnosticFactory<JetExpression> ABSTRACT_PROPERTY_WITH_INITIALIZER = DiagnosticFactory.create(ERROR, "Property with initializer cannot be abstract"); DiagnosticFactory<JetExpression> ABSTRACT_PROPERTY_WITH_INITIALIZER = DiagnosticFactory.create(ERROR, "Property with initializer cannot be abstract");
@@ -124,21 +124,21 @@ public interface Errors {
DiagnosticFactory<JetPropertyAccessor> ABSTRACT_PROPERTY_WITH_SETTER = DiagnosticFactory.create(ERROR, "Property with setter implementation cannot be abstract"); DiagnosticFactory<JetPropertyAccessor> ABSTRACT_PROPERTY_WITH_SETTER = DiagnosticFactory.create(ERROR, "Property with setter implementation cannot be abstract");
DiagnosticFactory<PsiElement> GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY = DiagnosticFactory.create(ERROR, "Getter visibility must be the same as property visibility"); DiagnosticFactory<PsiElement> GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY = DiagnosticFactory.create(ERROR, "Getter visibility must be the same as property visibility");
DiagnosticFactory BACKING_FIELD_IN_TRAIT = DiagnosticFactory.create(ERROR, "Property in a trait cannot have a backing field"); DiagnosticFactory<JetProperty> BACKING_FIELD_IN_TRAIT = DiagnosticFactory.create(ERROR, "Property in a trait cannot have a backing field", PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory MUST_BE_INITIALIZED = DiagnosticFactory.create(ERROR, "Property must be initialized"); DiagnosticFactory<JetProperty> MUST_BE_INITIALIZED = DiagnosticFactory.create(ERROR, "Property must be initialized", PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory<PsiElement> MUST_BE_INITIALIZED_OR_BE_ABSTRACT = DiagnosticFactory.create(ERROR, "Property must be initialized or be abstract"); DiagnosticFactory<JetProperty> MUST_BE_INITIALIZED_OR_BE_ABSTRACT = DiagnosticFactory.create(ERROR, "Property must be initialized or be abstract", PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory<JetExpression> PROPERTY_INITIALIZER_IN_TRAIT = DiagnosticFactory.create(ERROR, "Property initializers are not allowed in traits"); DiagnosticFactory<JetExpression> PROPERTY_INITIALIZER_IN_TRAIT = DiagnosticFactory.create(ERROR, "Property initializers are not allowed in traits");
DiagnosticFactory PROPERTY_INITIALIZER_NO_BACKING_FIELD = DiagnosticFactory.create(ERROR, "Initializer is not allowed here because this property has no backing field"); DiagnosticFactory<JetExpression> PROPERTY_INITIALIZER_NO_BACKING_FIELD = DiagnosticFactory.create(ERROR, "Initializer is not allowed here because this property has no backing field");
DiagnosticFactory3<JetModifierListOwner, String, ClassDescriptor, JetClass> ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = DiagnosticFactory3.create(ERROR, "Abstract property {0} in non-abstract class {1}", PositioningStrategies.POSITION_ABSTRACT_MODIFIER); DiagnosticFactory3<JetModifierListOwner, String, ClassDescriptor, JetClass> ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = DiagnosticFactory3.create(ERROR, "Abstract property {0} in non-abstract class {1}", PositioningStrategies.POSITION_ABSTRACT_MODIFIER);
DiagnosticFactory3<JetFunction, String, ClassDescriptor, JetClass> ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS = DiagnosticFactory3.create(ERROR, "Abstract function {0} in non-abstract class {1}", PositioningStrategies.POSITION_ABSTRACT_MODIFIER); DiagnosticFactory3<JetFunction, String, ClassDescriptor, JetClass> ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS = DiagnosticFactory3.create(ERROR, "Abstract function {0} in non-abstract class {1}", PositioningStrategies.POSITION_ABSTRACT_MODIFIER);
DiagnosticFactory1<PsiElement, SimpleFunctionDescriptor> ABSTRACT_FUNCTION_WITH_BODY = DiagnosticFactory1.create(ERROR, "A function {0} with body cannot be abstract"); DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> ABSTRACT_FUNCTION_WITH_BODY = DiagnosticFactory1.create(ERROR, "A function {0} with body cannot be abstract", PositioningStrategies.POSITION_ABSTRACT_MODIFIER);
DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> NON_ABSTRACT_FUNCTION_WITH_NO_BODY = DiagnosticFactory1.create(ERROR, "Method {0} without a body must be abstract", PositioningStrategies.POSITION_NAME_IDENTIFIER); DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> NON_ABSTRACT_FUNCTION_WITH_NO_BODY = DiagnosticFactory1.create(ERROR, "Method {0} without a body must be abstract", PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory1<JetModifierListOwner, SimpleFunctionDescriptor> NON_MEMBER_ABSTRACT_FUNCTION = DiagnosticFactory1.create(ERROR, "Function {0} is not a class or trait member and cannot be abstract", PositioningStrategies.POSITION_ABSTRACT_MODIFIER); DiagnosticFactory1<JetModifierListOwner, SimpleFunctionDescriptor> NON_MEMBER_ABSTRACT_FUNCTION = DiagnosticFactory1.create(ERROR, "Function {0} is not a class or trait member and cannot be abstract", PositioningStrategies.POSITION_ABSTRACT_MODIFIER);
DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> NON_MEMBER_FUNCTION_NO_BODY = DiagnosticFactory1.create(ERROR, "Function {0} must have a body", PositioningStrategies.POSITION_NAME_IDENTIFIER); DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> NON_MEMBER_FUNCTION_NO_BODY = DiagnosticFactory1.create(ERROR, "Function {0} must have a body", PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory<PsiElement> NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticFactory.create(ERROR, "Non final member in a final class"); DiagnosticFactory<JetNamedDeclaration> NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticFactory.create(ERROR, "Non final member in a final class", PositioningStrategies.positionModifier(JetTokens.OPEN_KEYWORD));
DiagnosticFactory<PsiElement> PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE = DiagnosticFactory.create(ERROR, "Public or protected member should specify a type"); DiagnosticFactory<JetNamedDeclaration> PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE = DiagnosticFactory.create(ERROR, "Public or protected member should specify a type", PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory<JetTypeProjection> PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT = DiagnosticFactory.create(ERROR, "Projections are not allowed on type arguments of functions and properties"); // TODO : better positioning DiagnosticFactory<JetTypeProjection> PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT = DiagnosticFactory.create(ERROR, "Projections are not allowed on type arguments of functions and properties"); // TODO : better positioning
DiagnosticFactory<JetDelegatorToSuperClass> SUPERTYPE_NOT_INITIALIZED = DiagnosticFactory.create(ERROR, "This type has a constructor, and thus must be initialized here"); DiagnosticFactory<JetDelegatorToSuperClass> SUPERTYPE_NOT_INITIALIZED = DiagnosticFactory.create(ERROR, "This type has a constructor, and thus must be initialized here");
@@ -189,20 +189,8 @@ public interface Errors {
DiagnosticFactory<JetPropertyAccessor> LOCAL_VARIABLE_WITH_SETTER = DiagnosticFactory.create(ERROR, "Local variables are not allowed to have setters"); DiagnosticFactory<JetPropertyAccessor> LOCAL_VARIABLE_WITH_SETTER = DiagnosticFactory.create(ERROR, "Local variables are not allowed to have setters");
DiagnosticFactory<JetPropertyAccessor> VAL_WITH_SETTER = DiagnosticFactory.create(ERROR, "A 'val'-property cannot have a setter"); DiagnosticFactory<JetPropertyAccessor> VAL_WITH_SETTER = DiagnosticFactory.create(ERROR, "A 'val'-property cannot have a setter");
DiagnosticFactory<JetArrayAccessExpression> NO_GET_METHOD = DiagnosticFactory.create(ERROR, "No get method providing array access", new PositioningStrategy<JetArrayAccessExpression>() { DiagnosticFactory<JetArrayAccessExpression> NO_GET_METHOD = DiagnosticFactory.create(ERROR, "No get method providing array access", PositioningStrategies.POSITION_ARRAY_ACCESS);
@NotNull DiagnosticFactory<JetArrayAccessExpression> NO_SET_METHOD = DiagnosticFactory.create(ERROR, "No set method providing array access", PositioningStrategies.POSITION_ARRAY_ACCESS);
@Override
public List<TextRange> mark(@NotNull JetArrayAccessExpression element) {
return markElement(element.getIndicesNode());
}
});
DiagnosticFactory<JetArrayAccessExpression> NO_SET_METHOD = DiagnosticFactory.create(ERROR, "No set method providing array access", new PositioningStrategy<JetArrayAccessExpression>() {
@NotNull
@Override
public List<TextRange> mark(@NotNull JetArrayAccessExpression element) {
return markElement(element.getIndicesNode());
}
});
DiagnosticFactory<JetSimpleNameExpression> INC_DEC_SHOULD_NOT_RETURN_UNIT = DiagnosticFactory.create(ERROR, "Functions inc(), dec() shouldn't return Unit to be used by operators ++, --"); DiagnosticFactory<JetSimpleNameExpression> INC_DEC_SHOULD_NOT_RETURN_UNIT = DiagnosticFactory.create(ERROR, "Functions inc(), dec() shouldn't return Unit to be used by operators ++, --");
DiagnosticFactory2<JetSimpleNameExpression, DeclarationDescriptor, JetSimpleNameExpression> ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT = DiagnosticFactory2<JetSimpleNameExpression, DeclarationDescriptor, JetSimpleNameExpression> ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT =
@@ -218,10 +206,9 @@ public interface Errors {
DiagnosticFactory<JetThisExpression> NO_THIS = DiagnosticFactory.create(ERROR, "'this' is not defined in this context"); DiagnosticFactory<JetThisExpression> NO_THIS = DiagnosticFactory.create(ERROR, "'this' is not defined in this context");
DiagnosticFactory<JetSuperExpression> SUPER_NOT_AVAILABLE = DiagnosticFactory.create(ERROR, "No supertypes are accessible in this context"); DiagnosticFactory<JetSuperExpression> SUPER_NOT_AVAILABLE = DiagnosticFactory.create(ERROR, "No supertypes are accessible in this context");
DiagnosticFactory<JetSuperExpression> AMBIGUOUS_SUPER = DiagnosticFactory.create(ERROR, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super<Foo>'"); DiagnosticFactory<JetSuperExpression> AMBIGUOUS_SUPER = DiagnosticFactory.create(ERROR, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super<Foo>'");
DiagnosticFactory<JetExpression> ABSTRACT_SUPER_CALL = DiagnosticFactory.create(ERROR, "Abstarct member cannot be accessed directly"); DiagnosticFactory<JetExpression> ABSTRACT_SUPER_CALL = DiagnosticFactory.create(ERROR, "Abstract member cannot be accessed directly");
DiagnosticFactory<JetTypeReference> NOT_A_SUPERTYPE = DiagnosticFactory.create(ERROR, "Not a supertype"); DiagnosticFactory<JetTypeReference> NOT_A_SUPERTYPE = DiagnosticFactory.create(ERROR, "Not a supertype");
DiagnosticFactory<PsiElement> TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER = DiagnosticFactory.create(WARNING, "Type arguments do not need to be specified in a 'super' qualifier"); DiagnosticFactory<PsiElement> TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER = DiagnosticFactory.create(WARNING, "Type arguments do not need to be specified in a 'super' qualifier");
DiagnosticFactory<JetWhenExpression> NO_WHEN_ENTRIES = DiagnosticFactory.create(ERROR, "Entries are required for when-expression"); // TODO : Scope, and maybe this should not be an error
DiagnosticFactory<JetSimpleNameExpression> USELESS_CAST_STATIC_ASSERT_IS_FINE = DiagnosticFactory.create(WARNING, "No cast needed, use ':' instead"); DiagnosticFactory<JetSimpleNameExpression> USELESS_CAST_STATIC_ASSERT_IS_FINE = DiagnosticFactory.create(WARNING, "No cast needed, use ':' instead");
DiagnosticFactory<JetSimpleNameExpression> USELESS_CAST = DiagnosticFactory.create(WARNING, "No cast needed"); DiagnosticFactory<JetSimpleNameExpression> USELESS_CAST = DiagnosticFactory.create(WARNING, "No cast needed");
DiagnosticFactory<JetSimpleNameExpression> CAST_NEVER_SUCCEEDS = DiagnosticFactory.create(WARNING, "This cast can never succeed"); DiagnosticFactory<JetSimpleNameExpression> CAST_NEVER_SUCCEEDS = DiagnosticFactory.create(WARNING, "This cast can never succeed");
@@ -285,6 +272,7 @@ public interface Errors {
@NotNull @NotNull
@Override @Override
public List<TextRange> mark(@NotNull JetWhenExpression element) { public List<TextRange> mark(@NotNull JetWhenExpression element) {
if (hasSyntaxError(element)) return Collections.emptyList();
return markElement(element.getWhenKeywordElement()); return markElement(element.getWhenKeywordElement());
} }
}); });
@@ -20,6 +20,7 @@ package org.jetbrains.jet.lang.diagnostics;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNameIdentifierOwner;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -35,32 +36,7 @@ import java.util.List;
public class PositioningStrategies { public class PositioningStrategies {
public static final PositioningStrategy<PsiElement> DEFAULT = new PositioningStrategy<PsiElement>(); public static final PositioningStrategy<PsiElement> DEFAULT = new PositioningStrategy<PsiElement>();
public static final PositioningStrategy<JetFunction> MARK_FUNCTION = new PositioningStrategy<JetFunction>() {
@NotNull
@Override
public List<TextRange> mark(@NotNull JetFunction function) {
TextRange textRange;
PsiElement nameIdentifier = function.getNameIdentifier();
JetTypeReference returnTypeRef = function.getReturnTypeRef();
JetParameterList valueParameterList = function.getValueParameterList();
if (nameIdentifier == null) {
textRange = TextRange.from(function.getTextRange().getEndOffset(), 0);
}
else if (returnTypeRef != null) {
textRange = TextRange.from(returnTypeRef.getTextRange().getEndOffset(), 1);
}
else if (valueParameterList != null) {
textRange = TextRange.from(valueParameterList.getTextRange().getEndOffset(), 1);
}
else {
textRange = TextRange.from(nameIdentifier.getTextRange().getEndOffset(), 1);
}
return markRange(textRange);
}
};
public static final PositioningStrategy<JetDeclaration> POSITION_DECLARATION = new PositioningStrategy<JetDeclaration>() { public static final PositioningStrategy<JetDeclaration> POSITION_DECLARATION = new PositioningStrategy<JetDeclaration>() {
@NotNull @NotNull
@Override @Override
@@ -87,16 +63,20 @@ public class PositioningStrategies {
return super.mark(declaration); return super.mark(declaration);
} }
private ASTNode getNameNode(JetNamedDeclaration function) { private ASTNode getNameNode(JetNamedDeclaration function) {
PsiElement nameIdentifier = function.getNameIdentifier(); PsiElement nameIdentifier = function.getNameIdentifier();
return nameIdentifier == null ? null : nameIdentifier.getNode(); return nameIdentifier == null ? null : nameIdentifier.getNode();
} }
}; };
public static final PositioningStrategy<PsiNameIdentifierOwner> POSITION_NAME_IDENTIFIER = new PositioningStrategy<PsiNameIdentifierOwner>() { public static final PositioningStrategy<PsiNameIdentifierOwner> POSITION_NAME_IDENTIFIER = new PositioningStrategy<PsiNameIdentifierOwner>() {
@NotNull @NotNull
@Override @Override
public List<TextRange> mark(@NotNull PsiNameIdentifierOwner element) { public List<TextRange> mark(@NotNull PsiNameIdentifierOwner element) {
if (element.getLastChild() instanceof PsiErrorElement) {
return Collections.emptyList();
}
PsiElement nameIdentifier = element.getNameIdentifier(); PsiElement nameIdentifier = element.getNameIdentifier();
if (nameIdentifier != null) { if (nameIdentifier != null) {
return markElement(nameIdentifier); return markElement(nameIdentifier);
@@ -114,7 +94,7 @@ public class PositioningStrategies {
public List<TextRange> mark(@NotNull JetModifierListOwner modifierListOwner) { public List<TextRange> mark(@NotNull JetModifierListOwner modifierListOwner) {
if (modifierListOwner.hasModifier(token)) { if (modifierListOwner.hasModifier(token)) {
JetModifierList modifierList = modifierListOwner.getModifierList(); JetModifierList modifierList = modifierListOwner.getModifierList();
assert modifierList != null; assert modifierList != null;
ASTNode node = modifierList.getModifierNode(token); ASTNode node = modifierList.getModifierNode(token);
assert node != null; assert node != null;
return Collections.singletonList(node.getTextRange()); return Collections.singletonList(node.getTextRange());
@@ -123,4 +103,12 @@ public class PositioningStrategies {
} }
}; };
} }
public static PositioningStrategy<JetArrayAccessExpression> POSITION_ARRAY_ACCESS = new PositioningStrategy<JetArrayAccessExpression>() {
@NotNull
@Override
public List<TextRange> mark(@NotNull JetArrayAccessExpression element) {
return markElement(element.getIndicesNode());
}
};
} }
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.diagnostics;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collections; import java.util.Collections;
@@ -33,6 +34,10 @@ public class PositioningStrategy<E extends PsiElement> {
return markElement(element); return markElement(element);
} }
protected boolean hasSyntaxError(@NotNull E element) {
return element.getLastChild() instanceof PsiErrorElement;
}
@NotNull @NotNull
protected static List<TextRange> markElement(@NotNull PsiElement element) { protected static List<TextRange> markElement(@NotNull PsiElement element) {
return Collections.singletonList(element.getTextRange()); return Collections.singletonList(element.getTextRange());
@@ -93,7 +93,7 @@ public class DeclarationsChecker {
} }
private void checkClass(JetClass aClass, MutableClassDescriptor classDescriptor) { private void checkClass(JetClass aClass, MutableClassDescriptor classDescriptor) {
checkOpenMembers(aClass, classDescriptor); checkOpenMembers(classDescriptor);
checkTraitModifiers(aClass); checkTraitModifiers(aClass);
checkEnum(aClass, classDescriptor); checkEnum(aClass, classDescriptor);
} }
@@ -118,15 +118,12 @@ public class DeclarationsChecker {
checkIllegalInThisContextModifiers(objectDeclaration.getModifierList(), Sets.newHashSet(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.OVERRIDE_KEYWORD)); checkIllegalInThisContextModifiers(objectDeclaration.getModifierList(), Sets.newHashSet(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.OVERRIDE_KEYWORD));
} }
private void checkOpenMembers(JetClass aClass, MutableClassDescriptor classDescriptor) { private void checkOpenMembers(MutableClassDescriptor classDescriptor) {
for (CallableMemberDescriptor memberDescriptor : classDescriptor.getCallableMembers()) { for (CallableMemberDescriptor memberDescriptor : classDescriptor.getCallableMembers()) {
JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, memberDescriptor); JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, memberDescriptor);
if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) { if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
JetModifierList modifierList = member.getModifierList(); context.getTrace().report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
assert modifierList != null;
ASTNode openModifierNode = modifierList.getModifierNode(JetTokens.OPEN_KEYWORD);
context.getTrace().report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(openModifierNode.getPsi()));
} }
} }
} }
@@ -143,7 +140,6 @@ public class DeclarationsChecker {
} }
private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) { private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) {
PsiElement nameIdentifier = member.getNameIdentifier();
boolean hasDeferredType; boolean hasDeferredType;
if (member instanceof JetProperty) { if (member instanceof JetProperty) {
hasDeferredType = ((JetProperty) member).getPropertyTypeRef() == null && DescriptorResolver.hasBody((JetProperty) member); hasDeferredType = ((JetProperty) member).getPropertyTypeRef() == null && DescriptorResolver.hasBody((JetProperty) member);
@@ -153,9 +149,8 @@ public class DeclarationsChecker {
JetFunction function = (JetFunction) member; JetFunction function = (JetFunction) member;
hasDeferredType = function.getReturnTypeRef() == null && function.getBodyExpression() != null && !function.hasBlockBody(); hasDeferredType = function.getReturnTypeRef() == null && function.getBodyExpression() != null && !function.hasBlockBody();
} }
if ((memberDescriptor.getVisibility() == Visibility.PUBLIC || memberDescriptor.getVisibility() == Visibility.PROTECTED) && if ((memberDescriptor.getVisibility() == Visibility.PUBLIC || memberDescriptor.getVisibility() == Visibility.PROTECTED) && hasDeferredType) {
hasDeferredType && nameIdentifier != null) { context.getTrace().report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member));
context.getTrace().report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(nameIdentifier));
} }
} }
@@ -212,27 +207,21 @@ public class DeclarationsChecker {
JetExpression initializer = property.getInitializer(); JetExpression initializer = property.getInitializer();
boolean backingFieldRequired = context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); boolean backingFieldRequired = context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
PsiElement nameIdentifier = property.getNameIdentifier(); if (inTrait && backingFieldRequired && hasAccessorImplementation) {
context.getTrace().report(BACKING_FIELD_IN_TRAIT.on(property));
if (inTrait && backingFieldRequired && hasAccessorImplementation && nameIdentifier != null) {
context.getTrace().report(BACKING_FIELD_IN_TRAIT.on(nameIdentifier));
} }
if (initializer == null) { if (initializer == null) {
if (nameIdentifier != null && backingFieldRequired && !inTrait && !context.getTrace().getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { if (backingFieldRequired && !inTrait && !context.getTrace().getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) {
if (classDescriptor == null || hasAccessorImplementation) { if (classDescriptor == null || hasAccessorImplementation) {
context.getTrace().report(MUST_BE_INITIALIZED.on(nameIdentifier)); context.getTrace().report(MUST_BE_INITIALIZED.on(property));
} }
else { else {
context.getTrace().report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(nameIdentifier)); context.getTrace().report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
} }
} }
return; return;
} }
if (inTrait) { if (inTrait) {
JetType returnType = propertyDescriptor.getReturnType();
if (returnType instanceof DeferredType) {
returnType = ((DeferredType) returnType).getActualType();
}
context.getTrace().report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer)); context.getTrace().report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
} }
else if (!backingFieldRequired) { else if (!backingFieldRequired) {
@@ -242,10 +231,7 @@ public class DeclarationsChecker {
protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) { protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration(); DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
PsiElement nameIdentifier = function.getNameIdentifier(); boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
JetModifierList modifierList = function.getModifierList();
ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
boolean hasAbstractModifier = abstractNode != null;
checkDeclaredTypeInPublicMember(function, functionDescriptor); checkDeclaredTypeInPublicMember(function, functionDescriptor);
if (containingDescriptor instanceof ClassDescriptor) { if (containingDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
@@ -261,9 +247,9 @@ public class DeclarationsChecker {
context.getTrace().report(ABSTRACT_MODIFIER_IN_TRAIT.on(function)); context.getTrace().report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
} }
if (function.getBodyExpression() != null && hasAbstractModifier) { if (function.getBodyExpression() != null && hasAbstractModifier) {
context.getTrace().report(ABSTRACT_FUNCTION_WITH_BODY.on(abstractNode.getPsi(), functionDescriptor)); context.getTrace().report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
} }
if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null) { if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait) {
context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor)); context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
} }
return; return;
@@ -271,7 +257,7 @@ public class DeclarationsChecker {
if (hasAbstractModifier) { if (hasAbstractModifier) {
context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(function, functionDescriptor)); context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(function, functionDescriptor));
} }
if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { if (function.getBodyExpression() == null && !hasAbstractModifier) {
context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)); context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
} }
} }
@@ -199,7 +199,6 @@ public class DescriptorResolver {
}); });
} }
else { else {
trace.report(FUNCTION_WITH_NO_TYPE_NO_BODY.on(function.asElement()));
returnType = ErrorUtils.createErrorType("No type, no body"); returnType = ErrorUtils.createErrorType("No type, no body");
} }
} }
@@ -124,10 +124,6 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
if (!expressionTypes.isEmpty()) { if (!expressionTypes.isEmpty()) {
return DataFlowUtils.checkImplicitCast(CommonSupertypes.commonSupertype(expressionTypes), expression, contextWithExpectedType, isStatement); return DataFlowUtils.checkImplicitCast(CommonSupertypes.commonSupertype(expressionTypes), expression, contextWithExpectedType, isStatement);
} }
else if (expression.getEntries().isEmpty()) {
// context.trace.getErrorHandler().genericError(expression.getNode(), "Entries required for when-expression");
context.trace.report(NO_WHEN_ENTRIES.on(expression));
}
return null; return null;
} }
@@ -256,7 +256,9 @@ public class JetPsiChecker implements Annotator {
@Nullable @Nullable
private Annotation markRedeclaration(@NotNull Set<PsiElement> redeclarations, @NotNull RedeclarationDiagnostic diagnostic, @NotNull AnnotationHolder holder) { private Annotation markRedeclaration(@NotNull Set<PsiElement> redeclarations, @NotNull RedeclarationDiagnostic diagnostic, @NotNull AnnotationHolder holder) {
if (!redeclarations.add(diagnostic.getPsiElement())) return null; if (!redeclarations.add(diagnostic.getPsiElement())) return null;
return holder.createErrorAnnotation(diagnostic.getTextRanges().get(0), getMessage(diagnostic)); List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return null;
return holder.createErrorAnnotation(textRanges.get(0), getMessage(diagnostic));
} }