Browse Source

Merge branch 'master' of github.com:icsharpcode/NRefactory

newNRvisualizers
Mike Krüger 14 years ago
parent
commit
c3feace3a4
  1. 11
      ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  2. 160
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  3. 83
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  4. 4
      ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs
  5. 26
      ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
  6. 6
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  7. 2
      ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs
  8. 1
      ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs
  9. 1
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs
  10. 6
      ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs
  11. 93
      ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
  12. 36
      ICSharpCode.NRefactory.CSharp/Refactoring/IInspector.cs
  13. 61
      ICSharpCode.NRefactory.CSharp/Refactoring/InspectionIssue.cs
  14. 131
      ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/ConditionalToNullCoalescingInspector.cs
  15. 58
      ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/GatherVisitorBase.cs
  16. 54
      ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs
  17. 2
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  18. 75
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpOperators.cs
  19. 14
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  20. 42
      ICSharpCode.NRefactory.CSharp/Resolver/FindReferencedEntities.cs
  21. 35
      ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs
  22. 2
      ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  23. 11
      ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  24. 8
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  25. 24
      ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  26. 9
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs
  27. 9
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAttribute.cs
  28. 2
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpParsedFile.cs
  29. 9
      ICSharpCode.NRefactory.CSharp/TypeSystem/ResolvedUsingScope.cs
  30. 52
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs
  31. 13
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs
  32. 13
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs
  33. 19
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs
  34. 2
      ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs
  35. 48
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  36. 3
      ICSharpCode.NRefactory.Xml/AXmlObject.cs
  37. 2
      ICSharpCode.NRefactory/Editor/ITextSource.cs
  38. 4
      ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
  39. 6
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  40. 17
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  41. 1
      ICSharpCode.NRefactory/TypeSystem/IMember.cs
  42. 6
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs
  43. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
  44. 21
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  45. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs
  46. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs
  47. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedParameter.cs
  48. 10
      ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs
  49. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs
  50. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs
  51. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs
  52. 23
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedEvent.cs
  53. 15
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedField.cs
  54. 184
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs
  55. 103
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs
  56. 21
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedProperty.cs
  57. 45
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs
  58. 94
      ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs
  59. 17
      ICSharpCode.NRefactory/TypeSystem/InheritanceHelper.cs
  60. 23
      ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs
  61. 7
      ICSharpCode.NRefactory/Utils/EmptyList.cs
  62. 14
      ICSharpCode.NRefactory/Utils/LazyInit.cs
  63. 6
      ICSharpCode.NRefactory/Utils/ProjectedList.cs

11
ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -273,6 +273,17 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
/// <summary>
/// Gets the ancestors of this node (including this node itself)
/// </summary>
public IEnumerable<AstNode> AncestorsAndSelf {
get {
for (AstNode cur = this; cur != null; cur = cur.parent) {
yield return cur;
}
}
}
/// <summary> /// <summary>
/// Gets all descendants of this node (excluding this node itself). /// Gets all descendants of this node (excluding this node itself).
/// </summary> /// </summary>

160
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs

@ -73,6 +73,34 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
this.IndentString = "\t"; this.IndentString = "\t";
} }
public bool TryGetCompletionWord (int offset, out int startPos, out int wordLength)
{
startPos = wordLength = 0;
int pos = offset - 1;
while (pos >= 0) {
char c = document.GetCharAt (pos);
if (!char.IsLetterOrDigit (c) && c != '_')
break;
pos--;
}
if (pos == -1)
return false;
pos++;
startPos = pos;
while (pos < document.TextLength) {
char c = document.GetCharAt (pos);
if (!char.IsLetterOrDigit (c) && c != '_')
break;
pos++;
}
wordLength = pos - startPos;
return true;
}
public IEnumerable<ICompletionData> GetCompletionData(int offset, bool controlSpace) public IEnumerable<ICompletionData> GetCompletionData(int offset, bool controlSpace)
{ {
this.AutoCompleteEmptyMatch = true; this.AutoCompleteEmptyMatch = true;
@ -161,6 +189,29 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
} }
IEnumerable<ICompletionData> HandleMemberReferenceCompletion(ExpressionResult expr)
{
if (expr == null)
return null;
// do not complete <number>. (but <number>.<number>.)
if (expr.Node is PrimitiveExpression) {
var pexpr = (PrimitiveExpression)expr.Node;
if (!(pexpr.Value is string || pexpr.Value is char) && !pexpr.LiteralValue.Contains('.')) {
return null;
}
}
var resolveResult = ResolveExpression (expr);
if (resolveResult == null) {
return null;
}
if (expr.Node is AstType) {
return CreateTypeAndNamespaceCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
}
return CreateCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
}
IEnumerable<ICompletionData> MagicKeyCompletion(char completionChar, bool controlSpace) IEnumerable<ICompletionData> MagicKeyCompletion(char completionChar, bool controlSpace)
{ {
ExpressionResult expr; ExpressionResult expr;
@ -173,26 +224,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (IsInsideCommentOrString()) { if (IsInsideCommentOrString()) {
return Enumerable.Empty<ICompletionData>(); return Enumerable.Empty<ICompletionData>();
} }
expr = GetExpressionBeforeCursor(); return HandleMemberReferenceCompletion(GetExpressionBeforeCursor());
if (expr == null) {
return null;
}
// do not complete <number>. (but <number>.<number>.)
if (expr.Node is PrimitiveExpression) {
var pexpr = (PrimitiveExpression)expr.Node;
if (!(pexpr.Value is string || pexpr.Value is char) && !pexpr.LiteralValue.Contains('.')) {
return null;
}
}
resolveResult = ResolveExpression(expr);
if (resolveResult == null) {
return null;
}
if (expr.Node is AstType) {
return CreateTypeAndNamespaceCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
}
return CreateCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
case '#': case '#':
if (IsInsideCommentOrString()) { if (IsInsideCommentOrString()) {
return null; return null;
@ -478,19 +510,32 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
var contextList = new CompletionDataWrapper (this); var contextList = new CompletionDataWrapper (this);
var identifierStart = GetExpressionAtCursor(); var identifierStart = GetExpressionAtCursor();
if (identifierStart != null && identifierStart.Node is TypeParameterDeclaration) { if (identifierStart != null) {
return null;
}
if (identifierStart != null && identifierStart.Node is VariableInitializer && location <= ((VariableInitializer)identifierStart.Node).NameToken.EndLocation) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null; if (identifierStart.Node is TypeParameterDeclaration) {
}
if (identifierStart != null && identifierStart.Node is CatchClause) {
if (((CatchClause)identifierStart.Node).VariableNameToken.Contains(location)) {
return null; return null;
} }
identifierStart = null;
if (identifierStart.Node is MemberReferenceExpression) {
return HandleMemberReferenceCompletion(new ExpressionResult (((MemberReferenceExpression)identifierStart.Node).Target, identifierStart.Unit));
}
if (identifierStart.Node is Identifier) {
// May happen in variable names
return controlSpace ? DefaultControlSpaceItems(identifierStart) : null;
}
if (identifierStart.Node is VariableInitializer && location <= ((VariableInitializer)identifierStart.Node).NameToken.EndLocation) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
}
if (identifierStart.Node is CatchClause) {
if (((CatchClause)identifierStart.Node).VariableNameToken.Contains(location)) {
return null;
}
identifierStart = null;
}
} }
if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Node.Parent is ArrayInitializerExpression))) { if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Node.Parent is ArrayInitializerExpression))) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null; return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
@ -1415,7 +1460,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
if (newParentNode is ReturnStatement) { if (newParentNode is ReturnStatement) {
var varDecl = (ReturnStatement)newParentNode; //var varDecl = (ReturnStatement)newParentNode;
if (ctx.CurrentMember != null) { if (ctx.CurrentMember != null) {
hintType = ctx.CurrentMember.ReturnType; hintType = ctx.CurrentMember.ReturnType;
} }
@ -1561,8 +1606,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
IEnumerable<ICompletionData> GetOverrideCompletionData(IUnresolvedTypeDefinition type, string modifiers) IEnumerable<ICompletionData> GetOverrideCompletionData(IUnresolvedTypeDefinition type, string modifiers)
{ {
var wrapper = new CompletionDataWrapper (this); var wrapper = new CompletionDataWrapper (this);
var alreadyInserted = new Dictionary<string, bool> (); var alreadyInserted = new List<IMember> ();
bool addedVirtuals = false; //bool addedVirtuals = false;
int declarationBegin = offset; int declarationBegin = offset;
int j = declarationBegin; int j = declarationBegin;
@ -1643,16 +1688,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return null; return null;
} }
static string GetNameWithParamCount(IMember member) void AddVirtuals(List<IMember> alreadyInserted, CompletionDataWrapper col, string modifiers, IType curType, int declarationBegin)
{
var e = member as IMethod;
if (e == null || e.TypeParameters.Count == 0) {
return member.Name;
}
return e.Name + "`" + e.TypeParameters.Count;
}
void AddVirtuals(Dictionary<string, bool> alreadyInserted, CompletionDataWrapper col, string modifiers, IType curType, int declarationBegin)
{ {
if (curType == null) { if (curType == null) {
return; return;
@ -1667,17 +1703,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
var data = factory.CreateNewOverrideCompletionData(declarationBegin, currentType, m); var data = factory.CreateNewOverrideCompletionData(declarationBegin, currentType, m);
string text = GetNameWithParamCount(m);
// check if the member is already implemented // check if the member is already implemented
bool foundMember = curType.GetMembers().Any(cm => GetNameWithParamCount(cm) == text && cm.DeclaringTypeDefinition == curType.GetDefinition()); bool foundMember = curType.GetMembers().Any(cm => SignatureComparer.Ordinal.Equals(cm, m) && cm.DeclaringTypeDefinition == curType.GetDefinition());
if (foundMember) { if (foundMember) {
continue; continue;
} }
if (alreadyInserted.ContainsKey(text)) { if (alreadyInserted.Any(cm => SignatureComparer.Ordinal.Equals(cm, m)))
continue; continue;
} alreadyInserted.Add (m);
alreadyInserted [text] = true;
data.CompletionCategory = col.GetCompletionCategory(curType); data.CompletionCategory = col.GetCompletionCategory(curType);
col.Add(data); col.Add(data);
} }
@ -1742,7 +1775,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
IMethod delegateMethod = delegateType.GetDelegateInvokeMethod(); IMethod delegateMethod = delegateType.GetDelegateInvokeMethod();
var thisLineIndent = GetLineIndent(location.Line); var thisLineIndent = GetLineIndent(location.Line);
string delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : ""); string delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : "");
bool containsDelegateData = completionList.Result.Any(d => d.DisplayText.StartsWith("delegate(")); //bool containsDelegateData = completionList.Result.Any(d => d.DisplayText.StartsWith("delegate("));
if (addDefault) { if (addDefault) {
completionList.AddCustom("delegate", "Creates anonymous delegate.", "delegate {" + EolMarker + thisLineIndent + IndentString + "|" + delegateEndString); completionList.AddCustom("delegate", "Creates anonymous delegate.", "delegate {" + EolMarker + thisLineIndent + IndentString + "|" + delegateEndString);
} }
@ -1800,8 +1833,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
} }
if (member.IsInternal || member.IsProtectedAndInternal || member.IsProtectedOrInternal) { if (member.IsInternal || member.IsProtectedAndInternal || member.IsProtectedOrInternal) {
var type1 = member is ITypeDefinition ? (ITypeDefinition)member : member.DeclaringTypeDefinition; //var type1 = member is ITypeDefinition ? (ITypeDefinition)member : member.DeclaringTypeDefinition;
var type2 = currentMember is ITypeDefinition ? (ITypeDefinition)currentMember : currentMember.DeclaringTypeDefinition; //var type2 = currentMember is ITypeDefinition ? (ITypeDefinition)currentMember : currentMember.DeclaringTypeDefinition;
bool result = true; bool result = true;
// easy case, projects are the same // easy case, projects are the same
/*// if (type1.ProjectContent == type2.ProjectContent) { /*// if (type1.ProjectContent == type2.ProjectContent) {
@ -2008,7 +2041,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
IType type = resolveResult.Type; IType type = resolveResult.Type;
var typeDef = resolveResult.Type.GetDefinition(); //var typeDef = resolveResult.Type.GetDefinition();
var result = new CompletionDataWrapper (this); var result = new CompletionDataWrapper (this);
bool includeStaticMembers = false; bool includeStaticMembers = false;
@ -2240,7 +2273,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
return null; return null;
} }
var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
if (mref == null) { if (mref == null) {
var invoke = baseUnit.GetNodeAt<InvocationExpression>(location); var invoke = baseUnit.GetNodeAt<InvocationExpression>(location);
if (invoke != null) { if (invoke != null) {
@ -2290,14 +2323,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
ExpressionResult GetExpressionAtCursor() ExpressionResult GetExpressionAtCursor()
{ {
TextLocation memberLocation; // TextLocation memberLocation;
if (currentMember != null) { // if (currentMember != null) {
memberLocation = currentMember.Region.Begin; // memberLocation = currentMember.Region.Begin;
} else if (currentType != null) { // } else if (currentType != null) {
memberLocation = currentType.Region.Begin; // memberLocation = currentType.Region.Begin;
} else { // } else {
memberLocation = location; // memberLocation = location;
} // }
var baseUnit = ParseStub("a"); var baseUnit = ParseStub("a");
var tmpUnit = baseUnit; var tmpUnit = baseUnit;
@ -2305,7 +2338,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (expr == null) { if (expr == null) {
expr = baseUnit.GetNodeAt<AstType>(location.Line, location.Column - 1); expr = baseUnit.GetNodeAt<AstType>(location.Line, location.Column - 1);
} }
if (expr == null)
expr = baseUnit.GetNodeAt<Identifier>(location.Line, location.Column - 1);
// try insertStatement // try insertStatement
if (expr == null && baseUnit.GetNodeAt<EmptyStatement>(location.Line, location.Column) != null) { if (expr == null && baseUnit.GetNodeAt<EmptyStatement>(location.Line, location.Column) != null) {
tmpUnit = baseUnit = ParseStub("a();", false); tmpUnit = baseUnit = ParseStub("a();", false);

83
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs

@ -365,7 +365,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{ {
var bracketStack = GetBracketStack (memberText); var bracketStack = GetBracketStack (memberText);
bool didAppendSemicolon = !appendSemicolon; bool didAppendSemicolon = !appendSemicolon;
char lastBracket = '\0'; //char lastBracket = '\0';
while (bracketStack.Count > 0) { while (bracketStack.Count > 0) {
var t = bracketStack.Pop (); var t = bracketStack.Pop ();
switch (t.Item1) { switch (t.Item1) {
@ -373,19 +373,19 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
wrapper.Append (')'); wrapper.Append (')');
if (appendSemicolon) if (appendSemicolon)
didAppendSemicolon = false; didAppendSemicolon = false;
lastBracket = ')'; //lastBracket = ')';
break; break;
case '[': case '[':
wrapper.Append (']'); wrapper.Append (']');
if (appendSemicolon) if (appendSemicolon)
didAppendSemicolon = false; didAppendSemicolon = false;
lastBracket = ']'; //lastBracket = ']';
break; break;
case '<': case '<':
wrapper.Append ('>'); wrapper.Append ('>');
if (appendSemicolon) if (appendSemicolon)
didAppendSemicolon = false; didAppendSemicolon = false;
lastBracket = '>'; //lastBracket = '>';
break; break;
case '{': case '{':
int o = t.Item2 - 1; int o = t.Item2 - 1;
@ -421,7 +421,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (mt == null) { if (mt == null) {
return null; return null;
} }
string memberText = mt.Item1; string memberText = mt.Item1;
var memberLocation = mt.Item2; var memberLocation = mt.Item2;
int closingBrackets = 1; int closingBrackets = 1;
@ -429,18 +429,38 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
var wrapper = new StringBuilder (); var wrapper = new StringBuilder ();
bool wrapInClass = memberLocation != new TextLocation (1, 1); bool wrapInClass = memberLocation != new TextLocation (1, 1);
if (wrapInClass) { if (wrapInClass) {
/* foreach (var child in Unit.Children) { var nodeAtLocation = Unit.GetNodeAt(memberLocation, n => n is TypeDeclaration || n is NamespaceDeclaration);
if (child is UsingDeclaration) { if (nodeAtLocation != null) {
var offset = document.GetOffset (child.StartLocation); foreach (var n in nodeAtLocation.AncestorsAndSelf) {
wrapper.Append (document.GetText (offset, document.GetOffset (child.EndLocation) - offset)); if (memberLocation == n.StartLocation) {
continue;
}
if (n is TypeDeclaration) {
var t = (TypeDeclaration)n;
switch (t.ClassType) {
case ClassType.Class:
wrapper.Append("class");
break;
case ClassType.Struct:
wrapper.Append("struct");
break;
case ClassType.Interface:
wrapper.Append("interface");
break;
case ClassType.Enum:
wrapper.Append("enum");
break;
}
wrapper.Append(" " + t.Name + " {");
wrapper.AppendLine();
closingBrackets++;
generatedLines++;
} else {
Console.WriteLine(n);
}
} }
}*/ }
wrapper.Append("class Stub {");
wrapper.AppendLine();
closingBrackets++;
generatedLines = 1;
} }
wrapper.Append(memberText); wrapper.Append(memberText);
wrapper.Append(continuation); wrapper.Append(continuation);
AppendMissingClosingBrackets(wrapper, memberText, appendSemicolon); AppendMissingClosingBrackets(wrapper, memberText, appendSemicolon);
@ -486,7 +506,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
--startOffset; --startOffset;
} }
startOffset = 0;
if (cachedText == null) if (cachedText == null)
cachedText = document.GetText (startOffset, offset - startOffset); cachedText = document.GetText (startOffset, offset - startOffset);
@ -508,7 +527,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
baseUnit = ParseStub (afterBracket ? "" : "x"); baseUnit = ParseStub (afterBracket ? "" : "x");
var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
var mref = baseUnit.GetNodeAt (location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression); var mref = baseUnit.GetNodeAt (location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
AstNode expr = null; AstNode expr = null;
if (mref is InvocationExpression) { if (mref is InvocationExpression) {
@ -552,10 +571,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return ResolveExpression (tuple.Node, tuple.Unit); return ResolveExpression (tuple.Node, tuple.Unit);
} }
protected Tuple<ResolveResult, CSharpResolver> ResolveExpression (AstNode expr, CompilationUnit unit) protected Tuple<ResolveResult, CSharpResolver> ResolveExpression(AstNode expr, CompilationUnit unit)
{ {
if (expr == null) if (expr == null) {
return null; return null;
}
AstNode resolveNode; AstNode resolveNode;
if (expr is Expression || expr is AstType) { if (expr is Expression || expr is AstType) {
resolveNode = expr; resolveNode = expr;
@ -565,21 +585,21 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
resolveNode = expr; resolveNode = expr;
} }
try { try {
var csResolver = new CSharpAstResolver (GetState (), unit, CSharpParsedFile); var ctx = CSharpParsedFile.GetResolver(Compilation, location);
var result = csResolver.Resolve (resolveNode); var root = expr.AncestorsAndSelf.FirstOrDefault(n => n is EntityDeclaration || n is CompilationUnit);
var state = csResolver.GetResolverStateBefore (resolveNode); if (root == null) {
return Tuple.Create (result, state); return null;
}
var csResolver = new CSharpAstResolver (ctx, root, CSharpParsedFile);
var result = csResolver.Resolve(resolveNode);
var state = csResolver.GetResolverStateBefore(resolveNode);
return Tuple.Create(result, state);
} catch (Exception e) { } catch (Exception e) {
Console.WriteLine(e);
return null; return null;
} }
} }
protected static void Print (AstNode node)
{
var v = new CSharpOutputVisitor (Console.Out, new CSharpFormattingOptions ());
node.AcceptVisitor (v);
}
#endregion #endregion
class DefaultMemberProvider : IMemberProvider class DefaultMemberProvider : IMemberProvider
@ -594,7 +614,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
public void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember) public void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember)
{ {
var document = engine.document; //var document = engine.document;
var location = engine.location; var location = engine.location;
currentType = null; currentType = null;
@ -648,7 +668,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
int startOffset = document.GetOffset (currentType.Region.Begin); int startOffset = document.GetOffset (currentType.Region.Begin);
int endOffset = document.GetOffset (location); int endOffset = document.GetOffset (location);
bool foundEndBracket = false; //bool foundEndBracket = false;
var bracketStack = new Stack<char> (); var bracketStack = new Stack<char> ();
@ -702,6 +722,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return bracketStack.Any (t => t == '{'); return bracketStack.Any (t => t == '{');
} }
} }
} }
} }

4
ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs

@ -58,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return null; return null;
baseUnit = ParseStub ("x] = a[1"); baseUnit = ParseStub ("x] = a[1");
var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
var mref = baseUnit.GetNodeAt (location, n => n is IndexerExpression); var mref = baseUnit.GetNodeAt (location, n => n is IndexerExpression);
AstNode expr; AstNode expr;
if (mref is IndexerExpression) { if (mref is IndexerExpression) {
@ -94,7 +94,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return null; return null;
baseUnit = ParseStub ("x> a"); baseUnit = ParseStub ("x> a");
var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
var expr = baseUnit.GetNodeAt<AstType> (location.Line, location.Column + 1); // '>' position var expr = baseUnit.GetNodeAt<AstType> (location.Line, location.Column + 1); // '>' position
return new ExpressionResult ((AstNode)expr, baseUnit); return new ExpressionResult ((AstNode)expr, baseUnit);
} }

26
ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs

@ -129,12 +129,12 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public void ApplyChanges() public void ApplyChanges()
{ {
ApplyChanges(0, document.TextLength, document.Replace); ApplyChanges(0, document.TextLength, document.Replace, (o, l, v) => document.GetText(o, l) == v);
} }
public void ApplyChanges(int startOffset, int length) public void ApplyChanges(int startOffset, int length)
{ {
ApplyChanges(startOffset, length, document.Replace); ApplyChanges(startOffset, length, document.Replace, (o, l, v) => document.GetText(o, l) == v);
} }
/// <summary> /// <summary>
@ -150,11 +150,12 @@ namespace ICSharpCode.NRefactory.CSharp
ApplyChanges(startOffset, length, script.Replace); ApplyChanges(startOffset, length, script.Replace);
} }
public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace) public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace, Func<int, int, string, bool> filter = null)
{ {
int endOffset = startOffset + length; int endOffset = startOffset + length;
TextReplaceAction previousChange = null; TextReplaceAction previousChange = null;
int delta = 0; int delta = 0;
var depChanges = new List<TextReplaceAction> ();
foreach (var change in changes.OrderBy(c => c.Offset)) { foreach (var change in changes.OrderBy(c => c.Offset)) {
if (previousChange != null) { if (previousChange != null) {
if (change.Equals(previousChange)) { if (change.Equals(previousChange)) {
@ -174,16 +175,17 @@ namespace ICSharpCode.NRefactory.CSharp
} }
previousChange = change; previousChange = change;
if (change.Offset < startOffset) { bool skipChange = change.Offset < startOffset || change.Offset > endOffset;
// skip all changes in front of the begin offset skipChange |= filter != null && filter(change.Offset + delta, change.RemovalLength, change.NewText);
continue; skipChange &= !depChanges.Contains(change);
} else if (change.Offset > endOffset) {
// skip this change unless it depends on one that we already applied if (!skipChange) {
continue; documentReplace(change.Offset + delta, change.RemovalLength, change.NewText);
delta += change.NewText.Length - change.RemovalLength;
if (change.DependsOn != null) {
depChanges.Add(change.DependsOn);
}
} }
documentReplace(change.Offset + delta, change.RemovalLength, change.NewText);
delta += change.NewText.Length - change.RemovalLength;
} }
changes.Clear(); changes.Clear();
} }

6
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -322,6 +322,11 @@
<Compile Include="Refactoring\ContextAction\RemoveRegion.cs" /> <Compile Include="Refactoring\ContextAction\RemoveRegion.cs" />
<Compile Include="Refactoring\ContextAction\GenerateProperty.cs" /> <Compile Include="Refactoring\ContextAction\GenerateProperty.cs" />
<Compile Include="Ast\Roles.cs" /> <Compile Include="Ast\Roles.cs" />
<Compile Include="Refactoring\Inspector\ConditionalToNullCoalescingInspector.cs" />
<Compile Include="Refactoring\IInspector.cs" />
<Compile Include="Refactoring\InspectionIssue.cs" />
<Compile Include="Refactoring\BaseRefactoringContext.cs" />
<Compile Include="Refactoring\Inspector\GatherVisitorBase.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@ -332,6 +337,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup> <ItemGroup>
<Folder Include="Completion\" /> <Folder Include="Completion\" />
<Folder Include="Refactoring\Inspector\" />
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>

2
ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs

@ -717,7 +717,7 @@ namespace ICSharpCode.NRefactory.CSharp
CodeObject IAstVisitor<CodeObject>.VisitTypeDeclaration(TypeDeclaration typeDeclaration) CodeObject IAstVisitor<CodeObject>.VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{ {
bool isNestedType = typeStack.Count > 0; //bool isNestedType = typeStack.Count > 0;
CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(typeDeclaration.Name); CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(typeDeclaration.Name);
typeDecl.Attributes = ConvertMemberAttributes(typeDeclaration.Modifiers); typeDecl.Attributes = ConvertMemberAttributes(typeDeclaration.Modifiers);
typeDecl.CustomAttributes.AddRange(Convert(typeDeclaration.Attributes)); typeDecl.CustomAttributes.AddRange(Convert(typeDeclaration.Attributes));

1
ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs

@ -3658,7 +3658,6 @@ namespace ICSharpCode.NRefactory.CSharp
var file = new SourceFile (fileName, fileName, 0); var file = new SourceFile (fileName, fileName, 0);
Location.Initialize (new List<SourceFile> (new [] { file })); Location.Initialize (new List<SourceFile> (new [] { file }));
var module = new ModuleContainer (ctx); var module = new ModuleContainer (ctx);
var driver = new Driver (ctx);
var parser = Driver.Parse (reader, file, module, lineModifier); var parser = Driver.Parse (reader, file, module, lineModifier);
var top = new CompilerCompilationUnit () { var top = new CompilerCompilationUnit () {

1
ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs

@ -1535,7 +1535,6 @@ namespace Mono.CSharp
#endif #endif
number_pos = 0; number_pos = 0;
var loc = Location; var loc = Location;
bool hasLeadingDot = c == '.';
if (c >= '0' && c <= '9'){ if (c >= '0' && c <= '9'){
if (c == '0'){ if (c == '0'){

6
ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs

@ -2056,8 +2056,8 @@ namespace Mono.CSharp {
static int id; static int id;
public int ID = id++; public int ID = id++;
static int clone_id_counter; // static int clone_id_counter;
int clone_id; // int clone_id;
#endif #endif
// int assignable_slots; // int assignable_slots;
@ -2369,7 +2369,7 @@ namespace Mono.CSharp {
{ {
Block target = (Block) t; Block target = (Block) t;
#if DEBUG #if DEBUG
target.clone_id = clone_id_counter++; // target.clone_id = clone_id_counter++;
#endif #endif
clonectx.AddBlockMap (this, target); clonectx.AddBlockMap (this, target);

93
ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs

@ -0,0 +1,93 @@
//
// BaseRefactoringContext.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// 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;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public abstract class BaseRefactoringContext
{
protected readonly CSharpAstResolver resolver;
readonly CancellationToken cancellationToken;
public virtual bool Supports(Version version)
{
return true;
}
public CancellationToken CancellationToken {
get { return cancellationToken; }
}
public virtual AstNode RootNode {
get { return resolver.RootNode; }
}
public ICompilation Compilation {
get { return resolver.Compilation; }
}
public BaseRefactoringContext (ICSharpCode.NRefactory.CSharp.Resolver.CSharpAstResolver resolver, System.Threading.CancellationToken cancellationToken)
{
this.resolver = resolver;
this.cancellationToken = cancellationToken;
}
#region Resolving
public ResolveResult Resolve (AstNode node)
{
return resolver.Resolve (node, cancellationToken);
}
public IType ResolveType (AstType type)
{
return resolver.Resolve (type, cancellationToken).Type;
}
public IType GetExpectedType (Expression expression)
{
return resolver.GetExpectedType(expression, cancellationToken);
}
public Conversion GetConversion (Expression expression)
{
return resolver.GetConversion(expression, cancellationToken);
}
#endregion
public abstract Script StartScript();
}
}

36
ICSharpCode.NRefactory.CSharp/Refactoring/IInspector.cs

@ -0,0 +1,36 @@
//
// IInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// 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;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public interface IInspector
{
IEnumerable<InspectionIssue> Run (BaseRefactoringContext context);
}
}

61
ICSharpCode.NRefactory.CSharp/Refactoring/InspectionIssue.cs

@ -0,0 +1,61 @@
//
// InspectionIssue.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class InspectionIssue
{
public string Title {
get;
private set;
}
public TextLocation Start {
get;
private set;
}
public TextLocation End {
get;
private set;
}
public System.Action Fix {
get;
private set;
}
public InspectionIssue (string title, TextLocation start, TextLocation end, System.Action fix)
{
this.Title = title;
this.Start = start;
this.End = end;
this.Fix = fix;
}
}
}

131
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/ConditionalToNullCoalescingInspector.cs

@ -0,0 +1,131 @@
//
// ConditionalToNullCoalescingInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// 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;
using System.Collections.Generic;
using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Checks for obj != null ? obj : <expr>
/// Converts to: obj ?? <expr>
/// </summary>
public class ConditionalToNullCoalescingInspector : IInspector
{
static ConditionalExpression[] Matches;
string title = "Convert to '??' expression";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public ConditionalToNullCoalescingInspector ()
{
Matches = new [] {
new ConditionalExpression (new BinaryOperatorExpression (new NullReferenceExpression (), BinaryOperatorType.Equality, new AnyNode ()), new AnyNode (), new AnyNode ()),
new ConditionalExpression (new BinaryOperatorExpression (new AnyNode (), BinaryOperatorType.Equality, new NullReferenceExpression ()), new AnyNode (), new AnyNode ()),
new ConditionalExpression (new BinaryOperatorExpression (new NullReferenceExpression (), BinaryOperatorType.InEquality, new AnyNode ()), new AnyNode (), new AnyNode ()),
new ConditionalExpression (new BinaryOperatorExpression (new AnyNode (), BinaryOperatorType.InEquality, new NullReferenceExpression ()), new AnyNode (), new AnyNode ()),
};
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly ConditionalToNullCoalescingInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, ConditionalToNullCoalescingInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitConditionalExpression (ConditionalExpression conditionalExpression)
{
foreach (var match in Matches) {
if (match.IsMatch (conditionalExpression) && IsCandidate (conditionalExpression)) {
AddIssue (conditionalExpression,
inspector.Title,
delegate {
using (var script = ctx.StartScript ()) {
var expressions = SortExpressions (conditionalExpression);
var expr = new BinaryOperatorExpression (expressions.Item1.Clone (), BinaryOperatorType.NullCoalescing, expressions.Item2.Clone ());
script.Replace (conditionalExpression, expr);
}
});
}
}
base.VisitConditionalExpression (conditionalExpression);
}
}
static bool IsCandidate (ConditionalExpression node)
{
var condition = node.Condition as BinaryOperatorExpression;
var compareNode = condition.Left is NullReferenceExpression ? condition.Right : condition.Left;
if (compareNode.IsMatch (node.TrueExpression)) {
// a == null ? a : other
if (condition.Operator == BinaryOperatorType.Equality)
return false;
// a != null ? a : other
return compareNode.IsMatch (node.TrueExpression);
} else {
// a == null ? other : a
if (condition.Operator == BinaryOperatorType.Equality)
return compareNode.IsMatch (node.FalseExpression);
// a != null ? other : a
return false;
}
}
static Tuple<Expression, Expression> SortExpressions (ConditionalExpression cond)
{
var condition = cond.Condition as BinaryOperatorExpression;
var compareNode = condition.Left is NullReferenceExpression ? condition.Right : condition.Left;
if (compareNode.IsMatch (cond.TrueExpression)) {
// a != null ? a : other
return new Tuple<Expression, Expression> (cond.TrueExpression, cond.FalseExpression);
}
// a == null ? other : a
return new Tuple<Expression, Expression> (cond.FalseExpression, cond.TrueExpression);
}
}
}

58
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/GatherVisitorBase.cs

@ -0,0 +1,58 @@
//
// GatherVisitorBase.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// 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;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
class GatherVisitorBase : DepthFirstAstVisitor
{
protected readonly BaseRefactoringContext ctx;
public readonly List<InspectionIssue> FoundIssues = new List<InspectionIssue> ();
public GatherVisitorBase (BaseRefactoringContext ctx)
{
this.ctx = ctx;
}
protected override void VisitChildren (AstNode node)
{
if (ctx.CancellationToken.IsCancellationRequested)
return;
base.VisitChildren (node);
}
protected void AddIssue (AstNode node, string title, System.Action fix)
{
FoundIssues.Add (new InspectionIssue (title, node.StartLocation, node.EndLocation, fix));
}
}
}

54
ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs

@ -36,36 +36,14 @@ using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
public abstract class RefactoringContext public abstract class RefactoringContext : BaseRefactoringContext
{ {
readonly CSharpAstResolver resolver; public RefactoringContext(CSharpAstResolver resolver, CancellationToken cancellationToken) : base (resolver, cancellationToken)
readonly CancellationToken cancellationToken;
public RefactoringContext(CSharpAstResolver resolver, CancellationToken cancellationToken)
{ {
this.resolver = resolver;
this.cancellationToken = cancellationToken;
}
public CancellationToken CancellationToken {
get { return cancellationToken; }
}
public virtual AstNode RootNode {
get { return resolver.RootNode; }
} }
public abstract TextLocation Location { get; } public abstract TextLocation Location { get; }
public virtual bool Supports(Version version)
{
return true;
}
public ICompilation Compilation {
get { return resolver.Compilation; }
}
public virtual AstType CreateShortType (IType fullType) public virtual AstType CreateShortType (IType fullType)
{ {
var csResolver = resolver.GetResolverStateBefore(GetNode()); var csResolver = resolver.GetResolverStateBefore(GetNode());
@ -132,29 +110,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public abstract string GetText (ISegment segment); public abstract string GetText (ISegment segment);
#endregion #endregion
#region Resolving
public ResolveResult Resolve (AstNode node)
{
return resolver.Resolve (node, cancellationToken);
}
public IType ResolveType (AstType type)
{
return resolver.Resolve (type, cancellationToken).Type;
}
public IType GetExpectedType (Expression expression)
{
return resolver.GetExpectedType(expression, cancellationToken);
}
public Conversion GetConversion (Expression expression)
{
return resolver.GetConversion(expression, cancellationToken);
}
#endregion
public virtual string GetNameProposal (string name, bool camelCase = true) public virtual string GetNameProposal (string name, bool camelCase = true)
{ {
string baseName = (camelCase ? char.ToLower (name [0]) : char.ToUpper (name [0])) + name.Substring (1); string baseName = (camelCase ? char.ToLower (name [0]) : char.ToUpper (name [0])) + name.Substring (1);
@ -175,8 +131,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
return baseName + (number > 0 ? (number + 1).ToString () : ""); return baseName + (number > 0 ? (number + 1).ToString () : "");
} }
public abstract Script StartScript();
} }
} }

2
ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs

@ -418,7 +418,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ParameterizedType toPT = toType as ParameterizedType; ParameterizedType toPT = toType as ParameterizedType;
if (fromArray.Dimensions == 1 && toPT != null && toPT.TypeParameterCount == 1 if (fromArray.Dimensions == 1 && toPT != null && toPT.TypeParameterCount == 1
&& toPT.Namespace == "System.Collections.Generic" && toPT.Namespace == "System.Collections.Generic"
&& (toPT.Name == "IList" || toPT.Name == "ICollection" || toPT.Name == "IEnumerable")) && (toPT.Name == "IList" || toPT.Name == "ICollection" || toPT.Name == "IEnumerable" || toPT.Name == "IReadOnlyList"))
{ {
// array covariance plays a part here as well (string[] is IList<object>) // array covariance plays a part here as well (string[] is IList<object>)
return IdentityConversion(fromArray.ElementType, toPT.GetTypeArgument(0)) return IdentityConversion(fromArray.ElementType, toPT.GetTypeArgument(0))

75
ICSharpCode.NRefactory.CSharp/Resolver/CSharpOperators.cs

@ -327,9 +327,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] UnaryPlusOperators { public OperatorMethod[] UnaryPlusOperators {
get { get {
OperatorMethod[] ops = unaryPlusOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref unaryPlusOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref unaryPlusOperators, Lift( return LazyInit.GetOrSet(ref unaryPlusOperators, Lift(
@ -350,9 +349,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] UncheckedUnaryMinusOperators { public OperatorMethod[] UncheckedUnaryMinusOperators {
get { get {
OperatorMethod[] ops = uncheckedUnaryMinusOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref uncheckedUnaryMinusOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref uncheckedUnaryMinusOperators, Lift( return LazyInit.GetOrSet(ref uncheckedUnaryMinusOperators, Lift(
@ -370,9 +368,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] CheckedUnaryMinusOperators { public OperatorMethod[] CheckedUnaryMinusOperators {
get { get {
OperatorMethod[] ops = checkedUnaryMinusOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref checkedUnaryMinusOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref checkedUnaryMinusOperators, Lift( return LazyInit.GetOrSet(ref checkedUnaryMinusOperators, Lift(
@ -391,9 +388,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] LogicalNegationOperators { public OperatorMethod[] LogicalNegationOperators {
get { get {
OperatorMethod[] ops = logicalNegationOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalNegationOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref logicalNegationOperators, Lift( return LazyInit.GetOrSet(ref logicalNegationOperators, Lift(
@ -408,9 +404,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] BitwiseComplementOperators { public OperatorMethod[] BitwiseComplementOperators {
get { get {
OperatorMethod[] ops = bitwiseComplementOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseComplementOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref bitwiseComplementOperators, Lift( return LazyInit.GetOrSet(ref bitwiseComplementOperators, Lift(
@ -501,9 +496,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] MultiplicationOperators { public OperatorMethod[] MultiplicationOperators {
get { get {
OperatorMethod[] ops = multiplicationOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref multiplicationOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref multiplicationOperators, Lift( return LazyInit.GetOrSet(ref multiplicationOperators, Lift(
@ -524,9 +518,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] DivisionOperators { public OperatorMethod[] DivisionOperators {
get { get {
OperatorMethod[] ops = divisionOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref divisionOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref divisionOperators, Lift( return LazyInit.GetOrSet(ref divisionOperators, Lift(
@ -547,9 +540,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] RemainderOperators { public OperatorMethod[] RemainderOperators {
get { get {
OperatorMethod[] ops = remainderOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref remainderOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref remainderOperators, Lift( return LazyInit.GetOrSet(ref remainderOperators, Lift(
@ -570,9 +562,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] AdditionOperators { public OperatorMethod[] AdditionOperators {
get { get {
OperatorMethod[] ops = additionOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref additionOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref additionOperators, Lift( return LazyInit.GetOrSet(ref additionOperators, Lift(
@ -620,9 +611,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] SubtractionOperators { public OperatorMethod[] SubtractionOperators {
get { get {
OperatorMethod[] ops = subtractionOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref subtractionOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref subtractionOperators, Lift( return LazyInit.GetOrSet(ref subtractionOperators, Lift(
@ -643,9 +633,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] ShiftLeftOperators { public OperatorMethod[] ShiftLeftOperators {
get { get {
OperatorMethod[] ops = shiftLeftOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftLeftOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref shiftLeftOperators, Lift( return LazyInit.GetOrSet(ref shiftLeftOperators, Lift(
@ -662,9 +651,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] ShiftRightOperators { public OperatorMethod[] ShiftRightOperators {
get { get {
OperatorMethod[] ops = shiftRightOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftRightOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref shiftRightOperators, Lift( return LazyInit.GetOrSet(ref shiftRightOperators, Lift(
@ -767,9 +755,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] ValueEqualityOperators { public OperatorMethod[] ValueEqualityOperators {
get { get {
OperatorMethod[] ops = valueEqualityOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref valueEqualityOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref valueEqualityOperators, Lift( return LazyInit.GetOrSet(ref valueEqualityOperators, Lift(
@ -783,9 +770,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] ValueInequalityOperators { public OperatorMethod[] ValueInequalityOperators {
get { get {
OperatorMethod[] ops = valueInequalityOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref valueInequalityOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref valueInequalityOperators, Lift( return LazyInit.GetOrSet(ref valueInequalityOperators, Lift(
@ -799,9 +785,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] ReferenceEqualityOperators { public OperatorMethod[] ReferenceEqualityOperators {
get { get {
OperatorMethod[] ops = referenceEqualityOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceEqualityOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref referenceEqualityOperators, Lift( return LazyInit.GetOrSet(ref referenceEqualityOperators, Lift(
@ -816,9 +801,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] ReferenceInequalityOperators { public OperatorMethod[] ReferenceInequalityOperators {
get { get {
OperatorMethod[] ops = referenceInequalityOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceInequalityOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref referenceInequalityOperators, Lift( return LazyInit.GetOrSet(ref referenceInequalityOperators, Lift(
@ -868,9 +852,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] LessThanOperators { public OperatorMethod[] LessThanOperators {
get { get {
OperatorMethod[] ops = lessThanOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref lessThanOperators, Lift( return LazyInit.GetOrSet(ref lessThanOperators, Lift(
@ -890,9 +873,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] LessThanOrEqualOperators { public OperatorMethod[] LessThanOrEqualOperators {
get { get {
OperatorMethod[] ops = lessThanOrEqualOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOrEqualOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref lessThanOrEqualOperators, Lift( return LazyInit.GetOrSet(ref lessThanOrEqualOperators, Lift(
@ -912,9 +894,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] GreaterThanOperators { public OperatorMethod[] GreaterThanOperators {
get { get {
OperatorMethod[] ops = greaterThanOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref greaterThanOperators, Lift( return LazyInit.GetOrSet(ref greaterThanOperators, Lift(
@ -934,9 +915,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] GreaterThanOrEqualOperators { public OperatorMethod[] GreaterThanOrEqualOperators {
get { get {
OperatorMethod[] ops = greaterThanOrEqualOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOrEqualOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref greaterThanOrEqualOperators, Lift( return LazyInit.GetOrSet(ref greaterThanOrEqualOperators, Lift(
@ -958,9 +938,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] LogicalAndOperators { public OperatorMethod[] LogicalAndOperators {
get { get {
OperatorMethod[] ops = logicalAndOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalAndOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref logicalAndOperators, new OperatorMethod[] { return LazyInit.GetOrSet(ref logicalAndOperators, new OperatorMethod[] {
@ -975,9 +954,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] BitwiseAndOperators { public OperatorMethod[] BitwiseAndOperators {
get { get {
OperatorMethod[] ops = bitwiseAndOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseAndOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref bitwiseAndOperators, Lift( return LazyInit.GetOrSet(ref bitwiseAndOperators, Lift(
@ -996,9 +974,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] LogicalOrOperators { public OperatorMethod[] LogicalOrOperators {
get { get {
OperatorMethod[] ops = logicalOrOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalOrOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref logicalOrOperators, new OperatorMethod[] { return LazyInit.GetOrSet(ref logicalOrOperators, new OperatorMethod[] {
@ -1012,9 +989,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] BitwiseOrOperators { public OperatorMethod[] BitwiseOrOperators {
get { get {
OperatorMethod[] ops = bitwiseOrOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseOrOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref bitwiseOrOperators, Lift( return LazyInit.GetOrSet(ref bitwiseOrOperators, Lift(
@ -1036,9 +1012,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public OperatorMethod[] BitwiseXorOperators { public OperatorMethod[] BitwiseXorOperators {
get { get {
OperatorMethod[] ops = bitwiseXorOperators; OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseXorOperators);
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref bitwiseXorOperators, Lift( return LazyInit.GetOrSet(ref bitwiseXorOperators, Lift(

14
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -1167,13 +1167,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal readonly IParameterizedMember nonLiftedOperator; internal readonly IParameterizedMember nonLiftedOperator;
public LiftedUserDefinedOperator(IMethod nonLiftedMethod) public LiftedUserDefinedOperator(IMethod nonLiftedMethod)
: base(nonLiftedMethod.DeclaringType, (IMethod)nonLiftedMethod.MemberDefinition, : base(nonLiftedMethod, TypeParameterSubstitution.Identity)
EmptyList<IType>.Instance, new MakeNullableVisitor(nonLiftedMethod.Compilation))
{ {
this.nonLiftedOperator = nonLiftedMethod; this.nonLiftedOperator = nonLiftedMethod;
var substitution = new MakeNullableVisitor(nonLiftedMethod.Compilation);
this.Parameters = base.CreateParameters(substitution);
// Comparison operators keep the 'bool' return type even when lifted. // Comparison operators keep the 'bool' return type even when lifted.
if (IsComparisonOperator(nonLiftedMethod)) if (IsComparisonOperator(nonLiftedMethod))
this.ReturnType = nonLiftedMethod.ReturnType; this.ReturnType = nonLiftedMethod.ReturnType;
else
this.ReturnType = nonLiftedMethod.ReturnType.AcceptVisitor(substitution);
} }
public IList<IParameter> NonLiftedParameters { public IList<IParameter> NonLiftedParameters {
@ -1726,13 +1729,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (typeArguments != null && typeArguments.Count > 0) { if (typeArguments != null && typeArguments.Count > 0) {
if (method.TypeParameters.Count != typeArguments.Count) if (method.TypeParameters.Count != typeArguments.Count)
continue; continue;
SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments); SpecializedMethod sm = new SpecializedMethod(method, new TypeParameterSubstitution(null, typeArguments));
if (IsEligibleExtensionMethod(targetType, method, false, out inferredTypes)) if (IsEligibleExtensionMethod(targetType, method, false, out inferredTypes))
outputGroup.Add(sm); outputGroup.Add(sm);
} else { } else {
if (IsEligibleExtensionMethod(targetType, method, true, out inferredTypes)) { if (IsEligibleExtensionMethod(targetType, method, true, out inferredTypes)) {
if (substituteInferredTypes && inferredTypes != null) { if (substituteInferredTypes && inferredTypes != null) {
outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes)); outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
} else { } else {
outputGroup.Add(method); outputGroup.Add(method);
} }
@ -1794,9 +1797,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var currentUsingScope = context.CurrentUsingScope; var currentUsingScope = context.CurrentUsingScope;
if (currentUsingScope == null) if (currentUsingScope == null)
return EmptyList<List<IMethod>>.Instance; return EmptyList<List<IMethod>>.Instance;
List<List<IMethod>> extensionMethodGroups = currentUsingScope.AllExtensionMethods; List<List<IMethod>> extensionMethodGroups = LazyInit.VolatileRead(ref currentUsingScope.AllExtensionMethods);
if (extensionMethodGroups != null) { if (extensionMethodGroups != null) {
LazyInit.ReadBarrier();
return extensionMethodGroups; return extensionMethodGroups;
} }
extensionMethodGroups = new List<List<IMethod>>(); extensionMethodGroups = new List<List<IMethod>>();

42
ICSharpCode.NRefactory.CSharp/Resolver/FindReferencedEntities.cs

@ -27,13 +27,39 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public sealed class FindReferencedEntities : IResolveVisitorNavigator public sealed class FindReferencedEntities : IResolveVisitorNavigator
{ {
readonly Action<AstNode, IEntity> referenceFound; readonly Action<AstNode, IMember> memberReferenceFound;
readonly Action<AstNode, IType> typeReferenceFound;
/// <summary>
/// Creates a new FindReferencedEntities instance that
/// looks for entity definitions.
/// The visitor will report type definitions and member definitions (not specialized members).
/// </summary>
public FindReferencedEntities(Action<AstNode, IEntity> referenceFound) public FindReferencedEntities(Action<AstNode, IEntity> referenceFound)
{ {
if (referenceFound == null) if (referenceFound == null)
throw new ArgumentNullException("referenceFound"); throw new ArgumentNullException("referenceFound");
this.referenceFound = referenceFound; this.memberReferenceFound = (node, member) => referenceFound(node, member.MemberDefinition);
this.typeReferenceFound = (node, type) => {
var def = type.GetDefinition();
if (def != null)
referenceFound(node, def);
};
}
/// <summary>
/// Creates a new FindReferencedEntities instance that
/// looks for types and members.
/// The visitor will report parameterized types and potentially specialized members.
/// </summary>
public FindReferencedEntities(Action<AstNode, IType> typeReferenceFound, Action<AstNode, IMember> memberReferenceFound)
{
if (typeReferenceFound == null)
throw new ArgumentNullException("typeReferenceFound");
if (memberReferenceFound == null)
throw new ArgumentNullException("memberReferenceFound");
this.typeReferenceFound = typeReferenceFound;
this.memberReferenceFound = memberReferenceFound;
} }
public ResolveVisitorNavigationMode Scan(AstNode node) public ResolveVisitorNavigationMode Scan(AstNode node)
@ -48,28 +74,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
MemberResolveResult mrr = result as MemberResolveResult; MemberResolveResult mrr = result as MemberResolveResult;
if (mrr != null) { if (mrr != null) {
referenceFound(node, mrr.Member.MemberDefinition); memberReferenceFound(node, mrr.Member);
} }
TypeResolveResult trr = result as TypeResolveResult; TypeResolveResult trr = result as TypeResolveResult;
if (trr != null) { if (trr != null) {
ITypeDefinition typeDef = trr.Type.GetDefinition(); typeReferenceFound(node, trr.Type);
if (typeDef != null)
referenceFound(node, typeDef);
} }
ForEachResolveResult ferr = result as ForEachResolveResult; ForEachResolveResult ferr = result as ForEachResolveResult;
if (ferr != null) { if (ferr != null) {
Resolved(node, ferr.GetEnumeratorCall); Resolved(node, ferr.GetEnumeratorCall);
if (ferr.CurrentProperty != null) if (ferr.CurrentProperty != null)
referenceFound(node, ferr.CurrentProperty.MemberDefinition); memberReferenceFound(node, ferr.CurrentProperty);
if (ferr.MoveNextMethod != null) if (ferr.MoveNextMethod != null)
referenceFound(node, ferr.MoveNextMethod.MemberDefinition); memberReferenceFound(node, ferr.MoveNextMethod);
} }
} }
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType) public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{ {
if (conversion.IsUserDefined || conversion.IsMethodGroupConversion) { if (conversion.IsUserDefined || conversion.IsMethodGroupConversion) {
referenceFound(expression, conversion.Method.MemberDefinition); memberReferenceFound(expression, conversion.Method);
} }
} }
} }

35
ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs

@ -42,9 +42,42 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
#region Properties #region Properties
/// <summary> /// <summary>
/// Gets/Sets whether to find type references even if an alias is being used. /// Specifies whether to find type references even if an alias is being used.
/// Aliases may be <c>var</c> or <c>using Alias = ...;</c>.
/// </summary> /// </summary>
public bool FindTypeReferencesEvenIfAliased { get; set; } public bool FindTypeReferencesEvenIfAliased { get; set; }
/// <summary>
/// Specifies whether find references should only look for specialized matches
/// with equal type parameter substitution to the member we are searching for.
/// </summary>
public bool FindOnlySpecializedReferences { get; set; }
/// <summary>
/// If this option is enabled, find references on a overridden member
/// will find calls to the base member.
/// </summary>
public bool FindCallsThroughVirtualBaseMethod { get; set; }
/// <summary>
/// If this option is enabled, find references on a member implementing
/// an interface will also find calls to the interface.
/// </summary>
public bool FindCallsThroughInterface { get; set; }
/// <summary>
/// If this option is enabled, find references will look for all references
/// to the virtual method slot.
/// </summary>
public bool WholeVirtualSlot { get; set; }
/// <summary>
/// Specifies whether to look for references in documentation comments.
/// This will find entity references in <c>cref</c> attributes and
/// parameter references in <c>&lt;param&gt;</c> and <c>&lt;paramref&gt;</c> tags.
/// TODO: implement this feature.
/// </summary>
public bool SearchInDocumentationComments { get; set; }
#endregion #endregion
#region GetEffectiveAccessibility #region GetEffectiveAccessibility

2
ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs

@ -164,7 +164,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.TargetType, method, true, out inferredTypes)) this.TargetType, method, true, out inferredTypes))
{ {
if (substituteInferredTypes && inferredTypes != null) { if (substituteInferredTypes && inferredTypes != null) {
outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes)); outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
} else { } else {
outputGroup.Add(method); outputGroup.Add(method);
} }

11
ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs

@ -807,7 +807,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return null; return null;
IMethod method = bestCandidate.Member as IMethod; IMethod method = bestCandidate.Member as IMethod;
if (method != null && method.TypeParameters.Count > 0) { if (method != null && method.TypeParameters.Count > 0) {
return new SpecializedMethod(method.DeclaringType, (IMethod)method.MemberDefinition, bestCandidate.InferredTypes); SpecializedMethod sm = method as SpecializedMethod;
if (sm != null) {
// Do not compose the substitutions, but merge them.
// This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
return new SpecializedMethod(
(IMethod)method.MemberDefinition,
new TypeParameterSubstitution(sm.Substitution.ClassTypeArguments, bestCandidate.InferredTypes));
} else {
return new SpecializedMethod(method, new TypeParameterSubstitution(null, bestCandidate.InferredTypes));
}
} else { } else {
return bestCandidate.Member; return bestCandidate.Member;
} }

8
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -1310,8 +1310,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
if (resolverEnabled || !objectCreateExpression.Initializer.IsNull) { if (resolverEnabled || !objectCreateExpression.Initializer.IsNull) {
var typeResolveResult = Resolve(objectCreateExpression.Type); var typeResolveResult = Resolve(objectCreateExpression.Type);
if (typeResolveResult.IsError) if (typeResolveResult.IsError) {
ScanChildren (objectCreateExpression);
return typeResolveResult; return typeResolveResult;
}
IType type = typeResolveResult.Type; IType type = typeResolveResult.Type;
List<ResolveResult> initializerStatements = null; List<ResolveResult> initializerStatements = null;
@ -1712,7 +1714,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
CSharpResolver oldResolver = resolver; CSharpResolver oldResolver = resolver;
List<IParameter> parameters = (hasParameterList || parameterDeclarations.Any()) ? new List<IParameter>() : null; List<IParameter> parameters = (hasParameterList || parameterDeclarations.Any()) ? new List<IParameter>() : null;
bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression; //bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression;
resolver = resolver.WithIsWithinLambdaExpression(true); resolver = resolver.WithIsWithinLambdaExpression(true);
foreach (var pd in parameterDeclarations) { foreach (var pd in parameterDeclarations) {
IType type = ResolveType(pd.Type); IType type = ResolveType(pd.Type);
@ -2626,7 +2628,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (string.IsNullOrEmpty(catchClause.VariableName)) { if (string.IsNullOrEmpty(catchClause.VariableName)) {
Scan(catchClause.Type); Scan(catchClause.Type);
} else { } else {
DomRegion region = MakeRegion(catchClause.VariableNameToken); //DomRegion region = MakeRegion(catchClause.VariableNameToken);
StoreCurrentState(catchClause.VariableNameToken); StoreCurrentState(catchClause.VariableNameToken);
IVariable v = MakeVariable(ResolveType(catchClause.Type), catchClause.VariableNameToken); IVariable v = MakeVariable(ResolveType(catchClause.Type), catchClause.VariableNameToken);
resolver = resolver.AddVariable(v); resolver = resolver.AddVariable(v);

24
ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs

@ -629,15 +629,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Handle array types: // Handle array types:
ArrayType arrU = U as ArrayType; ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType; ArrayType arrV = V as ArrayType;
ParameterizedType pV = V as ParameterizedType;
if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) { if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) {
MakeLowerBoundInference(arrU.ElementType, arrV.ElementType); MakeLowerBoundInference(arrU.ElementType, arrV.ElementType);
return; return;
} else if (arrU != null && IsIEnumerableCollectionOrList(pV) && arrU.Dimensions == 1) {
MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0));
return;
} }
// Handle parameterized types: // Handle parameterized types:
ParameterizedType pV = V as ParameterizedType;
if (pV != null) { if (pV != null) {
ParameterizedType uniqueBaseType = null; ParameterizedType uniqueBaseType = null;
foreach (IType baseU in U.GetAllBaseTypes()) { foreach (IType baseU in U.GetAllBaseTypes()) {
@ -677,20 +674,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Log.Unindent(); Log.Unindent();
} }
} }
static bool IsIEnumerableCollectionOrList(ParameterizedType rt)
{
if (rt == null || rt.TypeParameterCount != 1)
return false;
switch (rt.GetDefinition().FullName) {
case "System.Collections.Generic.IList":
case "System.Collections.Generic.ICollection":
case "System.Collections.Generic.IEnumerable":
return true;
default:
return false;
}
}
#endregion #endregion
#region MakeUpperBoundInference (§7.5.2.10) #region MakeUpperBoundInference (§7.5.2.10)
@ -713,15 +696,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Handle array types: // Handle array types:
ArrayType arrU = U as ArrayType; ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType; ArrayType arrV = V as ArrayType;
ParameterizedType pU = U as ParameterizedType;
if (arrV != null && arrU != null && arrU.Dimensions == arrV.Dimensions) { if (arrV != null && arrU != null && arrU.Dimensions == arrV.Dimensions) {
MakeUpperBoundInference(arrU.ElementType, arrV.ElementType); MakeUpperBoundInference(arrU.ElementType, arrV.ElementType);
return; return;
} else if (arrV != null && IsIEnumerableCollectionOrList(pU) && arrV.Dimensions == 1) {
MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType);
return;
} }
// Handle parameterized types: // Handle parameterized types:
ParameterizedType pU = U as ParameterizedType;
if (pU != null) { if (pU != null) {
ParameterizedType uniqueBaseType = null; ParameterizedType uniqueBaseType = null;
foreach (IType baseV in V.GetAllBaseTypes()) { foreach (IType baseV in V.GetAllBaseTypes()) {

9
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs

@ -68,9 +68,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
IList<IAttribute> GetAttributes(ref IList<IAttribute> field, bool assemblyAttributes) IList<IAttribute> GetAttributes(ref IList<IAttribute> field, bool assemblyAttributes)
{ {
IList<IAttribute> result = field; IList<IAttribute> result = LazyInit.VolatileRead(ref field);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
result = new List<IAttribute>(); result = new List<IAttribute>();
@ -89,9 +88,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
public INamespace RootNamespace { public INamespace RootNamespace {
get { get {
NS root = this.rootNamespace; NS root = LazyInit.VolatileRead(ref this.rootNamespace);
if (root != null) { if (root != null) {
LazyInit.ReadBarrier();
return root; return root;
} else { } else {
root = new NS(this); root = new NS(this);
@ -183,9 +181,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
Dictionary<FullNameAndTypeParameterCount, ITypeDefinition> GetTypes() Dictionary<FullNameAndTypeParameterCount, ITypeDefinition> GetTypes()
{ {
var dict = this.typeDict; var dict = LazyInit.VolatileRead(ref this.typeDict);
if (dict != null) { if (dict != null) {
LazyInit.ReadBarrier();
return dict; return dict;
} else { } else {
// Always use the ordinal comparer for the main dictionary so that partial classes // Always use the ordinal comparer for the main dictionary so that partial classes

9
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAttribute.cs

@ -93,9 +93,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
InvocationResolveResult GetCtorInvocation() InvocationResolveResult GetCtorInvocation()
{ {
ResolveResult rr = this.ctorInvocation; ResolveResult rr = LazyInit.VolatileRead(ref this.ctorInvocation);
if (rr != null) { if (rr != null) {
LazyInit.ReadBarrier();
return rr as InvocationResolveResult; return rr as InvocationResolveResult;
} else { } else {
CSharpResolver resolver = new CSharpResolver(context); CSharpResolver resolver = new CSharpResolver(context);
@ -132,9 +131,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
IList<ResolveResult> IAttribute.PositionalArguments { IList<ResolveResult> IAttribute.PositionalArguments {
get { get {
var result = this.positionalArguments; var result = LazyInit.VolatileRead(ref this.positionalArguments);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
var invocation = GetCtorInvocation(); var invocation = GetCtorInvocation();
@ -149,9 +147,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
IList<KeyValuePair<IMember, ResolveResult>> IAttribute.NamedArguments { IList<KeyValuePair<IMember, ResolveResult>> IAttribute.NamedArguments {
get { get {
var namedArgs = this.namedArguments; var namedArgs = LazyInit.VolatileRead(ref this.namedArguments);
if (namedArgs != null) { if (namedArgs != null) {
LazyInit.ReadBarrier();
return namedArgs; return namedArgs;
} else { } else {
namedArgs = new List<KeyValuePair<IMember, ResolveResult>>(); namedArgs = new List<KeyValuePair<IMember, ResolveResult>>();

2
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpParsedFile.cs

@ -159,7 +159,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
return null; return null;
} }
public CSharpTypeResolveContext GetTypeResolveContext (ICompilation compilation, TextLocation loc) public CSharpTypeResolveContext GetTypeResolveContext(ICompilation compilation, TextLocation loc)
{ {
var rctx = new CSharpTypeResolveContext (compilation.MainAssembly); var rctx = new CSharpTypeResolveContext (compilation.MainAssembly);
rctx = rctx.WithUsingScope (GetUsingScope (loc).Resolve (compilation)); rctx = rctx.WithUsingScope (GetUsingScope (loc).Resolve (compilation));

9
ICSharpCode.NRefactory.CSharp/TypeSystem/ResolvedUsingScope.cs

@ -64,9 +64,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
public INamespace Namespace { public INamespace Namespace {
get { get {
INamespace result = this.@namespace; INamespace result = LazyInit.VolatileRead(ref this.@namespace);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
if (parentContext.CurrentUsingScope != null) { if (parentContext.CurrentUsingScope != null) {
@ -90,9 +89,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
public IList<INamespace> Usings { public IList<INamespace> Usings {
get { get {
var result = this.usings; var result = LazyInit.VolatileRead(ref this.usings);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
result = new List<INamespace>(); result = new List<INamespace>();
@ -111,9 +109,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
public IList<KeyValuePair<string, ResolveResult>> UsingAliases { public IList<KeyValuePair<string, ResolveResult>> UsingAliases {
get { get {
var result = this.usingAliases; var result = LazyInit.VolatileRead(ref this.usingAliases);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
CSharpResolver resolver = new CSharpResolver(parentContext.WithUsingScope(this)); CSharpResolver resolver = new CSharpResolver(parentContext.WithUsingScope(this));

52
ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs

@ -43,8 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
[TestFixture()] [TestFixture()]
public class CodeCompletionBugTests : TestBase public class CodeCompletionBugTests : TestBase
{ {
static int pcount = 0;
public static CompletionDataList CreateProvider (string text) public static CompletionDataList CreateProvider (string text)
{ {
return CreateProvider (text, false); return CreateProvider (text, false);
@ -350,7 +349,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
} }
} }
} catch (Exception e) { } catch (Exception e) {
Console.WriteLine ("Exception in:" + file); Console.WriteLine ("Exception in:" + file + "/" + e);
exceptions++; exceptions++;
} }
} }
@ -4765,5 +4764,52 @@ class MainClass
Assert.IsNull (provider.Find ("IEnumerable"), "'IEnumerable' found."); Assert.IsNull (provider.Find ("IEnumerable"), "'IEnumerable' found.");
} }
/// <summary>
/// Bug 3957 - [New Resolver]Override completion doesn't work well for overloaded methods
/// </summary>
[Test()]
public void TestBug3957 ()
{
var provider = CreateProvider (
@"class A
{
public virtual void Method()
{}
public virtual void Method(int i)
{}
}
class B : A
{
$override $
}
");
Assert.AreEqual (2, provider.Data.Where (d => d.DisplayText == "Method").Count ());
}
/// <summary>
/// Bug 3973 - code completion forgets context if text is deleted
/// </summary>
[Test()]
public void TestBug3973 ()
{
var provider = CreateProvider (
@"
using System;
class A
{
public static void Main (string[] args)
{
Console.$W$
}
}
");
Assert.IsNotNull (provider.Find ("WriteLine"), "'WriteLine' not found.");
}
} }
} }

13
ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs

@ -122,6 +122,19 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty."); Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty.");
} }
[Test()]
public void TestForLoopLocalVariableName ()
{
var provider = CodeCompletionBugTests.CreateProvider (@"class MyClass {
void Test()
{
$for (int f$
}
}");
Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty.");
}
[Test()] [Test()]
public void TestCatchExceptionName () public void TestCatchExceptionName ()
{ {

13
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs

@ -260,5 +260,18 @@ class Test {
Assert.AreEqual("Test", rr.Type.ReflectionName); Assert.AreEqual("Test", rr.Type.ReflectionName);
Assert.AreEqual(5, rr.InitializerStatements.Count); Assert.AreEqual(5, rr.InitializerStatements.Count);
} }
[Test]
public void CreateGeneric()
{
string program = @"using System;
class Test<T> where T : new() {
object x = $new T()$;
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(TypeKind.TypeParameter, rr.Type.Kind);
Assert.AreEqual(TypeKind.TypeParameter, rr.Member.DeclaringType.Kind);
}
} }
} }

19
ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs

@ -70,6 +70,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[Test]
public void ArrayToReadOnlyList()
{
ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
IType stringType = compilation.FindType(KnownTypeCode.String);
ITypeDefinition readOnlyListType = compilation.FindType(KnownTypeCode.IReadOnlyListOfT).GetDefinition();
if (readOnlyListType == null)
Assert.Ignore(".NET 4.5 IReadOnlyList not available");
bool success;
Assert.AreEqual(
new [] { stringType },
ti.InferTypeArguments(new [] { tp },
new [] { new ResolveResult(new ArrayType(compilation, stringType)) },
new [] { new ParameterizedType(readOnlyListType, new [] { tp }) },
out success));
Assert.IsTrue(success);
}
[Test] [Test]
public void EnumerableToArrayInContravariantType() public void EnumerableToArrayInContravariantType()
{ {

2
ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs

@ -69,6 +69,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
[Test] [Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void ArrayOfString() public void ArrayOfString()
{ {
Assert.AreEqual(GetTypes(typeof(string[]), typeof(Array), typeof(object), Assert.AreEqual(GetTypes(typeof(string[]), typeof(Array), typeof(object),
@ -216,6 +217,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
[Test] [Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypeDefinitionsOfStringArray() public void BaseTypeDefinitionsOfStringArray()
{ {
Assert.AreEqual( Assert.AreEqual(

48
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -182,6 +182,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex"); IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex");
Assert.AreEqual("T", m.TypeParameters[0].Name); Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType); Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
Assert.AreSame(m, m.TypeParameters[0].Owner);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First(); ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First();
Assert.AreEqual("IEquatable", constraint.Name); Assert.AreEqual("IEquatable", constraint.Name);
@ -190,6 +191,53 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]); Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]);
} }
[Test]
public void GetIndexSpecializedTypeParameter()
{
var testClass = GetTypeDefinition(typeof(GenericClass<,>));
var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex");
var m = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.Int16), compilation.FindType(KnownTypeCode.Int32) },
null
));
Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
Assert.AreSame(m, m.TypeParameters[0].Owner);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First();
Assert.AreEqual("IEquatable", constraint.Name);
Assert.AreEqual(1, constraint.TypeParameterCount);
Assert.AreEqual(1, constraint.TypeArguments.Count);
Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]);
}
[Test]
public void GetIndexDoubleSpecialization()
{
var testClass = GetTypeDefinition(typeof(GenericClass<,>));
// GenericClass<A, B>.GetIndex<T>
var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex");
// GenericClass<B, A>.GetIndex<A>
var m1 = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { testClass.TypeParameters[1], testClass.TypeParameters[0] },
new[] { testClass.TypeParameters[0] }
));
// GenericClass<string, int>.GetIndex<int>
var m2 = new SpecializedMethod(m1, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.Int32), compilation.FindType(KnownTypeCode.String) },
null
));
// GenericClass<string, int>.GetIndex<int>
var m12 = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.String), compilation.FindType(KnownTypeCode.Int32) },
new[] { compilation.FindType(KnownTypeCode.Int32) }
));
Assert.AreEqual(m12, m2);
}
[Test] [Test]
public void GenericEnum() public void GenericEnum()
{ {

3
ICSharpCode.NRefactory.Xml/AXmlObject.cs

@ -79,9 +79,8 @@ namespace ICSharpCode.NRefactory.Xml
/// </summary> /// </summary>
public IList<AXmlObject> Children { public IList<AXmlObject> Children {
get { get {
var result = this.children; var result = LazyInit.VolatileRead(ref this.children);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
if (internalObject.NestedObjects != null) { if (internalObject.NestedObjects != null) {

2
ICSharpCode.NRefactory/Editor/ITextSource.cs

@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.Editor
/// <remarks> /// <remarks>
/// Verions can be used to efficiently detect whether a document has changed and needs reparsing; /// Verions can be used to efficiently detect whether a document has changed and needs reparsing;
/// or even to implement incremental parsers. /// or even to implement incremental parsers.
/// It is a separate class from ITextBuffer to allow the GC to collect the text buffer while /// It is a separate class from ITextSource to allow the GC to collect the text source while
/// the version checkpoint is still in use. /// the version checkpoint is still in use.
/// </remarks> /// </remarks>
public interface ITextSourceVersion public interface ITextSourceVersion

4
ICSharpCode.NRefactory/TypeSystem/ArrayType.cs

@ -85,6 +85,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
ITypeDefinition def = compilation.FindType(KnownTypeCode.IListOfT) as ITypeDefinition; ITypeDefinition def = compilation.FindType(KnownTypeCode.IListOfT) as ITypeDefinition;
if (def != null) if (def != null)
baseTypes.Add(new ParameterizedType(def, new[] { elementType })); baseTypes.Add(new ParameterizedType(def, new[] { elementType }));
// And in .NET 4.5 they also implement IReadOnlyList<T>
def = compilation.FindType(KnownTypeCode.IReadOnlyListOfT) as ITypeDefinition;
if (def != null)
baseTypes.Add(new ParameterizedType(def, new[] { elementType }));
} }
return baseTypes; return baseTypes;
} }

6
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -869,9 +869,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
public IList<ResolveResult> PositionalArguments { public IList<ResolveResult> PositionalArguments {
get { get {
var result = this.positionalArguments; var result = LazyInit.VolatileRead(ref this.positionalArguments);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} }
DecodeBlob(); DecodeBlob();
@ -881,9 +880,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
public IList<KeyValuePair<IMember, ResolveResult>> NamedArguments { public IList<KeyValuePair<IMember, ResolveResult>> NamedArguments {
get { get {
var result = this.namedArguments; var result = LazyInit.VolatileRead(ref this.namedArguments);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} }
DecodeBlob(); DecodeBlob();

17
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -246,19 +246,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
{ {
if (type == null) if (type == null)
throw new ArgumentNullException("type"); throw new ArgumentNullException("type");
ITypeDefinition def = type.GetDefinition(); if (type.Kind == TypeKind.Delegate)
if (def != null && def.Kind == TypeKind.Delegate) { return type.GetMethods(m => m.Name == "Invoke", GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
foreach (IMember member in def.Members) { else
if (member.Name == "Invoke" && member is IMethod) { return null;
ParameterizedType pt = type as ParameterizedType;
if (pt != null) {
return new SpecializedMethod(pt, (IMethod)member);
}
return (IMethod)member;
}
}
}
return null;
} }
#endregion #endregion

1
ICSharpCode.NRefactory/TypeSystem/IMember.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.Contracts; using System.Diagnostics.Contracts;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem namespace ICSharpCode.NRefactory.TypeSystem
{ {

6
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs

@ -56,9 +56,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IList<IMember> ImplementedInterfaceMembers { public IList<IMember> ImplementedInterfaceMembers {
get { get {
IList<IMember> result = this.implementedInterfaceMembers; IList<IMember> result = LazyInit.VolatileRead(ref this.implementedInterfaceMembers);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
return LazyInit.GetOrSet(ref implementedInterfaceMembers, FindImplementedInterfaceMembers()); return LazyInit.GetOrSet(ref implementedInterfaceMembers, FindImplementedInterfaceMembers());
@ -123,9 +122,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{ {
if (unresolvedAccessor == null) if (unresolvedAccessor == null)
return null; return null;
IMethod result = accessorField; IMethod result = LazyInit.VolatileRead(ref accessorField);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
return LazyInit.GetOrSet(ref accessorField, (IMethod)unresolvedAccessor.CreateResolved(context)); return LazyInit.GetOrSet(ref accessorField, (IMethod)unresolvedAccessor.CreateResolved(context));

2
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs

@ -261,7 +261,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) { if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) {
if (filter == null || filter(dummyConstructor)) { if (filter == null || filter(dummyConstructor)) {
var resolvedCtor = GetDummyConstructor(compilation); var resolvedCtor = GetDummyConstructor(compilation);
IMethod m = new SpecializedMethod(this, resolvedCtor, EmptyList<IType>.Instance); IMethod m = new SpecializedMethod(resolvedCtor, TypeParameterSubstitution.Identity) { DeclaringType = this };
return new [] { m }; return new [] { m };
} }
} }

21
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -61,9 +61,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IList<ITypeParameter> TypeParameters { public IList<ITypeParameter> TypeParameters {
get { get {
var result = this.typeParameters; var result = LazyInit.VolatileRead(ref this.typeParameters);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} }
ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext); ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext);
@ -91,9 +90,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IList<IAttribute> Attributes { public IList<IAttribute> Attributes {
get { get {
var result = this.attributes; var result = LazyInit.VolatileRead(ref this.attributes);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} }
result = new List<IAttribute>(); result = new List<IAttribute>();
@ -126,9 +124,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IList<ITypeDefinition> NestedTypes { public IList<ITypeDefinition> NestedTypes {
get { get {
IList<ITypeDefinition> result = this.nestedTypes; IList<ITypeDefinition> result = LazyInit.VolatileRead(ref this.nestedTypes);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
result = ( result = (
@ -171,9 +168,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IMember this[int index] { public IMember this[int index] {
get { get {
IMember output = resolvedMembers[index]; IMember output = LazyInit.VolatileRead(ref resolvedMembers[index]);
if (output != null) { if (output != null) {
LazyInit.ReadBarrier();
return output; return output;
} }
return LazyInit.GetOrSet(ref resolvedMembers[index], unresolvedMembers[index].CreateResolved(contextPerMember[index])); return LazyInit.GetOrSet(ref resolvedMembers[index], unresolvedMembers[index].CreateResolved(contextPerMember[index]));
@ -288,9 +284,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
MemberList GetMemberList() MemberList GetMemberList()
{ {
var result = this.memberList; var result = LazyInit.VolatileRead(ref this.memberList);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} }
List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>(); List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>();
@ -506,9 +501,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IEnumerable<IType> DirectBaseTypes { public IEnumerable<IType> DirectBaseTypes {
get { get {
IList<IType> result = this.directBaseTypes; IList<IType> result = LazyInit.VolatileRead(ref this.directBaseTypes);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
result = CalculateDirectBaseTypes(); result = CalculateDirectBaseTypes();
@ -787,7 +781,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IType coClass = ComHelper.GetCoClass(this); IType coClass = ComHelper.GetCoClass(this);
using (var busyLock = BusyManager.Enter(this)) { using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) { if (busyLock.Success) {
return coClass.GetConstructors(filter, options).Select(m => new SpecializedMethod(this, m)); return coClass.GetConstructors(filter, options)
.Select(m => new SpecializedMethod(m, TypeParameterSubstitution.Identity) { DeclaringType = this });
} }
} }
return EmptyList<IMethod>.Instance; return EmptyList<IMethod>.Instance;

3
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs

@ -340,9 +340,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IEnumerable<ITypeDefinition> INamespace.Types { IEnumerable<ITypeDefinition> INamespace.Types {
get { get {
var result = this.types; var result = LazyInit.VolatileRead(ref this.types);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
var hashSet = new HashSet<ITypeDefinition>(); var hashSet = new HashSet<ITypeDefinition>();

3
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs

@ -246,9 +246,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IList<KeyValuePair<IMember, ResolveResult>> NamedArguments { public IList<KeyValuePair<IMember, ResolveResult>> NamedArguments {
get { get {
var namedArgs = this.namedArguments; var namedArgs = LazyInit.VolatileRead(ref this.namedArguments);
if (namedArgs != null) { if (namedArgs != null) {
LazyInit.ReadBarrier();
return namedArgs; return namedArgs;
} else { } else {
namedArgs = new List<KeyValuePair<IMember, ResolveResult>>(); namedArgs = new List<KeyValuePair<IMember, ResolveResult>>();

3
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedParameter.cs

@ -234,9 +234,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public object ConstantValue { public object ConstantValue {
get { get {
ResolveResult rr = this.resolvedDefaultValue; ResolveResult rr = LazyInit.VolatileRead(ref this.resolvedDefaultValue);
if (rr != null) { if (rr != null) {
LazyInit.ReadBarrier();
return rr.ConstantValue; return rr.ConstantValue;
} else { } else {
rr = defaultValue.Resolve(context); rr = defaultValue.Resolve(context);

10
ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs

@ -132,7 +132,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
else else
substitution = new TypeParameterSubstitution(null, methodTypeArguments); substitution = new TypeParameterSubstitution(null, methodTypeArguments);
} }
yield return new SpecializedMethod(baseType, m, methodTypeArguments, substitution); yield return new SpecializedMethod(m, substitution);
} }
} else { } else {
foreach (IMethod m in declaredMethods) { foreach (IMethod m in declaredMethods) {
@ -162,7 +162,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType; ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) { if (pt != null) {
var substitution = pt.GetSubstitution(); var substitution = pt.GetSubstitution();
return declaredCtors.Select(m => new SpecializedMethod(pt, m, null, substitution)); return declaredCtors.Select(m => new SpecializedMethod(m, substitution) { DeclaringType = pt });
} else { } else {
return declaredCtors; return declaredCtors;
} }
@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType; ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) { if (pt != null) {
var substitution = pt.GetSubstitution(); var substitution = pt.GetSubstitution();
return declaredProperties.Select(m => new SpecializedProperty(pt, m, substitution)); return declaredProperties.Select(m => new SpecializedProperty(m, substitution) { DeclaringType = pt });
} else { } else {
return declaredProperties; return declaredProperties;
} }
@ -216,7 +216,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType; ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) { if (pt != null) {
var substitution = pt.GetSubstitution(); var substitution = pt.GetSubstitution();
return declaredFields.Select(m => new SpecializedField(pt, m, substitution)); return declaredFields.Select(m => new SpecializedField(m, substitution) { DeclaringType = pt });
} else { } else {
return declaredFields; return declaredFields;
} }
@ -243,7 +243,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType; ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) { if (pt != null) {
var substitution = pt.GetSubstitution(); var substitution = pt.GetSubstitution();
return declaredEvents.Select(m => new SpecializedEvent(pt, m, substitution)); return declaredEvents.Select(m => new SpecializedEvent(m, substitution) { DeclaringType = pt });
} else { } else {
return declaredEvents; return declaredEvents;
} }

3
ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs

@ -36,9 +36,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IType FindType(KnownTypeCode typeCode) public IType FindType(KnownTypeCode typeCode)
{ {
IType type = knownTypes[(int)typeCode]; IType type = LazyInit.VolatileRead(ref knownTypes[(int)typeCode]);
if (type != null) { if (type != null) {
LazyInit.ReadBarrier();
return type; return type;
} }
return LazyInit.GetOrSet(ref knownTypes[(int)typeCode], SearchType(typeCode)); return LazyInit.GetOrSet(ref knownTypes[(int)typeCode], SearchType(typeCode));

3
ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs

@ -111,9 +111,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
Dictionary<string, INamespace> GetChildNamespaces() Dictionary<string, INamespace> GetChildNamespaces()
{ {
var result = this.childNamespaces; var result = LazyInit.VolatileRead(ref this.childNamespaces);
if (result != null) { if (result != null) {
LazyInit.ReadBarrier();
return result; return result;
} else { } else {
result = new Dictionary<string, INamespace>(compilation.NameComparer); result = new Dictionary<string, INamespace>(compilation.NameComparer);

3
ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs

@ -110,9 +110,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public INamespace RootNamespace { public INamespace RootNamespace {
get { get {
INamespace ns = this.rootNamespace; INamespace ns = LazyInit.VolatileRead(ref this.rootNamespace);
if (ns != null) { if (ns != null) {
LazyInit.ReadBarrier();
return ns; return ns;
} else { } else {
if (referencedAssemblies == null) if (referencedAssemblies == null)

23
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedEvent.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{ {
readonly IEvent eventDefinition; readonly IEvent eventDefinition;
public SpecializedEvent(IType declaringType, IEvent eventDefinition) public SpecializedEvent(IEvent eventDefinition, TypeParameterSubstitution substitution)
: base(declaringType, eventDefinition) : base(eventDefinition)
{ {
this.eventDefinition = eventDefinition; AddSubstitution(substitution);
Initialize(GetSubstitution(declaringType)); this.eventDefinition = (IEvent)base.MemberDefinition;
}
internal SpecializedEvent(IType declaringType, IEvent eventDefinition, TypeVisitor substitution)
: base(declaringType, eventDefinition)
{
this.eventDefinition = eventDefinition;
Initialize(substitution);
} }
public bool CanAdd { public bool CanAdd {
@ -53,16 +46,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return eventDefinition.CanInvoke; } get { return eventDefinition.CanInvoke; }
} }
IMethod addAccessor, removeAccessor, invokeAccessor;
public IMethod AddAccessor { public IMethod AddAccessor {
get { return WrapAccessor(eventDefinition.AddAccessor); } get { return WrapAccessor(ref this.addAccessor, eventDefinition.AddAccessor); }
} }
public IMethod RemoveAccessor { public IMethod RemoveAccessor {
get { return WrapAccessor(eventDefinition.RemoveAccessor); } get { return WrapAccessor(ref this.removeAccessor, eventDefinition.RemoveAccessor); }
} }
public IMethod InvokeAccessor { public IMethod InvokeAccessor {
get { return WrapAccessor(eventDefinition.InvokeAccessor); } get { return WrapAccessor(ref this.invokeAccessor, eventDefinition.InvokeAccessor); }
} }
} }
} }

15
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedField.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{ {
readonly IField fieldDefinition; readonly IField fieldDefinition;
public SpecializedField(IType declaringType, IField fieldDefinition) public SpecializedField(IField fieldDefinition, TypeParameterSubstitution substitution)
: base(declaringType, fieldDefinition) : base(fieldDefinition)
{ {
this.fieldDefinition = fieldDefinition; AddSubstitution(substitution);
Initialize(GetSubstitution(declaringType)); this.fieldDefinition = (IField)base.MemberDefinition;
}
internal SpecializedField(IType declaringType, IField fieldDefinition, TypeVisitor substitution)
: base(declaringType, fieldDefinition)
{
this.fieldDefinition = fieldDefinition;
Initialize(substitution);
} }
public bool IsReadOnly { public bool IsReadOnly {

184
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@ -31,58 +32,115 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary> /// </summary>
public abstract class SpecializedMember : IMember public abstract class SpecializedMember : IMember
{ {
readonly IType declaringType;
readonly IMember memberDefinition; readonly IMember memberDefinition;
TypeParameterSubstitution substitution;
IType declaringType;
IType returnType; IType returnType;
protected SpecializedMember(IType declaringType, IMember memberDefinition) protected SpecializedMember(IMember memberDefinition)
{ {
if (declaringType == null)
throw new ArgumentNullException("declaringType");
if (memberDefinition == null) if (memberDefinition == null)
throw new ArgumentNullException("memberDefinition"); throw new ArgumentNullException("memberDefinition");
this.declaringType = declaringType; SpecializedMember sm = memberDefinition as SpecializedMember;
this.memberDefinition = memberDefinition; if (sm != null) {
this.memberDefinition = sm.memberDefinition;
this.substitution = sm.substitution;
} else {
this.memberDefinition = memberDefinition;
this.substitution = TypeParameterSubstitution.Identity;
}
} }
protected virtual void Initialize(TypeVisitor substitution) /// <summary>
/// Performs a substitution. This method may only be called by constructors in derived classes.
/// </summary>
protected void AddSubstitution(TypeParameterSubstitution newSubstitution)
{ {
this.returnType = Substitute(memberDefinition.ReturnType, substitution); Debug.Assert(declaringType == null);
Debug.Assert(returnType == null);
this.substitution = TypeParameterSubstitution.Compose(newSubstitution, this.substitution);
} }
public virtual IMemberReference ToMemberReference() public static SpecializedMember Create(IMember memberDefinition, TypeParameterSubstitution substitution)
{ {
return new SpecializingMemberReference(declaringType.ToTypeReference(), memberDefinition.ToMemberReference()); if (memberDefinition == null) {
return null;
} else if (memberDefinition is IMethod) {
return new SpecializedMethod((IMethod)memberDefinition, substitution);
} else if (memberDefinition is IProperty) {
return new SpecializedProperty((IProperty)memberDefinition, substitution);
} else if (memberDefinition is IField) {
return new SpecializedField((IField)memberDefinition, substitution);
} else if (memberDefinition is IEvent) {
return new SpecializedEvent((IEvent)memberDefinition, substitution);
} else {
throw new NotSupportedException("Unknown IMember: " + memberDefinition);
}
} }
internal static TypeVisitor GetSubstitution(IType declaringType) public IMemberReference ToMemberReference()
{ {
ParameterizedType pt = declaringType as ParameterizedType; return new SpecializingMemberReference(
if (pt != null) memberDefinition.ToMemberReference(),
return pt.GetSubstitution(); ToTypeReference(substitution.ClassTypeArguments),
else ToTypeReference(substitution.MethodTypeArguments));
return null;
} }
internal static IType Substitute(IType type, TypeVisitor substitution) static IList<ITypeReference> ToTypeReference(IList<IType> typeArguments)
{ {
if (substitution == null) if (typeArguments == null)
return type; return null;
else else
return type.AcceptVisitor(substitution); return typeArguments.Select(t => t.ToTypeReference()).ToArray();
} }
internal IMethod WrapAccessor(IMethod accessorDefinition) internal IMethod WrapAccessor(ref IMethod cachingField, IMethod accessorDefinition)
{ {
if (accessorDefinition == null) if (accessorDefinition == null)
return null; return null;
var result = LazyInit.VolatileRead(ref cachingField);
if (result != null)
return result;
else else
return new SpecializedMethod(declaringType, accessorDefinition); return LazyInit.GetOrSet(ref cachingField, new SpecializedMethod(accessorDefinition, substitution));
}
/// <summary>
/// Gets the substitution belonging to this specialized member.
/// </summary>
public TypeParameterSubstitution Substitution {
get { return substitution; }
} }
public IType DeclaringType { public IType DeclaringType {
get { return declaringType; } get {
var result = LazyInit.VolatileRead(ref this.declaringType);
if (result != null)
return result;
IType definitionDeclaringType = memberDefinition.DeclaringType;
ITypeDefinition definitionDeclaringTypeDef = definitionDeclaringType as ITypeDefinition;
if (definitionDeclaringTypeDef != null && definitionDeclaringType.TypeParameterCount > 0) {
if (substitution.ClassTypeArguments != null && substitution.ClassTypeArguments.Count == definitionDeclaringType.TypeParameterCount) {
result = new ParameterizedType(definitionDeclaringTypeDef, substitution.ClassTypeArguments);
} else {
result = new ParameterizedType(definitionDeclaringTypeDef, definitionDeclaringTypeDef.TypeParameters).AcceptVisitor(substitution);
}
} else {
result = definitionDeclaringType.AcceptVisitor(substitution);
}
return LazyInit.GetOrSet(ref this.declaringType, result);
}
internal set {
// This setter is used as an optimization when the code constructing
// the SpecializedMember already knows the declaring type.
Debug.Assert(this.declaringType == null);
Debug.Assert(value != null);
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.declaringType = value;
}
} }
public IMember MemberDefinition { public IMember MemberDefinition {
@ -94,8 +152,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
public IType ReturnType { public IType ReturnType {
get { return returnType; } get {
protected set { returnType = value; } var result = LazyInit.VolatileRead(ref this.returnType);
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.returnType, memberDefinition.ReturnType.AcceptVisitor(substitution));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
// (not a normal type parameter substitution).
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.returnType = value;
}
} }
public bool IsVirtual { public bool IsVirtual {
@ -143,19 +214,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
var definitionImplementations = memberDefinition.ImplementedInterfaceMembers; var definitionImplementations = memberDefinition.ImplementedInterfaceMembers;
IMember[] result = new IMember[definitionImplementations.Count]; IMember[] result = new IMember[definitionImplementations.Count];
for (int i = 0; i < result.Length; i++) { for (int i = 0; i < result.Length; i++) {
result[i] = Specialize(definitionImplementations[i]); result[i] = SpecializedMember.Create(definitionImplementations[i], substitution);
} }
return result; return result;
} }
/// <summary>
/// Specialize another member using the same type arguments as this member.
/// </summary>
protected virtual IMember Specialize(IMember otherMember)
{
return SpecializingMemberReference.CreateSpecializedMember(declaringType, memberDefinition, null);
}
public bool IsExplicitInterfaceImplementation { public bool IsExplicitInterfaceImplementation {
get { return memberDefinition.IsExplicitInterfaceImplementation; } get { return memberDefinition.IsExplicitInterfaceImplementation; }
} }
@ -241,13 +304,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
SpecializedMember other = obj as SpecializedMember; SpecializedMember other = obj as SpecializedMember;
if (other == null) if (other == null)
return false; return false;
return this.declaringType.Equals(other.declaringType) && this.memberDefinition.Equals(other.memberDefinition); return this.memberDefinition.Equals(other.memberDefinition) && this.substitution.Equals(other.substitution);
} }
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked { unchecked {
return 1000000007 * declaringType.GetHashCode() + 1000000009 * memberDefinition.GetHashCode(); return 1000000007 * memberDefinition.GetHashCode() + 1000000009 * substitution.GetHashCode();
} }
} }
@ -256,11 +319,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
StringBuilder b = new StringBuilder("["); StringBuilder b = new StringBuilder("[");
b.Append(GetType().Name); b.Append(GetType().Name);
b.Append(' '); b.Append(' ');
b.Append(declaringType.ToString()); b.Append(this.DeclaringType.ToString());
b.Append('.'); b.Append('.');
b.Append(this.Name); b.Append(this.Name);
b.Append(':'); b.Append(':');
b.Append(returnType.ToString()); b.Append(this.ReturnType.ToString());
b.Append(']'); b.Append(']');
return b.ToString(); return b.ToString();
} }
@ -270,36 +333,48 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{ {
IList<IParameter> parameters; IList<IParameter> parameters;
protected SpecializedParameterizedMember(IType declaringType, IParameterizedMember memberDefinition) protected SpecializedParameterizedMember(IParameterizedMember memberDefinition)
: base(declaringType, memberDefinition) : base(memberDefinition)
{ {
} }
protected override void Initialize(TypeVisitor substitution) public IList<IParameter> Parameters {
get {
var result = LazyInit.VolatileRead(ref this.parameters);
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.parameters, CreateParameters(this.Substitution));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
// (not a normal type parameter substitution).
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.parameters = value;
}
}
protected IList<IParameter> CreateParameters(TypeVisitor substitution)
{ {
base.Initialize(substitution);
var paramDefs = ((IParameterizedMember)this.MemberDefinition).Parameters; var paramDefs = ((IParameterizedMember)this.MemberDefinition).Parameters;
if (paramDefs.Count == 0) { if (paramDefs.Count == 0) {
this.parameters = EmptyList<IParameter>.Instance; return EmptyList<IParameter>.Instance;
} else { } else {
var parameters = new IParameter[paramDefs.Count]; var parameters = new IParameter[paramDefs.Count];
for (int i = 0; i < parameters.Length; i++) { for (int i = 0; i < parameters.Length; i++) {
IType newType = Substitute(paramDefs[i].Type, substitution); IType newType = paramDefs[i].Type.AcceptVisitor(substitution);
if (newType != paramDefs[i].Type) { if (newType != paramDefs[i].Type) {
parameters[i] = new SpecializedParameter(paramDefs[i], newType); parameters[i] = new SpecializedParameter(paramDefs[i], newType);
} else { } else {
parameters[i] = paramDefs[i]; parameters[i] = paramDefs[i];
} }
} }
this.parameters = Array.AsReadOnly(parameters); return Array.AsReadOnly(parameters);
} }
} }
public IList<IParameter> Parameters {
get { return parameters; }
}
public override string ToString() public override string ToString()
{ {
StringBuilder b = new StringBuilder("["); StringBuilder b = new StringBuilder("[");
@ -309,9 +384,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append('.'); b.Append('.');
b.Append(this.Name); b.Append(this.Name);
b.Append('('); b.Append('(');
for (int i = 0; i < parameters.Count; i++) { for (int i = 0; i < this.Parameters.Count; i++) {
if (i > 0) b.Append(", "); if (i > 0) b.Append(", ");
b.Append(parameters[i].ToString()); b.Append(this.Parameters[i].ToString());
} }
b.Append("):"); b.Append("):");
b.Append(this.ReturnType.ToString()); b.Append(this.ReturnType.ToString());
@ -326,7 +401,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public SpecializedParameter(IParameter originalParameter, IType newType) public SpecializedParameter(IParameter originalParameter, IType newType)
{ {
this.originalParameter = originalParameter; if (originalParameter is SpecializedParameter)
this.originalParameter = ((SpecializedParameter)originalParameter).originalParameter;
else
this.originalParameter = originalParameter;
this.newType = newType; this.newType = newType;
} }

103
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs

@ -32,50 +32,36 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public class SpecializedMethod : SpecializedParameterizedMember, IMethod public class SpecializedMethod : SpecializedParameterizedMember, IMethod
{ {
readonly IMethod methodDefinition; readonly IMethod methodDefinition;
readonly IList<IType> typeArguments; readonly ITypeParameter[] specializedTypeParameters;
readonly IList<ITypeParameter> specializedTypeParameters;
public SpecializedMethod(IType declaringType, IMethod methodDefinition, IList<IType> typeArguments = null) public SpecializedMethod(IMethod methodDefinition, TypeParameterSubstitution substitution)
: this(declaringType, methodDefinition, typeArguments, GetSubstitution(declaringType, typeArguments)) : base(methodDefinition)
{ {
} // The base ctor might have unpacked a SpecializedMember
// (in case we are specializing an already-specialized method)
internal protected SpecializedMethod(IType declaringType, IMethod methodDefinition, IList<IType> typeArguments, TypeVisitor substitution) methodDefinition = (IMethod)base.MemberDefinition;
: base(declaringType, methodDefinition)
{
if (declaringType == null)
throw new ArgumentNullException("declaringType");
if (methodDefinition == null)
throw new ArgumentNullException("methodDefinition");
this.methodDefinition = methodDefinition; this.methodDefinition = methodDefinition;
this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
if (methodDefinition.TypeParameters.Any(ConstraintNeedsSpecialization)) { if (methodDefinition.TypeParameters.Any(ConstraintNeedsSpecialization)) {
// The method is generic, and we need to specialize the type parameters // The method is generic, and we need to specialize the type parameters
specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count]; specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count];
for (int i = 0; i < specializedTypeParameters.Count; i++) { for (int i = 0; i < specializedTypeParameters.Length; i++) {
ITypeParameter tp = methodDefinition.TypeParameters[i]; ITypeParameter tp = methodDefinition.TypeParameters[i];
if (ConstraintNeedsSpecialization(tp)) if (ConstraintNeedsSpecialization(tp))
tp = new SpecializedTypeParameter(tp, this, substitution); tp = new SpecializedTypeParameter(tp, this);
specializedTypeParameters[i] = tp; specializedTypeParameters[i] = tp;
} }
// add substitution that replaces the base method's type parameters with our specialized version
AddSubstitution(new TypeParameterSubstitution(null, specializedTypeParameters));
} }
if (typeArguments != null && typeArguments.Count > 0) { // Add the main substitution after the method type parameter specialization.
if (typeArguments.Count != methodDefinition.TypeParameters.Count) AddSubstitution(substitution);
throw new ArgumentException("Incorrect number of type arguments"); if (specializedTypeParameters != null) {
} else if (specializedTypeParameters != null) { // Set the substitution on the type parameters to the final composed substitution
// No type arguments were specified, but the method is generic. foreach (var tp in specializedTypeParameters.OfType<SpecializedTypeParameter>()) {
// -> substitute original type parameters with the specialized ones if (tp.Owner == this)
substitution = GetSubstitution(declaringType, specializedTypeParameters.ToArray<IType>()); tp.substitution = base.Substitution;
for (int i = 0; i < specializedTypeParameters.Count; i++) {
if (ConstraintNeedsSpecialization(methodDefinition.TypeParameters[i])) {
((SpecializedTypeParameter)specializedTypeParameters[i]).substitution = substitution;
}
} }
} }
Initialize(substitution);
} }
static bool ConstraintNeedsSpecialization(ITypeParameter tp) static bool ConstraintNeedsSpecialization(ITypeParameter tp)
@ -95,53 +81,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return null; return null;
} }
public override IMemberReference ToMemberReference()
{
return new SpecializingMemberReference(
this.DeclaringType.ToTypeReference(),
this.MemberDefinition.ToMemberReference(),
typeArguments.Select(ta => ta.ToTypeReference()).ToList()
);
}
protected override IMember Specialize(IMember otherMember)
{
return SpecializingMemberReference.CreateSpecializedMember(this.DeclaringType, this.MemberDefinition, typeArguments);
}
/// <summary> /// <summary>
/// Gets the type arguments passed to this method. /// Gets the type arguments passed to this method.
/// If only the type parameters for the class were specified and the generic method /// If only the type parameters for the class were specified and the generic method
/// itself is not specialized yet, this property will return an empty list. /// itself is not specialized yet, this property will return an empty list.
/// </summary> /// </summary>
public IList<IType> TypeArguments { public IList<IType> TypeArguments {
get { return typeArguments; } get { return this.Substitution.MethodTypeArguments ?? EmptyList<IType>.Instance; }
}
public override int GetHashCode()
{
int hashCode = base.GetHashCode();
unchecked {
for (int i = 0; i < typeArguments.Count; i++) {
hashCode *= 362631391;
hashCode += typeArguments[i].GetHashCode();
}
}
return hashCode;
}
public override bool Equals(object obj)
{
SpecializedMethod other = obj as SpecializedMethod;
if (!base.Equals(other))
return false;
if (typeArguments.Count != other.typeArguments.Count)
return false;
for (int i = 0; i < typeArguments.Count; i++) {
if (!typeArguments[i].Equals(other.typeArguments[i]))
return false;
}
return true;
} }
public IList<IUnresolvedMethod> Parts { public IList<IUnresolvedMethod> Parts {
@ -182,11 +128,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append(this.DeclaringType.ToString()); b.Append(this.DeclaringType.ToString());
b.Append('.'); b.Append('.');
b.Append(this.Name); b.Append(this.Name);
if (typeArguments.Count > 0) { if (this.TypeArguments.Count > 0) {
b.Append('['); b.Append('[');
for (int i = 0; i < typeArguments.Count; i++) { for (int i = 0; i < this.TypeArguments.Count; i++) {
if (i > 0) b.Append(", "); if (i > 0) b.Append(", ");
b.Append(typeArguments[i].ToString()); b.Append(this.TypeArguments[i].ToString());
} }
b.Append(']'); b.Append(']');
} }
@ -205,14 +151,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{ {
readonly ITypeParameter baseTp; readonly ITypeParameter baseTp;
// not readonly: The substition may be replaced at the end of SpecializedMethod constructor // The substition is set at the end of SpecializedMethod constructor
internal TypeVisitor substitution; internal TypeVisitor substitution;
public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner, TypeVisitor substitution) public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner)
: base(specializedOwner, baseTp.Index, baseTp.Name, baseTp.Variance, baseTp.Attributes, baseTp.Region) : base(specializedOwner, baseTp.Index, baseTp.Name, baseTp.Variance, baseTp.Attributes, baseTp.Region)
{ {
// We don't have to consider already-specialized baseTps because
// we read the baseTp directly from the unpacked memberDefinition.
this.baseTp = baseTp; this.baseTp = baseTp;
this.substitution = substitution;
} }
public override int GetHashCode() public override int GetHashCode()

21
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedProperty.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{ {
readonly IProperty propertyDefinition; readonly IProperty propertyDefinition;
public SpecializedProperty(IType declaringType, IProperty propertyDefinition) public SpecializedProperty(IProperty propertyDefinition, TypeParameterSubstitution substitution)
: base(declaringType, propertyDefinition) : base(propertyDefinition)
{ {
this.propertyDefinition = propertyDefinition; AddSubstitution(substitution);
Initialize(GetSubstitution(declaringType)); this.propertyDefinition = (IProperty)base.MemberDefinition;
}
internal SpecializedProperty(IType declaringType, IProperty propertyDefinition, TypeVisitor substitution)
: base(declaringType, propertyDefinition)
{
this.propertyDefinition = propertyDefinition;
Initialize(substitution);
} }
public bool CanGet { public bool CanGet {
@ -49,12 +42,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return propertyDefinition.CanSet; } get { return propertyDefinition.CanSet; }
} }
IMethod getter, setter;
public IMethod Getter { public IMethod Getter {
get { return WrapAccessor(propertyDefinition.Getter); } get { return WrapAccessor(ref this.getter, propertyDefinition.Getter); }
} }
public IMethod Setter { public IMethod Setter {
get { return WrapAccessor(propertyDefinition.Setter); } get { return WrapAccessor(ref this.setter, propertyDefinition.Setter); }
} }
public bool IsIndexer { public bool IsIndexer {

45
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs

@ -24,50 +24,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
[Serializable] [Serializable]
public sealed class SpecializingMemberReference : IMemberReference public sealed class SpecializingMemberReference : IMemberReference
{ {
ITypeReference declaringTypeReference;
IMemberReference memberDefinitionReference; IMemberReference memberDefinitionReference;
IList<ITypeReference> typeArgumentReferences; IList<ITypeReference> classTypeArgumentReferences;
IList<ITypeReference> methodTypeArgumentReferences;
public SpecializingMemberReference(ITypeReference declaringTypeReference, IMemberReference memberDefinitionReference, IList<ITypeReference> typeArgumentReferences = null) public SpecializingMemberReference(IMemberReference memberDefinitionReference, IList<ITypeReference> classTypeArgumentReferences = null, IList<ITypeReference> methodTypeArgumentReferences = null)
{ {
if (declaringTypeReference == null)
throw new ArgumentNullException("declaringTypeReference");
if (memberDefinitionReference == null) if (memberDefinitionReference == null)
throw new ArgumentNullException("memberDefinitionReference"); throw new ArgumentNullException("memberDefinitionReference");
this.declaringTypeReference = declaringTypeReference;
this.memberDefinitionReference = memberDefinitionReference; this.memberDefinitionReference = memberDefinitionReference;
this.typeArgumentReferences = typeArgumentReferences; this.classTypeArgumentReferences = classTypeArgumentReferences;
this.methodTypeArgumentReferences = methodTypeArgumentReferences;
} }
public IMember Resolve(ITypeResolveContext context) public IMember Resolve(ITypeResolveContext context)
{ {
var declaringType = declaringTypeReference.Resolve(context);
var memberDefinition = memberDefinitionReference.Resolve(context); var memberDefinition = memberDefinitionReference.Resolve(context);
IType[] typeArguments = null; return SpecializedMember.Create(
if (typeArgumentReferences != null) { memberDefinition,
typeArguments = new IType[typeArgumentReferences.Count]; new TypeParameterSubstitution(
for (int i = 0; i < typeArguments.Length; i++) { classTypeArgumentReferences != null ? classTypeArgumentReferences.Resolve(context) : null,
typeArguments[i] = typeArgumentReferences[i].Resolve(context); methodTypeArgumentReferences != null ? methodTypeArgumentReferences.Resolve(context) : null
} )
} );
return CreateSpecializedMember(declaringType, memberDefinition, typeArguments);
}
internal static IMember CreateSpecializedMember(IType declaringType, IMember memberDefinition, IList<IType> typeArguments)
{
if (memberDefinition == null) {
return null;
} else if (memberDefinition is IMethod) {
return new SpecializedMethod(declaringType, (IMethod)memberDefinition, typeArguments);
} else if (memberDefinition is IProperty) {
return new SpecializedProperty(declaringType, (IProperty)memberDefinition);
} else if (memberDefinition is IField) {
return new SpecializedField(declaringType, (IField)memberDefinition);
} else if (memberDefinition is IEvent) {
return new SpecializedEvent(declaringType, (IEvent)memberDefinition);
} else {
throw new NotSupportedException("Unknown IMember: " + memberDefinition);
}
} }
} }
} }

94
ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs

@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary> /// </summary>
public class TypeParameterSubstitution : TypeVisitor public class TypeParameterSubstitution : TypeVisitor
{ {
/// <summary>
/// The identity function.
/// </summary>
public static readonly TypeParameterSubstitution Identity = new TypeParameterSubstitution(null, null);
readonly IList<IType> classTypeArguments; readonly IList<IType> classTypeArguments;
readonly IList<IType> methodTypeArguments; readonly IList<IType> methodTypeArguments;
@ -47,6 +52,95 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.methodTypeArguments = methodTypeArguments; this.methodTypeArguments = methodTypeArguments;
} }
/// <summary>
/// Gets the list of class type arguments.
/// Returns <c>null</c> if this substitution keeps class type parameter unmodified.
/// </summary>
public IList<IType> ClassTypeArguments {
get { return classTypeArguments; }
}
public IList<IType> MethodTypeArguments {
get { return methodTypeArguments; }
}
#region Compose
/// <summary>
/// Computes a single TypeParameterSubstitution so that for all types <c>t</c>:
/// <c>t.AcceptVisitor(Compose(g, f)) equals t.AcceptVisitor(f).AcceptVisitor(g)</c>
/// </summary>
/// <remarks>If you consider type parameter substitution to be a function, this is function composition.</remarks>
public static TypeParameterSubstitution Compose(TypeParameterSubstitution g, TypeParameterSubstitution f)
{
if (g == null)
return f;
if (f == null || (f.classTypeArguments == null && f.methodTypeArguments == null))
return g;
// The composition is a copy of 'f', with 'g' applied on the array elements.
// If 'f' has a null list (keeps type parameters unmodified), we have to treat it as
// the identity function, and thus use the list from 'g'.
var classTypeArguments = f.classTypeArguments != null ? GetComposedTypeArguments(f.classTypeArguments, g) : g.classTypeArguments;
var methodTypeArguments = f.methodTypeArguments != null ? GetComposedTypeArguments(f.methodTypeArguments, g) : g.methodTypeArguments;
return new TypeParameterSubstitution(classTypeArguments, methodTypeArguments);
}
static IList<IType> GetComposedTypeArguments(IList<IType> input, TypeParameterSubstitution substitution)
{
IType[] result = new IType[input.Count];
for (int i = 0; i < result.Length; i++) {
result[i] = input[i].AcceptVisitor(substitution);
}
return result;
}
#endregion
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
TypeParameterSubstitution other = obj as TypeParameterSubstitution;
if (other == null)
return false;
return TypeListEquals(classTypeArguments, other.classTypeArguments)
&& TypeListEquals(methodTypeArguments, other.methodTypeArguments);
}
public override int GetHashCode()
{
unchecked {
return 1124131 * TypeListHashCode(classTypeArguments) + 1821779 * TypeListHashCode(methodTypeArguments);
}
}
static bool TypeListEquals(IList<IType> a, IList<IType> b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
if (!a[i].Equals(b[i]))
return false;
}
return true;
}
static int TypeListHashCode(IList<IType> obj)
{
if (obj == null)
return 0;
unchecked {
int hashCode = 1;
foreach (var element in obj) {
hashCode *= 27;
hashCode += element.GetHashCode();
}
return hashCode;
}
}
#endregion
public override IType VisitTypeParameter(ITypeParameter type) public override IType VisitTypeParameter(ITypeParameter type)
{ {
int index = type.Index; int index = type.Index;

17
ICSharpCode.NRefactory/TypeSystem/InheritanceHelper.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem namespace ICSharpCode.NRefactory.TypeSystem
{ {
@ -50,13 +51,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (member == null) if (member == null)
throw new ArgumentNullException("member"); throw new ArgumentNullException("member");
member = member.MemberDefinition;
if (member.IsExplicitInterfaceImplementation && member.ImplementedInterfaceMembers.Count == 1) { if (member.IsExplicitInterfaceImplementation && member.ImplementedInterfaceMembers.Count == 1) {
// C#-style explicit interface implementation // C#-style explicit interface implementation
yield return member.ImplementedInterfaceMembers[0]; member = member.ImplementedInterfaceMembers[0];
member = member.ImplementedInterfaceMembers[0].MemberDefinition; yield return member;
} }
SpecializedMember specializedMember = member as SpecializedMember;
member = member.MemberDefinition;
IEnumerable<IType> allBaseTypes; IEnumerable<IType> allBaseTypes;
if (includeImplementedInterfaces) { if (includeImplementedInterfaces) {
allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes(); allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes();
@ -68,8 +71,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
continue; continue;
foreach (IMember baseMember in baseType.GetMembers(m => m.Name == member.Name, GetMemberOptions.IgnoreInheritedMembers)) { foreach (IMember baseMember in baseType.GetMembers(m => m.Name == member.Name, GetMemberOptions.IgnoreInheritedMembers)) {
if (SignatureComparer.Ordinal.Equals(member, baseMember)) if (SignatureComparer.Ordinal.Equals(member, baseMember)) {
yield return baseMember; if (specializedMember != null)
yield return SpecializedMember.Create(baseMember, specializedMember.Substitution);
else
yield return baseMember;
}
} }
} }
} }

23
ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs

@ -103,6 +103,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
IEnumeratorOfT, IEnumeratorOfT,
/// <summary><c>System.Collections.Generic.IList{T}</c></summary> /// <summary><c>System.Collections.Generic.IList{T}</c></summary>
IListOfT, IListOfT,
/// <summary><c>System.Collections.Generic.IReadOnlyList{T}</c></summary>
IReadOnlyListOfT,
/// <summary><c>System.Threading.Tasks.Task</c></summary> /// <summary><c>System.Threading.Tasks.Task</c></summary>
Task, Task,
/// <summary><c>System.Threading.Tasks.Task{T}</c></summary> /// <summary><c>System.Threading.Tasks.Task{T}</c></summary>
@ -157,6 +159,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
new KnownTypeReference(KnownTypeCode.IEnumerableOfT, "System.Collections.Generic", "IEnumerable", 1), new KnownTypeReference(KnownTypeCode.IEnumerableOfT, "System.Collections.Generic", "IEnumerable", 1),
new KnownTypeReference(KnownTypeCode.IEnumeratorOfT, "System.Collections.Generic", "IEnumerator", 1), new KnownTypeReference(KnownTypeCode.IEnumeratorOfT, "System.Collections.Generic", "IEnumerator", 1),
new KnownTypeReference(KnownTypeCode.IListOfT, "System.Collections.Generic", "IList", 1), new KnownTypeReference(KnownTypeCode.IListOfT, "System.Collections.Generic", "IList", 1),
new KnownTypeReference(KnownTypeCode.IReadOnlyListOfT, "System.Collections.Generic", "IReadOnlyList", 1),
new KnownTypeReference(KnownTypeCode.Task, "System.Threading.Tasks", "Task"), new KnownTypeReference(KnownTypeCode.Task, "System.Threading.Tasks", "Task"),
new KnownTypeReference(KnownTypeCode.TaskOfT, "System.Threading.Tasks", "Task", 1, baseType: KnownTypeCode.Task), new KnownTypeReference(KnownTypeCode.TaskOfT, "System.Threading.Tasks", "Task", 1, baseType: KnownTypeCode.Task),
new KnownTypeReference(KnownTypeCode.NullableOfT, "System", "Nullable", 1, baseType: KnownTypeCode.ValueType), new KnownTypeReference(KnownTypeCode.NullableOfT, "System", "Nullable", 1, baseType: KnownTypeCode.ValueType),
@ -312,16 +315,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
public static readonly KnownTypeReference UIntPtr = Get(KnownTypeCode.UIntPtr); public static readonly KnownTypeReference UIntPtr = Get(KnownTypeCode.UIntPtr);
/// <summary>
/// Gets a type reference pointing to the <c>System.Collections.Generic.IList{T}</c> type.
/// </summary>
public static readonly KnownTypeReference GenericIList = Get(KnownTypeCode.IListOfT);
/// <summary>
/// Gets a type reference pointing to the <c>System.Nullable{T}</c> type.
/// </summary>
public static readonly KnownTypeReference NullableOfT = Get(KnownTypeCode.NullableOfT);
/// <summary> /// <summary>
/// Gets a type reference pointing to the <c>System.Collections.IEnumerable</c> type. /// Gets a type reference pointing to the <c>System.Collections.IEnumerable</c> type.
/// </summary> /// </summary>
@ -347,6 +340,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
public static readonly KnownTypeReference IListOfT = Get(KnownTypeCode.IListOfT); public static readonly KnownTypeReference IListOfT = Get(KnownTypeCode.IListOfT);
/// <summary>
/// Gets a type reference pointing to the <c>System.Collections.Generic.IReadOnlyList{T}</c> type.
/// </summary>
public static readonly KnownTypeReference IReadOnlyListOfT = Get(KnownTypeCode.IReadOnlyListOfT);
/// <summary> /// <summary>
/// Gets a type reference pointing to the <c>System.Threading.Tasks.Task</c> type. /// Gets a type reference pointing to the <c>System.Threading.Tasks.Task</c> type.
/// </summary> /// </summary>
@ -357,6 +355,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
public static readonly KnownTypeReference TaskOfT = Get(KnownTypeCode.TaskOfT); public static readonly KnownTypeReference TaskOfT = Get(KnownTypeCode.TaskOfT);
/// <summary>
/// Gets a type reference pointing to the <c>System.Nullable{T}</c> type.
/// </summary>
public static readonly KnownTypeReference NullableOfT = Get(KnownTypeCode.NullableOfT);
/// <summary> /// <summary>
/// Gets a type reference pointing to the <c>System.IDisposable</c> type. /// Gets a type reference pointing to the <c>System.IDisposable</c> type.
/// </summary> /// </summary>

7
ICSharpCode.NRefactory/Utils/EmptyList.cs

@ -25,17 +25,20 @@ namespace ICSharpCode.NRefactory
{ {
[Serializable] [Serializable]
public sealed class EmptyList<T> : IList<T>, IEnumerator<T> public sealed class EmptyList<T> : IList<T>, IEnumerator<T>
#if NET45
, IReadOnlyList<T>
#endif
{ {
public static readonly EmptyList<T> Instance = new EmptyList<T>(); public static readonly EmptyList<T> Instance = new EmptyList<T>();
private EmptyList() {} private EmptyList() {}
T IList<T>.this[int index] { public T this[int index] {
get { throw new ArgumentOutOfRangeException("index"); } get { throw new ArgumentOutOfRangeException("index"); }
set { throw new ArgumentOutOfRangeException("index"); } set { throw new ArgumentOutOfRangeException("index"); }
} }
int ICollection<T>.Count { public int Count {
get { return 0; } get { return 0; }
} }

14
ICSharpCode.NRefactory/Utils/LazyInit.cs

@ -26,13 +26,15 @@ namespace ICSharpCode.NRefactory.Utils
{ {
public static class LazyInit public static class LazyInit
{ {
static volatile object barrier = null; public static T VolatileRead<T>(ref T location) where T : class
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "tmp",
Justification = "The volatile read is important to cause a read barrier.")]
public static void ReadBarrier()
{ {
object tmp = barrier; #if NET45
return Volatile.Read(ref location);
#else
T result = location;
Thread.MemoryBarrier();
return result;
#endif
} }
/// <summary> /// <summary>

6
ICSharpCode.NRefactory/Utils/ProjectedList.cs

@ -40,9 +40,8 @@ namespace ICSharpCode.NRefactory.Utils
public TOutput this[int index] { public TOutput this[int index] {
get { get {
TOutput output = items[index]; TOutput output = LazyInit.VolatileRead(ref items[index]);
if (output != null) { if (output != null) {
LazyInit.ReadBarrier();
return output; return output;
} }
return LazyInit.GetOrSet(ref items[index], projection(input[index])); return LazyInit.GetOrSet(ref items[index], projection(input[index]));
@ -150,9 +149,8 @@ namespace ICSharpCode.NRefactory.Utils
public TOutput this[int index] { public TOutput this[int index] {
get { get {
TOutput output = items[index]; TOutput output = LazyInit.VolatileRead(ref items[index]);
if (output != null) { if (output != null) {
LazyInit.ReadBarrier();
return output; return output;
} }
return LazyInit.GetOrSet(ref items[index], projection(context, input[index])); return LazyInit.GetOrSet(ref items[index], projection(context, input[index]));

Loading…
Cancel
Save