Add warning for ambiguous annotated expression syntax

#KT-14238 In Progress
This commit is contained in:
Denis Zharkov
2016-10-12 11:40:12 +03:00
parent 993d226c8f
commit 84153f9636
13 changed files with 159 additions and 12 deletions
@@ -115,8 +115,8 @@ public interface KtNodeTypes {
KtNodeType BREAK = new KtNodeType("BREAK", KtBreakExpression.class);
KtNodeType IF = new KtNodeType("IF", KtIfExpression.class);
KtNodeType CONDITION = new KtNodeType("CONDITION", KtContainerNode.class);
KtNodeType THEN = new KtNodeType("THEN", KtContainerNode.class);
KtNodeType ELSE = new KtNodeType("ELSE", KtContainerNode.class);
KtNodeType THEN = new KtNodeType("THEN", KtContainerNodeForControlStructureBody.class);
KtNodeType ELSE = new KtNodeType("ELSE", KtContainerNodeForControlStructureBody.class);
KtNodeType TRY = new KtNodeType("TRY", KtTryExpression.class);
KtNodeType CATCH = new KtNodeType("CATCH", KtCatchClause.class);
KtNodeType FINALLY = new KtNodeType("FINALLY", KtFinallySection.class);
@@ -124,7 +124,7 @@ public interface KtNodeTypes {
KtNodeType WHILE = new KtNodeType("WHILE", KtWhileExpression.class);
KtNodeType DO_WHILE = new KtNodeType("DO_WHILE", KtDoWhileExpression.class);
KtNodeType LOOP_RANGE = new KtNodeType("LOOP_RANGE", KtContainerNode.class);
KtNodeType BODY = new KtNodeType("BODY", KtContainerNode.class);
KtNodeType BODY = new KtNodeType("BODY", KtContainerNodeForControlStructureBody.class);
KtNodeType BLOCK = new KtNodeType("BLOCK", KtBlockExpression.class);
IElementType LAMBDA_EXPRESSION = new IErrorCounterReparseableElementType("LAMBDA_EXPRESSION", KotlinLanguage.INSTANCE) {
@@ -180,6 +180,7 @@ public interface Errors {
DiagnosticFactory0<KtExpression> ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotatedExpression> ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> ILLEGAL_SINCE_KOTLIN_VALUE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> NEWER_VERSION_IN_SINCE_KOTLIN = DiagnosticFactory1.create(WARNING);
@@ -725,6 +725,10 @@ public class DefaultErrorMessages {
MAP.put(ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL, "An annotation parameter must be a class literal (T::class)");
MAP.put(ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT, "Default value of annotation parameter must be a compile-time constant");
MAP.put(ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE,
"Annotations on block-level expressions are being parsed differently depending on presence of a new line after them. " +
"Use new line if whole block-level expression must be annotated or wrap annotated expression in parentheses");
MAP.put(CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, "Const 'val' are only allowed on top level or in objects");
MAP.put(CONST_VAL_WITH_DELEGATE, "Const 'val' should not have a delegate");
MAP.put(CONST_VAL_WITH_GETTER, "Const 'val' should not have a getter");
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2016 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.kotlin.psi
import com.intellij.lang.ASTNode
class KtContainerNodeForControlStructureBody(node: ASTNode) : KtContainerNode(node)
@@ -1539,12 +1539,47 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
protected void resolveAnnotationsOnExpression(KtAnnotatedExpression expression, ExpressionTypingContext context) {
if (isAnnotatedExpressionInBlockLevelBinary(expression)) {
context.trace.report(ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE.on(expression));
}
if (!(expression.getBaseExpression() instanceof KtObjectLiteralExpression)) {
// annotations on object literals are resolved later inside LazyClassDescriptor
components.annotationResolver.resolveAnnotationsWithArguments(context.scope, expression.getAnnotationEntries(), context.trace);
}
}
private static boolean isAnnotatedExpressionInBlockLevelBinary(KtAnnotatedExpression annotatedExpression) {
PsiElement current = annotatedExpression;
PsiElement parent = current.getParent();
// Here we implicitly assume that grammar rules are:
// blockLevelExpression = annotations expression
// expression = binaryExpression
// binaryExpression = prefixExpression <op> prefixExpression
// prefixExpression = annotations expression
// If there is no binary parent, annotations are being parsed the same way independently of newline after them
if (!(parent instanceof KtBinaryExpression)) return false;
while (parent instanceof KtBinaryExpression) {
// if we came not from the left parent, there's no need to report an error
if (((KtBinaryExpression) parent).getLeft() != current) {
return false;
}
current = parent;
parent = parent.getParent();
}
return isParentForBlockLevelExpression(parent);
}
private static boolean isParentForBlockLevelExpression(@Nullable PsiElement parent) {
return parent instanceof KtBlockExpression ||
parent instanceof KtContainerNodeForControlStructureBody ||
parent instanceof KtWhenEntry;
}
@Override
public KotlinTypeInfo visitKtElement(@NotNull KtElement element, ExpressionTypingContext context) {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));