Browse Source

Merge remote-tracking branch 'upstream/master' into simonl

Conflicts:
	ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
newNRvisualizers
Simon Lindgren 14 years ago
parent
commit
c954742a33
  1. 2
      ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs
  2. 17
      ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs
  3. 11
      ICSharpCode.NRefactory.CSharp/Ast/Expressions/PointerReferenceExpression.cs
  4. 13
      ICSharpCode.NRefactory.CSharp/CSharpProjectContent.cs
  5. 12
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  6. 2
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  7. 2
      ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs
  8. 8
      ICSharpCode.NRefactory.CSharp/Completion/CompletionDataWrapper.cs
  9. 7
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  10. 137
      ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs
  11. 7
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs
  12. 5
      ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs
  13. 1
      ICSharpCode.NRefactory.CSharp/Parser/mcs/driver.cs
  14. 8
      ICSharpCode.NRefactory.CSharp/Parser/mcs/namespace.cs
  15. 124
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs
  16. 9
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableLookupVisitor.cs
  17. 146
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableUsageAnalyzation.cs
  18. 63
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementAbstractMembersAction.cs
  19. 176
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceAction.cs
  20. 4
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceExplicitAction.cs
  21. 6
      ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
  22. 14
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  23. 76
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  24. 37
      ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs
  25. 45
      ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  26. 126
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  27. 1
      ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  28. 4
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs
  29. 19
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs
  30. 4
      ICSharpCode.NRefactory.CSharp/TypeSystem/ResolvedUsingScope.cs
  31. 38
      ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs
  32. 70
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractMethodTests.cs
  33. 10
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementAbstractMembersTest.cs
  34. 5
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceExplicitTests.cs
  35. 72
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceTests.cs
  36. 12
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs
  37. 44
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs
  38. 2
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs
  39. 15
      ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs
  40. 14
      ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs
  41. 113
      ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs
  42. 49
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  43. 612
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs
  44. 117
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExtensionMethodTests.cs
  45. 41
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs
  46. 24
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs
  47. 21
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs
  48. 20
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs
  49. 71
      ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs
  50. 17
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  51. 38
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  52. 2
      ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs
  53. 16
      ICSharpCode.NRefactory/Semantics/Conversion.cs
  54. 2
      ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs
  55. 79
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  56. 6
      ICSharpCode.NRefactory/TypeSystem/IAssembly.cs
  57. 5
      ICSharpCode.NRefactory/TypeSystem/INamespace.cs
  58. 5
      ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs
  59. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs
  60. 25
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs
  61. 15
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs
  62. 5
      ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs
  63. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs
  64. 4
      Packages/ICSharpCode.NRefactory.nuspec

2
ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs

@ -721,7 +721,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
} }
DefiniteAssignmentStatus afterTrue = conditionalExpression.TrueExpression.AcceptVisitor(this, beforeTrue); DefiniteAssignmentStatus afterTrue = conditionalExpression.TrueExpression.AcceptVisitor(this, beforeTrue);
DefiniteAssignmentStatus afterFalse = conditionalExpression.TrueExpression.AcceptVisitor(this, beforeFalse); DefiniteAssignmentStatus afterFalse = conditionalExpression.FalseExpression.AcceptVisitor(this, beforeFalse);
return MergeStatus(CleanSpecialValues(afterTrue), CleanSpecialValues(afterFalse)); return MergeStatus(CleanSpecialValues(afterTrue), CleanSpecialValues(afterFalse));
} }
} }

17
ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs

@ -62,12 +62,29 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole(MemberRole); } get { return GetChildrenByRole(MemberRole); }
} }
IList<string> conditionalSymbols = null;
List<Error> errors = new List<Error> (); List<Error> errors = new List<Error> ();
public List<Error> Errors { public List<Error> Errors {
get { return errors; } get { return errors; }
} }
/// <summary>
/// Gets the conditional symbols used to parse the source file. Note that this list contains
/// the conditional symbols at the start of the first token in the file - including the ones defined
/// in the source file.
/// </summary>
public IList<string> ConditionalSymbols {
get {
return conditionalSymbols ?? EmptyList<string>.Instance;
}
internal set {
conditionalSymbols = value;
}
}
/// <summary> /// <summary>
/// Gets the expression that was on top of the parse stack. /// Gets the expression that was on top of the parse stack.
/// This is the only way to get an expression that isn't part of a statment. /// This is the only way to get an expression that isn't part of a statment.

11
ICSharpCode.NRefactory.CSharp/Ast/Expressions/PointerReferenceExpression.cs

@ -49,7 +49,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole(Roles.Identifier, Identifier.Create (value)); SetChildByRole(Roles.Identifier, Identifier.Create (value));
}
}
public Identifier MemberNameToken {
get {
return GetChildByRole (Roles.Identifier);
}
set {
SetChildByRole (Roles.Identifier, value);
} }
} }

13
ICSharpCode.NRefactory.CSharp/CSharpProjectContent.cs

@ -31,6 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp
public class CSharpProjectContent : IProjectContent public class CSharpProjectContent : IProjectContent
{ {
string assemblyName; string assemblyName;
string location;
Dictionary<string, IParsedFile> parsedFiles; Dictionary<string, IParsedFile> parsedFiles;
List<IAssemblyReference> assemblyReferences; List<IAssemblyReference> assemblyReferences;
CompilerSettings compilerSettings; CompilerSettings compilerSettings;
@ -47,6 +48,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected CSharpProjectContent(CSharpProjectContent pc) protected CSharpProjectContent(CSharpProjectContent pc)
{ {
this.assemblyName = pc.assemblyName; this.assemblyName = pc.assemblyName;
this.location = pc.location;
this.parsedFiles = new Dictionary<string, IParsedFile>(pc.parsedFiles, Platform.FileNameComparer); this.parsedFiles = new Dictionary<string, IParsedFile>(pc.parsedFiles, Platform.FileNameComparer);
this.assemblyReferences = new List<IAssemblyReference>(pc.assemblyReferences); this.assemblyReferences = new List<IAssemblyReference>(pc.assemblyReferences);
this.compilerSettings = pc.compilerSettings; this.compilerSettings = pc.compilerSettings;
@ -64,6 +66,10 @@ namespace ICSharpCode.NRefactory.CSharp
get { return assemblyName; } get { return assemblyName; }
} }
public string Location {
get { return location; }
}
public CompilerSettings CompilerSettings { public CompilerSettings CompilerSettings {
get { return compilerSettings; } get { return compilerSettings; }
} }
@ -124,6 +130,13 @@ namespace ICSharpCode.NRefactory.CSharp
return pc; return pc;
} }
public IProjectContent SetLocation(string location)
{
CSharpProjectContent pc = Clone();
pc.location = location;
return pc;
}
public IProjectContent SetCompilerSettings(object compilerSettings) public IProjectContent SetCompilerSettings(object compilerSettings)
{ {
if (!(compilerSettings is CompilerSettings)) if (!(compilerSettings is CompilerSettings))

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

@ -712,7 +712,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
} }
idx++; idx++;
foreach (var list in mgr.GetExtensionMethods ()) { foreach (var list in mgr.GetEligibleExtensionMethods (true)) {
foreach (var method in list) { foreach (var method in list) {
if (idx < method.Parameters.Count && method.Parameters [idx].Type.Kind == TypeKind.Delegate) { if (idx < method.Parameters.Count && method.Parameters [idx].Type.Kind == TypeKind.Delegate) {
AutoSelect = false; AutoSelect = false;
@ -2268,11 +2268,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
continue; continue;
result.AddMember(field); result.AddMember(field);
} }
foreach (var m in type.GetMethods ()) {
if (m.Name == "TryParse") {
result.AddMember(m);
}
}
return result.Result; return result.Result;
} }
@ -2296,11 +2291,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
foreach (var field in trr.Type.GetFields ()) { foreach (var field in trr.Type.GetFields ()) {
result.AddMember(field); result.AddMember(field);
} }
foreach (var m in trr.Type.GetMethods ()) {
if (m.Name == "TryParse" && m.IsStatic) {
result.AddMember(m);
}
}
return result.Result; return result.Result;
} }
} }

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

@ -801,6 +801,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (root == null) { if (root == null) {
return null; return null;
} }
if (root is Accessor)
root = root.Parent;
var csResolver = CompletionContextProvider.GetResolver (GetState(), root); var csResolver = CompletionContextProvider.GetResolver (GetState(), root);
var result = csResolver.Resolve(resolveNode); var result = csResolver.Resolve(resolveNode);
var state = csResolver.GetResolverStateBefore(resolveNode); var state = csResolver.GetResolverStateBefore(resolveNode);

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

@ -121,7 +121,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
yield return method; yield return method;
} }
foreach (var extMethods in resolveResult.GetExtensionMethods ()) { foreach (var extMethods in resolveResult.GetEligibleExtensionMethods (true)) {
foreach (var method in extMethods) { foreach (var method in extMethods) {
yield return method; yield return method;
} }

8
ICSharpCode.NRefactory.CSharp/Completion/CompletionDataWrapper.cs

@ -80,6 +80,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{ {
if (type == null || string.IsNullOrEmpty(shortType) || usedTypes.Contains(shortType)) if (type == null || string.IsNullOrEmpty(shortType) || usedTypes.Contains(shortType))
return null; return null;
if (type.Name == "Void" && type.Namespace == "System")
return null;
usedTypes.Add(shortType); usedTypes.Add(shortType);
var iCompletionData = Factory.CreateTypeCompletionData(type, shortType); var iCompletionData = Factory.CreateTypeCompletionData(type, shortType);
result.Add(iCompletionData); result.Add(iCompletionData);
@ -90,6 +92,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{ {
if (type == null || string.IsNullOrEmpty(shortType) || usedTypes.Contains(shortType)) if (type == null || string.IsNullOrEmpty(shortType) || usedTypes.Contains(shortType))
return null; return null;
if (type.Name == "Void" && type.Namespace == "System")
return null;
usedTypes.Add(shortType); usedTypes.Add(shortType);
var iCompletionData = Factory.CreateTypeCompletionData(type, shortType); var iCompletionData = Factory.CreateTypeCompletionData(type, shortType);
result.Add(iCompletionData); result.Add(iCompletionData);
@ -134,7 +138,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{ {
var newData = Factory.CreateEntityCompletionData (member); var newData = Factory.CreateEntityCompletionData (member);
// newData.HideExtensionParameter = HideExtensionParameter; // newData.HideExtensionParameter = HideExtensionParameter;
string memberKey = newData.DisplayText; string memberKey = newData.DisplayText;
if (memberKey == null) if (memberKey == null)
return null; return null;
@ -171,7 +175,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{ {
var newData = Factory.CreateEntityCompletionData (member); var newData = Factory.CreateEntityCompletionData (member);
// newData.HideExtensionParameter = HideExtensionParameter; // newData.HideExtensionParameter = HideExtensionParameter;
string memberKey = newData.DisplayText; string memberKey = newData.DisplayText;
if (memberKey == null) if (memberKey == null)
return null; return null;

7
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -14,7 +14,7 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<ProductVersion>10.0.0</ProductVersion> <ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<SignAssembly>true</SignAssembly> <SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign> <DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode> <AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
@ -41,11 +41,11 @@
<DefineConstants>TRACE;FULL_AST</DefineConstants> <DefineConstants>TRACE;FULL_AST</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType> <DebugType>PdbOnly</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType> <DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>True</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
@ -402,6 +402,7 @@
<Compile Include="Refactoring\CodeIssues\RedundantToStringIssue.cs" /> <Compile Include="Refactoring\CodeIssues\RedundantToStringIssue.cs" />
<Compile Include="Refactoring\CodeIssues\CallToObjectEqualsViaBaseIssue.cs" /> <Compile Include="Refactoring\CodeIssues\CallToObjectEqualsViaBaseIssue.cs" />
<Compile Include="Refactoring\CodeIssues\IncorrectCallToObjectGetHashCodeIssue.cs" /> <Compile Include="Refactoring\CodeIssues\IncorrectCallToObjectGetHashCodeIssue.cs" />
<Compile Include="Refactoring\CodeActions\ExtractMethod\VariableUsageAnalyzation.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">

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

@ -3472,6 +3472,73 @@ namespace ICSharpCode.NRefactory.CSharp
return result; return result;
} }
#endregion #endregion
#region XmlDoc
public DocumentationReference ConvertXmlDoc(DocumentationBuilder doc)
{
DocumentationReference result = new DocumentationReference();
if (doc.ParsedName != null) {
if (doc.ParsedName.Name == "<this>") {
result.EntityType = EntityType.Indexer;
} else {
result.MemberName = doc.ParsedName.Name;
}
if (doc.ParsedName.Left != null) {
result.DeclaringType = ConvertToType(doc.ParsedName.Left);
} else if (doc.ParsedBuiltinType != null) {
result.DeclaringType = ConvertToType(doc.ParsedBuiltinType);
}
if (doc.ParsedName.TypeParameters != null) {
for (int i = 0; i < doc.ParsedName.TypeParameters.Count; i++) {
result.TypeArguments.Add(ConvertToType(doc.ParsedName.TypeParameters[i]));
}
}
} else if (doc.ParsedBuiltinType != null) {
result.EntityType = EntityType.TypeDefinition;
result.DeclaringType = ConvertToType(doc.ParsedBuiltinType);
}
if (doc.ParsedParameters != null) {
result.HasParameterList = true;
result.Parameters.AddRange(doc.ParsedParameters.Select(ConvertXmlDocParameter));
}
if (doc.ParsedOperator != null) {
result.EntityType = EntityType.Operator;
result.OperatorType = (OperatorType)doc.ParsedOperator;
if (result.OperatorType == OperatorType.Implicit || result.OperatorType == OperatorType.Explicit) {
var returnTypeParam = result.Parameters.LastOrNullObject();
returnTypeParam.Remove(); // detach from parameter list
var returnType = returnTypeParam.Type;
returnType.Remove();
result.ConversionOperatorReturnType = returnType;
}
if (result.Parameters.Count == 0) {
// reset HasParameterList if necessary
result.HasParameterList = false;
}
}
return result;
}
ParameterDeclaration ConvertXmlDocParameter(DocumentationParameter p)
{
ParameterDeclaration result = new ParameterDeclaration();
switch (p.Modifier) {
case Parameter.Modifier.OUT:
result.ParameterModifier = ParameterModifier.Out;
break;
case Parameter.Modifier.REF:
result.ParameterModifier = ParameterModifier.Ref;
break;
case Parameter.Modifier.PARAMS:
result.ParameterModifier = ParameterModifier.Params;
break;
}
if (p.Type != null) {
result.Type = ConvertToType(p.Type);
}
return result;
}
#endregion
} }
public CSharpParser () public CSharpParser ()
@ -3672,7 +3739,9 @@ namespace ICSharpCode.NRefactory.CSharp
if (top.LastYYValue is Mono.CSharp.Expression) { if (top.LastYYValue is Mono.CSharp.Expression) {
conversionVisitor.Unit.TopExpression = ((Mono.CSharp.Expression)top.LastYYValue).Accept(conversionVisitor) as AstNode; conversionVisitor.Unit.TopExpression = ((Mono.CSharp.Expression)top.LastYYValue).Accept(conversionVisitor) as AstNode;
} }
conversionVisitor.Unit.FileName = fileName; conversionVisitor.Unit.FileName = fileName;
conversionVisitor.Unit.ConditionalSymbols = top.Conditionals.ToArray ();
return conversionVisitor.Unit; return conversionVisitor.Unit;
} }
@ -3717,7 +3786,8 @@ namespace ICSharpCode.NRefactory.CSharp
var top = new CompilerCompilationUnit () { var top = new CompilerCompilationUnit () {
ModuleCompiled = module, ModuleCompiled = module,
LocationsBag = parser.LocationsBag, LocationsBag = parser.LocationsBag,
SpecialsBag = parser.Lexer.sbag SpecialsBag = parser.Lexer.sbag,
Conditionals = parser.Lexer.SourceFile.Conditionals
}; };
var unit = Parse (top, fileName, lineModifier); var unit = Parse (top, fileName, lineModifier);
unit.Errors.AddRange (errorReportPrinter.Errors); unit.Errors.AddRange (errorReportPrinter.Errors);
@ -3733,8 +3803,13 @@ namespace ICSharpCode.NRefactory.CSharp
if (cu == null) if (cu == null)
return Enumerable.Empty<EntityDeclaration> (); return Enumerable.Empty<EntityDeclaration> ();
var td = cu.Children.FirstOrDefault () as TypeDeclaration; var td = cu.Children.FirstOrDefault () as TypeDeclaration;
if (td != null) if (td != null) {
return td.Members; var members = td.Members.ToArray();
// detach members from parent
foreach (var m in members)
m.Remove();
return members;
}
return Enumerable.Empty<EntityDeclaration> (); return Enumerable.Empty<EntityDeclaration> ();
} }
@ -3743,8 +3818,13 @@ namespace ICSharpCode.NRefactory.CSharp
string code = "void M() { " + Environment.NewLine + reader.ReadToEnd () + "}"; string code = "void M() { " + Environment.NewLine + reader.ReadToEnd () + "}";
var members = ParseTypeMembers (new StringReader (code), lineModifier - 1); var members = ParseTypeMembers (new StringReader (code), lineModifier - 1);
var method = members.FirstOrDefault () as MethodDeclaration; var method = members.FirstOrDefault () as MethodDeclaration;
if (method != null && method.Body != null) if (method != null && method.Body != null) {
return method.Body.Statements; var statements = method.Body.Statements.ToArray();
// detach statements from parent
foreach (var st in statements)
st.Remove();
return statements;
}
return Enumerable.Empty<Statement> (); return Enumerable.Empty<Statement> ();
} }
@ -3753,8 +3833,11 @@ namespace ICSharpCode.NRefactory.CSharp
string code = reader.ReadToEnd () + " a;"; string code = reader.ReadToEnd () + " a;";
var members = ParseTypeMembers (new StringReader (code)); var members = ParseTypeMembers (new StringReader (code));
var field = members.FirstOrDefault () as FieldDeclaration; var field = members.FirstOrDefault () as FieldDeclaration;
if (field != null) if (field != null) {
return field.ReturnType; AstType type = field.ReturnType;
type.Remove();
return type;
}
return AstType.Null; return AstType.Null;
} }
@ -3763,8 +3846,11 @@ namespace ICSharpCode.NRefactory.CSharp
var es = ParseStatements (new StringReader ("tmp = " + Environment.NewLine + reader.ReadToEnd () + ";"), -1).FirstOrDefault () as ExpressionStatement; var es = ParseStatements (new StringReader ("tmp = " + Environment.NewLine + reader.ReadToEnd () + ";"), -1).FirstOrDefault () as ExpressionStatement;
if (es != null) { if (es != null) {
AssignmentExpression ae = es.Expression as AssignmentExpression; AssignmentExpression ae = es.Expression as AssignmentExpression;
if (ae != null) if (ae != null) {
return ae.Right; Expression expr = ae.Right;
expr.Remove();
return expr;
}
} }
return Expression.Null; return Expression.Null;
} }
@ -3780,12 +3866,39 @@ namespace ICSharpCode.NRefactory.CSharp
public DocumentationReference ParseDocumentationReference (string cref) public DocumentationReference ParseDocumentationReference (string cref)
{ {
// see Mono.CSharp.DocumentationBuilder.HandleXrefCommon
if (cref == null) if (cref == null)
throw new ArgumentNullException ("cref"); throw new ArgumentNullException ("cref");
// Additional symbols for < and > are allowed for easier XML typing
cref = cref.Replace ('{', '<').Replace ('}', '>'); cref = cref.Replace ('{', '<').Replace ('}', '>');
// TODO: add support for parsing cref attributes
// (documentation_parsing production, see DocumentationBuilder.HandleXrefCommon) lock (parseLock) {
throw new NotImplementedException (); errorReportPrinter = new ErrorReportPrinter("");
var ctx = new CompilerContext(compilerSettings.ToMono(), errorReportPrinter);
ctx.Settings.TabSize = 1;
var stream = new MemoryStream(Encoding.Unicode.GetBytes(cref));
var reader = new SeekableStreamReader(stream, Encoding.Unicode);
var file = new SourceFile("", "", 0);
Location.Initialize(new List<SourceFile> (new [] { file }));
var module = new ModuleContainer(ctx);
module.DocumentationBuilder = new DocumentationBuilder();
var source_file = new CompilationSourceFile (module);
var report = new Report (ctx, errorReportPrinter);
var parser = new Mono.CSharp.CSharpParser (reader, source_file, report);
parser.Lexer.putback_char = Tokenizer.DocumentationXref;
parser.Lexer.parsing_generic_declaration_doc = true;
parser.parse ();
if (report.Errors > 0) {
// Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
// mc.GetSignatureForError (), cref);
}
ConversionVisitor conversionVisitor = new ConversionVisitor (false, parser.LocationsBag);
DocumentationReference docRef = conversionVisitor.ConvertXmlDoc(module.DocumentationBuilder);
CompilerCallableEntryPoint.Reset();
return docRef;
}
} }
} }
} }

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

@ -174,6 +174,13 @@ namespace Mono.CSharp
readonly SeekableStreamReader reader; readonly SeekableStreamReader reader;
readonly CompilationSourceFile source_file; readonly CompilationSourceFile source_file;
public CompilationSourceFile SourceFile {
get {
return source_file;
}
}
readonly CompilerContext context; readonly CompilerContext context;
SourceFile current_source; SourceFile current_source;

5
ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs

@ -57,6 +57,11 @@ namespace Mono.CSharp
XmlDocumentation.PreserveWhitespace = false; XmlDocumentation.PreserveWhitespace = false;
} }
internal DocumentationBuilder()
{
// for NRefactory CSharpParser.ParseDocumentationReference
}
Report Report { Report Report {
get { get {
return module.Compiler.Report; return module.Compiler.Report;

1
ICSharpCode.NRefactory.CSharp/Parser/mcs/driver.cs

@ -369,6 +369,7 @@ namespace Mono.CSharp
public ModuleContainer ModuleCompiled { get; set; } public ModuleContainer ModuleCompiled { get; set; }
public LocationsBag LocationsBag { get; set; } public LocationsBag LocationsBag { get; set; }
public SpecialsBag SpecialsBag { get; set; } public SpecialsBag SpecialsBag { get; set; }
public IEnumerable<string> Conditionals { get; set; }
public object LastYYValue { get; set; } public object LastYYValue { get; set; }
} }

8
ICSharpCode.NRefactory.CSharp/Parser/mcs/namespace.cs

@ -591,6 +591,14 @@ namespace Mono.CSharp {
} }
} }
public IEnumerable<string> Conditionals {
get {
if (conditionals == null)
return Enumerable.Empty<string> ();
return conditionals.Where (kv => kv.Value).Select (kv => kv.Key);
}
}
public string FileName { public string FileName {
get { get {
return file.Name; return file.Name;

124
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs

@ -80,11 +80,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
if (!StaticVisitor.UsesNotStaticMember(context, expression)) if (!StaticVisitor.UsesNotStaticMember(context, expression))
method.Modifiers |= Modifiers.Static; method.Modifiers |= Modifiers.Static;
var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method); var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
task.ContinueWith (delegate {
Action<Task> replaceStatements = delegate {
var target = new IdentifierExpression(methodName); var target = new IdentifierExpression(methodName);
script.Replace(expression, new InvocationExpression(target)); script.Replace(expression, new InvocationExpression(target));
script.Link(target, method.NameToken); script.Link(target, method.NameToken);
}, TaskScheduler.FromCurrentSynchronizationContext ()); };
if (task.IsCompleted) {
replaceStatements (null);
} else {
task.ContinueWith (replaceStatements, TaskScheduler.FromCurrentSynchronizationContext ());
}
}); });
} }
@ -113,84 +120,87 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
var usedVariables = VariableLookupVisitor.Analyze(context, statements); var usedVariables = VariableLookupVisitor.Analyze(context, statements);
var extractedCodeAnalysis = new DefiniteAssignmentAnalysis( var inExtractedRegion = new VariableUsageAnalyzation (context, usedVariables);
(Statement)statements [0].Parent,
context.Resolver,
context.CancellationToken);
var lastStatement = statements [statements.Count - 1]; var lastStatement = statements [statements.Count - 1];
extractedCodeAnalysis.SetAnalyzedRange(statements [0], lastStatement);
var statusAfterMethod = new List<Tuple<IVariable, DefiniteAssignmentStatus>>();
foreach (var variable in usedVariables) {
extractedCodeAnalysis.Analyze(
variable.Name,
DefiniteAssignmentStatus.PotentiallyAssigned,
context.CancellationToken);
statusAfterMethod.Add(Tuple.Create(variable, extractedCodeAnalysis.GetStatusAfter(lastStatement)));
}
var stmt = statements [0].GetParent<BlockStatement>(); var stmt = statements [0].GetParent<BlockStatement>();
while (stmt.GetParent<BlockStatement> () != null) { while (stmt.GetParent<BlockStatement> () != null) {
stmt = stmt.GetParent<BlockStatement>(); stmt = stmt.GetParent<BlockStatement>();
} }
var wholeCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken); inExtractedRegion.SetAnalyzedRange(statements [0], lastStatement);
var statusBeforeMethod = new Dictionary<IVariable, DefiniteAssignmentStatus>(); stmt.AcceptVisitor (inExtractedRegion);
var beforeExtractedRegion = new VariableUsageAnalyzation (context, usedVariables);
beforeExtractedRegion.SetAnalyzedRange(statements [0].Parent, statements [0], true, false);
stmt.AcceptVisitor (beforeExtractedRegion);
var afterExtractedRegion = new VariableUsageAnalyzation (context, usedVariables);
afterExtractedRegion.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);
stmt.AcceptVisitor (afterExtractedRegion);
usedVariables.Sort ((l, r) => l.Region.Begin.CompareTo (r.Region.Begin));
IVariable generatedReturnVariable = null;
foreach (var variable in usedVariables) { foreach (var variable in usedVariables) {
wholeCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken); if ((variable is IParameter) || beforeExtractedRegion.Has (variable) || !afterExtractedRegion.Has (variable))
statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]); continue;
generatedReturnVariable = variable;
method.ReturnType = context.CreateShortType (variable.Type);
method.Body.Add (new ReturnStatement (new IdentifierExpression (variable.Name)));
break;
} }
var afterCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
var statusAtEnd = new Dictionary<IVariable, DefiniteAssignmentStatus>();
afterCodeAnalysis.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);
foreach (var variable in usedVariables) { foreach (var variable in usedVariables) {
afterCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken); if (!(variable is IParameter) && !beforeExtractedRegion.Has (variable) && !afterExtractedRegion.Has (variable))
statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]); continue;
} if (variable == generatedReturnVariable)
var beforeVisitor = new VariableLookupVisitor(context);
beforeVisitor.SetAnalyzedRange(stmt, statements [0], true, false);
stmt.AcceptVisitor(beforeVisitor);
var afterVisitor = new VariableLookupVisitor(context);
afterVisitor.SetAnalyzedRange(lastStatement, stmt, false, true);
stmt.AcceptVisitor(afterVisitor);
foreach (var status in statusAfterMethod) {
if (!beforeVisitor.UsedVariables.Contains(status.Item1) && !afterVisitor.UsedVariables.Contains(status.Item1))
continue; continue;
Expression argumentExpression = new IdentifierExpression(status.Item1.Name); Expression argumentExpression = new IdentifierExpression(variable.Name);
ParameterModifier mod; ParameterModifier mod = ParameterModifier.None;
switch (status.Item2) { if (inExtractedRegion.GetStatus (variable) == VariableState.Changed) {
case DefiniteAssignmentStatus.AssignedAfterTrueExpression: if (beforeExtractedRegion.GetStatus (variable) == VariableState.None) {
case DefiniteAssignmentStatus.AssignedAfterFalseExpression:
case DefiniteAssignmentStatus.PotentiallyAssigned:
mod = ParameterModifier.Ref;
argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
break;
case DefiniteAssignmentStatus.DefinitelyAssigned:
if (statusBeforeMethod [status.Item1] != DefiniteAssignmentStatus.PotentiallyAssigned)
goto case DefiniteAssignmentStatus.PotentiallyAssigned;
mod = ParameterModifier.Out; mod = ParameterModifier.Out;
argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression); argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
break; } else {
// case DefiniteAssignmentStatus.Unassigned: mod = ParameterModifier.Ref;
default: argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
mod = ParameterModifier.None; }
break;
} }
method.Parameters.Add(
new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod)); method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(variable.Type), variable.Name, mod));
invocation.Arguments.Add(argumentExpression); invocation.Arguments.Add(argumentExpression);
} }
var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method); var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
task.ContinueWith (delegate { Action<Task> replaceStatements = delegate {
foreach (var node in statements.Skip (1)) { foreach (var node in statements.Skip (1)) {
script.Remove(node); script.Remove(node);
} }
script.Replace(statements [0], new ExpressionStatement(invocation)); foreach (var variable in usedVariables) {
if ((variable is IParameter) || beforeExtractedRegion.Has (variable) || !afterExtractedRegion.Has (variable))
continue;
if (variable == generatedReturnVariable)
continue;
script.InsertBefore (statements [0], new VariableDeclarationStatement (context.CreateShortType(variable.Type), variable.Name));
}
AstNode invocationStatement;
if (generatedReturnVariable != null) {
invocationStatement = new VariableDeclarationStatement (new SimpleType ("var"), generatedReturnVariable.Name, invocation);
} else {
invocationStatement = new ExpressionStatement(invocation);
}
script.Replace(statements [0], invocationStatement);
script.Link(target, method.NameToken); script.Link(target, method.NameToken);
}, TaskScheduler.FromCurrentSynchronizationContext ()); };
if (task.IsCompleted) {
replaceStatements (null);
} else {
task.ContinueWith (replaceStatements, TaskScheduler.FromCurrentSynchronizationContext ());
}
}); });
} }
} }

9
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableLookupVisitor.cs

@ -39,12 +39,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
TextLocation startLocation = TextLocation.Empty; TextLocation startLocation = TextLocation.Empty;
TextLocation endLocation = TextLocation.Empty; TextLocation endLocation = TextLocation.Empty;
public VariableLookupVisitor (RefactoringContext context) public VariableLookupVisitor (RefactoringContext context)
{ {
this.context = context; this.context = context;
} }
public bool Has (IVariable item1)
{
return UsedVariables.Contains (item1);
}
public void SetAnalyzedRange(AstNode start, AstNode end, bool startInclusive = true, bool endInclusive = true) public void SetAnalyzedRange(AstNode start, AstNode end, bool startInclusive = true, bool endInclusive = true)
{ {
if (start == null) if (start == null)
@ -60,10 +64,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
if (startLocation.IsEmpty || startLocation <= identifierExpression.StartLocation && identifierExpression.EndLocation <= endLocation) { if (startLocation.IsEmpty || startLocation <= identifierExpression.StartLocation && identifierExpression.EndLocation <= endLocation) {
var result = context.Resolve(identifierExpression); var result = context.Resolve(identifierExpression);
var local = result as LocalResolveResult; var local = result as LocalResolveResult;
if (local != null && !UsedVariables.Contains(local.Variable)) if (local != null && !UsedVariables.Contains(local.Variable)) {
UsedVariables.Add(local.Variable); UsedVariables.Add(local.Variable);
} }
} }
}
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
{ {

146
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableUsageAnalyzation.cs

@ -0,0 +1,146 @@
//
// VariableUsageAnalyzation.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (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.TypeSystem;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
{
public enum VariableState {
None,
Used,
Changed
}
public class VariableUsageAnalyzation : DepthFirstAstVisitor
{
readonly RefactoringContext context;
readonly List<IVariable> usedVariables;
Dictionary<IVariable, VariableState> states = new Dictionary<IVariable, VariableState> ();
TextLocation startLocation = TextLocation.Empty;
TextLocation endLocation = TextLocation.Empty;
public VariableUsageAnalyzation (RefactoringContext context, List<IVariable> usedVariables)
{
this.context = context;
this.usedVariables = usedVariables;
}
public bool Has(IVariable variable)
{
return states.ContainsKey (variable);
}
public void SetAnalyzedRange(AstNode start, AstNode end, bool startInclusive = true, bool endInclusive = true)
{
if (start == null)
throw new ArgumentNullException("start");
if (end == null)
throw new ArgumentNullException("end");
startLocation = startInclusive ? start.StartLocation : start.EndLocation;
endLocation = endInclusive ? end.EndLocation : end.StartLocation;
states.Clear ();
}
public VariableState GetStatus (IVariable variable)
{
VariableState state;
if (!states.TryGetValue (variable, out state))
return VariableState.None;
return state;
}
void SetState (string identifier, VariableState state)
{
var variable = usedVariables.FirstOrDefault (v => v.Name == identifier);
if (variable == null)
return;
VariableState oldState;
if (states.TryGetValue (variable, out oldState)) {
if (oldState < state)
states [variable] = state;
} else {
states [variable] = state;
}
}
public override void VisitIdentifierExpression(IdentifierExpression identifierExpression)
{
if (startLocation.IsEmpty || startLocation <= identifierExpression.StartLocation && identifierExpression.EndLocation <= endLocation) {
SetState (identifierExpression.Identifier, VariableState.Used);
}
}
public override void VisitAssignmentExpression(AssignmentExpression assignmentExpression)
{
if (startLocation.IsEmpty || startLocation <= assignmentExpression.StartLocation && assignmentExpression.EndLocation <= endLocation) {
var left = assignmentExpression.Left as IdentifierExpression;
if (left != null)
SetState(left.Identifier, VariableState.Changed);
}
base.VisitAssignmentExpression (assignmentExpression);
}
public override void VisitDirectionExpression(DirectionExpression directionExpression)
{
if (startLocation.IsEmpty || startLocation <= directionExpression.StartLocation && directionExpression.EndLocation <= endLocation) {
var expr = directionExpression.Expression as IdentifierExpression;
if (expr != null)
SetState(expr.Identifier, VariableState.Changed);
}
base.VisitDirectionExpression (directionExpression);
}
public override void VisitVariableInitializer(VariableInitializer variableInitializer)
{
if (startLocation.IsEmpty || startLocation <= variableInitializer.StartLocation && variableInitializer.EndLocation <= endLocation) {
SetState(variableInitializer.Name, variableInitializer.Initializer.IsNull ? VariableState.None : VariableState.Changed);
}
base.VisitVariableInitializer(variableInitializer);
}
public override void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
{
if (startLocation.IsEmpty || startLocation <= unaryOperatorExpression.StartLocation && unaryOperatorExpression.EndLocation <= endLocation) {
if (unaryOperatorExpression.Operator == UnaryOperatorType.Increment || unaryOperatorExpression.Operator == UnaryOperatorType.Decrement ||
unaryOperatorExpression.Operator == UnaryOperatorType.PostIncrement || unaryOperatorExpression.Operator == UnaryOperatorType.PostDecrement) {
var expr = unaryOperatorExpression.Expression as IdentifierExpression;
if (expr != null)
SetState(expr.Identifier, VariableState.Changed);
}
}
base.VisitUnaryOperatorExpression (unaryOperatorExpression);
}
}
}

63
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementAbstractMembersAction.cs

@ -31,7 +31,7 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
// [ContextAction("Implement abstract members", Description = "Implements abstract members from an abstract class.")] [ContextAction("Implement abstract members", Description = "Implements abstract members from an abstract class.")]
public class ImplementAbstractMembersAction : ICodeActionProvider public class ImplementAbstractMembersAction : ICodeActionProvider
{ {
public IEnumerable<CodeAction> GetActions(RefactoringContext context) public IEnumerable<CodeAction> GetActions(RefactoringContext context)
@ -47,15 +47,70 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolveResult.Type.Kind != TypeKind.Class || resolveResult.Type.GetDefinition() == null || !resolveResult.Type.GetDefinition().IsAbstract) if (resolveResult.Type.Kind != TypeKind.Class || resolveResult.Type.GetDefinition() == null || !resolveResult.Type.GetDefinition().IsAbstract)
yield break; yield break;
var toImplement = CollectMembersToImplement(state.CurrentTypeDefinition, resolveResult.Type);
if (toImplement.Count == 0)
yield break; yield break;
/*
yield return new CodeAction(context.TranslateString("Implement abstract members"), script => { yield return new CodeAction(context.TranslateString("Implement abstract members"), script => {
script.InsertWithCursor( script.InsertWithCursor(
context.TranslateString("Implement abstract members"), context.TranslateString("Implement abstract members"),
state.CurrentTypeDefinition, state.CurrentTypeDefinition,
ImplementInterfaceAction.GenerateImplementation (context, toImplement) ImplementInterfaceAction.GenerateImplementation (context, toImplement.Select (m => Tuple.Create (m, false))).Select (entity => {
var decl = entity as EntityDeclaration;
if (decl != null)
decl.Modifiers |= Modifiers.Override;
return entity;
})
);
});
}
public static List<IMember> CollectMembersToImplement(ITypeDefinition implementingType, IType abstractType)
{
var def = abstractType.GetDefinition();
var toImplement = new List<IMember>();
bool alreadyImplemented;
// Stub out non-implemented events defined by @iface
foreach (var ev in abstractType.GetEvents (e => !e.IsSynthetic && e.IsAbstract)) {
alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any(
x => x.Kind != TypeKind.Interface && x.Events.Any (y => y.Name == ev.Name)
); );
});*/
if (!alreadyImplemented)
toImplement.Add(ev);
}
// Stub out non-implemented methods defined by @iface
foreach (var method in abstractType.GetMethods (d => !d.IsSynthetic && d.IsAbstract)) {
alreadyImplemented = false;
foreach (var cmet in implementingType.GetMethods ()) {
if (!cmet.IsAbstract && ImplementInterfaceAction.CompareMethods(method, cmet)) {
alreadyImplemented = true;
} }
} }
if (!alreadyImplemented)
toImplement.Add(method);
}
// Stub out non-implemented properties defined by @iface
foreach (var prop in abstractType.GetProperties (p => !p.IsSynthetic && p.IsAbstract)) {
alreadyImplemented = false;
foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) {
if (t.Kind == TypeKind.Interface)
continue;
foreach (IProperty cprop in t.Properties) {
if (!cprop.IsAbstract && cprop.Name == prop.Name) {
alreadyImplemented = true;
}
}
}
if (!alreadyImplemented)
toImplement.Add(prop);
}
return toImplement;
}
}
} }

176
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceAction.cs

@ -23,7 +23,6 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // 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 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System; using System;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using System.Threading; using System.Threading;
@ -32,7 +31,7 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
// [ContextAction("Implement interface", Description = "Creates an interface implementation.")] [ContextAction("Implement interface", Description = "Creates an interface implementation.")]
public class ImplementInterfaceAction : ICodeActionProvider public class ImplementInterfaceAction : ICodeActionProvider
{ {
public IEnumerable<CodeAction> GetActions(RefactoringContext context) public IEnumerable<CodeAction> GetActions(RefactoringContext context)
@ -48,19 +47,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var resolveResult = context.Resolve(type); var resolveResult = context.Resolve(type);
if (resolveResult.Type.Kind != TypeKind.Interface) if (resolveResult.Type.Kind != TypeKind.Interface)
yield break; yield break;
var toImplement = CollectMembersToImplement(state.CurrentTypeDefinition, resolveResult.Type, false); var toImplement = CollectMembersToImplement(state.CurrentTypeDefinition, resolveResult.Type, false);
if (toImplement.Count == 0) if (toImplement.Count == 0)
yield break; yield break;
yield return new CodeAction(context.TranslateString("Implement interface"), script => { yield return new CodeAction(context.TranslateString("Implement interface"), script => {
script.InsertWithCursor( script.InsertWithCursor(
context.TranslateString ("Implement Interface"), context.TranslateString("Implement Interface"),
state.CurrentTypeDefinition, state.CurrentTypeDefinition,
GenerateImplementation (context, toImplement) GenerateImplementation(context, toImplement)
); );
}); });
} }
public static IEnumerable<AstNode> GenerateImplementation(RefactoringContext context, List<Tuple<IMember, bool>> toImplement) public static IEnumerable<AstNode> GenerateImplementation(RefactoringContext context, IEnumerable<Tuple<IMember, bool>> toImplement)
{ {
var nodes = new Dictionary<IType, List<AstNode>>(); var nodes = new Dictionary<IType, List<AstNode>>();
@ -71,9 +72,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
foreach (var kv in nodes) { foreach (var kv in nodes) {
if (kv.Key.Kind == TypeKind.Interface) {
yield return new PreProcessorDirective( yield return new PreProcessorDirective(
PreProcessorDirectiveType.Region, PreProcessorDirectiveType.Region,
string.Format("{0} implementation", kv.Key.Name)); string.Format("{0} implementation", kv.Key.Name));
} else {
yield return new PreProcessorDirective(
PreProcessorDirectiveType.Region,
string.Format("implemented abstract members of {0}", kv.Key.Name));
}
foreach (var member in kv.Value) foreach (var member in kv.Value)
yield return member; yield return member;
yield return new PreProcessorDirective( yield return new PreProcessorDirective(
@ -86,11 +93,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
switch (member.Item1.EntityType) { switch (member.Item1.EntityType) {
case EntityType.Property: case EntityType.Property:
return null; return GenerateProperty(context, (IProperty)member.Item1, member.Item2);
case EntityType.Indexer: case EntityType.Indexer:
return null; return GenerateIndexer(context, (IProperty)member.Item1, member.Item2);
case EntityType.Event: case EntityType.Event:
return null; return GenerateEvent(context, (IEvent)member.Item1, member.Item2);
case EntityType.Method: case EntityType.Method:
return GenerateMethod(context, (IMethod)member.Item1, member.Item2); return GenerateMethod(context, (IMethod)member.Item1, member.Item2);
default: default:
@ -98,6 +105,114 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
} }
static AstNode GenerateEvent(RefactoringContext context, IEvent evt, bool explicitImplementation)
{
if (!explicitImplementation) {
return new EventDeclaration() {
Modifiers = Modifiers.Public,
Name = evt.Name,
ReturnType = context.CreateShortType (evt.ReturnType)
};
}
return new CustomEventDeclaration() {
Name = evt.Name,
ReturnType = context.CreateShortType (evt.ReturnType),
PrivateImplementationType = context.CreateShortType(evt.DeclaringType),
AddAccessor = new Accessor {
Body = new BlockStatement() {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
},
RemoveAccessor = new Accessor {
Body = new BlockStatement() {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
}
};
}
static AstNode GenerateProperty(RefactoringContext context, IProperty property, bool explicitImplementation)
{
var result = new PropertyDeclaration() {
Name = property.Name,
ReturnType = context.CreateShortType (property.ReturnType)
};
if (!explicitImplementation) {
result.Modifiers = Modifiers.Public;
} else {
result.PrivateImplementationType = context.CreateShortType(property.DeclaringType);
}
if (property.CanGet) {
if (property.DeclaringType.Kind != TypeKind.Interface) {
result.Getter = new Accessor() {
Body = new BlockStatement () {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
} else {
result.Getter = new Accessor();
}
}
if (property.CanSet) {
if (property.DeclaringType.Kind != TypeKind.Interface) {
result.Setter = new Accessor() {
Body = new BlockStatement () {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
} else {
result.Setter = new Accessor();
}
}
return result;
}
static AstNode GenerateIndexer(RefactoringContext context, IProperty indexer, bool explicitImplementation)
{
var result = new IndexerDeclaration() {
ReturnType = context.CreateShortType (indexer.ReturnType)
};
if (!explicitImplementation) {
result.Modifiers = Modifiers.Public;
} else {
result.PrivateImplementationType = context.CreateShortType(indexer.DeclaringType);
}
foreach (var p in indexer.Parameters) {
ParameterModifier modifier;
if (p.IsOut) {
modifier = ParameterModifier.Out;
} else if (p.IsRef) {
modifier = ParameterModifier.Ref;
} else if (p.IsParams) {
modifier = ParameterModifier.Params;
} else {
modifier = ParameterModifier.None;
}
result.Parameters.Add(new ParameterDeclaration(context.CreateShortType(p.Type), p.Name, modifier));
}
if (indexer.CanGet) {
result.Getter = new Accessor() {
Body = new BlockStatement () {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
}
if (indexer.CanSet) {
result.Setter = new Accessor() {
Body = new BlockStatement () {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
}
return result;
}
static AstNode GenerateMethod(RefactoringContext context, IMethod method, bool explicitImplementation) static AstNode GenerateMethod(RefactoringContext context, IMethod method, bool explicitImplementation)
{ {
var result = new MethodDeclaration() { var result = new MethodDeclaration() {
@ -116,6 +231,29 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
foreach (var typeParam in method.TypeParameters) { foreach (var typeParam in method.TypeParameters) {
result.TypeParameters.Add(new TypeParameterDeclaration(typeParam.Name)); result.TypeParameters.Add(new TypeParameterDeclaration(typeParam.Name));
var constraint = new Constraint() {
TypeParameter = new SimpleType(typeParam.Name)
};
if (typeParam.HasDefaultConstructorConstraint) {
constraint.BaseTypes.Add(new PrimitiveType("new"));
} else if (typeParam.HasReferenceTypeConstraint) {
constraint.BaseTypes.Add(new PrimitiveType("class"));
} else if (typeParam.HasValueTypeConstraint) {
constraint.BaseTypes.Add(new PrimitiveType("struct"));
}
foreach (var type in typeParam.DirectBaseTypes) {
if (type.FullName == "System.Object")
continue;
if (type.FullName == "System.ValueType")
continue;
constraint.BaseTypes.Add(context.CreateShortType(type));
}
if (constraint.BaseTypes.Count == 0)
continue;
result.Constraints.Add(constraint);
} }
foreach (var p in method.Parameters) { foreach (var p in method.Parameters) {
@ -135,17 +273,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return result; return result;
} }
public static List<Tuple<IMember, bool>> CollectMembersToImplement(ITypeDefinition implementingType, IType interfaceType, bool explicitly) public static List<Tuple<IMember, bool>> CollectMembersToImplement(ITypeDefinition implementingType, IType interfaceType, bool explicitly)
{ {
var def = interfaceType.GetDefinition(); var def = interfaceType.GetDefinition();
List<Tuple<IMember, bool>> toImplement = new List<Tuple<IMember, bool>>(); List<Tuple<IMember, bool>> toImplement = new List<Tuple<IMember, bool>>();
bool alreadyImplemented; bool alreadyImplemented;
// Stub out non-implemented events defined by @iface // Stub out non-implemented events defined by @iface
foreach (var ev in interfaceType.GetEvents (e => !e.IsSynthetic && e.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) { foreach (var evGroup in interfaceType.GetEvents (e => !e.IsSynthetic && e.DeclaringTypeDefinition.ReflectionName == def.ReflectionName).GroupBy (m => m.DeclaringType).Reverse ())
foreach (var ev in evGroup) {
bool needsExplicitly = explicitly; bool needsExplicitly = explicitly;
alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any( alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any(
x => x.Kind != TypeKind.Interface && x.Events.Any (y => y.Name == ev.Name) x => x.Kind != TypeKind.Interface && x.Events.Any(y => y.Name == ev.Name)
); );
if (!alreadyImplemented) if (!alreadyImplemented)
@ -153,7 +292,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
// Stub out non-implemented methods defined by @iface // Stub out non-implemented methods defined by @iface
foreach (var method in interfaceType.GetMethods (d => !d.IsSynthetic && d.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) { foreach (var methodGroup in interfaceType.GetMethods (d => !d.IsSynthetic).GroupBy (m => m.DeclaringType).Reverse ())
foreach (var method in methodGroup) {
bool needsExplicitly = explicitly; bool needsExplicitly = explicitly;
alreadyImplemented = false; alreadyImplemented = false;
@ -165,12 +306,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
alreadyImplemented |= !needsExplicitly /*|| cmet.InterfaceImplementations.Any (impl => impl.InterfaceType.Equals (interfaceType))*/; alreadyImplemented |= !needsExplicitly /*|| cmet.InterfaceImplementations.Any (impl => impl.InterfaceType.Equals (interfaceType))*/;
} }
} }
if (toImplement.Where(t => t.Item1 is IMethod).Any(t => CompareMethods(method, (IMethod)t.Item1)))
needsExplicitly = true;
if (!alreadyImplemented) if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(method, needsExplicitly)); toImplement.Add(new Tuple<IMember, bool>(method, needsExplicitly));
} }
// Stub out non-implemented properties defined by @iface // Stub out non-implemented properties defined by @iface
foreach (var prop in interfaceType.GetProperties (p => !p.IsSynthetic && p.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) { foreach (var propGroup in interfaceType.GetProperties (p => !p.IsSynthetic && p.DeclaringTypeDefinition.ReflectionName == def.ReflectionName).GroupBy (m => m.DeclaringType).Reverse ())
foreach (var prop in propGroup) {
bool needsExplicitly = explicitly; bool needsExplicitly = explicitly;
alreadyImplemented = false; alreadyImplemented = false;
foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) { foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) {
@ -191,11 +335,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return toImplement; return toImplement;
} }
static bool CompareMethods (IMethod interfaceMethod, IMethod typeMethod) internal static bool CompareMethods(IMethod interfaceMethod, IMethod typeMethod)
{ {
if (typeMethod.IsExplicitInterfaceImplementation) if (typeMethod.IsExplicitInterfaceImplementation)
return typeMethod.ImplementedInterfaceMembers.Any (m => m.Equals (interfaceMethod)); return typeMethod.ImplementedInterfaceMembers.Any(m => m.Equals(interfaceMethod));
return SignatureComparer.Ordinal.Equals (interfaceMethod, typeMethod); return SignatureComparer.Ordinal.Equals(interfaceMethod, typeMethod);
} }
} }
} }

4
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceExplicitAction.cs

@ -32,7 +32,7 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
// [ContextAction("Implement interface explicit", Description = "Creates an interface implementation.")] [ContextAction("Implement interface explicit", Description = "Creates an interface implementation.")]
public class ImplementInterfaceExplicitAction : ICodeActionProvider public class ImplementInterfaceExplicitAction : ICodeActionProvider
{ {
public IEnumerable<CodeAction> GetActions(RefactoringContext context) public IEnumerable<CodeAction> GetActions(RefactoringContext context)
@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
script.InsertWithCursor( script.InsertWithCursor(
context.TranslateString("Implement Interface"), context.TranslateString("Implement Interface"),
state.CurrentTypeDefinition, state.CurrentTypeDefinition,
ImplementInterfaceAction.GenerateImplementation (context, toImplement) ImplementInterfaceAction.GenerateImplementation (context, toImplement.Select (t => Tuple.Create (t.Item1, true)))
); );
}); });
} }

6
ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs

@ -178,7 +178,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
// Default implementation: do nothing // Default implementation: do nothing
// Derived classes are supposed to enter the text editor's linked state. // Derived classes are supposed to enter the text editor's linked state.
return null;
// Immediately signal the task as completed:
var tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
return tcs.Task;
} }
public void Replace (AstNode node, AstNode replaceWith) public void Replace (AstNode node, AstNode replaceWith)

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

@ -84,6 +84,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public bool Equals(TypePair other) public bool Equals(TypePair other)
{ {
if (this.FromType == null || this.ToType == null || other.FromType == null || other.ToType == null)
return false;
return this.FromType.Equals(other.FromType) && this.ToType.Equals(other.ToType); return this.FromType.Equals(other.FromType) && this.ToType.Equals(other.ToType);
} }
@ -110,6 +112,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
c = ImplicitConversion(resolveResult.Type, toType); c = ImplicitConversion(resolveResult.Type, toType);
if (c.IsValid) return c; if (c.IsValid) return c;
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
c = AnonymousFunctionConversion(resolveResult, toType); c = AnonymousFunctionConversion(resolveResult, toType);
if (c.IsValid) return c; if (c.IsValid) return c;
c = MethodGroupConversion(resolveResult, toType); c = MethodGroupConversion(resolveResult, toType);
@ -157,8 +161,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Conversion.ImplicitReferenceConversion; return Conversion.ImplicitReferenceConversion;
if (IsBoxingConversion(fromType, toType)) if (IsBoxingConversion(fromType, toType))
return Conversion.BoxingConversion; return Conversion.BoxingConversion;
if (fromType.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
if (ImplicitTypeParameterConversion(fromType, toType)) { if (ImplicitTypeParameterConversion(fromType, toType)) {
// Implicit type parameter conversions that aren't also // Implicit type parameter conversions that aren't also
// reference conversions are considered to be boxing conversions // reference conversions are considered to be boxing conversions
@ -469,7 +471,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool IdentityOrVarianceConversion(IType s, IType t, int subtypeCheckNestingDepth) bool IdentityOrVarianceConversion(IType s, IType t, int subtypeCheckNestingDepth)
{ {
ITypeDefinition def = s.GetDefinition(); ITypeDefinition def = s.GetDefinition();
if (def != null && def.Equals(t.GetDefinition())) { if (def != null) {
if (!def.Equals(t.GetDefinition()))
return false;
ParameterizedType ps = s as ParameterizedType; ParameterizedType ps = s as ParameterizedType;
ParameterizedType pt = t as ParameterizedType; ParameterizedType pt = t as ParameterizedType;
if (ps != null && pt != null) { if (ps != null && pt != null) {
@ -497,8 +501,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return false; // only of of them is parameterized, or counts don't match? -> not valid conversion return false; // only of of them is parameterized, or counts don't match? -> not valid conversion
} }
return true; return true;
} else {
// not type definitions? we still need to check for equal types (e.g. s and t might be type parameters)
return s.Equals(t);
} }
return false;
} }
#endregion #endregion

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

@ -1618,6 +1618,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new NotSupportedException("Invalid value for NameLookupMode"); throw new NotSupportedException("Invalid value for NameLookupMode");
} }
if (result is UnknownMemberResolveResult) { if (result is UnknownMemberResolveResult) {
// We intentionally use all extension methods here, not just the eligible ones.
// Proper eligibility checking is only possible for the full invocation
// (after we know the remaining arguments).
// The eligibility check in GetExtensionMethods is only intended for code completion.
var extensionMethods = GetExtensionMethods(identifier, typeArguments); var extensionMethods = GetExtensionMethods(identifier, typeArguments);
if (extensionMethods.Count > 0) { if (extensionMethods.Count > 0) {
return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) { return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) {
@ -1755,7 +1759,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (method.TypeParameters.Count != typeArguments.Count) if (method.TypeParameters.Count != typeArguments.Count)
continue; continue;
SpecializedMethod sm = new SpecializedMethod(method, new TypeParameterSubstitution(null, typeArguments)); SpecializedMethod sm = new SpecializedMethod(method, new TypeParameterSubstitution(null, typeArguments));
if (IsEligibleExtensionMethod(compilation, conversions, targetType, method, false, out inferredTypes)) if (IsEligibleExtensionMethod(compilation, conversions, targetType, sm, false, out inferredTypes))
outputGroup.Add(sm); outputGroup.Add(sm);
} else { } else {
if (IsEligibleExtensionMethod(compilation, conversions, targetType, method, true, out inferredTypes)) { if (IsEligibleExtensionMethod(compilation, conversions, targetType, method, true, out inferredTypes)) {
@ -1896,15 +1900,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §7.6.5 // C# 4.0 spec: §7.6.5
if (target.Type.Kind == TypeKind.Dynamic) { if (target.Type.Kind == TypeKind.Dynamic) {
return new DynamicInvocationResolveResult(target, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly()); return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
} }
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) { if (mgrr != null) {
if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method.
var or2 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray());
var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList();
if (applicableMethods.Count > 1) {
ResolveResult actualTarget;
if (applicableMethods.All(x => x.Method.IsStatic) && !(mgrr.TargetResult is TypeResolveResult))
actualTarget = new TypeResolveResult(mgrr.TargetType);
else
actualTarget = mgrr.TargetResult;
var l = new List<MethodListWithDeclaringType>();
foreach (var m in applicableMethods) {
if (l.Count == 0 || l[l.Count - 1].DeclaringType != m.DeclaringType)
l.Add(new MethodListWithDeclaringType(m.DeclaringType));
l[l.Count - 1].Add(m.Method);
}
return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
}
}
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions); OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions);
if (or.BestCandidate != null) { if (or.BestCandidate != null) {
if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult)) if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetResult.Type)); return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType));
else else
return or.CreateResolveResult(mgrr.TargetResult); return or.CreateResolveResult(mgrr.TargetResult);
} else { } else {
@ -2039,10 +2065,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
switch (target.Type.Kind) { switch (target.Type.Kind) {
case TypeKind.Dynamic: case TypeKind.Dynamic:
for (int i = 0; i < arguments.Length; i++) { return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
arguments[i] = Convert(arguments[i], SpecialType.Dynamic);
}
return new ArrayAccessResolveResult(SpecialType.Dynamic, target, arguments);
case TypeKind.Array: case TypeKind.Array:
case TypeKind.Pointer: case TypeKind.Pointer:
@ -2052,9 +2075,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
// §7.6.6.2 Indexer access // §7.6.6.2 Indexer access
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
MemberLookup lookup = CreateMemberLookup(); MemberLookup lookup = CreateMemberLookup();
var indexers = lookup.LookupIndexers(target.Type); var indexers = lookup.LookupIndexers(target.Type);
if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable indexer.
var or2 = CreateOverloadResolution(arguments, argumentNames, null);
var applicableIndexers = indexers.SelectMany(x => x).Where(m => OverloadResolution.IsApplicable(or2.AddCandidate(m))).ToList();
if (applicableIndexers.Count > 1) {
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
}
}
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
or.AddMethodLists(indexers); or.AddMethodLists(indexers);
if (or.BestCandidate != null) { if (or.BestCandidate != null) {
return or.CreateResolveResult(target); return or.CreateResolveResult(target);
@ -2105,16 +2140,35 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList<ResolveResult> initializerStatements = null) public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList<ResolveResult> initializerStatements = null)
{ {
if (type.Kind == TypeKind.Delegate && arguments.Length == 1) { if (type.Kind == TypeKind.Delegate && arguments.Length == 1) {
return Convert(arguments[0], type); ResolveResult input = arguments[0];
IMethod invoke = input.Type.GetDelegateInvokeMethod();
if (invoke != null) {
input = new MethodGroupResolveResult(
input, invoke.Name,
methods: new[] { new MethodListWithDeclaringType(invoke.DeclaringType) { invoke } },
typeArguments: EmptyList<IType>.Instance
);
}
return Convert(input, type);
} }
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
MemberLookup lookup = CreateMemberLookup(); MemberLookup lookup = CreateMemberLookup();
var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List<IMethod>() : null);
foreach (IMethod ctor in type.GetConstructors()) { foreach (IMethod ctor in type.GetConstructors()) {
if (lookup.IsAccessible(ctor, allowProtectedAccess)) if (lookup.IsAccessible(ctor, allowProtectedAccess)) {
or.AddCandidate(ctor); var orErrors = or.AddCandidate(ctor);
if (allApplicable != null && OverloadResolution.IsApplicable(orErrors))
allApplicable.Add(ctor);
}
else else
or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible); or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible);
} }
if (allApplicable != null && allApplicable.Count > 1) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable constructor.
return new DynamicInvocationResolveResult(new MethodGroupResolveResult(null, allApplicable[0].Name, new[] { new MethodListWithDeclaringType(type, allApplicable) }, null), DynamicInvocationType.ObjectCreation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly(), initializerStatements);
}
if (or.BestCandidate != null) { if (or.BestCandidate != null) {
return or.CreateResolveResult(null, initializerStatements); return or.CreateResolveResult(null, initializerStatements);
} else { } else {

37
ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs

@ -45,24 +45,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
public enum DynamicInvocationType {
/// <summary>
/// The invocation is a normal invocation ( 'a(b)' ).
/// </summary>
Invocation,
/// <summary>
/// The invocation is an indexing ( 'a[b]' ).
/// </summary>
Indexing,
/// <summary>
/// The invocation is an object creation ( 'new a(b)' ). Also used when invoking a base constructor ( ' : base(a) ' ) and chaining constructors ( ' : this(a) ').
/// </summary>
ObjectCreation,
}
/// <summary> /// <summary>
/// Represents the result of an invocation of a member of a dynamic object. /// Represents the result of an invocation of a member of a dynamic object.
/// </summary> /// </summary>
public class DynamicInvocationResolveResult : ResolveResult public class DynamicInvocationResolveResult : ResolveResult
{ {
/// <summary> /// <summary>
/// Target of the invocation (a dynamic object). /// Target of the invocation. Can be a dynamic expression or a <see cref="MethodGroupResolveResult"/>.
/// </summary> /// </summary>
public readonly ResolveResult Target; public readonly ResolveResult Target;
/// <summary>
/// Type of the invocation.
/// </summary>
public readonly DynamicInvocationType InvocationType;
/// <summary> /// <summary>
/// Arguments for the call. /// Arguments for the call.
/// </summary> /// </summary>
public readonly IList<DynamicInvocationArgument> Arguments; public readonly IList<DynamicInvocationArgument> Arguments;
public DynamicInvocationResolveResult(ResolveResult target, IList<DynamicInvocationArgument> arguments) : base(SpecialType.Dynamic) { /// <summary>
/// Gets the list of initializer statements that are appplied to the result of this invocation.
/// This is used to represent object and collection initializers.
/// With the initializer statements, the <see cref="InitializedObjectResolveResult"/> is used
/// to refer to the result of this invocation.
/// Initializer statements can only exist if the <see cref="InvocationType"/> is <see cref="DynamicInvocationType.ObjectCreation"/>.
/// </summary>
public readonly IList<ResolveResult> InitializerStatements;
public DynamicInvocationResolveResult(ResolveResult target, DynamicInvocationType invocationType, IList<DynamicInvocationArgument> arguments, IList<ResolveResult> initializerStatements = null) : base(SpecialType.Dynamic) {
this.Target = target; this.Target = target;
this.InvocationType = invocationType;
this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance; this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance;
this.InitializerStatements = initializerStatements ?? EmptyList<ResolveResult>.Instance;
} }
public override string ToString() public override string ToString()

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

@ -29,10 +29,32 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
/// <summary>
/// A method list that belongs to a declaring type.
/// </summary>
public class MethodListWithDeclaringType : List<IParameterizedMember> public class MethodListWithDeclaringType : List<IParameterizedMember>
{ {
readonly IType declaringType; readonly IType declaringType;
/// <summary>
/// The declaring type.
/// </summary>
/// <remarks>
/// Not all methods in this list necessarily have this as their declaring type.
/// For example, this program:
/// <code>
/// class Base {
/// public virtual void M() {}
/// }
/// class Derived : Base {
/// public override void M() {}
/// public void M(int i) {}
/// }
/// </code>
/// results in two lists:
/// <c>new MethodListWithDeclaringType(Base) { Derived.M() }</c>,
/// <c>new MethodListWithDeclaringType(Derived) { Derived.M(int) }</c>
/// </remarks>
public IType DeclaringType { public IType DeclaringType {
get { return declaringType; } get { return declaringType; }
} }
@ -64,8 +86,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType) public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType)
{ {
if (targetResult == null)
throw new ArgumentNullException("targetResult");
if (methods == null) if (methods == null)
throw new ArgumentNullException("methods"); throw new ArgumentNullException("methods");
this.targetResult = targetResult; this.targetResult = targetResult;
@ -85,7 +105,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets the type of the reference to the target object. /// Gets the type of the reference to the target object.
/// </summary> /// </summary>
public IType TargetType { public IType TargetType {
get { return targetResult.Type; } get { return targetResult != null ? targetResult.Type : SpecialType.UnknownType; }
} }
/// <summary> /// <summary>
@ -132,6 +152,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets all candidate extension methods. /// Gets all candidate extension methods.
/// Note: this includes candidates that are not eligible due to an inapplicable /// Note: this includes candidates that are not eligible due to an inapplicable
/// this argument. /// this argument.
/// The candidates will only be specialized if the type arguments were provided explicitly.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// The results are stored in nested lists because they are grouped by using scope. /// The results are stored in nested lists because they are grouped by using scope.
@ -155,6 +176,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>(); return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>();
} }
/// <summary>
/// Gets the eligible extension methods.
/// </summary>
/// <param name="substituteInferredTypes">
/// Specifies whether to produce a <see cref="SpecializedMethod"/>
/// when type arguments could be inferred from <see cref="TargetType"/>.
/// This setting is only used for inferred types and has no effect if the type parameters are
/// specified explicitly.
/// </param>
/// <remarks>
/// The results are stored in nested lists because they are grouped by using scope.
/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
/// the return value will be
/// new List {
/// new List { all extensions from MoreExtensions },
/// new List { all extensions from SomeExtensions }
/// }
/// </remarks>
public IEnumerable<IEnumerable<IMethod>> GetEligibleExtensionMethods(bool substituteInferredTypes) public IEnumerable<IEnumerable<IMethod>> GetEligibleExtensionMethods(bool substituteInferredTypes)
{ {
var result = new List<List<IMethod>>(); var result = new List<List<IMethod>>();

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

@ -938,6 +938,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ScanChildren(parameterDeclaration); ScanChildren(parameterDeclaration);
if (resolverEnabled) { if (resolverEnabled) {
string name = parameterDeclaration.Name; string name = parameterDeclaration.Name;
if (parameterDeclaration.Parent is DocumentationReference) {
// create a dummy parameter
IType type = ResolveType(parameterDeclaration.Type);
switch (parameterDeclaration.ParameterModifier) {
case ParameterModifier.Ref:
case ParameterModifier.Out:
type = new ByReferenceType(type);
break;
}
return new LocalResolveResult(new DefaultParameter(
type, name,
isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref,
isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out,
isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params));
}
// Look in lambda parameters: // Look in lambda parameters:
foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) { foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) {
if (p.Name == name) if (p.Name == name)
@ -1479,12 +1496,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements); ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements);
if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) { if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) {
// process conversion in case it's a delegate creation // Apply conversion to argument if it directly wraps the argument
ProcessConversionResult(objectCreateExpression.Arguments.Single(), rr as ConversionResolveResult); // (but not when creating a delegate from a delegate, as then there would be a MGRR for .Invoke in between)
// This is necessary for lambda type inference.
var crr = rr as ConversionResolveResult;
if (crr != null && crr.Input == arguments[0]) {
ProcessConversionResult(objectCreateExpression.Arguments.Single(), crr);
// wrap the result so that the delegate creation is not handled as a reference // wrap the result so that the delegate creation is not handled as a reference
// to the target method - otherwise FindReferencedEntities would produce two results for // to the target method - otherwise FindReferencedEntities would produce two results for
// the same delegate creation. // the same delegate creation.
return WrapResult(rr); return WrapResult(rr);
} else {
return rr;
}
} else { } else {
// process conversions in all other cases // process conversions in all other cases
ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as CSharpInvocationResolveResult); ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as CSharpInvocationResolveResult);
@ -3847,7 +3872,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Documentation Reference #region Documentation Reference
ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference) ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference)
{ {
throw new NotImplementedException(); // Resolve child nodes:
ITypeDefinition declaringTypeDef;
if (documentationReference.DeclaringType.IsNull)
declaringTypeDef = resolver.CurrentTypeDefinition;
else
declaringTypeDef = ResolveType(documentationReference.DeclaringType).GetDefinition();
IType[] typeArguments = documentationReference.TypeArguments.Select(ResolveType).ToArray();
IType conversionOperatorReturnType = ResolveType(documentationReference.ConversionOperatorReturnType);
IParameter[] parameters = documentationReference.Parameters.Select(ResolveXmlDocParameter).ToArray();
if (documentationReference.EntityType == EntityType.TypeDefinition) {
if (declaringTypeDef != null)
return new TypeResolveResult(declaringTypeDef);
else
return errorResult;
}
if (documentationReference.EntityType == EntityType.None) {
// might be a type, member or ctor
string memberName = documentationReference.MemberName;
ResolveResult rr;
if (documentationReference.DeclaringType.IsNull) {
rr = resolver.LookupSimpleNameOrTypeName(memberName, typeArguments, NameLookupMode.Expression);
} else {
var target = Resolve(documentationReference.DeclaringType);
rr = resolver.ResolveMemberAccess(target, memberName, typeArguments);
}
// reduce to definition:
if (rr.IsError) {
return rr;
} else if (rr is TypeResolveResult) {
var typeDef = rr.Type.GetDefinition();
if (typeDef == null)
return errorResult;
if (documentationReference.HasParameterList) {
var ctors = typeDef.GetConstructors(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions);
return FindByParameters(ctors, parameters);
} else {
return new TypeResolveResult(typeDef);
}
} else if (rr is MemberResolveResult) {
var mrr = (MemberResolveResult)rr;
return new MemberResolveResult(null, mrr.Member.MemberDefinition);
} else if (rr is MethodGroupResolveResult) {
var mgrr = (MethodGroupResolveResult)rr;
var methods = mgrr.MethodsGroupedByDeclaringType.Reverse()
.SelectMany(ml => ml.Select(m => (IParameterizedMember)m.MemberDefinition));
return FindByParameters(methods, parameters);
}
return rr;
}
// Indexer or operator
if (declaringTypeDef == null)
return errorResult;
if (documentationReference.EntityType == EntityType.Indexer) {
var indexers = declaringTypeDef.Properties.Where(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation);
return FindByParameters(indexers, parameters);
} else if (documentationReference.EntityType == EntityType.Operator) {
var opType = documentationReference.OperatorType;
string memberName = OperatorDeclaration.GetName(opType);
var methods = declaringTypeDef.Methods.Where(m => m.IsOperator && m.Name == memberName);
if (opType == OperatorType.Implicit || opType == OperatorType.Explicit) {
// conversion operator
foreach (var method in methods) {
if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) {
if (method.ReturnType.Equals(conversionOperatorReturnType))
return new MemberResolveResult(null, method);
}
}
return new MemberResolveResult(null, methods.FirstOrDefault());
} else {
// not a conversion operator
return FindByParameters(methods, parameters);
}
} else {
throw new NotSupportedException(); // unknown entity type
}
}
IParameter ResolveXmlDocParameter(ParameterDeclaration p)
{
var lrr = Resolve(p) as LocalResolveResult;
if (lrr != null && lrr.IsParameter)
return (IParameter)lrr.Variable;
else
return new DefaultParameter(SpecialType.UnknownType, string.Empty);
}
ResolveResult FindByParameters(IEnumerable<IParameterizedMember> methods, IList<IParameter> parameters)
{
foreach (var method in methods) {
if (ParameterListComparer.Instance.Equals(method.Parameters, parameters))
return new MemberResolveResult(null, method);
}
return new MemberResolveResult(null, methods.FirstOrDefault());
} }
#endregion #endregion
} }

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

@ -510,7 +510,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
var or = mgrr.PerformOverloadResolution(compilation, var or = mgrr.PerformOverloadResolution(compilation,
args, args,
allowExtensionMethods: false,
allowExpandingParams: false); allowExpandingParams: false);
if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) { if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) {
IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType; IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;

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

@ -290,6 +290,10 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
get { return assembly.Compilation; } get { return assembly.Compilation; }
} }
IEnumerable<IAssembly> INamespace.ContributingAssemblies {
get { return new [] { assembly }; }
}
INamespace INamespace.GetChildNamespace(string name) INamespace INamespace.GetChildNamespace(string name)
{ {
var nameComparer = assembly.compilation.NameComparer; var nameComparer = assembly.compilation.NameComparer;

19
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs

@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Documentation; using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.TypeSystem namespace ICSharpCode.NRefactory.CSharp.TypeSystem
@ -38,6 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
// resolve ID string // resolve ID string
return base.ResolveCref(cref); return base.ResolveCref(cref);
} }
var documentationReference = new CSharpParser().ParseDocumentationReference(cref);
var csharpContext = context as CSharpTypeResolveContext;
CSharpResolver resolver;
if (csharpContext != null) {
resolver = new CSharpResolver(csharpContext);
} else {
resolver = new CSharpResolver(context.Compilation);
}
var astResolver = new CSharpAstResolver(resolver, documentationReference);
var rr = astResolver.Resolve(documentationReference);
MemberResolveResult mrr = rr as MemberResolveResult;
if (mrr != null)
return mrr.Member;
TypeResolveResult trr = rr as TypeResolveResult;
if (trr != null)
return trr.Type.GetDefinition();
return null; return null;
} }
} }

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

@ -172,6 +172,10 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
get { return EmptyList<ITypeDefinition>.Instance; } get { return EmptyList<ITypeDefinition>.Instance; }
} }
IEnumerable<IAssembly> INamespace.ContributingAssemblies {
get { return EmptyList<IAssembly>.Instance; }
}
ICompilation IResolved.Compilation { ICompilation IResolved.Compilation {
get { return parentNamespace.Compilation; } get { return parentNamespace.Compilation; }
} }

38
ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs

@ -17,9 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -289,5 +289,41 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(case2.Statements.First())); Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(case2.Statements.First()));
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(@switch)); Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(@switch));
} }
[Test]
public void ConditionalExpression1()
{
string code = "int a; int b = X ? (a = 1) : 0;";
var block = new BlockStatement();
block.Statements.AddRange(new CSharpParser().ParseStatements(new StringReader(code)));
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block);
da.Analyze("a");
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(block));
}
[Test]
public void ConditionalExpression2()
{
string code = "int a; int b = X ? (a = 1) : (a = 2);";
var block = new BlockStatement();
block.Statements.AddRange(new CSharpParser().ParseStatements(new StringReader(code)));
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block);
da.Analyze("a");
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(block));
}
[Test]
public void ConditionalExpression3()
{
string code = "int a; int b = true ? (a = 1) : 0;";
var block = new BlockStatement();
block.Statements.AddRange(new CSharpParser().ParseStatements(new StringReader(code)));
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block);
da.Analyze("a");
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(block));
}
} }
} }

70
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractMethodTests.cs

@ -28,10 +28,59 @@ using ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod;
namespace ICSharpCode.NRefactory.CSharp.CodeActions namespace ICSharpCode.NRefactory.CSharp.CodeActions
{ {
[Ignore("FIXME!!")]
[TestFixture] [TestFixture]
public class ExtractMethodTests : ContextActionTestBase public class ExtractMethodTests : ContextActionTestBase
{ {
[Test()]
public void SimpleArgument()
{
Test<ExtractMethodAction>(@"class TestClass
{
void TestMethod ()
{
int i = 5;
<-Console.WriteLine (i);->
}
}
", @"class TestClass
{
static void NewMethod (int i)
{
Console.WriteLine (i);
}
void TestMethod ()
{
int i = 5;
NewMethod (i);
}
}
");
}
[Test()]
public void NoArgument()
{
Test<ExtractMethodAction>(@"class TestClass
{
void TestMethod ()
{
int i = 5;
<-Console.WriteLine (""Hello World"");->
}
}
", @"class TestClass
{
static void NewMethod ()
{
Console.WriteLine (""Hello World"");
}
void TestMethod ()
{
int i = 5;
NewMethod ();
}
}
");
}
[Test()] [Test()]
public void ExtractMethodResultStatementTest() public void ExtractMethodResultStatementTest()
@ -91,7 +140,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
"); ");
} }
[Ignore("FIXME!!")]
[Test()] [Test()]
public void ExtractMethodStaticResultStatementTest() public void ExtractMethodStaticResultStatementTest()
{ {
@ -146,7 +194,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
"); ");
} }
[Ignore("FIXME!!")]
[Test()] [Test()]
public void ExtractMethodMultiVariableTest() public void ExtractMethodMultiVariableTest()
{ {
@ -164,7 +211,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
", @"class TestClass ", @"class TestClass
{ {
int member; int member;
void NewMethod (ref int j, int i, out int k) void NewMethod (int i, ref int j, out int k)
{ {
j = i + j; j = i + j;
k = j + member; k = j + member;
@ -185,7 +232,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
[Test()] [Test()]
public void TestBug607990() public void TestBug607990()
{ {
Test<ExtractMethodAction>(@"class TestClass Test<ExtractMethodAction>(@"using System;
class TestClass
{ {
void TestMethod () void TestMethod ()
{ {
@ -193,7 +241,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
obj1.ToString();-> obj1.ToString();->
} }
} }
", @"class TestClass ", @"using System;
class TestClass
{ {
static void NewMethod () static void NewMethod ()
{ {
@ -212,7 +261,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
/// <summary> /// <summary>
/// Bug 616193 - Extract method passes param with does not exists any more in main method /// Bug 616193 - Extract method passes param with does not exists any more in main method
/// </summary> /// </summary>
[Ignore("FIXME!!")]
[Test()] [Test()]
public void TestBug616193() public void TestBug616193()
{ {
@ -248,7 +296,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
/// <summary> /// <summary>
/// Bug 616199 - Extract method forgets to return a local var which is used in main method /// Bug 616199 - Extract method forgets to return a local var which is used in main method
/// </summary> /// </summary>
[Ignore("FIXME!!")]
[Test()] [Test()]
public void TestBug616199() public void TestBug616199()
{ {
@ -269,7 +316,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
} }
void TestMethod () void TestMethod ()
{ {
string z = NewMethod (); var z = NewMethod ();
string ret = ""test1"" + z; string ret = ""test1"" + z;
} }
} }
@ -331,8 +378,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
"); ");
} }
[Ignore("Fix me!")]
[Ignore("FIXME!!")]
[Test()] [Test()]
public void ExtractMethodMultiVariableWithLocalReturnVariableTest() public void ExtractMethodMultiVariableWithLocalReturnVariableTest()
{ {
@ -352,7 +398,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
", @"class TestClass ", @"class TestClass
{ {
int member; int member;
void NewMethod (ref int j, int i, out int k, out int test) void NewMethod (int i, ref int j, out int k, out int test)
{ {
j = i + j; j = i + j;
k = j + member; k = j + member;

10
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementAbstractMembersTest.cs

@ -29,12 +29,11 @@ using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions namespace ICSharpCode.NRefactory.CSharp.CodeActions
{ {
[Ignore("TODO")]
[TestFixture] [TestFixture]
public class ImplementAbstractMembersTest : ContextActionTestBase public class ImplementAbstractMembersTest : ContextActionTestBase
{ {
[Test()] [Test()]
public void TestSimpleInterface() public void TestSimpleBaseType()
{ {
Test<ImplementAbstractMembersAction>(@"abstract class Simple { Test<ImplementAbstractMembersAction>(@"abstract class Simple {
public abstract void FooBar (string foo, int bar); public abstract void FooBar (string foo, int bar);
@ -50,12 +49,13 @@ class Foo : $Simple
class Foo : Simple class Foo : Simple
{ {
#region implemented abstract members of Simple #region implemented abstract members of Simple
public override void FooBar(string foo, int bar) public override void FooBar (string foo, int bar)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException ();
} }
#endregion #endregion
}"); }
");
} }
} }

5
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceExplicitTests.cs

@ -29,7 +29,6 @@ using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions namespace ICSharpCode.NRefactory.CSharp.CodeActions
{ {
[Ignore("TODO")]
[TestFixture] [TestFixture]
public class ImplementInterfaceExplicitTests : ContextActionTestBase public class ImplementInterfaceExplicitTests : ContextActionTestBase
{ {
@ -44,9 +43,9 @@ class Foo : $IDisposable
class Foo : IDisposable class Foo : IDisposable
{ {
#region IDisposable implementation #region IDisposable implementation
void IDisposable.Dispose() void IDisposable.Dispose ()
{ {
throw new NotImplementedException(); throw new NotImplementedException ();
} }
#endregion #endregion
} }

72
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceTests.cs

@ -56,7 +56,6 @@ class Foo : IDisposable
/// <summary> /// <summary>
/// Bug 663842 - Interface implementation does not include constraints /// Bug 663842 - Interface implementation does not include constraints
/// </summary> /// </summary>
[Ignore("TODO")]
[Test()] [Test()]
public void TestBug663842() public void TestBug663842()
{ {
@ -82,21 +81,21 @@ interface ITest {
class Foo : ITest class Foo : ITest
{ {
#region ITest implementation #region ITest implementation
public void MyMethod1<T> (T t) where T : new () public void MyMethod1<T> (T t) where T : new()
{ {
throw new System.NotImplementedException (); throw new NotImplementedException ();
} }
public void MyMethod2<T> (T t) where T : class public void MyMethod2<T> (T t) where T : class
{ {
throw new System.NotImplementedException (); throw new NotImplementedException ();
} }
public void MyMethod3<T> (T t) where T : struct public void MyMethod3<T> (T t) where T : struct
{ {
throw new System.NotImplementedException (); throw new NotImplementedException ();
} }
public void MyMethod4<T> (T t) where T : IDisposable, IServiceProvider public void MyMethod4<T> (T t) where T : IDisposable, IServiceProvider
{ {
throw new System.NotImplementedException (); throw new NotImplementedException ();
} }
#endregion #endregion
} }
@ -206,7 +205,6 @@ class Foo : ITest
/// <summary> /// <summary>
/// Bug 3365 - MD cannot implement IEnumerable interface correctly - MD cannot implement IEnumerable interface correctly /// Bug 3365 - MD cannot implement IEnumerable interface correctly - MD cannot implement IEnumerable interface correctly
/// </summary> /// </summary>
[Ignore("TODO")]
[Test()] [Test()]
public void TestBug3365() public void TestBug3365()
{ {
@ -238,20 +236,68 @@ public interface ITest : IA, IEnumerable
class Foo : ITest class Foo : ITest
{ {
#region ITest implementation #region IEnumerable implementation
public bool GetEnumerator () public IEnumerator GetEnumerator ()
{ {
throw new System.NotImplementedException (); throw new NotImplementedException ();
} }
#endregion #endregion
#region IEnumerable implementation #region IA implementation
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () bool IA.GetEnumerator ()
{ {
throw new System.NotImplementedException (); throw new NotImplementedException ();
} }
#endregion #endregion
}"); }");
} }
/// <summary>
/// Bug 4818 - Implement implicit does not handle 'params' types
/// </summary>
[Test()]
public void TestBug4818()
{
Test<ImplementInterfaceAction>(@"using System;
interface ITest {
void OnScenesAdded (params ITest[] scenes);
}
class Foo : $ITest
{
}
", @"using System;
interface ITest {
void OnScenesAdded (params ITest[] scenes);
}
class Foo : ITest
{
#region ITest implementation
public void OnScenesAdded (params ITest[] scenes)
{
throw new NotImplementedException ();
}
#endregion
}
");
TestWrongContext<ImplementInterfaceAction>(@"using System;
interface ITest {
void OnScenesAdded (params ITest[] scenes);
}
class Foo : $ITest
{
#region ITest implementation
public void OnScenesAdded (params ITest[] scenes)
{
throw new NotImplementedException ();
}
#endregion
}
");
}
} }
} }

12
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs

@ -105,9 +105,9 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
foreach (var node in nodes) { foreach (var node in nodes) {
InsertBefore(entity, node); InsertBefore(entity, node);
} }
var t = new Task (() => {}); var tcs = new TaskCompletionSource<object> ();
t.RunSynchronously (); tcs.SetResult (null);
return t; return tcs.Task;
} }
public override Task InsertWithCursor (string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes) public override Task InsertWithCursor (string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes)
@ -121,9 +121,9 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
InsertText (startOffset, output.Text); InsertText (startOffset, output.Text);
output.RegisterTrackedSegments (this, startOffset); output.RegisterTrackedSegments (this, startOffset);
} }
var t = new Task (() => {}); var tcs = new TaskCompletionSource<object> ();
t.RunSynchronously (); tcs.SetResult (null);
return t; return tcs.Task;
} }
void Rename (AstNode node, string newName) void Rename (AstNode node, string newName)

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

@ -4572,7 +4572,7 @@ class Test
} }
} }
"); ");
Assert.AreEqual (4, provider.Count); // 2xTryParse + 2 fields Assert.AreEqual (2, provider.Count); // 2 fields
Assert.IsNotNull (provider.Find ("Value1"), "field 'Value1' not found."); Assert.IsNotNull (provider.Find ("Value1"), "field 'Value1' not found.");
Assert.IsNotNull (provider.Find ("Value2"), "field 'Value2' not found."); Assert.IsNotNull (provider.Find ("Value2"), "field 'Value2' not found.");
} }
@ -5241,7 +5241,7 @@ public class TestFoo
public void TestBug4961() public void TestBug4961()
{ {
CombinedProviderTest( CombinedProviderTest(
@"using System; @"using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EnumerationProblem namespace EnumerationProblem
@ -5323,7 +5323,47 @@ $mc->$
}); });
} }
/// <summary>
/// Bug 6146 - No intellisense on value keyword in property set method
/// </summary>
[Test()]
public void TestBug6146()
{
CombinedProviderTest(
@"using System;
public class FooBar
{
public FooBar Foo {
set {
$value.$
}
}
}
", provider => {
Assert.IsNotNull(provider.Find("Foo"));
});
}
[Test()]
public void TestBug6146Case2()
{
CombinedProviderTest(
@"using System;
public class FooBar
{
public FooBar Foo {
set {
$value.Foo.F$
}
}
}
", provider => {
Assert.IsNotNull(provider.Find("Foo"));
});
}
} }

2
ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs

@ -592,7 +592,7 @@ class TestClass
} }
}"); }");
Assert.IsNotNull (provider, "provider was not created."); Assert.IsNotNull (provider, "provider was not created.");
Assert.AreEqual (6, provider.Count); Assert.IsTrue (provider.Count > 0);
} }
[Test()] [Test()]

15
ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Text;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser.Expression namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
@ -234,5 +235,19 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
Assert.AreEqual(new TextLocation(1, 2), pe.EndLocation); Assert.AreEqual(new TextLocation(1, 2), pe.EndLocation);
Assert.AreEqual("0", pe.LiteralValue); Assert.AreEqual("0", pe.LiteralValue);
} }
[Test]
[Ignore("Mono parser crash")]
public void LargeVerbatimString()
{
StringBuilder b = new StringBuilder();
for (int i = 0; i < 10000; i++) {
b.Append(i.ToString());
b.Append("\r\n");
}
string literal = b.ToString();
var pe = ParseUtilCSharp.ParseExpression<PrimitiveExpression>("@\"" + literal + "\"");
Assert.AreEqual(literal, pe.Value);
}
} }
} }

14
ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs

@ -205,5 +205,19 @@ public class Form1 {
typeof(NamespaceDeclaration) typeof(NamespaceDeclaration)
}, cu.Children.Select(c => c.GetType()).ToArray()); }, cu.Children.Select(c => c.GetType()).ToArray());
} }
[Ignore("Fixme!")]
[Test]
public void AssemblyAttributeBeforeClass()
{
var cu = new CSharpParser().Parse(new StringReader("using System; [assembly: Attr] class X {}"), "code.cs");
Assert.AreEqual(
new Type[] {
typeof(UsingDeclaration),
typeof(AttributeSection),
typeof(TypeDeclaration)
}, cu.Children.Select(c => c.GetType()).ToArray());
Assert.That(((TypeDeclaration)cu.LastChild).Attributes, Is.Empty);
}
} }
} }

113
ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs

@ -132,5 +132,118 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope
Assert.AreEqual(PreProcessorDirectiveType.Pragma, ppd.Type); Assert.AreEqual(PreProcessorDirectiveType.Pragma, ppd.Type);
Assert.AreEqual("warning disable 809", ppd.Argument); Assert.AreEqual("warning disable 809", ppd.Argument);
} }
const string elifProgram = @"
#if AAA
class A { }
#elif BBB
class B { }
#endif";
[Test]
[Ignore("parser bug (missing comment node)")]
public void ElifBothFalse()
{
CSharpParser parser = new CSharpParser();
var cu = parser.Parse(elifProgram, "elif.cs");
Assert.IsFalse(parser.HasErrors);
Assert.AreEqual(new Role[] {
Roles.PreProcessorDirective,
Roles.Comment,
Roles.PreProcessorDirective,
Roles.Comment,
Roles.PreProcessorDirective
}, cu.Children.Select(c => c.Role).ToArray());
var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0);
Assert.IsFalse(aaa.Take);
Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type);
Assert.AreEqual("AAA", aaa.Argument);
var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1);
Assert.IsFalse(bbb.Take);
Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type);
Assert.AreEqual("BBB", bbb.Argument);
}
[Test]
[Ignore("parser bug (bbb.Take is true, should be false)")]
public void ElifBothTrue()
{
CSharpParser parser = new CSharpParser();
parser.CompilerSettings.ConditionalSymbols.Add("AAA");
var cu = parser.Parse(elifProgram, "elif.cs");
Assert.IsFalse(parser.HasErrors);
Assert.AreEqual(new Role[] {
Roles.PreProcessorDirective,
NamespaceDeclaration.MemberRole,
Roles.PreProcessorDirective,
Roles.Comment,
Roles.PreProcessorDirective
}, cu.Children.Select(c => c.Role).ToArray());
var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0);
Assert.IsTrue(aaa.Take);
Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type);
Assert.AreEqual("AAA", aaa.Argument);
var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1);
Assert.IsFalse(bbb.Take);
Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type);
Assert.AreEqual("BBB", bbb.Argument);
}
[Test]
[Ignore("parser bug (bbb.Take is true, should be false)")]
public void ElifFirstTaken()
{
CSharpParser parser = new CSharpParser();
parser.CompilerSettings.ConditionalSymbols.Add("AAA");
var cu = parser.Parse(elifProgram, "elif.cs");
Assert.IsFalse(parser.HasErrors);
Assert.AreEqual(new Role[] {
Roles.PreProcessorDirective,
NamespaceDeclaration.MemberRole,
Roles.PreProcessorDirective,
Roles.Comment,
Roles.PreProcessorDirective
}, cu.Children.Select(c => c.Role).ToArray());
var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0);
Assert.IsTrue(aaa.Take);
Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type);
Assert.AreEqual("AAA", aaa.Argument);
var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1);
Assert.IsFalse(bbb.Take);
Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type);
Assert.AreEqual("BBB", bbb.Argument);
}
[Test]
public void ElifSecondTaken()
{
CSharpParser parser = new CSharpParser();
parser.CompilerSettings.ConditionalSymbols.Add("BBB");
var cu = parser.Parse(elifProgram, "elif.cs");
Assert.IsFalse(parser.HasErrors);
Assert.AreEqual(new Role[] {
Roles.PreProcessorDirective,
Roles.Comment,
Roles.PreProcessorDirective,
NamespaceDeclaration.MemberRole,
Roles.PreProcessorDirective
}, cu.Children.Select(c => c.Role).ToArray());
var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0);
Assert.IsFalse(aaa.Take);
Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type);
Assert.AreEqual("AAA", aaa.Argument);
var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1);
Assert.IsTrue(bbb.Take);
Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type);
Assert.AreEqual("BBB", bbb.Argument);
}
} }
} }

49
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs

@ -73,8 +73,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test] [Test]
public void DynamicIdentityConversions() public void DynamicIdentityConversions()
{ {
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(ReflectionHelper.Dynamic))); Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(dynamic)));
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(ReflectionHelper.Dynamic), typeof(object))); Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(dynamic), typeof(object)));
} }
[Test] [Test]
@ -155,12 +155,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
[Test] [Test]
public void SimpleDynamicConversions() public void ConversionToDynamic()
{ {
Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string), typeof(dynamic))); Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string), typeof(dynamic)));
Assert.AreEqual(C.ImplicitDynamicConversion, ImplicitConversion(typeof(dynamic), typeof(string)));
Assert.AreEqual(C.BoxingConversion, ImplicitConversion(typeof(int), typeof(dynamic))); Assert.AreEqual(C.BoxingConversion, ImplicitConversion(typeof(int), typeof(dynamic)));
Assert.AreEqual(C.ImplicitDynamicConversion, ImplicitConversion(typeof(dynamic), typeof(int))); }
[Test]
public void ConversionFromDynamic()
{
// There is no conversion from the type 'dynamic' to other types (except object).
// Such conversions only exists from dynamic expression.
// This is an important distinction for type inference (see TypeInferenceTests.IEnumerableCovarianceWithDynamic)
Assert.AreEqual(C.None, ImplicitConversion(typeof(dynamic), typeof(string)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(dynamic), typeof(int)));
var dynamicRR = new ResolveResult(SpecialType.Dynamic);
Assert.AreEqual(C.ImplicitDynamicConversion, conversions.ImplicitConversion(dynamicRR, compilation.FindType(typeof(string))));
Assert.AreEqual(C.ImplicitDynamicConversion, conversions.ImplicitConversion(dynamicRR, compilation.FindType(typeof(int))));
} }
[Test] [Test]
@ -512,7 +524,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
[Test] [Test]
public void ExplicitUserDefinedConversion() { public void ExplicitUserDefinedConversion()
{
var rr = Resolve<ConversionResolveResult>(@" var rr = Resolve<ConversionResolveResult>(@"
class C1 {} class C1 {}
class C2 { class C2 {
@ -529,5 +542,29 @@ class C {
Assert.IsTrue(rr.Conversion.IsUserDefined); Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("op_Explicit", rr.Conversion.Method.Name); Assert.AreEqual("op_Explicit", rr.Conversion.Method.Name);
} }
[Test]
public void ImplicitTypeParameterConversion()
{
string program = @"using System;
class Test {
public void M<T, U>(T t) where T : U {
U u = $t$;
}
}";
Assert.AreEqual(C.BoxingConversion, GetConversion(program));
}
[Test]
public void InvalidImplicitTypeParameterConversion()
{
string program = @"using System;
class Test {
public void M<T, U>(T t) where U : T {
U u = $t$;
}
}";
Assert.AreEqual(C.None, GetConversion(program));
}
} }
} }

612
ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Text; using System.Text;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -37,6 +38,7 @@ class TestClass {
}"; }";
var rr = Resolve<DynamicInvocationResolveResult>(program); var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>()); Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target; var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj"); Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
@ -61,6 +63,7 @@ class TestClass {
}"; }";
var rr = Resolve<DynamicInvocationResolveResult>(program); var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>()); Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target; var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj"); Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
@ -86,12 +89,14 @@ class TestClass {
}"; }";
var rr = Resolve<DynamicInvocationResolveResult>(program); var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicInvocationResolveResult>()); Assert.That(rr.Target, Is.InstanceOf<DynamicInvocationResolveResult>());
var innerInvocation = (DynamicInvocationResolveResult)rr.Target; var innerInvocation = (DynamicInvocationResolveResult)rr.Target;
Assert.That(innerInvocation.Target, Is.InstanceOf<DynamicMemberResolveResult>()); Assert.That(innerInvocation.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)innerInvocation.Target; var dynamicMember = (DynamicMemberResolveResult)innerInvocation.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj"); Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod")); Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod"));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(innerInvocation.Arguments.Count, Is.EqualTo(1)); Assert.That(innerInvocation.Arguments.Count, Is.EqualTo(1));
Assert.That(innerInvocation.Arguments[0].Name, Is.Null); Assert.That(innerInvocation.Arguments[0].Name, Is.Null);
Assert.That(innerInvocation.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)innerInvocation.Arguments[0].Value).Variable.Name == "a"); Assert.That(innerInvocation.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)innerInvocation.Arguments[0].Value).Variable.Name == "a");
@ -99,5 +104,612 @@ class TestClass {
Assert.That(rr.Arguments[0].Name, Is.Null); Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "b"); Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "b");
} }
[Test]
public void InvocationWithDynamicArgumentWithOneApplicableMethod() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
public void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() {
string program = @"using System;
class TestBase {
public void SomeMethod(int a) {}
}
class TestClass : TestBase {
public void SomeMethod(string a) {}
public void SomeMethod(string a, int b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.Count(), Is.EqualTo(2));
Assert.That(mg.Methods.Any(m => m.Parameters.Count == 1 && m.DeclaringType.Name == "TestBase" && m.Name == "SomeMethod" && m.Parameters[0].Type.Name == "Int32"));
Assert.That(mg.Methods.Any(m => m.Parameters.Count == 1 && m.DeclaringType.Name == "TestClass" && m.Name == "SomeMethod" && m.Parameters[0].Type.Name == "String"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test, Ignore("Fails")]
public void InvocationWithDynamicArgumentWhenABaseMethodIsShadowed() {
string program = @"using System;
class TestBase {
public void SomeMethod(int a) {}
}
class TestClass : TestBase {
public void SomeMethod(int a) {}
public void SomeMethod(string a, int b) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestClass"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithTwoApplicableMethods() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
public void SomeMethod(string a) {}
public void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 1));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithTwoApplicableStaticMethods() {
string program = @"using System;
class TestClass {
public static void SomeMethod(int a) {}
public static void SomeMethod(string a) {}
public static void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<TypeResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 1));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithApplicableStaticAndNonStaticMethodsFavorTheNonStaticOne() {
string program = @"using System;
class TestClass {
public static void SomeMethod(int a) {}
public void SomeMethod(string a) {}
public static void SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
var x = $SomeMethod(obj)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 1));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWhenTheOnlyApplicableMethodIsAnExtensionMethod() {
string program = @"using System;
static class OtherClass {
public void SomeMethod(this TestClass x, int a) {}
public void SomeMethod(this TestClass x, string a) {}
public void SomeMethod(this TestClass x, int a, string b) {}
}
class TestClass {
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve(program);
Assert.That(rr.IsError, Is.True);
}
[Test]
public void InvocationWithDynamicArgumentWithTwoApplicableMethodsAndNamedArguments() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a, int i) {}
public void SomeMethod(string a, int i) {}
public void SomeMethod(int a, string b, int i) {}
void F() {
dynamic obj = null;
int idx = 0;
var x = $this.SomeMethod(a: obj, i: idx)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.InstanceOf<ThisResolveResult>());
Assert.That(mg.MethodName, Is.EqualTo("SomeMethod"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2) && mg.Methods.All(m => m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("a"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("i"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "idx");
}
[Test]
public void IndexingDynamicObjectWithUnnamedArguments() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0, b = 0;
object o = $obj[a]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj");
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a");
}
[Test]
public void IndexingDynamicObjectWithNamedArguments() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0, b = 0;
$obj[arg1: a, arg2: b]$ = 1;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj");
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("arg1"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("arg2"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "b");
}
[Test]
public void IndexingWithDynamicArgumentWithOneApplicableIndexer() {
string program = @"using System;
class TestClass {
public int this[int a] { get { return 0; } }
public int this[int a, string b] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("Item"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void IndexingWithDynamicArgumentWithTwoApplicableIndexersAndUnnamedArguments() {
string program = @"using System;
class TestClass {
public int this[int a] { get { return 0; } }
public int this[string a] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target, Is.InstanceOf<ThisResolveResult>());
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test]
public void IndexingWithDynamicArgumentWithAnApplicableBaseIndexer() {
string program = @"using System;
class TestBase {
public int this[int a] { get { return 0; } }
}
class TestClass : TestBase {
public int this[string a] { get { return 0; } }
public int this[string a, int b] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target, Is.InstanceOf<ThisResolveResult>());
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
}
[Test, Ignore("Fails")]
public void IndexingWithDynamicArgumentWithTheOnlyApplicableIndexerShadowingABaseIndexer() {
string program = @"using System;
class TestBase {
public int this[int a] { get { return 0; } }
}
class TestClass : TestBase {
public new int this[int a] { get { return 0; } }
public int this[int a, string b] { get { return 0; } }
void F() {
dynamic obj = null;
var x = $this[obj]$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo("Item"));
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void IndexingWithDynamicArgumentWithTwoApplicableIndexersAndNamedArguments() {
string program = @"using System;
class TestClass {
public int this[int a, int i] { get { return 0; } }
public int this[string a, int i] { get { return 0; } }
void F() {
dynamic obj = null;
int idx = 0;
var x = $this[a: obj, i: idx]$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing));
Assert.That(rr.Target, Is.InstanceOf<ThisResolveResult>());
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("a"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("i"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "idx");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithOneApplicableConstructor() {
string program = @"using System;
class TestClass {
public TestClass(int a) {}
public void TestClass(int a, string b) {}
void F() {
dynamic obj = null;
var x = $new TestClass(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo(".ctor"));
Assert.That(rr.TargetResult, Is.Null);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructors() {
string program = @"using System;
class TestClass {
public TestClass(int a, int b) {}
public TestClass(string a, int b) {}
public void TestClass(int a, string b) {}
void F() {
dynamic obj = null;
int i = 0;
var x = $new TestClass(obj, i)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "i");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructorsAndNamedArguments() {
string program = @"using System;
class TestClass {
public TestClass(int arg1, int arg2) {}
public TestClass(string arg1, int arg2) {}
public void TestClass(int a) {}
void F() {
dynamic obj = null;
int i = 0;
var x = $new TestClass(arg1: obj, arg2: i)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.EqualTo("arg1"));
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("arg2"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "i");
}
[Test]
public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructorsAndInitializerStatements() {
string program = @"using System;
class TestClass {
public TestClass(int a, int b) {}
public TestClass(string a, int b) {}
public int A { get; set; }
void F() {
dynamic obj = null;
int i = 0;
int j = 0;
var x = $new TestClass(obj, i) { A = j }$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
Assert.That(rr.InitializerStatements.Count, Is.EqualTo(1));
var or = rr.InitializerStatements[0] as OperatorResolveResult;
Assert.That(or, Is.Not.Null);
Assert.That(or.OperatorType, Is.EqualTo(ExpressionType.Assign));
var mrr = or.Operands[0] as MemberResolveResult;
Assert.That(mrr, Is.Not.Null);
Assert.That(mrr.TargetResult, Is.InstanceOf<InitializedObjectResolveResult>());
Assert.That(mrr.Member.Name, Is.EqualTo("A"));
Assert.That(or.Operands[1], Is.InstanceOf<LocalResolveResult>());
Assert.That(((LocalResolveResult)or.Operands[1]).Variable.Name, Is.EqualTo("j"));
}
[Test]
public void InitializingBaseWithDynamicArgumentAndOneApplicableConstructor() {
string program = @"using System;
class TestBase {
public TestBase(int a, int b) {}
public TestBase(string a) {}
}
class TestClass : TestBase {
private static dynamic d;
private static int i;
public TestClass() : $base(d, i)$ {}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo(".ctor"));
Assert.That(rr.TargetResult, Is.Null);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(2));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestBase"));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Input is MemberResolveResult && ((MemberResolveResult)cr.Input).Member.Name == "d");
Assert.That(rr.Arguments[1] is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1]).Member.Name == "i");
}
[Test]
public void InitializingBaseWithDynamicArgumentAndTwoApplicableConstructors() {
string program = @"using System;
class TestBase {
public TestBase(int a, int b) {}
public TestBase(string a, int b) {}
public TestBase(string a) {}
}
class TestClass : TestBase {
private static dynamic d;
private static int i;
public TestClass() : $base(d, i)$ {}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestBase"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[0].Value).Member.Name == "d");
Assert.That(rr.Arguments[1].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1].Value).Member.Name == "i");
}
[Test]
public void ConstructorChainingWithDynamicArgumentAndOneApplicableConstructor() {
string program = @"using System;
class TestClass {
private static dynamic d;
private static int i;
public TestClass(int a, int b) {}
public TestClass(string a) {}
public TestClass() : $this(d, i)$ {}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.Member.Name, Is.EqualTo(".ctor"));
Assert.That(rr.TargetResult, Is.Null);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(2));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestClass"));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Input is MemberResolveResult && ((MemberResolveResult)cr.Input).Member.Name == "d");
Assert.That(rr.Arguments[1] is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1]).Member.Name == "i");
}
[Test]
public void ConstructorChainingWithDynamicArgumentAndTwoApplicableConstructors() {
string program = @"using System;
class TestBase {
}
class TestClass {
private static dynamic d;
private static int i;
public TestClass(int a, int b) {}
public TestClass(string a, int b) {}
public TestClass(string a) {}
public TestClass() : $this(d, i)$ {}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation));
var mg = rr.Target as MethodGroupResolveResult;
Assert.That(mg, Is.Not.Null, "Expected a MethodGroup");
Assert.That(mg.TargetResult, Is.Null);
Assert.That(mg.MethodName, Is.EqualTo(".ctor"));
Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32"));
Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" }));
Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[0].Value).Member.Name == "d");
Assert.That(rr.Arguments[1].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1].Value).Member.Name == "i");
}
} }
} }

117
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExtensionMethodTests.cs

@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -118,5 +120,120 @@ public static class XC {
Assert.AreEqual(1, inferredTypes.Length); Assert.AreEqual(1, inferredTypes.Length);
Assert.AreEqual("System.String", inferredTypes[0].ReflectionName); Assert.AreEqual("System.String", inferredTypes[0].ReflectionName);
} }
[Test]
public void InferTypeFromOverwrittenMethodArguments()
{
string program = @"using System.Collections.Generic;
using System.Linq;
public class A { }
public class B : A { }
class Program
{
static void Main(string[] args)
{
IEnumerable<B> list = new List<B>();
var arr = $list.ToArray<A>()$;
}
}
";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual("A[]", rr.Type.ReflectionName);
Assert.AreEqual("System.Linq.Enumerable.ToArray", rr.Member.FullName);
Assert.AreEqual("A", ((SpecializedMethod)rr.Member).TypeArguments.Single().ReflectionName);
}
[Test]
public void TypeInferenceBasedOnTargetTypeAndArgumentType()
{
string program = @"using System.Collections.Generic;
using System.Linq;
public class A { }
public class B : A { }
static class Program
{
static void Main(A a, B b)
{
var x = $b.Choose(a)$;
}
public static T Choose<T>(this T a, T b) { }
}
";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual("A", rr.Type.ReflectionName);
}
[Test]
public void PartiallySpecializedMethod()
{
string program = @"using System.Collections.Generic;
using System.Linq;
public class A { }
public class B : A { }
static class Program
{
static void Main(A a, B b)
{
var x = $b.Choose$(a);
}
public static T Choose<T>(this T a, T b) { }
}
";
var rr = Resolve<MethodGroupResolveResult>(program);
Assert.IsFalse(rr.Methods.Any());
// We deliberately do not specialize the method unless partial specialization is requested explicitly.
// This is because the actual type (when considering the whole invocation, not just the method group)
// is actually A.
Assert.AreEqual("``0", rr.GetExtensionMethods().Single().Single().ReturnType.ReflectionName);
Assert.AreEqual("``0", rr.GetEligibleExtensionMethods(false).Single().Single().ReturnType.ReflectionName);
Assert.AreEqual("B", rr.GetEligibleExtensionMethods(true).Single().Single().ReturnType.ReflectionName);
}
[Test]
public void CreateDelegateFromExtensionMethod()
{
string program = @"using System;
static class Program
{
static void Main() {
Func<string> f = $"""".id$;
}
static string id(this string x) { return x; }
}
";
Conversion c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
Assert.AreEqual("Program.id", c.Method.FullName);
}
[Test]
public void InferDelegateTypeFromExtensionMethod()
{
string program = @"using System;
static class Program
{
static void Main() {
$call("""".id)$;
}
static string id(this string x) { return x; }
static T call<T>(Func<T> f) { }
}
";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual("System.String", rr.Type.FullName);
}
} }
} }

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

@ -275,5 +275,46 @@ class Test<T> where T : new() {
Assert.AreEqual(TypeKind.TypeParameter, rr.Type.Kind); Assert.AreEqual(TypeKind.TypeParameter, rr.Type.Kind);
Assert.AreEqual(TypeKind.TypeParameter, rr.Member.DeclaringType.Kind); Assert.AreEqual(TypeKind.TypeParameter, rr.Member.DeclaringType.Kind);
} }
[Test]
public void CreateDelegateFromMethodGroup()
{
string program = @"using System;
delegate void D(int i);
class C {
void M(int y) {
D d = $new D(M)$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Conversion.IsIdentityConversion);
var rr2 = (ConversionResolveResult)rr.Input;
Assert.IsFalse(rr2.IsError);
Assert.IsTrue(rr2.Conversion.IsMethodGroupConversion);
Assert.AreEqual("C.M", rr2.Conversion.Method.FullName);
var mgrr = (MethodGroupResolveResult)rr2.Input;
Assert.IsInstanceOf<ThisResolveResult>(mgrr.TargetResult);
}
[Test]
public void CreateDelegateFromDelegate()
{
string program = @"using System;
delegate void D1(int i);
delegate void D2(int i);
class C {
void M(D1 d1) {
D2 d2 = $new D2(d1)$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Conversion.IsMethodGroupConversion);
Assert.AreEqual("D1.Invoke", rr.Conversion.Method.FullName);
var mgrr = (MethodGroupResolveResult)rr.Input;
Assert.IsInstanceOf<LocalResolveResult>(mgrr.TargetResult);
}
} }
} }

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

@ -148,6 +148,30 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
out success)); out success));
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[Test]
public void IEnumerableCovarianceWithDynamic()
{
ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
var ienumerableOfT = new ParameterizedType(compilation.FindType(typeof(IEnumerable<>)).GetDefinition(), new[] { tp });
var ienumerableOfString = compilation.FindType(typeof(IEnumerable<string>));
var ienumerableOfDynamic = compilation.FindType(typeof(IEnumerable<ReflectionHelper.Dynamic>));
// static T M<T>(IEnumerable<T> x, IEnumerable<T> y) {}
// M(IEnumerable<dynamic>, IEnumerable<string>); -> should infer T=dynamic, no ambiguity
// See http://blogs.msdn.com/b/cburrows/archive/2010/04/01/errata-dynamic-conversions-and-overload-resolution.aspx
// for details.
bool success;
Assert.AreEqual(
new [] { SpecialType.Dynamic },
ti.InferTypeArguments(
new [] { tp },
new [] { new ResolveResult(ienumerableOfDynamic), new ResolveResult(ienumerableOfString) },
new [] { ienumerableOfT, ienumerableOfT },
out success));
Assert.IsTrue(success);
}
#endregion #endregion
#region Inference with Method Groups #region Inference with Method Groups

21
ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs

@ -26,7 +26,6 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation namespace ICSharpCode.NRefactory.Documentation
{ {
[TestFixture] [TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefLookupTests public class CSharpCrefLookupTests
{ {
IEntity Lookup(string cref) IEntity Lookup(string cref)
@ -58,7 +57,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
var pc = new CSharpProjectContent().AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib }); var pc = new CSharpProjectContent().AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib });
var cu = new CSharpParser().Parse(new StringReader(program), "program.cs"); var cu = new CSharpParser().Parse(new StringReader(program), "program.cs");
var compilation = pc.UpdateProjectContent(null, cu.ToTypeSystem()).CreateCompilation(); var compilation = pc.UpdateProjectContent(null, cu.ToTypeSystem()).CreateCompilation();
var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.Single(); var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.First();
IEntity entity = typeDefinition.Documentation.ResolveCref(cref); IEntity entity = typeDefinition.Documentation.ResolveCref(cref);
Assert.IsNotNull(entity, "ResolveCref() returned null."); Assert.IsNotNull(entity, "ResolveCref() returned null.");
return entity; return entity;
@ -109,7 +108,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
[Test] [Test]
public void M() public void M()
{ {
Assert.AreEqual("M:Test.M(System.String[0:,0:])", Assert.AreEqual("M:Test.M(System.Int32)",
IdStringProvider.GetIdString(Lookup("M"))); IdStringProvider.GetIdString(Lookup("M")));
} }
@ -141,19 +140,25 @@ class Impl<T> : IGeneric<List<string>[,], T> {
[Test] [Test]
public void MethodInGenericInterface() public void MethodInGenericInterface()
{ {
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)", Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)",
IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test"))); IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test")));
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)", Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)",
IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}"))); IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}")));
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)", Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)",
IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}(ref Z[,])"))); IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}(ref Z[,])")));
} }
[Test] [Test]
public void Indexer() [Ignore("Fails due to mcs parser bug (see CSharpCrefParserTests.This)")]
public void IndexerWithoutDeclaringType()
{ {
Assert.AreEqual("P:Test.Item(System.Int32)", Assert.AreEqual("P:Test.Item(System.Int32)",
IdStringProvider.GetIdString(Lookup("this"))); IdStringProvider.GetIdString(Lookup("this")));
}
[Test]
public void IndexerWithDeclaringType()
{
Assert.AreEqual("P:Test.Item(System.Int32)", Assert.AreEqual("P:Test.Item(System.Int32)",
IdStringProvider.GetIdString(Lookup("Test.this"))); IdStringProvider.GetIdString(Lookup("Test.this")));
Assert.AreEqual("P:Test.Item(System.Int32)", Assert.AreEqual("P:Test.Item(System.Int32)",
@ -161,6 +166,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
} }
[Test] [Test]
[Ignore("mcs bug, see CSharpCrefParserTests.OperatorPlusWithDeclaringType")]
public void OperatorPlus() public void OperatorPlus()
{ {
Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)", Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)",
@ -172,6 +178,7 @@ class Impl<T> : IGeneric<List<string>[,], T> {
} }
[Test] [Test]
[Ignore("mcs bug, see CSharpCrefParserTests.OperatorPlusWithDeclaringType")]
public void ImplicitOperator() public void ImplicitOperator()
{ {
Assert.AreEqual("M:Test.op_Implicit(Test)~System.Int32", Assert.AreEqual("M:Test.op_Implicit(Test)~System.Int32",

20
ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs

@ -25,7 +25,6 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation namespace ICSharpCode.NRefactory.Documentation
{ {
[TestFixture] [TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefParserTests public class CSharpCrefParserTests
{ {
[Test] [Test]
@ -39,6 +38,7 @@ namespace ICSharpCode.NRefactory.Documentation
} }
[Test] [Test]
[Ignore("mcs bug")]
public void This() public void This()
{ {
ParseUtilCSharp.AssertDocumentationReference( ParseUtilCSharp.AssertDocumentationReference(
@ -49,6 +49,7 @@ namespace ICSharpCode.NRefactory.Documentation
} }
[Test] [Test]
[Ignore("mcs bug (Unexpected symbol `this', expecting `explicit', `implicit', `operator', or `type')")]
public void ThisWithParameter() public void ThisWithParameter()
{ {
ParseUtilCSharp.AssertDocumentationReference( ParseUtilCSharp.AssertDocumentationReference(
@ -115,6 +116,21 @@ namespace ICSharpCode.NRefactory.Documentation
}); });
} }
[Test]
public void IntParse()
{
ParseUtilCSharp.AssertDocumentationReference(
"int.Parse(string)",
new DocumentationReference {
DeclaringType = new PrimitiveType("int"),
MemberName = "Parse",
HasParameterList = true,
Parameters = {
new ParameterDeclaration { Type = new PrimitiveType("string") }
}
});
}
[Test] [Test]
public void Generic() public void Generic()
{ {
@ -201,6 +217,7 @@ namespace ICSharpCode.NRefactory.Documentation
} }
[Test] [Test]
[Ignore("mcs bug (Unexpected symbol `operator', expecting `identifier' or `this')")]
public void OperatorPlusWithDeclaringType() public void OperatorPlusWithDeclaringType()
{ {
ParseUtilCSharp.AssertDocumentationReference( ParseUtilCSharp.AssertDocumentationReference(
@ -256,6 +273,7 @@ namespace ICSharpCode.NRefactory.Documentation
} }
[Test] [Test]
[Ignore("mcs bug (Unexpected symbol `explicit', expecting `identifier' or `this')")]
public void ExplicitOperatorWithParameterListAndDeclaringType() public void ExplicitOperatorWithParameterListAndDeclaringType()
{ {
ParseUtilCSharp.AssertDocumentationReference( ParseUtilCSharp.AssertDocumentationReference(

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

@ -21,6 +21,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework; using NUnit.Framework;
@ -31,12 +32,43 @@ namespace ICSharpCode.NRefactory.TypeSystem
[TestFixture] [TestFixture]
public class GetAllBaseTypesTest public class GetAllBaseTypesTest
{ {
const string corlib = @"
namespace System {
class Object {}
class ValueType {}
class String : System.Collections.Generic.IEnumerable<char>, IComparable<string> {}
class Array : System.Collections.IList, ICloneable {}
interface ICloneable {}
interface IComparable<in T> {}
struct Int32 {}
struct Char {}
}
namespace System.Collections {
interface IEnumerable {}
interface ICollection : IEnumerable {}
interface IList : ICollection {}
interface IDictionary : ICollection {}
}
namespace System.Collections.Generic {
interface IEnumerable<out T> : IEnumerable {}
interface ICollection<T> : IEnumerable<T> {}
interface IList<T> : ICollection<T> {}
interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>> {}
class List<T> : IList, IList<T> {}
class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary {}
struct KeyValuePair<TKey, TValue> {}
}
";
ICompilation compilation; ICompilation compilation;
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{ {
compilation = new SimpleCompilation(CecilLoaderTests.Mscorlib); var parsedFile = new CSharpParser().Parse(corlib, "corlib.cs").ToTypeSystem();
compilation = new CSharpProjectContent().SetAssemblyName("mscorlib").UpdateProjectContent(null, parsedFile).CreateCompilation();
} }
IType[] GetAllBaseTypes(Type type) IType[] GetAllBaseTypes(Type type)
@ -46,7 +78,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
IType[] GetTypes(params Type[] types) IType[] GetTypes(params Type[] types)
{ {
return types.Select(t => compilation.FindType(t)).OrderBy(t => t.ReflectionName).ToArray();; return types.Select(t => compilation.FindType(t)).OrderBy(t => t.ReflectionName).ToArray();
} }
ITypeDefinition Resolve(IUnresolvedTypeDefinition typeDef) ITypeDefinition Resolve(IUnresolvedTypeDefinition typeDef)
@ -58,24 +90,26 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void ObjectBaseTypes() public void ObjectBaseTypes()
{ {
Assert.AreEqual(GetTypes(typeof(object)), GetAllBaseTypes(typeof(object))); Assert.AreEqual(GetTypes(typeof(object)), GetAllBaseTypes(typeof(object)));
Assert.That(compilation.FindType(KnownTypeCode.Object).DirectBaseTypes, Is.Empty);
} }
[Test] [Test]
public void StringBaseTypes() public void StringBaseTypes()
{ {
Assert.AreEqual(GetTypes(typeof(string), typeof(object), typeof(IComparable), typeof(ICloneable), typeof(IConvertible), Assert.AreEqual(GetTypes(typeof(string), typeof(object),
typeof(IComparable<string>), typeof(IEquatable<string>), typeof(IEnumerable<char>), typeof(IEnumerable)), typeof(IComparable<string>), typeof(IEnumerable<char>), typeof(IEnumerable)),
GetAllBaseTypes(typeof(string))); GetAllBaseTypes(typeof(string)));
} }
[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), var expectedTypes = GetTypes(
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(string[]), typeof(Array), typeof(object),
typeof(IList<string>), typeof(ICollection<string>), typeof(IEnumerable<string>), typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)), typeof(IList<string>), typeof(ICollection<string>), typeof(IEnumerable<string>));
Assert.AreEqual(expectedTypes,
GetAllBaseTypes(typeof(string[]))); GetAllBaseTypes(typeof(string[])));
} }
@ -83,8 +117,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public unsafe void ArrayOfPointers() public unsafe void ArrayOfPointers()
{ {
Assert.AreEqual(GetTypes(typeof(int*[]), typeof(Array), typeof(object), Assert.AreEqual(GetTypes(typeof(int*[]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable)),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
GetAllBaseTypes(typeof(int*[]))); GetAllBaseTypes(typeof(int*[])));
} }
@ -92,8 +125,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void MultidimensionalArrayOfString() public void MultidimensionalArrayOfString()
{ {
Assert.AreEqual(GetTypes(typeof(string[,]), typeof(Array), typeof(object), Assert.AreEqual(GetTypes(typeof(string[,]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable)),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
GetAllBaseTypes(typeof(string[,]))); GetAllBaseTypes(typeof(string[,])));
} }
@ -175,7 +207,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
[Test] [Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypesOfListOfString() public void BaseTypesOfListOfString()
{ {
Assert.AreEqual( Assert.AreEqual(
@ -186,7 +217,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
[Test] [Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypesOfUnboundDictionary() public void BaseTypesOfUnboundDictionary()
{ {
Assert.AreEqual( Assert.AreEqual(
@ -198,15 +228,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
typeof(ICollection).FullName, typeof(ICollection).FullName,
typeof(IDictionary).FullName, typeof(IDictionary).FullName,
typeof(IEnumerable).FullName, typeof(IEnumerable).FullName,
typeof(object).FullName, typeof(object).FullName
typeof(IDeserializationCallback).FullName,
typeof(ISerializable).FullName,
}, },
GetAllBaseTypes(typeof(Dictionary<,>)).Select(t => t.ReflectionName).ToArray()); GetAllBaseTypes(typeof(Dictionary<,>)).Select(t => t.ReflectionName).OrderBy(n => n).ToArray());
} }
[Test] [Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypeDefinitionsOfListOfString() public void BaseTypeDefinitionsOfListOfString()
{ {
Assert.AreEqual( Assert.AreEqual(
@ -217,12 +244,10 @@ 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(
GetTypes(typeof(Array), typeof(object), GetTypes(typeof(Array), typeof(object), typeof(ICloneable),
typeof(ICloneable), typeof(IStructuralComparable), typeof(IStructuralEquatable),
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)), typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)),
compilation.FindType(typeof(string[])).GetAllBaseTypeDefinitions().OrderBy(t => t.ReflectionName).ToArray()); compilation.FindType(typeof(string[])).GetAllBaseTypeDefinitions().OrderBy(t => t.ReflectionName).ToArray());

17
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -44,6 +44,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
public class ParamsAttribute : Attribute public class ParamsAttribute : Attribute
{ {
public ParamsAttribute(params object[] x) {} public ParamsAttribute(params object[] x) {}
[Params(Property = new string[] { "a", "b" })]
public string[] Property { get; set; }
} }
[Double(1)] [Double(1)]
@ -291,4 +294,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
public class ClassThatImplementsEventExplicitly : IHasEvent { public class ClassThatImplementsEventExplicitly : IHasEvent {
event EventHandler IHasEvent.Event { add {} remove {} } event EventHandler IHasEvent.Event { add {} remove {} }
} }
public interface IShadowTestBase {
void Method();
int this[int i] { get; set; }
int Prop { get; set; }
event EventHandler Evt;
}
public interface IShadowTestDerived : IShadowTestBase {
new void Method();
new int this[int i] { get; set; }
new int Prop { get; set; }
new event EventHandler Evt;
}
} }

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

@ -821,6 +821,23 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual("Test", rr.Input.ConstantValue); Assert.AreEqual("Test", rr.Input.ConstantValue);
} }
[Test]
public void ParamsAttribute_Property()
{
ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute));
IProperty prop = type.Properties.Single(p => p.Name == "Property");
var attr = prop.Attributes.Single();
Assert.AreEqual(type, attr.AttributeType);
var normalArguments = ((ArrayCreateResolveResult)attr.PositionalArguments.Single()).InitializerElements;
Assert.AreEqual(0, normalArguments.Count);
var namedArg = attr.NamedArguments.Single();
Assert.AreEqual(prop, namedArg.Key);
var arrayElements = ((ArrayCreateResolveResult)namedArg.Value).InitializerElements;
Assert.AreEqual(2, arrayElements.Count);
}
[Test] [Test]
public void DoubleAttribute_ImplicitNumericConversion() public void DoubleAttribute_ImplicitNumericConversion()
{ {
@ -978,6 +995,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void ExplicitIndexerImplementationReturnsTheCorrectMembers() { public void ExplicitIndexerImplementationReturnsTheCorrectMembers() {
ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsIndexersExplicitly)); ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsIndexersExplicitly));
Assert.That(type.Properties.All(p => p.EntityType == EntityType.Indexer));
Assert.That(type.Properties.All(p => p.ImplementedInterfaceMembers.Count == 1)); Assert.That(type.Properties.All(p => p.ImplementedInterfaceMembers.Count == 1));
Assert.That(type.Properties.All(p => p.Getter.ImplementedInterfaceMembers.Count == 1)); Assert.That(type.Properties.All(p => p.Getter.ImplementedInterfaceMembers.Count == 1));
Assert.That(type.Properties.All(p => p.Setter.ImplementedInterfaceMembers.Count == 1)); Assert.That(type.Properties.All(p => p.Setter.ImplementedInterfaceMembers.Count == 1));
@ -1094,5 +1112,25 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.That(evt.AddAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.NRefactory.TypeSystem.TestCase.IHasEvent.add_Event" })); Assert.That(evt.AddAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.NRefactory.TypeSystem.TestCase.IHasEvent.add_Event" }));
Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.NRefactory.TypeSystem.TestCase.IHasEvent.remove_Event" })); Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.NRefactory.TypeSystem.TestCase.IHasEvent.remove_Event" }));
} }
[Test]
public void MembersDeclaredInDerivedInterfacesDoNotImplementBaseMembers() {
ITypeDefinition type = GetTypeDefinition(typeof(IShadowTestDerived));
var method = type.Methods.Single(m => m.Name == "Method");
var indexer = type.Properties.Single(p => p.IsIndexer);
var prop = type.Properties.Single(p => p.Name == "Prop");
var evt = type.Events.Single(e => e.Name == "Evt");
Assert.That(method.ImplementedInterfaceMembers, Is.Empty);
Assert.That(indexer.ImplementedInterfaceMembers, Is.Empty);
Assert.That(indexer.Getter.ImplementedInterfaceMembers, Is.Empty);
Assert.That(indexer.Setter.ImplementedInterfaceMembers, Is.Empty);
Assert.That(prop.ImplementedInterfaceMembers, Is.Empty);
Assert.That(prop.Getter.ImplementedInterfaceMembers, Is.Empty);
Assert.That(prop.Setter.ImplementedInterfaceMembers, Is.Empty);
Assert.That(evt.ImplementedInterfaceMembers, Is.Empty);
Assert.That(evt.AddAccessor.ImplementedInterfaceMembers, Is.Empty);
Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers, Is.Empty);
}
} }
} }

2
ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs

@ -23,4 +23,4 @@ using System.Runtime.InteropServices;
// [AssemblyFileVersion] is the version of the NuGet package, // [AssemblyFileVersion] is the version of the NuGet package,
// should follow http://semver.org/ rules // should follow http://semver.org/ rules
[assembly: AssemblyFileVersion("5.0.1")] [assembly: AssemblyFileVersion("5.1.0")]

16
ICSharpCode.NRefactory/Semantics/Conversion.cs

@ -185,6 +185,14 @@ namespace ICSharpCode.NRefactory.Semantics
get { return type == 0; } get { return type == 0; }
} }
public override bool IsNullLiteralConversion {
get { return type == 1; }
}
public override bool IsConstantExpressionConversion {
get { return type == 2; }
}
public override bool IsReferenceConversion { public override bool IsReferenceConversion {
get { return type == 3; } get { return type == 3; }
} }
@ -365,6 +373,14 @@ namespace ICSharpCode.NRefactory.Semantics
get { return false; } get { return false; }
} }
public virtual bool IsNullLiteralConversion {
get { return false; }
}
public virtual bool IsConstantExpressionConversion {
get { return false; }
}
public virtual bool IsNumericConversion { public virtual bool IsNumericConversion {
get { return false; } get { return false; }
} }

2
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.NRefactory.Semantics
/// <summary> /// <summary>
/// Represents the result of a member invocation. /// Represents the result of a member invocation.
/// Used for field/property/event access. /// Used for field/property/event access.
/// Also, <see cref="InvocationResultResult"/> derives from MemberResolveResult. /// Also, <see cref="InvocationResolveResult"/> derives from MemberResolveResult.
/// </summary> /// </summary>
public class MemberResolveResult : ResolveResult public class MemberResolveResult : ResolveResult
{ {

79
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -99,6 +99,21 @@ namespace ICSharpCode.NRefactory.TypeSystem
this.InterningProvider = new SimpleInterningProvider(); this.InterningProvider = new SimpleInterningProvider();
} }
/// <summary>
/// Creates a nested CecilLoader for lazy-loading.
/// </summary>
private CecilLoader(CecilLoader loader)
{
// use a shared typeSystemTranslationTable
this.typeSystemTranslationTable = loader.typeSystemTranslationTable;
this.IncludeInternalMembers = loader.IncludeInternalMembers;
this.LazyLoad = loader.LazyLoad;
this.currentModule = loader.currentModule;
this.currentAssembly = loader.currentAssembly;
// don't use interning - the interning provider is most likely not thread-safe
// don't use cancellation for delay-loaded members
}
#region Load From AssemblyDefinition #region Load From AssemblyDefinition
/// <summary> /// <summary>
/// Loads the assembly definition into a project content. /// Loads the assembly definition into a project content.
@ -124,6 +139,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
this.currentAssembly = new CecilUnresolvedAssembly(assemblyDefinition.Name.Name, this.DocumentationProvider); this.currentAssembly = new CecilUnresolvedAssembly(assemblyDefinition.Name.Name, this.DocumentationProvider);
currentAssembly.Location = assemblyDefinition.MainModule.FullyQualifiedName;
currentAssembly.AssemblyAttributes.AddRange(assemblyAttributes); currentAssembly.AssemblyAttributes.AddRange(assemblyAttributes);
currentAssembly.ModuleAttributes.AddRange(assemblyAttributes); currentAssembly.ModuleAttributes.AddRange(assemblyAttributes);
@ -133,6 +149,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
int typeParameterCount; int typeParameterCount;
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
var typeRef = new GetClassTypeReference(GetAssemblyReference(type.Scope), type.Namespace, name, typeParameterCount); var typeRef = new GetClassTypeReference(GetAssemblyReference(type.Scope), type.Namespace, name, typeParameterCount);
if (this.InterningProvider != null)
typeRef = this.InterningProvider.Intern(typeRef); typeRef = this.InterningProvider.Intern(typeRef);
var key = new FullNameAndTypeParameterCount(type.Namespace, name, typeParameterCount); var key = new FullNameAndTypeParameterCount(type.Namespace, name, typeParameterCount);
currentAssembly.AddTypeForwarder(key, typeRef); currentAssembly.AddTypeForwarder(key, typeRef);
@ -140,6 +157,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
// Create and register all types: // Create and register all types:
CecilLoader cecilLoaderCloneForLazyLoading = LazyLoad ? new CecilLoader(this) : null;
List<TypeDefinition> cecilTypeDefs = new List<TypeDefinition>(); List<TypeDefinition> cecilTypeDefs = new List<TypeDefinition>();
List<DefaultUnresolvedTypeDefinition> typeDefs = new List<DefaultUnresolvedTypeDefinition>(); List<DefaultUnresolvedTypeDefinition> typeDefs = new List<DefaultUnresolvedTypeDefinition>();
foreach (ModuleDefinition module in assemblyDefinition.Modules) { foreach (ModuleDefinition module in assemblyDefinition.Modules) {
@ -150,6 +168,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (name.Length == 0) if (name.Length == 0)
continue; continue;
if (this.LazyLoad) {
currentAssembly.AddTypeDefinition(new LazyCecilTypeDefinition(cecilLoaderCloneForLazyLoading, td));
} else {
var t = CreateTopLevelTypeDefinition(td); var t = CreateTopLevelTypeDefinition(td);
cecilTypeDefs.Add(td); cecilTypeDefs.Add(td);
typeDefs.Add(t); typeDefs.Add(t);
@ -157,13 +178,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
} }
} }
}
// Initialize the type's members: // Initialize the type's members:
for (int i = 0; i < typeDefs.Count; i++) { for (int i = 0; i < typeDefs.Count; i++) {
InitTypeDefinition(cecilTypeDefs[i], typeDefs[i]); InitTypeDefinition(cecilTypeDefs[i], typeDefs[i]);
} }
if (HasCecilReferences) RegisterCecilObject(this.currentAssembly, assemblyDefinition);
typeSystemTranslationTable[this.currentAssembly] = assemblyDefinition;
var result = this.currentAssembly; var result = this.currentAssembly;
this.currentAssembly = null; this.currentAssembly = null;
@ -229,8 +250,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
var param = new ReaderParameters { AssemblyResolver = new DummyAssemblyResolver() }; var param = new ReaderParameters { AssemblyResolver = new DummyAssemblyResolver() };
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(fileName, param); AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(fileName, param);
var result = LoadAssembly(asm); var result = LoadAssembly(asm);
if (HasCecilReferences) RegisterCecilObject(result, asm);
typeSystemTranslationTable[result] = asm;
return result; return result;
} }
@ -1175,7 +1195,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
public KeyValuePair<IMember, ResolveResult> ReadNamedArg(IType attributeType) public KeyValuePair<IMember, ResolveResult> ReadNamedArg(IType attributeType)
{ {
EntityType memberType; EntityType memberType;
switch (ReadByte()) { var b = ReadByte();
switch (b) {
case 0x53: case 0x53:
memberType = EntityType.Field; memberType = EntityType.Field;
break; break;
@ -1183,7 +1204,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
memberType = EntityType.Property; memberType = EntityType.Property;
break; break;
default: default:
throw new NotSupportedException(); throw new NotSupportedException(string.Format("Custom member type 0x{0:x} is not supported.", b));
} }
IType type = ReadCustomAttributeFieldOrPropType(); IType type = ReadCustomAttributeFieldOrPropType();
string name = ReadSerString(); string name = ReadSerString();
@ -1499,12 +1520,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
td.AddDefaultConstructorIfRequired = (td.Kind == TypeKind.Struct || td.Kind == TypeKind.Enum); td.AddDefaultConstructorIfRequired = (td.Kind == TypeKind.Struct || td.Kind == TypeKind.Enum);
InitMembers(typeDefinition, td, td.Members); InitMembers(typeDefinition, td, td.Members);
if (HasCecilReferences)
typeSystemTranslationTable[td] = typeDefinition;
if (this.InterningProvider != null) { if (this.InterningProvider != null) {
td.ApplyInterningProvider(this.InterningProvider); td.ApplyInterningProvider(this.InterningProvider);
} }
td.Freeze(); td.Freeze();
RegisterCecilObject(td, typeDefinition);
} }
void InitBaseTypes(TypeDefinition typeDefinition, IList<ITypeReference> baseTypes) void InitBaseTypes(TypeDefinition typeDefinition, IList<ITypeReference> baseTypes)
@ -1656,7 +1676,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
bool getterVisible = property.GetMethod != null && IsVisible(property.GetMethod.Attributes); bool getterVisible = property.GetMethod != null && IsVisible(property.GetMethod.Attributes);
bool setterVisible = property.SetMethod != null && IsVisible(property.SetMethod.Attributes); bool setterVisible = property.SetMethod != null && IsVisible(property.SetMethod.Attributes);
if (getterVisible || setterVisible) { if (getterVisible || setterVisible) {
EntityType type = property.Name == defaultMemberName ? EntityType.Indexer : EntityType.Property; EntityType type = EntityType.Property;
if (property.HasParameters) {
// Try to detect indexer:
if (property.Name == defaultMemberName) {
type = EntityType.Indexer; // normal indexer
} else if (property.Name.EndsWith(".Item", StringComparison.Ordinal) && (property.GetMethod ?? property.SetMethod).HasOverrides) {
// explicit interface implementation of indexer
type = EntityType.Indexer;
// We can't really tell parameterized properties and indexers apart in this case without
// resolving the interface, so we rely on the "Item" naming convention instead.
}
}
members.Add(ReadProperty(property, td, type)); members.Add(ReadProperty(property, td, type));
} }
} }
@ -1707,12 +1738,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
loader.AddAttributes(typeDefinition, this); loader.AddAttributes(typeDefinition, this);
flags[FlagHasExtensionMethods] = HasExtensionAttribute(typeDefinition); flags[FlagHasExtensionMethods] = HasExtensionAttribute(typeDefinition);
if (loader.HasCecilReferences)
loader.typeSystemTranslationTable[this] = typeDefinition;
if (loader.InterningProvider != null) { if (loader.InterningProvider != null) {
this.ApplyInterningProvider(loader.InterningProvider); this.ApplyInterningProvider(loader.InterningProvider);
} }
this.Freeze(); this.Freeze();
loader.RegisterCecilObject(this, typeDefinition);
} }
public override string Namespace { public override string Namespace {
@ -1720,6 +1750,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }
} }
public override string FullName {
// This works because LazyCecilTypeDefinition is only used for top-level types
get { return cecilTypeDef.FullName; }
}
public override string ReflectionName {
get { return cecilTypeDef.FullName; }
}
public TypeKind Kind { public TypeKind Kind {
get { return kind; } get { return kind; }
} }
@ -2123,14 +2162,24 @@ namespace ICSharpCode.NRefactory.TypeSystem
void FinishReadMember(AbstractUnresolvedMember member, object cecilDefinition) void FinishReadMember(AbstractUnresolvedMember member, object cecilDefinition)
{ {
if (this.InterningProvider != null)
member.ApplyInterningProvider(this.InterningProvider); member.ApplyInterningProvider(this.InterningProvider);
member.Freeze(); member.Freeze();
if (HasCecilReferences) RegisterCecilObject(member, cecilDefinition);
typeSystemTranslationTable[member] = cecilDefinition;
} }
#region Type system translation table #region Type system translation table
Dictionary<object, object> typeSystemTranslationTable; readonly Dictionary<object, object> typeSystemTranslationTable;
void RegisterCecilObject(object typeSystemObject, object cecilObject)
{
if (typeSystemTranslationTable != null) {
// When lazy-loading, the dictionary might be shared between multiple cecil-loaders that are used concurrently
lock (typeSystemTranslationTable) {
typeSystemTranslationTable[typeSystemObject] = cecilObject;
}
}
}
T InternalGetCecilObject<T> (object typeSystemObject) where T : class T InternalGetCecilObject<T> (object typeSystemObject) where T : class
{ {
@ -2139,8 +2188,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (!HasCecilReferences) if (!HasCecilReferences)
throw new NotSupportedException ("This instance contains no cecil references."); throw new NotSupportedException ("This instance contains no cecil references.");
object result; object result;
lock (typeSystemTranslationTable) {
if (!typeSystemTranslationTable.TryGetValue (typeSystemObject, out result)) if (!typeSystemTranslationTable.TryGetValue (typeSystemObject, out result))
return null; return null;
}
return result as T; return result as T;
} }

6
ICSharpCode.NRefactory/TypeSystem/IAssembly.cs

@ -31,6 +31,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
string AssemblyName { get; } string AssemblyName { get; }
/// <summary>
/// Gets the path to the assembly location.
/// For projects it is the same as the output path.
/// </summary>
string Location { get; }
/// <summary> /// <summary>
/// Gets the list of all assembly attributes in the project. /// Gets the list of all assembly attributes in the project.
/// </summary> /// </summary>

5
ICSharpCode.NRefactory/TypeSystem/INamespace.cs

@ -62,6 +62,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
IEnumerable<ITypeDefinition> Types { get; } IEnumerable<ITypeDefinition> Types { get; }
/// <summary>
/// Gets the assemblies that contribute types to this namespace (or to child namespaces).
/// </summary>
IEnumerable<IAssembly> ContributingAssemblies { get; }
/// <summary> /// <summary>
/// Gets a direct child namespace by its short name. /// Gets a direct child namespace by its short name.
/// Returns null when the namespace cannot be found. /// Returns null when the namespace cannot be found.

5
ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs

@ -70,6 +70,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
IProjectContent SetAssemblyName(string newAssemblyName); IProjectContent SetAssemblyName(string newAssemblyName);
/// <summary>
/// Changes the location of this project content.
/// </summary>
IProjectContent SetLocation(string newLocation);
/// <summary> /// <summary>
/// Add assembly references to this project content. /// Add assembly references to this project content.
/// </summary> /// </summary>

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

@ -76,7 +76,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
result.Add(member); result.Add(member);
} }
return result.ToArray(); return result.ToArray();
} else if (unresolved.IsStatic) { } else if (unresolved.IsStatic || DeclaringTypeDefinition == null || DeclaringTypeDefinition.Kind == TypeKind.Interface) {
return EmptyList<IMember>.Instance; return EmptyList<IMember>.Instance;
} else { } else {
// TODO: implement interface member mappings correctly // TODO: implement interface member mappings correctly

25
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs

@ -19,6 +19,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -217,6 +219,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public override string ToString()
{
StringBuilder b = new StringBuilder("[");
b.Append(this.EntityType);
b.Append(' ');
b.Append(this.DeclaringType.ReflectionName);
b.Append('.');
b.Append(this.Name);
if (this.TypeParameters.Count > 0) {
b.Append("``");
b.Append(this.TypeParameters.Count);
}
b.Append('(');
for (int i = 0; i < this.Parameters.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(this.Parameters[i].ToString());
}
b.Append("):");
b.Append(this.ReturnType.ReflectionName);
b.Append(']');
return b.ToString();
}
/// <summary> /// <summary>
/// Gets a dummy constructor for the specified compilation. /// Gets a dummy constructor for the specified compilation.
/// </summary> /// </summary>

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

@ -70,6 +70,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
string location;
public string Location {
get {
return location;
}
set {
FreezableHelper.ThrowIfFrozen(this);
location = value;
}
}
public IList<IUnresolvedAttribute> AssemblyAttributes { public IList<IUnresolvedAttribute> AssemblyAttributes {
get { return assemblyAttributes; } get { return assemblyAttributes; }
} }
@ -367,6 +378,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return parentNamespace; } get { return parentNamespace; }
} }
IEnumerable<IAssembly> INamespace.ContributingAssemblies {
get { return new [] { assembly }; }
}
IEnumerable<INamespace> INamespace.ChildNamespaces { IEnumerable<INamespace> INamespace.ChildNamespaces {
get { return childNamespaces; } get { return childNamespaces; }
} }

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

@ -20,7 +20,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -96,6 +95,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return compilation; } get { return compilation; }
} }
public IEnumerable<IAssembly> ContributingAssemblies {
get { return namespaces.SelectMany(ns => ns.ContributingAssemblies); }
}
public IEnumerable<INamespace> ChildNamespaces { public IEnumerable<INamespace> ChildNamespaces {
get { return GetChildNamespaces().Values; } get { return GetChildNamespaces().Values; }
} }

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

@ -195,6 +195,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append(this.TypeArguments[i].ReflectionName); b.Append(this.TypeArguments[i].ReflectionName);
} }
b.Append(']'); b.Append(']');
} else if (this.TypeParameters.Count > 0) {
b.Append("``");
b.Append(this.TypeParameters.Count);
} }
b.Append('('); b.Append('(');
for (int i = 0; i < this.Parameters.Count; i++) { for (int i = 0; i < this.Parameters.Count; i++) {

4
Packages/ICSharpCode.NRefactory.nuspec

@ -2,9 +2,9 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata> <metadata>
<id>ICSharpCode.NRefactory</id> <id>ICSharpCode.NRefactory</id>
<version>5.0.1</version> <version>5.1.0</version>
<title>NRefactory</title> <title>NRefactory</title>
<authors>Daniel Grunwald, Mike Krüger</authors> <authors>Daniel Grunwald, Mike Krüger, Erik Källén</authors>
<owners>Daniel Grunwald</owners> <owners>Daniel Grunwald</owners>
<licenseUrl>http://www.opensource.org/licenses/mit-license.php</licenseUrl> <licenseUrl>http://www.opensource.org/licenses/mit-license.php</licenseUrl>
<projectUrl>https://github.com/icsharpcode/NRefactory/</projectUrl> <projectUrl>https://github.com/icsharpcode/NRefactory/</projectUrl>

Loading…
Cancel
Save