Browse Source

C# semantic highlighting: distinguish between value and reference types.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
fa2c1a6397
  1. 15
      src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd
  2. 141
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs
  3. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSharp-Mode.xshd

15
src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd

@ -10,8 +10,8 @@
<Color name="Char" foreground="Magenta" exampleText="char linefeed = '\n';"/> <Color name="Char" foreground="Magenta" exampleText="char linefeed = '\n';"/>
<Color name="Preprocessor" foreground="Green" exampleText="#region Title" /> <Color name="Preprocessor" foreground="Green" exampleText="#region Title" />
<Color name="Punctuation" exampleText="a(b.c);" /> <Color name="Punctuation" exampleText="a(b.c);" />
<Color name="ValueTypes" fontWeight="bold" foreground="Red" exampleText="bool b = true;" /> <Color name="ValueTypeKeywords" fontWeight="bold" foreground="Red" exampleText="bool b = true;" />
<Color name="ReferenceTypes" foreground="Red" exampleText="object o;" /> <Color name="ReferenceTypeKeywords" foreground="Red" exampleText="object o;" />
<Color name="NumberLiteral" foreground="DarkBlue" exampleText="3.1415f"/> <Color name="NumberLiteral" foreground="DarkBlue" exampleText="3.1415f"/>
<Color name="ThisOrBaseReference" fontWeight="bold" exampleText="this.Do(); base.Do();"/> <Color name="ThisOrBaseReference" fontWeight="bold" exampleText="this.Do(); base.Do();"/>
<Color name="NullOrValueKeywords" fontWeight="bold" exampleText="if (value == null)"/> <Color name="NullOrValueKeywords" fontWeight="bold" exampleText="if (value == null)"/>
@ -31,9 +31,10 @@
<Color name="TypeKeywords" fontWeight="bold" foreground="DarkCyan" exampleText="if (x is int) { a = x as int; type = typeof(int); size = sizeof(int); c = new object(); }"/> <Color name="TypeKeywords" fontWeight="bold" foreground="DarkCyan" exampleText="if (x is int) { a = x as int; type = typeof(int); size = sizeof(int); c = new object(); }"/>
<!-- Colors used for semantic highlighting --> <!-- Colors used for semantic highlighting -->
<Color name="TypeReferences" foreground="#004085" exampleText="System.Uri uri;"/> <Color name="ReferenceTypes" foreground="#004085" exampleText="System.#{#Uri#}# uri;"/>
<Color name="MethodCall" foreground="MidnightBlue" fontWeight="bold" exampleText="o.ToString();"/> <Color name="ValueTypes" fontWeight="bold" foreground="#004085" exampleText="System.#{#DateTime#}# date;"/>
<Color name="FieldAccess" fontStyle="italic" exampleText="return this.name;"/> <Color name="MethodCall" foreground="MidnightBlue" fontWeight="bold" exampleText="o.#{#ToString#}#();"/>
<Color name="FieldAccess" fontStyle="italic" exampleText="return this.#{#name#}#;"/>
<RuleSet name="CommentMarkerSet"> <RuleSet name="CommentMarkerSet">
<Keywords fontWeight="bold" foreground="Red"> <Keywords fontWeight="bold" foreground="Red">
@ -197,7 +198,7 @@
<Word>unsafe</Word> <Word>unsafe</Word>
</Keywords> </Keywords>
<Keywords color="ValueTypes"> <Keywords color="ValueTypeKeywords">
<Word>bool</Word> <Word>bool</Word>
<Word>byte</Word> <Word>byte</Word>
<Word>char</Word> <Word>char</Word>
@ -215,7 +216,7 @@
<Word>ulong</Word> <Word>ulong</Word>
</Keywords> </Keywords>
<Keywords color="ReferenceTypes"> <Keywords color="ReferenceTypeKeywords">
<Word>class</Word> <Word>class</Word>
<Word>interface</Word> <Word>interface</Word>
<Word>delegate</Word> <Word>delegate</Word>

141
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.NRefactory; using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
@ -24,14 +24,54 @@ namespace CSharpBinding
{ {
readonly ITextEditor textEditor; readonly ITextEditor textEditor;
readonly ISyntaxHighlighter syntaxHighlighter; readonly ISyntaxHighlighter syntaxHighlighter;
readonly HighlightingColor typeReferenceColor; readonly HighlightingColor referenceTypeColor;
readonly HighlightingColor valueTypeColor;
readonly HighlightingColor methodCallColor; readonly HighlightingColor methodCallColor;
readonly HighlightingColor fieldAccessColor; readonly HighlightingColor fieldAccessColor;
readonly HighlightingColor valueKeywordColor; readonly HighlightingColor valueKeywordColor;
readonly HighlightingColor parameterModifierColor;
List<IDocumentLine> invalidLines = new List<IDocumentLine>(); List<IDocumentLine> invalidLines = new List<IDocumentLine>();
List<CachedLine> cachedLines = new List<CachedLine>(); List<CachedLine> cachedLines = new List<CachedLine>();
int lineNumber;
HighlightedLine line;
ResolveVisitor resolveVisitor;
bool isInAccessor;
#region Constructor + Dispose
public CSharpSemanticHighlighter(ITextEditor textEditor, ISyntaxHighlighter syntaxHighlighter)
{
if (textEditor == null)
throw new ArgumentNullException("textEditor");
if (syntaxHighlighter == null)
throw new ArgumentNullException("syntaxHighlighter");
this.textEditor = textEditor;
this.syntaxHighlighter = syntaxHighlighter;
IHighlightingDefinition highlightingDefinition = syntaxHighlighter.HighlightingDefinition;
this.referenceTypeColor = highlightingDefinition.GetNamedColor("ReferenceTypes");
this.valueTypeColor = highlightingDefinition.GetNamedColor("ValueTypes");
this.methodCallColor = highlightingDefinition.GetNamedColor("MethodCall");
this.fieldAccessColor = highlightingDefinition.GetNamedColor("FieldAccess");
this.valueKeywordColor = highlightingDefinition.GetNamedColor("NullOrValueKeywords");
this.parameterModifierColor = highlightingDefinition.GetNamedColor("ParameterModifiers");
ParserService.ParseInformationUpdated += ParserService_ParseInformationUpdated;
ParserService.LoadSolutionProjectsThreadEnded += ParserService_LoadSolutionProjectsThreadEnded;
syntaxHighlighter.VisibleDocumentLinesChanged += syntaxHighlighter_VisibleDocumentLinesChanged;
}
public void Dispose()
{
ParserService.ParseInformationUpdated -= ParserService_ParseInformationUpdated;
ParserService.LoadSolutionProjectsThreadEnded -= ParserService_LoadSolutionProjectsThreadEnded;
syntaxHighlighter.VisibleDocumentLinesChanged -= syntaxHighlighter_VisibleDocumentLinesChanged;
}
#endregion
#region Caching
// If a line gets edited and we need to display it while no parse information is ready for the // If a line gets edited and we need to display it while no parse information is ready for the
// changed file, the line would flicker (semantic highlightings disappear temporarily). // changed file, the line would flicker (semantic highlightings disappear temporarily).
// We avoid this issue by storing the semantic highlightings and updating them on document changes // We avoid this issue by storing the semantic highlightings and updating them on document changes
@ -88,40 +128,9 @@ namespace CSharpBinding
this.IsValid = false; this.IsValid = false;
} }
} }
#endregion
int lineNumber; #region Event Handlers
HighlightedLine line;
ResolveVisitor resolveVisitor;
bool isInAccessor;
public CSharpSemanticHighlighter(ITextEditor textEditor, ISyntaxHighlighter syntaxHighlighter)
{
if (textEditor == null)
throw new ArgumentNullException("textEditor");
if (syntaxHighlighter == null)
throw new ArgumentNullException("syntaxHighlighter");
this.textEditor = textEditor;
this.syntaxHighlighter = syntaxHighlighter;
IHighlightingDefinition highlightingDefinition = syntaxHighlighter.HighlightingDefinition;
this.typeReferenceColor = highlightingDefinition.GetNamedColor("TypeReferences");
this.methodCallColor = highlightingDefinition.GetNamedColor("MethodCall");
this.fieldAccessColor = highlightingDefinition.GetNamedColor("FieldAccess");
this.valueKeywordColor = highlightingDefinition.GetNamedColor("NullOrValueKeywords");
ParserService.ParseInformationUpdated += ParserService_ParseInformationUpdated;
ParserService.LoadSolutionProjectsThreadEnded += ParserService_LoadSolutionProjectsThreadEnded;
syntaxHighlighter.VisibleDocumentLinesChanged += syntaxHighlighter_VisibleDocumentLinesChanged;
}
public void Dispose()
{
ParserService.ParseInformationUpdated -= ParserService_ParseInformationUpdated;
ParserService.LoadSolutionProjectsThreadEnded -= ParserService_LoadSolutionProjectsThreadEnded;
syntaxHighlighter.VisibleDocumentLinesChanged -= syntaxHighlighter_VisibleDocumentLinesChanged;
}
void syntaxHighlighter_VisibleDocumentLinesChanged(object sender, EventArgs e) void syntaxHighlighter_VisibleDocumentLinesChanged(object sender, EventArgs e)
{ {
// use this event to remove cached lines which are no longer visible // use this event to remove cached lines which are no longer visible
@ -148,7 +157,9 @@ namespace CSharpBinding
invalidLines.Clear(); invalidLines.Clear();
} }
} }
#endregion
#region IHighlighter implementation
IDocument IHighlighter.Document { IDocument IHighlighter.Document {
get { return textEditor.Document; } get { return textEditor.Document; }
} }
@ -222,11 +233,17 @@ namespace CSharpBinding
return line; return line;
} }
} }
#endregion
#region Colorize
HighlightingColor GetColor(ResolveResult rr) HighlightingColor GetColor(ResolveResult rr)
{ {
if (rr is TypeResolveResult) if (rr is TypeResolveResult) {
return typeReferenceColor; if (rr.Type.IsReferenceType(resolveVisitor.TypeResolveContext) == false)
return valueTypeColor;
else
return referenceTypeColor;
}
MemberResolveResult mrr = rr as MemberResolveResult; MemberResolveResult mrr = rr as MemberResolveResult;
if (mrr != null) { if (mrr != null) {
if (mrr.Member is IField) if (mrr.Member is IField)
@ -250,6 +267,11 @@ namespace CSharpBinding
int lineStartOffset = line.DocumentLine.Offset; int lineStartOffset = line.DocumentLine.Offset;
int startOffset = lineStartOffset + start.Column - 1; int startOffset = lineStartOffset + start.Column - 1;
int endOffset = lineStartOffset + end.Column - 1; int endOffset = lineStartOffset + end.Column - 1;
if (line.Sections.Count > 0) {
HighlightedSection prevSection = line.Sections.Last();
if (startOffset < prevSection.Offset + prevSection.Length)
throw new InvalidOperationException("Cannot create unordered highlighting section");
}
line.Sections.Add(new HighlightedSection { line.Sections.Add(new HighlightedSection {
Offset = startOffset, Offset = startOffset,
Length = endOffset - startOffset, Length = endOffset - startOffset,
@ -257,7 +279,9 @@ namespace CSharpBinding
}); });
} }
} }
#endregion
#region IResolveVisitorNavigator implementation
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node) ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
{ {
if (node.StartLocation.Line <= lineNumber && node.EndLocation.Line >= lineNumber) { if (node.StartLocation.Line <= lineNumber && node.EndLocation.Line >= lineNumber) {
@ -281,7 +305,9 @@ namespace CSharpBinding
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType) void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{ {
} }
#endregion
#region AST Traversal
protected override object VisitChildren(AstNode node, object data) protected override object VisitChildren(AstNode node, object data)
{ {
for (var child = node.FirstChild; child != null; child = child.NextSibling) { for (var child = node.FirstChild; child != null; child = child.NextSibling) {
@ -293,8 +319,7 @@ namespace CSharpBinding
public override object VisitSimpleType(SimpleType simpleType, object data) public override object VisitSimpleType(SimpleType simpleType, object data)
{ {
if (resolveVisitor.GetResolveResult(simpleType) is TypeResolveResult) Colorize(simpleType.IdentifierToken, GetColor(resolveVisitor.GetResolveResult(simpleType)));
Colorize(simpleType.IdentifierToken, typeReferenceColor);
foreach (AstNode node in simpleType.TypeArguments) foreach (AstNode node in simpleType.TypeArguments)
node.AcceptVisitor(this); node.AcceptVisitor(this);
return null; return null;
@ -305,8 +330,7 @@ namespace CSharpBinding
// Ensure we visit/colorize the children in the correct order. // Ensure we visit/colorize the children in the correct order.
// This is required so that the resulting HighlightedSections are sorted correctly. // This is required so that the resulting HighlightedSections are sorted correctly.
memberType.Target.AcceptVisitor(this); memberType.Target.AcceptVisitor(this);
if (resolveVisitor.GetResolveResult(memberType) is TypeResolveResult) Colorize(memberType.MemberNameToken, GetColor(resolveVisitor.GetResolveResult(memberType)));
Colorize(memberType.MemberNameToken, typeReferenceColor);
foreach (AstNode node in memberType.TypeArguments) foreach (AstNode node in memberType.TypeArguments)
node.AcceptVisitor(this); node.AcceptVisitor(this);
return null; return null;
@ -382,7 +406,11 @@ namespace CSharpBinding
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{ {
Colorize(typeDeclaration.NameToken, typeReferenceColor); if (typeDeclaration.ClassType == ClassType.Enum || typeDeclaration.ClassType == ClassType.Struct)
Colorize(typeDeclaration.NameToken, valueTypeColor);
else
Colorize(typeDeclaration.NameToken, referenceTypeColor);
foreach (var node in typeDeclaration.TypeParameters) foreach (var node in typeDeclaration.TypeParameters)
node.AcceptVisitor(this); node.AcceptVisitor(this);
foreach (var node in typeDeclaration.BaseTypes) foreach (var node in typeDeclaration.BaseTypes)
@ -394,6 +422,34 @@ namespace CSharpBinding
return null; return null;
} }
public override object VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration, object data)
{
if (typeParameterDeclaration.Variance == VarianceModifier.Contravariant)
Colorize(typeParameterDeclaration.GetChildByRole(TypeParameterDeclaration.VarianceRole), parameterModifierColor);
bool isValueType = false;
if (typeParameterDeclaration.Parent != null) {
foreach (var constraint in typeParameterDeclaration.Parent.GetChildrenByRole(AstNode.Roles.Constraint)) {
if (constraint.TypeParameter == typeParameterDeclaration.Name) {
isValueType = constraint.BaseTypes.OfType<PrimitiveType>().Any(p => p.Keyword == "struct");
}
}
}
Colorize(typeParameterDeclaration.NameToken, isValueType ? valueTypeColor : referenceTypeColor);
return null;
}
public override object VisitConstraint(Constraint constraint, object data)
{
if (constraint.Parent != null && constraint.Parent.GetChildrenByRole(AstNode.Roles.TypeParameter).Any(tp => tp.Name == constraint.TypeParameter)) {
bool isValueType = constraint.BaseTypes.OfType<PrimitiveType>().Any(p => p.Keyword == "struct");
Colorize(constraint.GetChildByRole(AstNode.Roles.Identifier), isValueType ? valueTypeColor : referenceTypeColor);
}
foreach (var baseType in constraint.BaseTypes)
baseType.AcceptVisitor(this);
return null;
}
public override object VisitVariableInitializer(VariableInitializer variableInitializer, object data) public override object VisitVariableInitializer(VariableInitializer variableInitializer, object data)
{ {
if (variableInitializer.Parent is FieldDeclaration) { if (variableInitializer.Parent is FieldDeclaration) {
@ -402,5 +458,6 @@ namespace CSharpBinding
variableInitializer.Initializer.AcceptVisitor(this); variableInitializer.Initializer.AcceptVisitor(this);
return null; return null;
} }
#endregion
} }
} }

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSharp-Mode.xshd

@ -6,8 +6,8 @@
<Color name="Char" foreground="Magenta" exampleText="char linefeed = '\n';"/> <Color name="Char" foreground="Magenta" exampleText="char linefeed = '\n';"/>
<Color name="Preprocessor" foreground="Green" exampleText="#region Title" /> <Color name="Preprocessor" foreground="Green" exampleText="#region Title" />
<Color name="Punctuation" exampleText="a(b.c);" /> <Color name="Punctuation" exampleText="a(b.c);" />
<Color name="ValueTypes" fontWeight="bold" foreground="Red" exampleText="bool b = true;" /> <Color name="ValueTypeKeywords" fontWeight="bold" foreground="Red" exampleText="bool b = true;" />
<Color name="ReferenceTypes" foreground="Red" exampleText="object o;" /> <Color name="ReferenceTypeKeywords" foreground="Red" exampleText="object o;" />
<Color name="MethodCall" foreground="MidnightBlue" fontWeight="bold" exampleText="o.ToString();"/> <Color name="MethodCall" foreground="MidnightBlue" fontWeight="bold" exampleText="o.ToString();"/>
<Color name="NumberLiteral" foreground="DarkBlue" exampleText="3.1415f"/> <Color name="NumberLiteral" foreground="DarkBlue" exampleText="3.1415f"/>
<Color name="ThisOrBaseReference" fontWeight="bold" exampleText="this.Do(); base.Do();"/> <Color name="ThisOrBaseReference" fontWeight="bold" exampleText="this.Do(); base.Do();"/>
@ -189,7 +189,7 @@
<Word>unsafe</Word> <Word>unsafe</Word>
</Keywords> </Keywords>
<Keywords color="ValueTypes"> <Keywords color="ValueTypeKeywords">
<Word>bool</Word> <Word>bool</Word>
<Word>byte</Word> <Word>byte</Word>
<Word>char</Word> <Word>char</Word>
@ -207,7 +207,7 @@
<Word>ulong</Word> <Word>ulong</Word>
</Keywords> </Keywords>
<Keywords color="ReferenceTypes"> <Keywords color="ReferenceTypeKeywords">
<Word>class</Word> <Word>class</Word>
<Word>interface</Word> <Word>interface</Word>
<Word>delegate</Word> <Word>delegate</Word>

Loading…
Cancel
Save