[LSP4E] Support separate semantic highlightings for declarations of functions, methods, and local variables

Change-Id: Iee7252b55810b8691a1b2344593a804a47ab6cbe
diff --git a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/cquery/CqueryJsonParseTest.java b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/cquery/CqueryJsonParseTest.java
index 2d9b0ef..e891b9c 100644
--- a/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/cquery/CqueryJsonParseTest.java
+++ b/lsp/org.eclipse.cdt.lsp.core.tests/src/org/eclipse/cdt/lsp/core/tests/cquery/CqueryJsonParseTest.java
@@ -23,6 +23,7 @@
 import org.eclipse.cdt.lsp.core.cquery.HighlightSymbol;
 import org.eclipse.cdt.lsp.core.cquery.IndexingProgressStats;
 import org.eclipse.cdt.lsp.core.cquery.StorageClass;
+import org.eclipse.cdt.lsp.core.cquery.SymbolRole;
 import org.eclipse.lsp4j.Position;
 import org.eclipse.lsp4j.Range;
 import org.eclipse.lsp4j.jsonrpc.json.JsonRpcMethod;
@@ -84,9 +85,9 @@
 	public void testPublishSemanticHighlighting() {
 		String json = "{\"jsonrpc\": \"2.0\",\"method\": \"$cquery/publishSemanticHighlighting\"," //$NON-NLS-1$
 				+ "\"params\": {\"uri\": \"file:///home/foobar.cpp\",\"symbols\": [{\"stableId\": 21," //$NON-NLS-1$
-				+ "\"parentKind\": 8,\"kind\": 0,\"storage\": 3,\"ranges\": [{\"start\": {\"line\": 41," //$NON-NLS-1$
+				+ "\"parentKind\": 8,\"kind\": 0,\"storage\": 3,\"role\": 1,\"ranges\": [{\"start\": {\"line\": 41," //$NON-NLS-1$
 				+ "\"character\": 1},\"end\": {\"line\": 41,\"character\": 5}}]},{\"stableId\": 19," //$NON-NLS-1$
-				+ "\"parentKind\": 12,\"kind\": 253,\"storage\": 5,\"ranges\": [{\"start\": {\"line\": 39," //$NON-NLS-1$
+				+ "\"parentKind\": 12,\"kind\": 253,\"storage\": 5,\"role\": 4,\"ranges\": [{\"start\": {\"line\": 39," //$NON-NLS-1$
 				+ "\"character\": 9},\"end\": {\"line\": 39,\"character\": 10}}]}]}}"; //$NON-NLS-1$
 
 		URI uri = URI.create("file:///home/foobar.cpp"); //$NON-NLS-1$
@@ -106,8 +107,10 @@
 		ExtendedSymbolKindType kind2 = new ExtendedSymbolKindType(253);
 		StorageClass storage1 = StorageClass.Static;
 		StorageClass storage2 = StorageClass.Auto;
-		HighlightSymbol symbol1 = new HighlightSymbol(21, parentKind1, kind1, storage1, ranges1);
-		HighlightSymbol symbol2 = new HighlightSymbol(19, parentKind2, kind2, storage2, ranges2);
+		int role1 = SymbolRole.Declaration;
+		int role2 = SymbolRole.Reference;
+		HighlightSymbol symbol1 = new HighlightSymbol(21, parentKind1, kind1, storage1, role1, ranges1);
+		HighlightSymbol symbol2 = new HighlightSymbol(19, parentKind2, kind2, storage2, role2, ranges2);
 		List<HighlightSymbol> symbols = new ArrayList<>();
 		symbols.add(symbol1);
 		symbols.add(symbol2);
diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java
index eaed3ea..08b5570 100644
--- a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java
+++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java
@@ -168,7 +168,7 @@
 		for (HighlightSymbol highlight : highlights.getSymbols()) {
 
 			String highlightingName = HighlightSymbol.getHighlightingName(highlight.getKind(),
-					highlight.getParentKind(), highlight.getStorage());
+					highlight.getParentKind(), highlight.getStorage(), highlight.getRole());
 			String colorKey = PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + highlightingName
 					+ PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX;
 
diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/HighlightSymbol.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/HighlightSymbol.java
index 46313a2..b5b4820 100644
--- a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/HighlightSymbol.java
+++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/HighlightSymbol.java
@@ -25,15 +25,13 @@
 	private ExtendedSymbolKindType kind;
 	private StorageClass storage;
 	private List<Range> ranges;
+	private Integer role;
 	public static Map<Integer, String> semanticHighlightSymbolsMap = new HashMap<>();
 
 	static {
 		semanticHighlightSymbolsMap.put(SymbolKind.Namespace.getValue(), SemanticHighlightings.NAMESPACE);
 		semanticHighlightSymbolsMap.put(SymbolKind.Class.getValue(), SemanticHighlightings.CLASS);
-		semanticHighlightSymbolsMap.put(SymbolKind.Method.getValue(), SemanticHighlightings.METHOD);
-		semanticHighlightSymbolsMap.put(SymbolKind.Constructor.getValue(), SemanticHighlightings.METHOD);
 		semanticHighlightSymbolsMap.put(SymbolKind.Enum.getValue(), SemanticHighlightings.ENUM);
-		semanticHighlightSymbolsMap.put(SymbolKind.Function.getValue(), SemanticHighlightings.FUNCTION);
 		semanticHighlightSymbolsMap.put(SymbolKind.EnumMember.getValue(), SemanticHighlightings.ENUMERATOR);
 		semanticHighlightSymbolsMap.put(SymbolKind.Struct.getValue(), SemanticHighlightings.CLASS);
 		semanticHighlightSymbolsMap.put(SymbolKind.TypeParameter.getValue(), SemanticHighlightings.TEMPLATE_PARAMETER);
@@ -45,16 +43,24 @@
 		semanticHighlightSymbolsMap.put(CquerySymbolKind.Macro.getValue(), SemanticHighlightings.MACRO_DEFINITION);
 	}
 
+	public static boolean isDeclaration(int role) {
+		return (role & SymbolRole.Declaration) != 0 || (role & SymbolRole.Definition) != 0;
+	}
+
 	public static String getHighlightingName(ExtendedSymbolKindType kind, ExtendedSymbolKindType parentKind,
-			StorageClass storage) {
+			StorageClass storage, int role) {
+		// semanticHighlightSymbolsMap contains mappings where the color is determined entirely
+		// by the symbol kind.
+		// The additional checks below handle cases where the color also depends on the parent kind,
+		// storage class, or role.
 		String highlightingName = semanticHighlightSymbolsMap.get(kind.getValue());
 		if (highlightingName == null) {
 			if (kind.getValue() == SymbolKind.Variable.getValue()) {
 				if (parentKind.getValue() == SymbolKind.Function.getValue()
 						|| parentKind.getValue() == SymbolKind.Method.getValue()
 						|| parentKind.getValue() == SymbolKind.Constructor.getValue()) {
-
-					highlightingName = SemanticHighlightings.LOCAL_VARIABLE;
+					highlightingName = isDeclaration(role) ? SemanticHighlightings.LOCAL_VARIABLE_DECLARATION
+							: SemanticHighlightings.LOCAL_VARIABLE;
 				} else {
 					highlightingName = SemanticHighlightings.GLOBAL_VARIABLE;
 				}
@@ -64,17 +70,25 @@
 				} else {
 					highlightingName = SemanticHighlightings.FIELD;
 				}
+			} else if (kind.getValue() == SymbolKind.Function.getValue()) {
+				highlightingName = isDeclaration(role) ? SemanticHighlightings.FUNCTION_DECLARATION
+						: SemanticHighlightings.FUNCTION;
+			} else if (kind.getValue() == SymbolKind.Method.getValue()
+					|| kind.getValue() == SymbolKind.Constructor.getValue()) {
+				highlightingName = isDeclaration(role) ? SemanticHighlightings.METHOD_DECLARATION
+						: SemanticHighlightings.METHOD;
 			}
 		}
 		return highlightingName;
 	}
 
 	public HighlightSymbol(int stableId, ExtendedSymbolKindType parentKind, ExtendedSymbolKindType kind,
-			StorageClass storage, List<Range> ranges) {
+			StorageClass storage, Integer role, List<Range> ranges) {
 		this.stableId = stableId;
 		this.parentKind = parentKind;
 		this.kind = kind;
 		this.storage = storage;
+		this.role = role;
 		this.ranges = ranges;
 	}
 
@@ -94,6 +108,10 @@
 		return storage;
 	}
 
+	public Integer getRole() {
+		return role;
+	}
+
 	public List<Range> getRanges() {
 		return ranges;
 	}
diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/SymbolRole.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/SymbolRole.java
new file mode 100644
index 0000000..a163d71
--- /dev/null
+++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/cquery/SymbolRole.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Nathan Ridge and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.cdt.lsp.core.cquery;
+
+/**
+ * A class to contain constants that represent different roles
+ * a symbol can have.
+ * The constants are used as bit-flags to compose the value of
+ * HighlightSymbol.role.
+ */
+public final class SymbolRole {
+	public static final int Declaration = 1 << 0;
+	public static final int Definition = 1 << 1;
+	public static final int Reference = 1 << 2;
+	public static final int Read = 1 << 3;
+	public static final int Write = 1 << 4;
+	public static final int Call = 1 << 5;
+	public static final int Dynamic = 1 << 6;
+	public static final int Address = 1 << 7;
+	public static final int Implicit = 1 << 8;
+}
\ No newline at end of file