You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
16 KiB
575 lines
16 KiB
// Copyright (c) 2018 Siegfried Pammer
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
// software and associated documentation files (the "Software"), to deal in the Software
|
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all copies or
|
|
// substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using ICSharpCode.AvalonEdit.Highlighting;
|
|
using ICSharpCode.Decompiler.CSharp;
|
|
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
|
|
using ICSharpCode.Decompiler.CSharp.Syntax;
|
|
using ICSharpCode.Decompiler.IL;
|
|
using ICSharpCode.Decompiler.TypeSystem;
|
|
using ICSharpCode.ILSpyX.Extensions;
|
|
|
|
namespace ICSharpCode.ILSpy
|
|
{
|
|
class CSharpHighlightingTokenWriter : DecoratingTokenWriter
|
|
{
|
|
HighlightingColor visibilityKeywordsColor;
|
|
HighlightingColor namespaceKeywordsColor;
|
|
HighlightingColor structureKeywordsColor;
|
|
HighlightingColor gotoKeywordsColor;
|
|
HighlightingColor queryKeywordsColor;
|
|
HighlightingColor exceptionKeywordsColor;
|
|
HighlightingColor checkedKeywordColor;
|
|
HighlightingColor unsafeKeywordsColor;
|
|
HighlightingColor valueTypeKeywordsColor;
|
|
HighlightingColor referenceTypeKeywordsColor;
|
|
HighlightingColor operatorKeywordsColor;
|
|
HighlightingColor parameterModifierColor;
|
|
HighlightingColor modifiersColor;
|
|
HighlightingColor accessorKeywordsColor;
|
|
HighlightingColor attributeKeywordsColor;
|
|
|
|
HighlightingColor referenceTypeColor;
|
|
HighlightingColor valueTypeColor;
|
|
HighlightingColor interfaceTypeColor;
|
|
HighlightingColor enumerationTypeColor;
|
|
HighlightingColor typeParameterTypeColor;
|
|
HighlightingColor delegateTypeColor;
|
|
|
|
HighlightingColor methodCallColor;
|
|
HighlightingColor methodDeclarationColor;
|
|
HighlightingColor fieldDeclarationColor;
|
|
HighlightingColor fieldAccessColor;
|
|
HighlightingColor propertyDeclarationColor;
|
|
HighlightingColor propertyAccessColor;
|
|
HighlightingColor eventDeclarationColor;
|
|
HighlightingColor eventAccessColor;
|
|
|
|
HighlightingColor variableColor;
|
|
HighlightingColor parameterColor;
|
|
|
|
HighlightingColor valueKeywordColor;
|
|
HighlightingColor thisKeywordColor;
|
|
HighlightingColor trueKeywordColor;
|
|
HighlightingColor typeKeywordsColor;
|
|
|
|
public RichTextModel HighlightingModel { get; } = new RichTextModel();
|
|
|
|
public CSharpHighlightingTokenWriter(TokenWriter decoratedWriter, ISmartTextOutput textOutput = null, ILocatable locatable = null)
|
|
: base(decoratedWriter)
|
|
{
|
|
var highlighting = HighlightingManager.Instance.GetDefinition("C#");
|
|
|
|
this.locatable = locatable;
|
|
this.textOutput = textOutput;
|
|
|
|
this.visibilityKeywordsColor = highlighting.GetNamedColor("Visibility");
|
|
this.namespaceKeywordsColor = highlighting.GetNamedColor("NamespaceKeywords");
|
|
this.structureKeywordsColor = highlighting.GetNamedColor("Keywords");
|
|
this.gotoKeywordsColor = highlighting.GetNamedColor("GotoKeywords");
|
|
this.queryKeywordsColor = highlighting.GetNamedColor("QueryKeywords");
|
|
this.exceptionKeywordsColor = highlighting.GetNamedColor("ExceptionKeywords");
|
|
this.checkedKeywordColor = highlighting.GetNamedColor("CheckedKeyword");
|
|
this.unsafeKeywordsColor = highlighting.GetNamedColor("UnsafeKeywords");
|
|
this.valueTypeKeywordsColor = highlighting.GetNamedColor("ValueTypeKeywords");
|
|
this.referenceTypeKeywordsColor = highlighting.GetNamedColor("ReferenceTypeKeywords");
|
|
this.operatorKeywordsColor = highlighting.GetNamedColor("OperatorKeywords");
|
|
this.parameterModifierColor = highlighting.GetNamedColor("ParameterModifiers");
|
|
this.modifiersColor = highlighting.GetNamedColor("Modifiers");
|
|
this.accessorKeywordsColor = highlighting.GetNamedColor("GetSetAddRemove");
|
|
|
|
this.referenceTypeColor = highlighting.GetNamedColor("ReferenceTypes");
|
|
this.valueTypeColor = highlighting.GetNamedColor("ValueTypes");
|
|
this.interfaceTypeColor = highlighting.GetNamedColor("InterfaceTypes");
|
|
this.enumerationTypeColor = highlighting.GetNamedColor("EnumTypes");
|
|
this.typeParameterTypeColor = highlighting.GetNamedColor("TypeParameters");
|
|
this.delegateTypeColor = highlighting.GetNamedColor("DelegateTypes");
|
|
this.methodDeclarationColor = highlighting.GetNamedColor("MethodDeclaration");
|
|
this.methodCallColor = highlighting.GetNamedColor("MethodCall");
|
|
this.fieldDeclarationColor = highlighting.GetNamedColor("FieldDeclaration");
|
|
this.fieldAccessColor = highlighting.GetNamedColor("FieldAccess");
|
|
this.propertyDeclarationColor = highlighting.GetNamedColor("PropertyDeclaration");
|
|
this.propertyAccessColor = highlighting.GetNamedColor("PropertyAccess");
|
|
this.eventDeclarationColor = highlighting.GetNamedColor("EventDeclaration");
|
|
this.eventAccessColor = highlighting.GetNamedColor("EventAccess");
|
|
this.variableColor = highlighting.GetNamedColor("Variable");
|
|
this.parameterColor = highlighting.GetNamedColor("Parameter");
|
|
this.valueKeywordColor = highlighting.GetNamedColor("NullOrValueKeywords");
|
|
this.thisKeywordColor = highlighting.GetNamedColor("ThisOrBaseReference");
|
|
this.trueKeywordColor = highlighting.GetNamedColor("TrueFalse");
|
|
this.typeKeywordsColor = highlighting.GetNamedColor("TypeKeywords");
|
|
this.attributeKeywordsColor = highlighting.GetNamedColor("AttributeKeywords");
|
|
//this.externAliasKeywordColor = ...;
|
|
}
|
|
|
|
public override void WriteKeyword(Role role, string keyword)
|
|
{
|
|
HighlightingColor color = null;
|
|
switch (keyword)
|
|
{
|
|
case "namespace":
|
|
case "using":
|
|
if (role == UsingStatement.UsingKeywordRole)
|
|
color = structureKeywordsColor;
|
|
else
|
|
color = namespaceKeywordsColor;
|
|
break;
|
|
case "this":
|
|
case "base":
|
|
color = thisKeywordColor;
|
|
break;
|
|
case "true":
|
|
case "false":
|
|
color = trueKeywordColor;
|
|
break;
|
|
case "public":
|
|
case "internal":
|
|
case "protected":
|
|
case "private":
|
|
color = visibilityKeywordsColor;
|
|
break;
|
|
case "if":
|
|
case "else":
|
|
case "switch":
|
|
case "case":
|
|
case "default":
|
|
case "while":
|
|
case "do":
|
|
case "for":
|
|
case "foreach":
|
|
case "lock":
|
|
case "await":
|
|
color = structureKeywordsColor;
|
|
break;
|
|
case "where":
|
|
if (nodeStack.PeekOrDefault() is QueryClause)
|
|
color = queryKeywordsColor;
|
|
else
|
|
color = structureKeywordsColor;
|
|
break;
|
|
case "in":
|
|
if (nodeStack.PeekOrDefault() is ForeachStatement)
|
|
color = structureKeywordsColor;
|
|
else if (nodeStack.PeekOrDefault() is QueryClause)
|
|
color = queryKeywordsColor;
|
|
else
|
|
color = parameterModifierColor;
|
|
break;
|
|
case "as":
|
|
case "is":
|
|
case "new":
|
|
case "sizeof":
|
|
case "typeof":
|
|
case "nameof":
|
|
case "stackalloc":
|
|
color = typeKeywordsColor;
|
|
break;
|
|
case "with":
|
|
if (role == WithInitializerExpression.WithKeywordRole)
|
|
color = typeKeywordsColor;
|
|
break;
|
|
case "try":
|
|
case "throw":
|
|
case "catch":
|
|
case "finally":
|
|
color = exceptionKeywordsColor;
|
|
break;
|
|
case "when":
|
|
if (role == CatchClause.WhenKeywordRole)
|
|
color = exceptionKeywordsColor;
|
|
break;
|
|
case "get":
|
|
case "set":
|
|
case "add":
|
|
case "remove":
|
|
case "init":
|
|
if (role == PropertyDeclaration.GetKeywordRole ||
|
|
role == PropertyDeclaration.SetKeywordRole ||
|
|
role == PropertyDeclaration.InitKeywordRole ||
|
|
role == CustomEventDeclaration.AddKeywordRole ||
|
|
role == CustomEventDeclaration.RemoveKeywordRole)
|
|
color = accessorKeywordsColor;
|
|
break;
|
|
case "abstract":
|
|
case "const":
|
|
case "event":
|
|
case "extern":
|
|
case "override":
|
|
case "sealed":
|
|
case "static":
|
|
case "virtual":
|
|
case "volatile":
|
|
case "async":
|
|
case "partial":
|
|
color = modifiersColor;
|
|
break;
|
|
case "readonly":
|
|
if (role == ComposedType.ReadonlyRole)
|
|
color = parameterModifierColor;
|
|
else
|
|
color = modifiersColor;
|
|
break;
|
|
case "checked":
|
|
case "unchecked":
|
|
color = checkedKeywordColor;
|
|
break;
|
|
case "fixed":
|
|
case "unsafe":
|
|
color = unsafeKeywordsColor;
|
|
break;
|
|
case "enum":
|
|
case "struct":
|
|
color = valueTypeKeywordsColor;
|
|
break;
|
|
case "class":
|
|
case "interface":
|
|
case "delegate":
|
|
color = referenceTypeKeywordsColor;
|
|
break;
|
|
case "record":
|
|
color = role == Roles.RecordKeyword ? referenceTypeKeywordsColor : valueTypeKeywordsColor;
|
|
break;
|
|
case "select":
|
|
case "group":
|
|
case "by":
|
|
case "into":
|
|
case "from":
|
|
case "orderby":
|
|
case "let":
|
|
case "join":
|
|
case "on":
|
|
case "equals":
|
|
if (nodeStack.PeekOrDefault() is QueryClause)
|
|
color = queryKeywordsColor;
|
|
break;
|
|
case "ascending":
|
|
case "descending":
|
|
if (nodeStack.PeekOrDefault() is QueryOrdering)
|
|
color = queryKeywordsColor;
|
|
break;
|
|
case "explicit":
|
|
case "implicit":
|
|
case "operator":
|
|
color = operatorKeywordsColor;
|
|
break;
|
|
case "params":
|
|
case "ref":
|
|
case "out":
|
|
case "scoped":
|
|
color = parameterModifierColor;
|
|
break;
|
|
case "break":
|
|
case "continue":
|
|
case "goto":
|
|
case "yield":
|
|
case "return":
|
|
color = gotoKeywordsColor;
|
|
break;
|
|
}
|
|
if (nodeStack.PeekOrDefault() is AttributeSection)
|
|
color = attributeKeywordsColor;
|
|
if (color != null)
|
|
{
|
|
BeginSpan(color);
|
|
}
|
|
base.WriteKeyword(role, keyword);
|
|
if (color != null)
|
|
{
|
|
EndSpan();
|
|
}
|
|
}
|
|
|
|
public override void WritePrimitiveType(string type)
|
|
{
|
|
HighlightingColor color = null;
|
|
switch (type)
|
|
{
|
|
case "new":
|
|
case "notnull":
|
|
// Not sure if reference type or value type
|
|
color = referenceTypeKeywordsColor;
|
|
break;
|
|
case "bool":
|
|
case "byte":
|
|
case "char":
|
|
case "decimal":
|
|
case "double":
|
|
case "enum":
|
|
case "float":
|
|
case "int":
|
|
case "long":
|
|
case "sbyte":
|
|
case "short":
|
|
case "struct":
|
|
case "uint":
|
|
case "ushort":
|
|
case "ulong":
|
|
case "unmanaged":
|
|
case "nint":
|
|
case "nuint":
|
|
color = valueTypeKeywordsColor;
|
|
break;
|
|
case "class":
|
|
case "object":
|
|
case "string":
|
|
case "void":
|
|
case "dynamic":
|
|
color = referenceTypeKeywordsColor;
|
|
break;
|
|
}
|
|
if (color != null)
|
|
{
|
|
BeginSpan(color);
|
|
}
|
|
base.WritePrimitiveType(type);
|
|
if (color != null)
|
|
{
|
|
EndSpan();
|
|
}
|
|
}
|
|
|
|
public override void WriteIdentifier(Identifier identifier)
|
|
{
|
|
HighlightingColor color = null;
|
|
if (identifier.Parent?.GetResolveResult() is ILVariableResolveResult rr)
|
|
{
|
|
if (rr.Variable.Kind == VariableKind.Parameter)
|
|
{
|
|
if (identifier.Name == "value"
|
|
&& identifier.Ancestors.OfType<Accessor>().FirstOrDefault() is { } accessor
|
|
&& accessor.Role != PropertyDeclaration.GetterRole)
|
|
{
|
|
color = valueKeywordColor;
|
|
}
|
|
else
|
|
{
|
|
color = parameterColor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
color = variableColor;
|
|
}
|
|
}
|
|
if (identifier.Parent is AstType)
|
|
{
|
|
switch (identifier.Name)
|
|
{
|
|
case "var":
|
|
color = queryKeywordsColor;
|
|
break;
|
|
case "global":
|
|
color = structureKeywordsColor;
|
|
break;
|
|
}
|
|
}
|
|
switch (GetCurrentDefinition())
|
|
{
|
|
case ITypeDefinition t:
|
|
switch (t.Kind)
|
|
{
|
|
case TypeKind.Delegate:
|
|
color = delegateTypeColor;
|
|
break;
|
|
case TypeKind.Class:
|
|
color = referenceTypeColor;
|
|
break;
|
|
case TypeKind.Interface:
|
|
color = interfaceTypeColor;
|
|
break;
|
|
case TypeKind.Enum:
|
|
color = enumerationTypeColor;
|
|
break;
|
|
case TypeKind.Struct:
|
|
color = valueTypeColor;
|
|
break;
|
|
}
|
|
break;
|
|
case IMethod:
|
|
color = methodDeclarationColor;
|
|
break;
|
|
case IField:
|
|
color = fieldDeclarationColor;
|
|
break;
|
|
case IProperty:
|
|
color = propertyDeclarationColor;
|
|
break;
|
|
case IEvent:
|
|
color = eventDeclarationColor;
|
|
break;
|
|
}
|
|
switch (GetCurrentMemberReference())
|
|
{
|
|
case IType t:
|
|
switch (t.Kind)
|
|
{
|
|
case TypeKind.Delegate:
|
|
color = delegateTypeColor;
|
|
break;
|
|
case TypeKind.Class:
|
|
color = referenceTypeColor;
|
|
break;
|
|
case TypeKind.Interface:
|
|
color = interfaceTypeColor;
|
|
break;
|
|
case TypeKind.Enum:
|
|
color = enumerationTypeColor;
|
|
break;
|
|
case TypeKind.Struct:
|
|
color = valueTypeColor;
|
|
break;
|
|
}
|
|
break;
|
|
case IMethod:
|
|
color = methodCallColor;
|
|
break;
|
|
case IField:
|
|
color = fieldAccessColor;
|
|
break;
|
|
case IProperty:
|
|
color = propertyAccessColor;
|
|
break;
|
|
case IEvent:
|
|
color = eventAccessColor;
|
|
break;
|
|
}
|
|
if (color != null)
|
|
{
|
|
BeginSpan(color);
|
|
}
|
|
base.WriteIdentifier(identifier);
|
|
if (color != null)
|
|
{
|
|
EndSpan();
|
|
}
|
|
}
|
|
|
|
public override void WritePrimitiveValue(object value, Decompiler.CSharp.Syntax.LiteralFormat format)
|
|
{
|
|
HighlightingColor color = null;
|
|
if (value is null)
|
|
{
|
|
color = valueKeywordColor;
|
|
}
|
|
if (value is true || value is false)
|
|
{
|
|
color = trueKeywordColor;
|
|
}
|
|
if (color != null)
|
|
{
|
|
BeginSpan(color);
|
|
}
|
|
base.WritePrimitiveValue(value, format);
|
|
if (color != null)
|
|
{
|
|
EndSpan();
|
|
}
|
|
}
|
|
|
|
ISymbol GetCurrentDefinition()
|
|
{
|
|
if (nodeStack == null || nodeStack.Count == 0)
|
|
return null;
|
|
|
|
var node = nodeStack.Peek();
|
|
if (node is Identifier)
|
|
node = node.Parent;
|
|
if (Decompiler.TextTokenWriter.IsDefinition(ref node))
|
|
return node.GetSymbol();
|
|
|
|
return null;
|
|
}
|
|
|
|
ISymbol GetCurrentMemberReference()
|
|
{
|
|
if (nodeStack == null || nodeStack.Count == 0)
|
|
return null;
|
|
|
|
AstNode node = nodeStack.Peek();
|
|
var symbol = node.GetSymbol();
|
|
if (symbol == null && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression)
|
|
{
|
|
symbol = node.Parent.GetSymbol();
|
|
}
|
|
if (symbol != null && node.Parent is ObjectCreateExpression)
|
|
{
|
|
symbol = node.Parent.GetSymbol();
|
|
}
|
|
if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && symbol is IMember member)
|
|
{
|
|
var declaringType = member.DeclaringType;
|
|
if (declaringType != null && declaringType.Kind == TypeKind.Delegate)
|
|
return null;
|
|
}
|
|
return symbol;
|
|
}
|
|
|
|
readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
|
|
|
|
public override void StartNode(AstNode node)
|
|
{
|
|
nodeStack.Push(node);
|
|
base.StartNode(node);
|
|
}
|
|
|
|
public override void EndNode(AstNode node)
|
|
{
|
|
base.EndNode(node);
|
|
nodeStack.Pop();
|
|
}
|
|
|
|
readonly Stack<HighlightingColor> colorStack = new Stack<HighlightingColor>();
|
|
HighlightingColor currentColor = new HighlightingColor();
|
|
int currentColorBegin = -1;
|
|
readonly ILocatable locatable;
|
|
readonly ISmartTextOutput textOutput;
|
|
|
|
private void BeginSpan(HighlightingColor highlightingColor)
|
|
{
|
|
if (textOutput != null)
|
|
{
|
|
textOutput.BeginSpan(highlightingColor);
|
|
return;
|
|
}
|
|
|
|
if (currentColorBegin > -1)
|
|
HighlightingModel.SetHighlighting(currentColorBegin, locatable.Length - currentColorBegin, currentColor);
|
|
colorStack.Push(currentColor);
|
|
currentColor = currentColor.Clone();
|
|
currentColorBegin = locatable.Length;
|
|
currentColor.MergeWith(highlightingColor);
|
|
currentColor.Freeze();
|
|
}
|
|
|
|
private void EndSpan()
|
|
{
|
|
if (textOutput != null)
|
|
{
|
|
textOutput.EndSpan();
|
|
return;
|
|
}
|
|
|
|
HighlightingModel.SetHighlighting(currentColorBegin, locatable.Length - currentColorBegin, currentColor);
|
|
currentColor = colorStack.Pop();
|
|
currentColorBegin = locatable.Length;
|
|
}
|
|
}
|
|
}
|