Refine highlighting of '@'

- Do not highlight '@' as separate token.

- Highlight '@' the same way as element where it's located: annotation, label or modifier.

- Extend text range when positioning unresolved reference in annotation with '@'.

Note that currently '@' is collapsed with modifiers tokens
This commit is contained in:
Denis Zharkov
2015-05-05 15:16:41 +03:00
parent aa7bae213d
commit 1d77f50903
12 changed files with 125 additions and 3 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.JetNodeTypes
import org.jetbrains.kotlin.lexer.JetKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getCalleeHighlightingRange
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.utils.sure
import kotlin.platform.platformStatic
@@ -226,7 +227,7 @@ public object PositioningStrategies {
return ranges
}
}
return listOf(element.getTextRange())
return listOf(element.getCalleeHighlightingRange())
}
}
@@ -17,9 +17,11 @@
package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.JetNodeTypes;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationEntryStub;
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
@@ -101,4 +103,8 @@ public class JetAnnotationEntry extends JetElementImplStub<KotlinAnnotationEntry
return null;
}
@Nullable
public PsiElement getAtSymbol() {
return findChildByType(JetTokens.AT);
}
}
@@ -570,3 +570,15 @@ private fun JetAnnotationsContainer.collectAnnotationEntriesFromPsi() =
else -> emptyList<JetAnnotationEntry>()
}
}
public fun JetElement.getCalleeHighlightingRange(): TextRange {
val annotationEntry: JetAnnotationEntry =
PsiTreeUtil.getParentOfType<JetAnnotationEntry>(
this, javaClass<JetAnnotationEntry>(), /* strict = */false, javaClass<JetValueArgumentList>()
) ?: return getTextRange()
val startOffset = annotationEntry.getAtSymbol()?.getTextRange()?.getStartOffset()
?: annotationEntry.getCalleeExpression().getTextRange().getStartOffset()
return TextRange(startOffset, annotationEntry.getCalleeExpression().getTextRange().getEndOffset())
}
@@ -0,0 +1,3 @@
<!UNRESOLVED_REFERENCE!>@Ann<!> class A
<!UNRESOLVED_REFERENCE!>Ann<!> class B
<!UNRESOLVED_REFERENCE!>@Ann<!>(1) class C
@@ -0,0 +1,22 @@
package
[ERROR : Ann]() internal final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
[ERROR : Ann]() internal final class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
[ERROR : Ann]() internal final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -801,6 +801,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("unresolvedReferenceRange.kt")
public void testUnresolvedReferenceRange() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/unresolvedReferenceRange.kt");
doTest(fileName);
}
@TestMetadata("WrongAnnotationArgsOnObject.kt")
public void testWrongAnnotationArgsOnObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/WrongAnnotationArgsOnObject.kt");
@@ -52,7 +52,6 @@ public class JetHighlighter extends SyntaxHighlighterBase {
fillMap(keys1, JetTokens.KEYWORDS, JetHighlightingColors.KEYWORD);
keys1.put(JetTokens.AS_SAFE, JetHighlightingColors.KEYWORD);
keys1.put(JetTokens.AT, JetHighlightingColors.LABEL);
keys1.put(JetTokens.INTEGER_LITERAL, JetHighlightingColors.NUMBER);
keys1.put(JetTokens.FLOAT_LITERAL, JetHighlightingColors.NUMBER);
@@ -26,6 +26,7 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.colors.CodeInsightColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.util.TextRange
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -236,6 +237,12 @@ public open class JetPsiChecker : Annotator, HighlightRangeExtension {
}
}
platformStatic fun highlightName(holder: AnnotationHolder, textRange: TextRange, attributesKey: TextAttributesKey) {
if (namesHighlightingEnabled) {
holder.createInfoAnnotation(textRange, null).setTextAttributes(attributesKey)
}
}
private fun getBeforeAnalysisVisitors(holder: AnnotationHolder) = array(
SoftKeywordsHighlightingVisitor(holder),
LabelsHighlightingVisitor(holder),
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.idea.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.resolve.BindingContext;
class TypeKindHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
@@ -41,7 +43,13 @@ class TypeKindHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
}
if (referenceTarget instanceof ClassDescriptor) {
highlightName(expression, textAttributesKeyForClass((ClassDescriptor) referenceTarget));
TextAttributesKey textAttributesKey = textAttributesKeyForClass((ClassDescriptor) referenceTarget);
if (textAttributesKey == JetHighlightingColors.ANNOTATION) {
highlightAnnotation(expression);
}
else {
highlightName(expression, textAttributesKey);
}
}
else if (referenceTarget instanceof TypeParameterDescriptor) {
highlightName(expression, JetHighlightingColors.TYPE_PARAMETER);
@@ -49,6 +57,11 @@ class TypeKindHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
}
}
private void highlightAnnotation(@NotNull JetSimpleNameExpression expression) {
TextRange toHighlight = PsiUtilPackage.getCalleeHighlightingRange(expression);
JetPsiChecker.highlightName(holder, toHighlight, JetHighlightingColors.ANNOTATION);
}
@Override
public void visitObjectDeclarationName(@NotNull JetObjectDeclarationName declaration) {
PsiElement nameIdentifier = declaration.getNameIdentifier();
+24
View File
@@ -0,0 +1,24 @@
<info descr="null">annotation</info> class <info descr="null">Ann</info>
<info descr="null" textAttributesKey="KOTLIN_ANNOTATION">Ann</info> class <info descr="null">A1</info>
<info descr="null" textAttributesKey="KOTLIN_ANNOTATION">@Ann</info> class <info descr="null">A2</info>
fun <info descr="null">bar</info>(<info descr="null">block</info>: () -> <info descr="null">Int</info>) = <info descr="null"><info descr="null">block</info></info>()
<info descr="null" textAttributesKey="KOTLIN_BUILTIN_ANNOTATION">@private</info>
fun <info descr="null">foo</info>() {
1 + [<info descr="null" textAttributesKey="KOTLIN_ANNOTATION">Ann</info>] 2
<info descr="null" textAttributesKey="KOTLIN_ANNOTATION">@Ann</info> 3 + 4
<info descr="null"><info descr="null">bar</info></info> <info descr="null" textAttributesKey="KOTLIN_ANNOTATION">@Ann</info> { 1 }
<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: Err" textAttributesKey="WRONG_REFERENCES_ATTRIBUTES">@Err</error>
<warning descr="[UNUSED_EXPRESSION] The expression is unused" textAttributesKey="WARNING_ATTRIBUTES">5</warning>
}
<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: Err" textAttributesKey="WRONG_REFERENCES_ATTRIBUTES">@Err</error> class <info descr="null" textAttributesKey="KOTLIN_CLASS">Err1</info>
class <info descr="null">NotAnn</info>
<error descr="[NOT_AN_ANNOTATION_CLASS] 'NotAnn' is not an annotation class" textAttributesKey="ERRORS_ATTRIBUTES">@NotAnn</error>
class <info descr="null">C</info>
+17
View File
@@ -0,0 +1,17 @@
fun <info descr="null">bar</info>(<info descr="null">block</info>: () -> <info descr="null">Int</info>) = <info descr="null"><info descr="null">block</info></info>()
fun <info descr="null">foo</info>(): <info descr="null">Int</info> {
<info descr="null"><info descr="null">bar</info></info> <info descr="null" textAttributesKey="KOTLIN_LABEL">label@</info> {
return<info descr="null" textAttributesKey="KOTLIN_LABEL">@label</info> 2
}
<info descr="null" textAttributesKey="KOTLIN_LABEL">loop@</info> for (<info descr="null">i</info> in 1..100) {
break<info descr="null" textAttributesKey="KOTLIN_LABEL">@loop</info>
}
<info descr="null" textAttributesKey="KOTLIN_LABEL">loop2@</info> for (<info descr="null">i</info> in 1..100) {
break<error descr="There should be no space or comments before '@' in label reference"> </error><info descr="null" textAttributesKey="KOTLIN_LABEL">@loop2</info>
}
return 1
}
@@ -35,6 +35,12 @@ public class HighlightingTestGenerated extends AbstractHighlightingTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/highlighter"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("Annotations.kt")
public void testAnnotations() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/highlighter/Annotations.kt");
doTest(fileName);
}
@TestMetadata("Dynamic.kt")
public void testDynamic() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/highlighter/Dynamic.kt");
@@ -65,6 +71,12 @@ public class HighlightingTestGenerated extends AbstractHighlightingTest {
doTest(fileName);
}
@TestMetadata("Labels.kt")
public void testLabels() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/highlighter/Labels.kt");
doTest(fileName);
}
@TestMetadata("Object.kt")
public void testObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/highlighter/Object.kt");