/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Andre Soereng <[email protected]> - [syntax highlighting] highlight numbers - https://bugs.eclipse.org/bugs/show_bug.cgi?id=63573 * TypeFox - port to jdt.ls * * Copied from https://github.com/eclipse/eclipse.jdt.ui/blob/d41fa3326c5b75a6419c81fcecb37d7d7fb3ac43/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightings.java *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.highlighting; import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; import org.eclipse.jdt.core.dom.ArrayAccess; import org.eclipse.jdt.core.dom.CastExpression; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.ConditionalExpression; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.NameQualifiedType; import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.PrefixExpression; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.VariableDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.Bindings; import org.eclipse.jdt.internal.ui.javaeditor.SemanticToken; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; /** * Semantic highlightings * * @since 3.0 */ @SuppressWarnings("restriction") public class SemanticHighlightings { private static final ImmutableListMultimap.Builder<String, String> SCOPES_BUILDER = ImmutableListMultimap.builder(); /** * A named preference part that controls the highlighting of static final * fields. */ public static final String STATIC_FINAL_FIELD = "staticFinalField"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(STATIC_FINAL_FIELD, "storage.modifier.static.java", "storage.modifier.final.java", "variable.other.definition.java", "meta.definition.variable.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of static fields. */ public static final String STATIC_FIELD = "staticField"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(STATIC_FIELD, "storage.modifier.static.java", "variable.other.definition.java", "meta.definition.variable.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of fields. */ public static final String FIELD = "field"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(FIELD, "meta.definition.variable.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of method * declarations. */ public static final String METHOD_DECLARATION = "methodDeclarationName"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(METHOD_DECLARATION, "entity.name.function.java", "meta.method.identifier.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of static method * invocations. */ public static final String STATIC_METHOD_INVOCATION = "staticMethodInvocation"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(STATIC_METHOD_INVOCATION, "storage.modifier.static.java", "entity.name.function.java", "meta.function-call.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of inherited method * invocations. */ public static final String INHERITED_METHOD_INVOCATION = "inheritedMethodInvocation"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(INHERITED_METHOD_INVOCATION, "entity.name.function.java", "meta.function-call.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of annotation element * references. * * @since 3.1 */ public static final String ANNOTATION_ELEMENT_REFERENCE = "annotationElementReference"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(ANNOTATION_ELEMENT_REFERENCE, "constant.other.key.java", "meta.declaration.annotation.java", "source.java"); } /** * A named preference part that controls the highlighting of abstract method * invocations. */ public static final String ABSTRACT_METHOD_INVOCATION = "abstractMethodInvocation"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(ABSTRACT_METHOD_INVOCATION, "storage.modifier.abstract.java", "entity.name.function.java", "meta.function-call.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of local variables. */ public static final String LOCAL_VARIABLE_DECLARATION = "localVariableDeclaration"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(LOCAL_VARIABLE_DECLARATION, "variable.other.definition.java", "meta.definition.variable.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of local variables. */ public static final String LOCAL_VARIABLE = "localVariable"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(LOCAL_VARIABLE, "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of parameter * variables. */ public static final String PARAMETER_VARIABLE = "parameterVariable"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(PARAMETER_VARIABLE, "variable.parameter.java", "meta.method.identifier.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of deprecated members. */ public static final String DEPRECATED_MEMBER = "deprecatedMember"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(DEPRECATED_MEMBER, "invalid.deprecated.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of type parameters. * * @since 3.1 */ public static final String TYPE_VARIABLE = "typeParameter"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(TYPE_VARIABLE, "storage.type.generic.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of methods * (invocations and declarations). * * @since 3.1 */ public static final String METHOD = "method"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(METHOD, "entity.name.function.java", "meta.method.identifier.java", "meta.function-call.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of auto(un)boxed * expressions. * * @since 3.1 */ public static final String AUTOBOXING = "autoboxing"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(AUTOBOXING, "variable.other.autoboxing.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of classes. * * @since 3.2 */ public static final String CLASS = "class"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(CLASS, "entity.name.type.class.java", "meta.class.identifier.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of enums. * * @since 3.2 */ public static final String ENUM = "enum"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(ENUM, "entity.name.type.enum.java", "meta.enum.java", "source.java"); } /** * A named preference part that controls the highlighting of interfaces. * * @since 3.2 */ public static final String INTERFACE = "interface"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(INTERFACE, "entity.name.type.interface.java", "meta.class.identifier.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of annotations. * * @since 3.2 */ public static final String ANNOTATION = "annotation"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(ANNOTATION, "storage.type.annotation.java", "meta.declaration.annotation.java", "source.java"); } /** * A named preference part that controls the highlighting of type arguments. * * @since 3.2 */ public static final String TYPE_ARGUMENT = "typeArgument"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(TYPE_ARGUMENT, "storage.type.generic.java", "meta.definition.class.implemented.interfaces.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of numbers. * * @since 3.4 */ public static final String NUMBER = "number"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(NUMBER, "constant.numeric.decimal.java", "meta.definition.variable.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of abstract classes. * * @since 3.7 */ public static final String ABSTRACT_CLASS = "abstractClass"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(ABSTRACT_CLASS, "storage.modifier.abstract.java", "entity.name.type.class.java", "meta.class.identifier.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of inherited fields. * * @since 3.8 */ public static final String INHERITED_FIELD = "inheritedField"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(INHERITED_FIELD, "meta.function-call.java", "meta.method.body.java", "meta.method.java", "meta.class.body.java", "meta.class.java", "source.java"); } /** * A named preference part that controls the highlighting of 'var' keywords. */ public static final String VAR_KEYWORD = "varKeyword"; //$NON-NLS-1$ static { SCOPES_BUILDER.putAll(VAR_KEYWORD, "keyword.other.var.java", "meta.class.body.java", "meta.class.java", "source.java"); } private static final ListMultimap<String, String> SCOPES = SCOPES_BUILDER.build(); /** * Semantic highlightings */ private static SemanticHighlightingLS[] fgSemanticHighlightings; /** * Semantic highlighting for static final fields. */ private static final class StaticFinalFieldHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(STATIC_FINAL_FIELD); } @Override public boolean consumes(SemanticToken token) { IBinding binding = token.getBinding(); return binding != null && binding.getKind() == IBinding.VARIABLE && ((IVariableBinding) binding).isField() && (binding.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) == (Modifier.FINAL | Modifier.STATIC); } } /** * Semantic highlighting for static fields. */ private static final class StaticFieldHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(STATIC_FIELD); } @Override public boolean consumes(SemanticToken token) { IBinding binding = token.getBinding(); return binding != null && binding.getKind() == IBinding.VARIABLE && ((IVariableBinding) binding).isField() && (binding.getModifiers() & Modifier.STATIC) == Modifier.STATIC; } } /** * Semantic highlighting for fields. */ private static final class FieldHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(FIELD); } @Override public boolean consumes(SemanticToken token) { IBinding binding = token.getBinding(); return binding != null && binding.getKind() == IBinding.VARIABLE && ((IVariableBinding) binding).isField(); } } /** * Semantic highlighting for auto(un)boxed expressions. */ private static final class AutoboxHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(AUTOBOXING); } @Override public boolean consumesLiteral(SemanticToken token) { return isAutoUnBoxing(token.getLiteral()); } @Override public boolean consumes(SemanticToken token) { return isAutoUnBoxing(token.getNode()); } private boolean isAutoUnBoxing(Expression node) { if (isAutoUnBoxingExpression(node)) { return true; } // special cases: the autoboxing conversions happens at a // location that is not mapped directly to a simple name // or a literal, but can still be mapped somehow // A) expressions StructuralPropertyDescriptor desc = node.getLocationInParent(); if (desc == ArrayAccess.ARRAY_PROPERTY || desc == InfixExpression.LEFT_OPERAND_PROPERTY || desc == InfixExpression.RIGHT_OPERAND_PROPERTY || desc == ConditionalExpression.THEN_EXPRESSION_PROPERTY || desc == PrefixExpression.OPERAND_PROPERTY || desc == CastExpression.EXPRESSION_PROPERTY || desc == ConditionalExpression.ELSE_EXPRESSION_PROPERTY) { ASTNode parent = node.getParent(); if (parent instanceof Expression) { return isAutoUnBoxingExpression((Expression) parent); } } // B) constructor invocations if (desc == QualifiedName.NAME_PROPERTY) { node = (Expression) node.getParent(); desc = node.getLocationInParent(); } if (desc == SimpleType.NAME_PROPERTY || desc == NameQualifiedType.NAME_PROPERTY) { ASTNode parent = node.getParent(); if (parent != null && parent.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY) { parent = parent.getParent(); return isAutoUnBoxingExpression((ClassInstanceCreation) parent); } } return false; } private boolean isAutoUnBoxingExpression(Expression expression) { return expression.resolveBoxing() || expression.resolveUnboxing(); } } /** * Semantic highlighting for method declarations. */ private static final class MethodDeclarationHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(METHOD_DECLARATION); } @Override public boolean consumes(SemanticToken token) { StructuralPropertyDescriptor location = token.getNode().getLocationInParent(); return location == MethodDeclaration.NAME_PROPERTY || location == AnnotationTypeMemberDeclaration.NAME_PROPERTY; } } /** * Semantic highlighting for static method invocations. */ private static final class StaticMethodInvocationHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(STATIC_METHOD_INVOCATION); } @Override public boolean consumes(SemanticToken token) { SimpleName node = token.getNode(); if (node.isDeclaration()) { return false; } IBinding binding = token.getBinding(); return binding != null && binding.getKind() == IBinding.METHOD && (binding.getModifiers() & Modifier.STATIC) == Modifier.STATIC; } } /** * Semantic highlighting for annotation element references. * * @since 3.1 */ private static final class AnnotationElementReferenceHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(ANNOTATION_ELEMENT_REFERENCE); } @Override public boolean consumes(SemanticToken token) { SimpleName node = token.getNode(); if (node.getParent() instanceof MemberValuePair) { IBinding binding = token.getBinding(); boolean isAnnotationElement = binding != null && binding.getKind() == IBinding.METHOD; return isAnnotationElement; } return false; } } /** * Semantic highlighting for abstract method invocations. */ private static final class AbstractMethodInvocationHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(ABSTRACT_METHOD_INVOCATION); } @Override public boolean consumes(SemanticToken token) { SimpleName node = token.getNode(); if (node.isDeclaration()) { return false; } IBinding binding = token.getBinding(); boolean isAbstractMethod = binding != null && binding.getKind() == IBinding.METHOD && (binding.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT; if (!isAbstractMethod) { return false; } // filter out annotation value references if (binding != null) { ITypeBinding declaringType = ((IMethodBinding) binding).getDeclaringClass(); if (declaringType.isAnnotation()) { return false; } } return true; } } /** * Semantic highlighting for inherited method invocations. */ private static final class InheritedMethodInvocationHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(INHERITED_METHOD_INVOCATION); } @Override public boolean consumes(SemanticToken token) { SimpleName node = token.getNode(); if (node.isDeclaration()) { return false; } IBinding binding = token.getBinding(); if (binding == null || binding.getKind() != IBinding.METHOD) { return false; } ITypeBinding currentType = Bindings.getBindingOfParentType(node); ITypeBinding declaringType = ((IMethodBinding) binding).getDeclaringClass(); if (currentType == declaringType || currentType == null) { return false; } return Bindings.isSuperType(declaringType, currentType); } } /** * Semantic highlighting for inherited method invocations. */ private static final class MethodHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(METHOD); } @Override public boolean consumes(SemanticToken token) { IBinding binding = getBinding(token); return binding != null && binding.getKind() == IBinding.METHOD; } } /** * Semantic highlighting for local variable declarations. */ private static final class LocalVariableDeclarationHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(LOCAL_VARIABLE_DECLARATION); } @Override public boolean consumes(SemanticToken token) { SimpleName node = token.getNode(); StructuralPropertyDescriptor location = node.getLocationInParent(); if (location == VariableDeclarationFragment.NAME_PROPERTY || location == SingleVariableDeclaration.NAME_PROPERTY) { ASTNode parent = node.getParent(); if (parent instanceof VariableDeclaration) { parent = parent.getParent(); return parent == null || !(parent instanceof FieldDeclaration); } } return false; } } /** * Semantic highlighting for local variables. */ private static final class LocalVariableHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(LOCAL_VARIABLE); } @Override public boolean consumes(SemanticToken token) { IBinding binding = token.getBinding(); if (binding != null && binding.getKind() == IBinding.VARIABLE && !((IVariableBinding) binding).isField()) { ASTNode decl = token.getRoot().findDeclaringNode(binding); return decl instanceof VariableDeclaration; } return false; } } /** * Semantic highlighting for parameter variables. */ private static final class ParameterVariableHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(PARAMETER_VARIABLE); } @Override public boolean consumes(SemanticToken token) { IBinding binding = token.getBinding(); if (binding != null && binding.getKind() == IBinding.VARIABLE && !((IVariableBinding) binding).isField()) { ASTNode decl = token.getRoot().findDeclaringNode(binding); return decl != null && decl.getLocationInParent() == MethodDeclaration.PARAMETERS_PROPERTY; } return false; } } /** * Semantic highlighting for deprecated members. */ /*default*/ static final class DeprecatedMemberHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(DEPRECATED_MEMBER); } @Override public boolean consumes(SemanticToken token) { IBinding binding = getBinding(token); if (binding != null) { if (binding.isDeprecated()) { return true; } if (binding instanceof IMethodBinding) { IMethodBinding methodBinding = (IMethodBinding) binding; ITypeBinding declaringClass = methodBinding.getDeclaringClass(); if (declaringClass == null) { return false; } if (declaringClass.isAnonymous()) { ITypeBinding[] interfaces = declaringClass.getInterfaces(); if (interfaces.length > 0) { return interfaces[0].isDeprecated(); } else { return declaringClass.getSuperclass().isDeprecated(); } } return declaringClass.isDeprecated() && !(token.getNode().getParent() instanceof MethodDeclaration); } else if (binding instanceof IVariableBinding) { IVariableBinding variableBinding = (IVariableBinding) binding; ITypeBinding declaringClass = variableBinding.getDeclaringClass(); return declaringClass != null && declaringClass.isDeprecated() && !(token.getNode().getParent() instanceof VariableDeclaration); } } return false; } } /** * Semantic highlighting for type variables. * * @since 3.1 */ private static final class TypeVariableHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(TYPE_VARIABLE); } @Override public boolean consumes(SemanticToken token) { // 1: match types in type parameter lists SimpleName name = token.getNode(); ASTNode node = name.getParent(); if (node.getNodeType() != ASTNode.SIMPLE_TYPE && node.getNodeType() != ASTNode.TYPE_PARAMETER) { return false; } // 2: match generic type variable references IBinding binding = token.getBinding(); return binding instanceof ITypeBinding && ((ITypeBinding) binding).isTypeVariable(); } } /** * Semantic highlighting for classes. * * @since 3.2 */ private static final class ClassHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(CLASS); } @Override public boolean consumes(SemanticToken token) { // 1: match types SimpleName name = token.getNode(); ASTNode node = name.getParent(); int nodeType = node.getNodeType(); if (nodeType != ASTNode.SIMPLE_TYPE && nodeType != ASTNode.THIS_EXPRESSION && nodeType != ASTNode.QUALIFIED_TYPE && nodeType != ASTNode.QUALIFIED_NAME && nodeType != ASTNode.TYPE_DECLARATION && nodeType != ASTNode.METHOD_INVOCATION) { return false; } while (nodeType == ASTNode.QUALIFIED_NAME) { node = node.getParent(); nodeType = node.getNodeType(); if (nodeType == ASTNode.IMPORT_DECLARATION) { return false; } } // 2: match classes IBinding binding = token.getBinding(); return binding instanceof ITypeBinding && ((ITypeBinding) binding).isClass(); } } /** * Semantic highlighting for enums. * * @since 3.2 */ private static final class EnumHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(ENUM); } @Override public boolean consumes(SemanticToken token) { // 1: match types SimpleName name = token.getNode(); ASTNode node = name.getParent(); int nodeType = node.getNodeType(); if (nodeType != ASTNode.METHOD_INVOCATION && nodeType != ASTNode.SIMPLE_TYPE && nodeType != ASTNode.QUALIFIED_TYPE && nodeType != ASTNode.QUALIFIED_NAME && nodeType != ASTNode.QUALIFIED_NAME && nodeType != ASTNode.ENUM_DECLARATION) { return false; } while (nodeType == ASTNode.QUALIFIED_NAME) { node = node.getParent(); nodeType = node.getNodeType(); if (nodeType == ASTNode.IMPORT_DECLARATION) { return false; } } // 2: match enums IBinding binding = token.getBinding(); return binding instanceof ITypeBinding && ((ITypeBinding) binding).isEnum(); } } /** * Semantic highlighting for interfaces. * * @since 3.2 */ private static final class InterfaceHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(INTERFACE); } @Override public boolean consumes(SemanticToken token) { // 1: match types SimpleName name = token.getNode(); ASTNode node = name.getParent(); int nodeType = node.getNodeType(); if (nodeType != ASTNode.SIMPLE_TYPE && nodeType != ASTNode.QUALIFIED_TYPE && nodeType != ASTNode.QUALIFIED_NAME && nodeType != ASTNode.TYPE_DECLARATION) { return false; } while (nodeType == ASTNode.QUALIFIED_NAME) { node = node.getParent(); nodeType = node.getNodeType(); if (nodeType == ASTNode.IMPORT_DECLARATION) { return false; } } // 2: match interfaces IBinding binding = token.getBinding(); return binding instanceof ITypeBinding && ((ITypeBinding) binding).isInterface(); } } /** * Semantic highlighting for annotation types. * * @since 3.2 */ private static final class AnnotationHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(ANNOTATION); } @Override public boolean consumes(SemanticToken token) { // 1: match types SimpleName name = token.getNode(); ASTNode node = name.getParent(); int nodeType = node.getNodeType(); if (nodeType != ASTNode.SIMPLE_TYPE && nodeType != ASTNode.QUALIFIED_TYPE && nodeType != ASTNode.QUALIFIED_NAME && nodeType != ASTNode.ANNOTATION_TYPE_DECLARATION && nodeType != ASTNode.MARKER_ANNOTATION && nodeType != ASTNode.NORMAL_ANNOTATION && nodeType != ASTNode.SINGLE_MEMBER_ANNOTATION) { return false; } while (nodeType == ASTNode.QUALIFIED_NAME) { node = node.getParent(); nodeType = node.getNodeType(); if (nodeType == ASTNode.IMPORT_DECLARATION) { return false; } } // 2: match annotations IBinding binding = token.getBinding(); return binding instanceof ITypeBinding && ((ITypeBinding) binding).isAnnotation(); } } /** * Semantic highlighting for annotation types. * * @since 3.2 */ private static final class TypeArgumentHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(TYPE_ARGUMENT); } @Override public boolean consumes(SemanticToken token) { // 1: match types SimpleName name = token.getNode(); ASTNode node = name.getParent(); int nodeType = node.getNodeType(); if (nodeType != ASTNode.SIMPLE_TYPE && nodeType != ASTNode.QUALIFIED_TYPE) { return false; } // 2: match type arguments StructuralPropertyDescriptor locationInParent = node.getLocationInParent(); if (locationInParent == ParameterizedType.TYPE_ARGUMENTS_PROPERTY) { return true; } return false; } } /** * Semantic highlighting for numbers. * * @since 3.4 */ private static final class NumberHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(NUMBER); } @Override public boolean consumes(SemanticToken token) { return false; } @Override public boolean consumesLiteral(SemanticToken token) { Expression expr = token.getLiteral(); return expr != null && expr.getNodeType() == ASTNode.NUMBER_LITERAL; } } /** * Semantic highlighting for classes. * * @since 3.7 */ private static final class AbstractClassHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(ABSTRACT_CLASS); } @Override public boolean consumes(SemanticToken token) { // 1: match types SimpleName name = token.getNode(); ASTNode node = name.getParent(); int nodeType = node.getNodeType(); if (nodeType != ASTNode.SIMPLE_TYPE && nodeType != ASTNode.THIS_EXPRESSION && nodeType != ASTNode.QUALIFIED_TYPE && nodeType != ASTNode.QUALIFIED_NAME && nodeType != ASTNode.TYPE_DECLARATION && nodeType != ASTNode.METHOD_INVOCATION) { return false; } while (nodeType == ASTNode.QUALIFIED_NAME) { node = node.getParent(); nodeType = node.getNodeType(); if (nodeType == ASTNode.IMPORT_DECLARATION) { return false; } } // 2: match classes IBinding binding = token.getBinding(); if (binding instanceof ITypeBinding) { ITypeBinding typeBinding = (ITypeBinding) binding; // see also ClassHighlighting return typeBinding.isClass() && (typeBinding.getModifiers() & Modifier.ABSTRACT) != 0; } return false; } } /** * Semantic highlighting for inherited field access. * * @since 3.8 */ private static final class InheritedFieldHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(INHERITED_FIELD); } @Override public boolean consumes(final SemanticToken token) { final SimpleName node = token.getNode(); if (node.isDeclaration()) { return false; } final IBinding binding = token.getBinding(); if (binding == null || binding.getKind() != IBinding.VARIABLE) { return false; } ITypeBinding currentType = Bindings.getBindingOfParentType(node); ITypeBinding declaringType = ((IVariableBinding) binding).getDeclaringClass(); if (declaringType == null || currentType == declaringType) { return false; } return Bindings.isSuperType(declaringType, currentType); } } /** * Semantic highlighting for 'var' keyword. */ /*default*/ static final class VarKeywordHighlighting extends SemanticHighlightingLS { @Override public List<String> getScopes() { return SCOPES.get(VAR_KEYWORD); } @Override public boolean consumes(SemanticToken token) { return false; } } /** * @return The semantic highlightings, the order defines the precedence of * matches, the first match wins. */ public static SemanticHighlightingLS[] getSemanticHighlightings() { if (fgSemanticHighlightings == null) { fgSemanticHighlightings = new SemanticHighlightingLS[] { new DeprecatedMemberHighlighting(), new AutoboxHighlighting(), new StaticFinalFieldHighlighting(), new StaticFieldHighlighting(), new InheritedFieldHighlighting(), new FieldHighlighting(), new MethodDeclarationHighlighting(), new StaticMethodInvocationHighlighting(), new AbstractMethodInvocationHighlighting(), new AnnotationElementReferenceHighlighting(), new InheritedMethodInvocationHighlighting(), new ParameterVariableHighlighting(), new LocalVariableDeclarationHighlighting(), new LocalVariableHighlighting(), new TypeVariableHighlighting(), // before type arguments! new MethodHighlighting(), // before types to get ctors new TypeArgumentHighlighting(), // before other types new AbstractClassHighlighting(), // before classes new ClassHighlighting(), new EnumHighlighting(), new AnnotationHighlighting(), // before interfaces new InterfaceHighlighting(), new NumberHighlighting(), new VarKeywordHighlighting(), }; } return fgSemanticHighlightings; } /** * Extracts the binding from the token's simple name. Works around bug 62605 to * return the correct constructor binding in a ClassInstanceCreation. * * @param token * the token to extract the binding from * @return the token's binding, or <code>null</code> */ private static IBinding getBinding(SemanticToken token) { ASTNode node = token.getNode(); ASTNode normalized = ASTNodes.getNormalizedNode(node); if (normalized.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY) { // work around: https://bugs.eclipse.org/bugs/show_bug.cgi?id=62605 return ((ClassInstanceCreation) normalized.getParent()).resolveConstructorBinding(); } return token.getBinding(); } /** * Do not instantiate */ private SemanticHighlightings() { } }