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

// 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;
}
}
}